HarmonyOS鸿蒙Next中list的子条目item中子组件点击旋转动画
HarmonyOS鸿蒙Next中list的子条目item中子组件点击旋转动画
@Builder
itemHeader(index: number, str: string, isExpand: boolean) {
Row() {
Text(str + JSON.stringify(isExpand))
.fontColor(Color.Red)
.padding(6)
Button() {
Image($r('sys.media.ohos_ic_public_arrow_down'))
.width(24)
.height(24)
.fillColor('#3F72AF')
.rotate({ angle: isExpand ? 90 : 0 })
}
.width(36)
.height(36)
.backgroundColor(Color.Transparent)
.onClick(() => {
let bol = this.dataSource.getData(index).isExpand
this.dataSource.getData(index).isExpand = !bol
this.dataSource.notifyDataChange(index)
})
}
.justifyContent(FlexAlign.SpaceBetween)
.width('100%')
.backgroundColor(Color.Orange)
}
如何实现点击之后, 图片旋转的动画
更多关于HarmonyOS鸿蒙Next中list的子条目item中子组件点击旋转动画的实战教程也可以访问 https://www.itying.com/category-93-b0.html
如有复杂需求,可参考组件旋转动效实现。下面给出简单实现:
@Entry
@Component
struct Index {
uiContext: UIContext = this.getUIContext()
private images: Resource[] = [$r('app.media.xxx'), $r('app.media.xxx'), $r('app.media.xxx')]
@State angles: number[] = [0, 0, 0]
build() {
Column() {
List() {
ForEach(this.images, (item: Resource, index: number) => {
ListItem() {
Image(item)
.size({width: 40, height: 40})
.onClick(() => {
this.uiContext.animateTo({
duration: 1000,
curve: Curve.Linear
}, () => {
this.angles[index] += 90
})
})
.rotate({angle: this.angles[index]})
}
})
}
.size({width: 50, height: 50})
}
}
}
更多关于HarmonyOS鸿蒙Next中list的子条目item中子组件点击旋转动画的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
属性改变的时候加上试试animateTo
animateTo({ duration: 10 }, () => {
let bol = this.dataSource.getData(index).isExpand
this.dataSource.getData(index).isExpand = !bol
this.dataSource.notifyDataChange(index)
})
根据你的代码看动画的代码是没问题的,没生效的原因可能是有:
-
dataSource的item的class没有加@ObservedV2装饰器,isExpand没有加@Trace装饰器。
-
在@Builder函数中,当传递的参数为状态变量时,状态变量的改变不会引起@Builder函数内的UI刷新。按引用传递参数时,传递的参数可为状态变量,且状态变量的改变会引起@Builder函数内的UI刷新。故itemHeader的第三个参数应该为item,然后Image组件rotate用item.isExpand绑定。
参考代码如下:
[@ObservedV2](/user/ObservedV2)
class Data {
[@Trace](/user/Trace) isExpand: boolean = false;
}
class BasicDataSource<T> implements IDataSource {
private listeners: DataChangeListener[] = [];
private originDataArray: T[] = [];
public totalCount(): number {
return this.originDataArray.length;
}
public getData(index: number): T {
return this.originDataArray[index];
}
registerDataChangeListener(listener: DataChangeListener): void {
if (this.listeners.indexOf(listener) < 0) {
console.info('add listener');
this.listeners.push(listener);
}
}
unregisterDataChangeListener(listener: DataChangeListener): void {
const pos = this.listeners.indexOf(listener);
if (pos >= 0) {
console.info('remove listener');
this.listeners.splice(pos, 1);
}
}
notifyDataReload(): void {
this.listeners.forEach(listener => {
listener.onDataReloaded();
});
}
notifyDataAdd(index: number): void {
this.listeners.forEach(listener => {
listener.onDataAdd(index);
});
}
notifyDataChange(index: number): void {
this.listeners.forEach(listener => {
listener.onDataChange(index);
});
}
notifyDataDelete(index: number): void {
this.listeners.forEach(listener => {
listener.onDataDelete(index);
});
}
notifyDataMove(from: number, to: number): void {
this.listeners.forEach(listener => {
listener.onDataMove(from, to);
});
}
notifyDatasetChange(operations: DataOperation[]): void {
this.listeners.forEach(listener => {
listener.onDatasetChange(operations);
});
}
}
class MyDataSource<T> extends BasicDataSource<T> {
private dataArray: T[] = [];
public totalCount(): number {
return this.dataArray.length;
}
public getData(index: number): T {
return this.dataArray[index];
}
public pushData(data: T): void {
this.dataArray.push(data);
this.notifyDataAdd(this.dataArray.length - 1);
}
}
@Entry
@Component
struct Index {
@State message: string = 'Hello World';
@State private dataSource: MyDataSource<Data> = new MyDataSource<Data>();
@Builder
itemHeader(index: number, str: string, item: Data) {
Row() {
Text(str + JSON.stringify(item.isExpand))
.fontColor(Color.Red)
.padding(6)
Button() {
Image($r('sys.media.ohos_ic_public_arrow_down'))
.width(24)
.height(24)
.fillColor('#3F72AF')
.rotate({ angle: item.isExpand? 90: 0 })
.animation({
duration : 2000,
curve : Curve.Linear,
delay : 0
})
}
.width(36)
.height(36)
.backgroundColor(Color.Transparent)
.onClick(() => {
let bool:boolean = this.dataSource.getData(index).isExpand
this.dataSource.getData(index).isExpand = !bool
this.dataSource.notifyDataChange(index)
})
}.justifyContent(FlexAlign.SpaceBetween).width('100%').backgroundColor(Color.Orange)
}
aboutToAppear(): void {
this.dataSource.pushData(new Data())
this.dataSource.pushData(new Data())
this.dataSource.pushData(new Data())
}
build() {
List({ space: 3 }) {
LazyForEach(this.dataSource, (item: Data, index) => {
ListItem() {
this.itemHeader(index, index.toString(), item)
Text(item.isExpand ? '展开' : '收起')
}
}, (item: string) => item)
}.cachedCount(5)
}
}
有要学HarmonyOS AI的同学吗,联系我:https://www.itying.com/goods-1206.html
哈哈,之前那个长按左/*右滑动删除条目也是你的问题吧,你这是研究动画呢?
显式动画方案:
Button() {
Image($r('sys.media.ohos_ic_public_arrow_down'))
.rotate({ angle: isExpand ? 90 : 0 })
}
.onClick(() => {
animateTo({
duration: 300,
curve: Curve.EaseInOut
}, () => {
let bol = this.dataSource.getData(index).isExpand
this.dataSource.getData(index).isExpand = !bol
this.dataSource.notifyDataChange(index)
})
})
属性动画方案
Image($r('sys.media.ohos_ic_public_arrow_down'))
.rotate({
angle: isExpand ? 90 : 0
})
.animation({
duration: 300,
curve: Curve.EaseInOut,
iterations: 1,
playMode: PlayMode.Normal
})
2个方案,你体会一下
试过了,我那个场景可能比较特殊,是list的itemgroup 里的,sticky的header 加了isExpand ,我一设置动画.onClick(() => { animateTo({ duration: 300, curve: Curve.EaseInOut }, () => { let bol = this.dataSource.getData(index).isExpand this.dataSource.getData(index).isExpand = !bol this.dataSource.notifyDataChange(index) }) }),整个itemgroup 都在变,只需要header 旋转一个单独的image.
我的header 里图片的代码
```jsx
Image($r('sys.media.ohos_ic_public_arrow_down'))
.width(24)
.height(24)
.fillColor('#3F72AF')
.rotate({ angle: isExpand ? 90 : 0 })
.width(36)
.height(36)
.backgroundColor(Color.Transparent)
.onClick(() => {
animateTo({
duration: 2000,
curve: Curve.EaseInOut
}, () => {
let bol = this.dataSource.getData(index).isExpand
this.dataSource.getData(index).isExpand = !bol
this.dataSource.notifyDataChange(index)
})
})
x’x
在HarmonyOS鸿蒙Next中实现list子条目item中子组件的点击旋转动画,可以使用ArkUI的动画能力。通过给子组件添加点击事件,在事件回调中触发旋转动画。使用animateTo方法或显式动画API,设置旋转角度(如0到360度)和持续时间。例如:
// 子组件
@Component
struct RotatingComponent {
@State angle: number = 0
build() {
Column() {
Image($r('app.media.icon'))
.onClick(() => {
animateTo({ duration: 500 }, () => {
this.angle = this.angle === 0 ? 360 : 0
})
})
.rotate({ x: 0, y: 0, z: 1, angle: this.angle })
}
}
}
注意在list中使用时需处理好组件状态管理。
在HarmonyOS Next中实现点击旋转动画,建议使用显式动画API。修改代码如下:
Image($r('sys.media.ohos_ic_public_arrow_down'))
.width(24)
.height(24)
.fillColor('#3F72AF')
.rotate({ angle: isExpand ? 90 : 0 })
.onClick(() => {
animateTo({
duration: 200,
curve: Curve.EaseInOut
}, () => {
this.dataSource.getData(index).isExpand = !this.dataSource.getData(index).isExpand;
this.dataSource.notifyDataChange(index);
});
})
关键点:
- 使用
animateTo
包裹状态变更逻辑 - 移除原先Button的onClick,改为直接在Image上处理
- 动画参数建议使用较短的duration(200ms)和EaseInOut曲线
这样修改后,图片旋转时会带有平滑的动画效果。注意确保isExpand
状态变更后能正确触发UI更新。