OpenHarmony开发者论坛
标题:
Flutter到 OpenHarmony,不是有手就行吗? (仿掘金点赞按钮)
[打印本页]
作者:
zmtzawqlp
时间:
2024-2-27 14:09
标题:
Flutter到 OpenHarmony,不是有手就行吗? (仿掘金点赞按钮)
[md]## 前言
`Flutter` 提供了丰富的动画支持,使开发者能够轻松创建各种类型的动画效果,从简单的渐变和旋转到复杂的交互式动画都可以实现。而 `ArkUI` 从 `api` 上面看起来更简单,更容易编写代码。我们今天迁移的是 `Flutter` 上面的 [like_button](
https://github.com/fluttercandies/like_button
), 它使我们的点赞效果更简单酷炫和简单。
![LikeButton.gif](
https://forums-obs.openharmony.c ... j5jojni2nujzn31.gif
"LikeButton.gif")
## 点赞按钮
`Like Button `支持推特点赞效果和喜欢数量动画的 `ArkUI` 库.
## 安装
`ohpm install @candies/like_button`
## 参数
### 配置参数
| 参数 | 类型 | 描述 |
| -------------------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| likeWidgetSize | number | LikeWidget 的大小(默认30) |
| bubblesSize | number | 动画时候的泡泡的大小(默认为 likeWidgetSize 的 2 倍) |
| bubblesColor | BubblesColor | 动画时候的泡泡的颜色,可以分别设置 4 种(默认为 dotPrimaryColor: '#FFFFC107',dotSecondaryColor: '#FFFF9800',dotThirdColor: '#FFFF5722',dotLastColor: '#FFF44336' |
| circleSize | number | 动画时候的圈的最大大小(默认为 likeWidgetSize 的 0.8 倍) |
| circleColor | BubblesColor | 动画时候的圈的颜色,需要设置2种 (默认为 start: '#FFFF5722', end: '#FFFFC107') |
| isLiked | boolean | 是否喜欢。(默认 `false`) |
| animationDuration | number | LikeWidget 动画时长(默认 1000 毫秒) |
| likeCount | number | 喜欢数量。如果不设置(undefined),不显示 LikeCountWidget |
| flexOptions | FlexOptions | LikeWidget 和 LikeCountWidget 2个组件位置的配置(默认为 direction: FlexDirection.Row, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center) |
| likeCountAnimationType | LikeCountAnimationType | 喜欢数量动画的类型(none,part,all)。没有动画;只动画改变的部分;全部部分 |
| widgetsMargin | number | LikeWidget and LikeCountWidget 的距离 |
| likeCountAnimationDuration | number | LikeCountWidget 动画时长(默认 1000 毫秒) |
| controller | Controller | 可以通过调用 Controller 的 Tap 的方法,执行动画 |
### 回调
这是一个异步回调,你可以等待服务返回之后再改变状态。也可以先改变状态,请求失败之后重置回状态
```typescript
onTap: (isLike: boolean) => Promise<boolean> = async (isLike: boolean) => {
return !isLike;
};
```
### 组件创建回调
| 回调 | 参数 | 描述 |
| ---------------------- | --------------------------------------------------- | -------------------------- |
| likeWidgetBuilder | isLiked: boolean | 用于自定义 LikeWidget |
| likeCountWidgetBuilder | isLiked: boolean,likeCount: number,showText: string | 用于自定义 LikeCountWidget |
```typescript
@BuilderParam
likeWidgetBuilder?: ($$: { isLiked: boolean }) => void = this.buildLikeWidget.bind(this);
@BuilderParam
likeCountWidgetBuilder?: ($$: {
isLiked: boolean,
likeCount: number,
showText: string
}) => void = this.buildLikeCountWidget.bind(this);
```
## 例子
### 无限点赞
将 `onTap` 固定返回 `true`,可以实现无限点赞的效果。
```typescript
LikeButton(
{
likeCount: 666,
onTap: async (isLike: boolean): Promise<true> => {
return true;
},
}
)
```
### LikeCountWidget 特殊处理逻辑
你可以根据 `likeCount` 的值的不同,做一些特殊的处理。
```typescript
LikeButton(
{
likeCount: 999,
likeWidgetBuilder: this.buildLikeWidget8,
bubblesColor: new BubblesColor({
dotPrimaryColor: '#FF00796B',
dotSecondaryColor: '#FF004D40',
},),
circleColor: new CircleColor({
start: '#FF26A69A',
end: '#FFB2DFDB',
}),
likeCountWidgetBuilder: this.buildLikeCountWidget2,
}
)
@Builder
buildLikeCountWidget2($$: {
isLiked: boolean,
likeCount: number,
showText: string
}) {
if ($$.likeCount >= 1000)
Text(`${($$.likeCount / 1000).toFixed(1)}k`).fontColor($$.isLiked ? '#FF004D40' : Color.Gray)
else
Text(`${$$.showText}`).fontColor($$.isLiked ? '#FF004D40' : Color.Gray)
}
@Builder
buildLikeWidget8($$: { isLiked: boolean }) {
Image($r('app.media.save'))
.fillColor($$.isLiked ? '#FF004D40' : Color.Gray)
}
```
### 设置 LikeWidget 和 LikeCountWidget 的位置
```typescript
LikeButton(
{
likeCount: 888,
flexOptions: {
direction: FlexDirection.Column,
justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center,
},
}
)
```
## 学废了
### 动画
`ArkUI` 里面使用动画蛮简单的。
[动画概述-使用动画-基于ArkTS的声明式开发范式-UI开发-开发-HarmonyOS应用开发](
https://developer.harmonyos.com/ ... 0000001450755570-V3
)
```typescript
@Entry
@Component
struct LayoutChange2 {
@State myWidth: number = 100;
@State myHeight: number = 50;
// 标志位,true和false分别对应一组myWidth、myHeight值
@State flag: boolean = false;
build() {
Column({ space: 10 }) {
Button("text")
.type(ButtonType.Normal)
.width(this.myWidth)
.height(this.myHeight)
.margin(20)
Button("area: click me")
.fontSize(12)
.margin(20)
.onClick(() => {
animateTo({ duration: 1000, curve: Curve.Ease }, () => {
// 动画闭包中根据标志位改变控制第一个Button宽高的状态变量,使第一个Button做宽高动画
if (this.flag) {
this.myWidth = 100;
this.myHeight = 50;
} else {
this.myWidth = 200;
this.myHeight = 100;
}
this.flag = !this.flag;
});
})
}
.width("100%")
.height("100%")
}
}
```
但是你没法获取到每一帧的动画值。我们需要另外一个 `api` 来实现。
[@ohos.animator (动画)-UI界面-ArkTS接口参考-ArkTS API参考-HarmonyOS应用开发](
https://developer.harmonyos.com/ ... 604__animatorresult
)
```typescript
let options: AnimatorOptions = {
duration: 1000,
easing: "ease",
delay: 0,
fill: "forwards",
direction: "normal",
iterations: 1,
begin: 0.0,
end: 1.0
};
let animatorResult = animator.create(options);
animatorResult.onframe=(progress: number)=>{
};
animatorResult.onfinish=()=>{
};
animatorResult.play();
animatorResult.pause();
animatorResult.cancel();
animatorResult.reverse();
animatorResult.reset(options);
```
`onframe` 方法中的 `progress` 在 `begin` 和 `end` 之间的值。你可以在这个方法里面对某个属性做改变,达到动画的效果。
不过这个 `api` 没法像 `Flutter` 中一样, 使用同一个 `Controller` 对不同的属性,在不同时间段做不同的动画效果。比如下面的 `Controller` 的动画总时间为 `1000` 秒,那么就 `_innerCircleAnimation` 就是一个值从 `0.2` 开始 `1.0` 结束,并且是从 `200` 秒开始 `500` 秒结束的 `Curves.ease` 动画。虽然
`ArkUI` 中 `AnimatorOptions` 中可以设置 `delay` 来控制开始的时间,但是这也会影响整个动画的曲线。
```dart
_innerCircleAnimation = Tween<double>(
begin: 0.2,
end: 1.0,
).animate(
CurvedAnimation(
parent: _controller!,
curve: const Interval(
0.2,
0.5,
curve: Curves.ease,
),
),
);
```
最终我的实现方案是将 `Flutter` 中的动画曲线迁移到 `ArkUI` 中,使用固定的 `0.0` 到 `1.0` 的 `AnimatorOptions` 来作为 `Flutter` 中的
`AnimationController` 来驱动动画。
```
let options: AnimatorOptions = {
duration: this.animationDuration,
easing: "ease",
delay: 0,
fill: "forwards",
direction: "normal",
iterations: 1,
begin: 0.0,
end: 1.0
};
_outerCircleCurve = new Interval({
begin: 0.0,
end: 0.3,
curve: Cubic.ease,
beginValue: 0.1,
endValue: 1.0,
});
_innerCircleCurve = new Interval({
begin: 0.2,
end: 0.5,
curve: Cubic.ease,
beginValue: 0.2,
endValue: 1.0,
});
_bubblesCurve = new Interval({
begin: 0.1,
end: 1.0,
curve: new DecelerateCurve(),
beginValue: 0.0,
endValue: 1.0,
});
_iconScaleCurve = new Interval({
begin: 0.35,
end: 0.7,
curve: new OvershootCurve(),
beginValue: 0.1,
endValue: 1.0
});
this._animatorResult.onframe = (value: number) => {
this._outerCircleRadiusProgress = this._outerCircleCurve.transform(value);
this._innerCircleRadiusProgress = this._innerCircleCurve.transform(value);
this._bubblesProgress = this._bubblesCurve.transform(value);
this._iconScale = this._iconScaleCurve.transform(value);
};
```
这样子就能实现跟 `Flutter` 一模一样的动画曲线了。
## 结语
从 `Flutter` 迁移到 `ArkUI` 过程蛮简单的,只需要去找准对应的 `api` 即可,关于 `Canvas` 的 `api` 各种平台的都大差不差的。欢迎大家加入 [Harmony Candies](
https://github.com/HarmonyCandies
) ,为鸿蒙的生态添加更多有趣的组件。
爱 OpenHarmony ,爱 `糖果`,欢迎加入[Harmony Candies](
https://github.com/HarmonyCandies
),一起生产可爱的.
![DM_20231219092555_019.jpg](
https://forums-obs.openharmony.c ... u1twhjwi0i7tnw7.jpg
"DM_20231219092555_019.jpg")
## 参考
* [动画概述-使用动画-基于ArkTS的声明式开发范式-UI开发-开发-HarmonyOS应用开发](
https://developer.harmonyos.com/ ... 0000001450755570-V3
)
* [@ohos.animator (动画)-UI界面-ArkTS接口参考-ArkTS API参考-HarmonyOS应用开发](
https://developer.harmonyos.com/ ... 604__animatorresult
)
[/md]
欢迎光临 OpenHarmony开发者论坛 (https://forums.openharmony.cn/)
Powered by Discuz! X3.5