OpenHarmony折疊展開動效開發(fā)—使用List組件中的Groupcollapse和Groupexpand
折疊展開動效
場景介紹
由于目前移動端需要展示的內(nèi)容越來越多,但是移動端的空間彌足珍貴,在有限的空間內(nèi)不可能羅列展示全部種類內(nèi)容,因此折疊/展開功能就可以解決當(dāng)前問題,本文就介紹下如何使用ArkTS來實現(xiàn)折疊展開動效。
效果呈現(xiàn)
折疊展開動效定義:點擊展開按鈕,下拉動畫展示內(nèi)容,點擊折疊按鈕,折疊動畫折疊內(nèi)容。
本例最終效果如下:
運行環(huán)境
本例基于以下環(huán)境開發(fā),開發(fā)者也可以基于其它適配的版本進行開發(fā):
- IDE: DevEco Studio 3.1 Release。
- SDK: Ohos_sdk_public 3.2.12.5(API Version 9 Release)。
實現(xiàn)思路
創(chuàng)建折疊時的文本組件,根據(jù)List組件中的groupcollapse和groupexpand事件自定義一個CollapseAndExpand組件,父組件通過維護flag和onFlagChange來控制折疊/展開的動效,設(shè)置動效所需的參數(shù),添加邏輯來展示展開后的文本。
開發(fā)步驟
創(chuàng)建自定義接口IRowItem。
具體代碼如下:
interface IRowItem {
id?: number;
title?: string;
name1?: string;
name2?: string;
name3?: string;
flag?: boolean;
type?: string;
onFlagChange?: () => void;
}
創(chuàng)建自定義組件CollapseAndExpandDemo,根據(jù)自定義接口IRowItem添加內(nèi)容,創(chuàng)建UI展示文本。
具體代碼如下:
@Entry
@Component{
...
build() {
Column() {
Row() {
Image($r("app.media.ic_public_back"))
.width(20)
.height(20)
Text('周免英雄')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ left: 10 })
}
.width('100%')
.margin({ bottom: 30 })
Column() {
RowItem({ props: { title: 'AAAAA', name1: 'BBBBB', name2: 'CCCCC', name3: '武器大師' } })
// 文本折疊時,type為DOWN
RowItem({ props: { name1: 'DDDDD', name2: 'EEEEE', name3: 'FFFFF', type: 'DOWN', onFlagChange: this.onFlagChange } })
//被折疊的文本內(nèi)容
...
RowItem({ props: { title: '商城', name1: '免費', name2: '特價', name3: 'VIP' } })
RowItem({ props: { title: '分類', name1: '按職業(yè)', name2: '按位置', name3: '按城市' } })
}
.width('100%')
}
被折疊文本信息。
具體代碼如下:
CollapseAndExpand({
items: [
{ id: 0, name1: 'GGGGG', name2: 'HHHHH', name3: 'JJJJJ' },
{ id: 1, name1: 'KKKKK', name2: 'LLLLL', name3: 'MMMMM' },
{ id: 2, name1: 'NNNNN', name2: 'OOOOO', name3: 'PPPPP' },
// 文本展開時,type為UP
{ id: 3, name1: 'QQQQQ', name2: 'RRRRR', name3: 'SSSSS', type: 'UP', onFlagChange: this.onFlagChange }
],
})
將步驟2創(chuàng)建的文本進行渲染。
具體如下:
build() {
Flex() {
Text(this.props.title)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
.fontColor(Color.Red)
.margin({ right: 10 })
Flex({ alignItems: ItemAlign.Center }) {
Text(this.props.name1).fontSize(14).margin({ right: 10 })
Text(this.props.name2).fontSize(14).margin({ right: 10 })
Text(this.props.name3).fontSize(14).margin({ right: 10 })
...
}
}
}
創(chuàng)建自定義組件CollapseAndExpand。
根據(jù)自定義組件說明動效,@Provide負責(zé)數(shù)據(jù)更新,并且觸發(fā)渲染;@Consume在感知數(shù)據(jù)更新后,重新渲染。
具體代碼如下:
@Entry
@Component
struct CollapseAndExpandDemo {
@Provide("flag") flag: boolean = false
private onFlagChange = () => {
animateTo({
duration: 650,
curve: Curve.Smooth
}, () => {
this.flag = !this.flag;
})
}
...
@Component
struct CollapseAndExpand {
private items: IRowItem[] = [];
@Consume("flag") flag: boolean;
build() {
Column() {
ForEach(this.items, (item: IRowItem) => {
RowItem({ props: item })
}, (item: IRowItem) => item.id.toString())
}
.width('100%')
.clip(true)
.height(this.flag ? 130 : 0)
}
}
根據(jù)步驟4最終的flag以及props的type值,判斷折疊展開的效果實現(xiàn)。
具體代碼如下:
build() {
...
// 當(dāng)文本折疊(flag為false且type為down)時,展示展開按鈕
// 當(dāng)文本展開(flag為true且type為up)時,展示折疊按鈕
if (!this.flag && this.props.type === 'DOWN' || this.flag && this.props.type === 'UP') {
Image($r("app.media.icon"))
.width(16)
.height(16)
.objectFit(ImageFit.Contain)
.rotate({ angle: !this.flag && this.props.type === 'DOWN' ? 0 : 180 })
// 點擊按鈕后旋轉(zhuǎn)180°,展示折疊按鈕
.onClick(() =>
this.props.onFlagChange()
)
.transition({ type: TransitionType.All, opacity: 0 })
}
}
完整代碼
示例代碼如下:
interface IRowItem {
id?: number;
title?: string;
name1?: string;
name2?: string;
name3?: string;
flag?: boolean;
type?: string;
onFlagChange?: () => void;
}
@Entry
@Component
struct CollapseAndExpandDemo {
@Provide("flag") flag: boolean = false
private onFlagChange = () => {
animateTo({
duration: 650,
curve: Curve.Smooth
}, () => {
this.flag = !this.flag;
})
}
build() {
Column() {
Row() {
Image($r("app.media.ic_public_back")).width(20).height(20)
Text('周免英雄')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.margin({ left: 10 })
}
.width('100%')
.margin({ bottom: 30 })
Column() {
RowItem({
props: { title: '英雄', name1: 'AAAAA', name2: 'BBBBB', name3: 'CCCCC' } })
RowItem({
props: {
name1: 'DDDDD',
name2: 'EEEEE',
name3: 'FFFFF',
// 文本折疊時,type為DOWN
type: 'DOWN',
onFlagChange: this.onFlagChange
}
})
// 直接調(diào)用折疊展開組件
CollapseAndExpand({
items: [
{ id: 0, name1: 'GGGGG', name2: 'HHHHH', name3: 'JJJJJ' },
{ id: 1, name1: 'KKKKK', name2: 'LLLLL', name3: 'MMMMM' },
{ id: 2, name1: 'NNNNN', name2: 'OOOOO', name3: 'PPPPP' },
{ id: 3,
name1: 'QQQQQ',
name2: 'RRRRR',
name3: 'SSSSS',
// 文本折疊時,type為UP
type: 'UP',
onFlagChange: this.onFlagChange }
],
})
RowItem({ props: { title: '商城', name1: '免費', name2: '特價', name3: 'VIP' } })
RowItem({ props: { title: '分類', name1: '按職業(yè)', name2: '按位置', name3: '按城市' } })
}
.width('100%')
}
.height('100%')
.padding({ top: 30, right: 30, left: 30 })
}
}
@Component
struct RowItem {
private props: IRowItem;
@Consume("flag") flag: boolean
build() {
Flex() {
Text(this.props.title)
.fontSize(14)
.fontWeight(FontWeight.Bold)
.layoutWeight(1)
.fontColor(Color.Red)
.margin({ right: 10 })
Flex({ alignItems: ItemAlign.Center }) {
Text(this.props.name1).fontSize(14).margin({ right: 10 })
Text(this.props.name2).fontSize(14).margin({ right: 10 })
Text(this.props.name3).fontSize(14).margin({ right: 10 })
// 當(dāng)文本折疊(flag為false且type為down)時,展示展開按鈕
// 當(dāng)文本展開(flag為true且type為up)時,展示折疊按鈕
if (!this.flag && this.props.type === 'DOWN' || this.flag && this.props.type === 'UP') {
Image($r("app.media.ic_public_arrow_down_0"))
.width(16)
.height(16)
.objectFit(ImageFit.Contain)
.rotate({ angle: !this.flag && this.props.type === 'DOWN' ? 0 : 180 })
// 點擊展開按鈕后旋轉(zhuǎn)180°,展示折疊按鈕
.onClick(() => this.props.onFlagChange())
.transition({ type: TransitionType.All, opacity: 0 })
}
}
.layoutWeight(3)
}
.width('100%')
.height(16)
.margin({ top: 15 })
}
}
@Component
struct CollapseAndExpand {
private items: IRowItem[] = [];
@Consume("flag") flag: boolean;
build() {
Column() {
ForEach(this.items, (item: IRowItem) => {
RowItem({ props: item })
}, (item: IRowItem) => item.id.toString())
}
.width('100%')
.clip(true)
.height(this.flag ? 130 : 0)
}
}