溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Flutter怎么實(shí)現(xiàn)笑嘻嘻的動(dòng)態(tài)表情

發(fā)布時(shí)間:2022-04-24 10:12:41 來源:億速云 閱讀:127 作者:iii 欄目:開發(fā)技術(shù)

這篇文章主要介紹“Flutter怎么實(shí)現(xiàn)笑嘻嘻的動(dòng)態(tài)表情”的相關(guān)知識(shí),小編通過實(shí)際案例向大家展示操作過程,操作方法簡單快捷,實(shí)用性強(qiáng),希望這篇“Flutter怎么實(shí)現(xiàn)笑嘻嘻的動(dòng)態(tài)表情”文章能幫助大家解決問題。

效果如下圖所示

Flutter怎么實(shí)現(xiàn)笑嘻嘻的動(dòng)態(tài)表情

AnimatedContainer 介紹

在實(shí)現(xiàn)之前,先介紹一個(gè)新組件 —— AnimatedContainer ??催@個(gè)名字就知道和 Container 有關(guān),實(shí)際上AnimatedContainer是 Flutter 中的一個(gè)動(dòng)畫容器,Container 有的屬性基本上它都有,我們看一下二者的構(gòu)造方法的區(qū)別。

AnimatedContainer({
    Key? key,
    this.alignment,
    this.padding,
    Color? color,
    Decoration? decoration,
    this.foregroundDecoration,
    double? width,
    double? height,
    BoxConstraints? constraints,
    this.margin,
    this.transform,
    this.transformAlignment,
    this.child,
    this.clipBehavior = Clip.none,
    Curve curve = Curves.linear,
    required Duration duration,
    VoidCallback? onEnd,
  });

Container({
    Key? key,
    this.alignment,
    this.padding,
    this.color,
    this.decoration,
    this.foregroundDecoration,
    double? width,
    double? height,
    BoxConstraints? constraints,
    this.margin,
    this.transform,
    this.transformAlignment,
    this.child,
    this.clipBehavior = Clip.none,
  });

可以看到,實(shí)際上 AnimatedContainer 和 Container 只差了3個(gè)屬性,而這三個(gè)屬性就是控制動(dòng)畫的參數(shù):

  • curve:動(dòng)畫曲線,默認(rèn)是線性;

  • duration:動(dòng)效時(shí)長參數(shù);

  • onEnd:動(dòng)效結(jié)束后的回調(diào)方法。

AnimatedContainer的特性是所有涉及外觀的屬性都會(huì)生成一個(gè)過渡動(dòng)效,當(dāng)這些外觀屬性發(fā)生改變的時(shí)候就會(huì)使用生成的的動(dòng)效來完成過渡,從而展現(xiàn)出動(dòng)畫效果。像我們要實(shí)現(xiàn)的笑嘻嘻的表情其實(shí)就是利用 AnimatedContainer 實(shí)現(xiàn)的。

組件結(jié)構(gòu)

我們的笑嘻嘻動(dòng)效,底部是一個(gè)圓形腦袋,上面有兩顆眼睛和一個(gè)嘴巴,其中眼睛和嘴巴有移動(dòng)動(dòng)效,而眼睛的眼珠還有方向的動(dòng)效。這些動(dòng)效都可以使用AnimatedContainer來實(shí)現(xiàn)。大的頁面結(jié)構(gòu)如下:

Flutter怎么實(shí)現(xiàn)笑嘻嘻的動(dòng)態(tài)表情

細(xì)節(jié)實(shí)現(xiàn)

腦袋這個(gè)很容易,直接用原型裁剪,設(shè)置尺寸和底色即可:

// 腦袋
ClipOval(
  child: Container(
    width: 120,
    height: 120,
    color: Colors.blue,
  ),
),

眼睛左眼和右眼有點(diǎn)不一樣,眼球?qū)嶋H就是AnimatedContainer使用 borderRadius 裁剪為圓形,而眼珠是AnimatedContainer的子組件 —— 黑色的圓圈。具體實(shí)現(xiàn)向左或向右看使用一個(gè)變量 seeLeft 控制,而向左向右的轉(zhuǎn)換過渡效果都由 AnimatedContainer 控制。

  • seeLeft = true,向左看:眼珠對齊的方式是 bottomLeft,左眼縱向方向上稍微往下移一點(diǎn);右眼往左移動(dòng)一定的位置,這樣就會(huì)有向左看的效果了;

  • seeLeft = false,向右看:眼珠對齊的方式是 bottomRight,右眼縱向方向上稍微往下移一點(diǎn);左眼往右移動(dòng)一定的位置,這樣就會(huì)有向右看的效果了;

實(shí)現(xiàn)代碼如下:

// 左眼
Positioned(
  top: marginTop,
  left: marginLR,
  child: AnimatedContainer(
    alignment:
        seeLeft ? Alignment.bottomLeft : Alignment.bottomRight,
    padding: EdgeInsets.all(eyePadding),
    transform: Matrix4.identity()
      ..translate(
          seeLeft ? 0.0 : sideOffset, seeLeft ? eyeOffset : 0.0, 0),
    duration: Duration(seconds: 1),
    curve: Curves.fastOutSlowIn,
    width: eyeSize,
    height: eyeSize,
    decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.circular(eyeSize / 2),
    ),
    child: ClipOval(
      child: Container(
        color: Colors.black,
        width: eyeBallSize,
        height: eyeBallSize,
      ),
    ),
  ),
),
// 右眼
Positioned(
  top: marginTop,
  right: marginLR,
  child: AnimatedContainer(
    alignment:
        seeLeft ? Alignment.bottomLeft : Alignment.bottomRight,
    padding: EdgeInsets.all(eyePadding),
    transform: Matrix4.identity()
      ..translate(seeLeft ? -sideOffset : 0.0,
          seeLeft ? 0.0 : eyeOffset, 0),
    duration: Duration(seconds: 1),
    curve: Curves.fastOutSlowIn,
    width: eyeSize,
    height: eyeSize,
    decoration: BoxDecoration(
      color: Colors.white,
      borderRadius: BorderRadius.circular(eyeSize / 2),
    ),
    child: ClipOval(
      child: Container(
        color: Colors.black,
        width: eyeBallSize,
        height: eyeBallSize,
      ),
    ),
  ),
),

這里的眼珠對齊使用的就是AnimatedContainer 的 alignment參數(shù)控制,而眼球的位置使用 Matrix4 的平移實(shí)現(xiàn):

Matrix4.identity()
  ..translate(seeLeft ? -sideOffset : 0.0, seeLeft ? 0.0 : eyeOffset, 0),

笑臉的實(shí)現(xiàn)使用ClipPath,繪制兩條弧線就可以了,然后平移的幅度和眼珠保持一致,就可以感覺是轉(zhuǎn)頭的效果了,AnimatedContainer 部分的代碼如下:

// 笑嘻嘻的嘴巴
Positioned(
  bottom: 10,
  height: 40,
  left: 0,
  child: AnimatedContainer(
    alignment:
        seeLeft ? Alignment.bottomLeft : Alignment.bottomRight,
    padding: EdgeInsets.all(4.0),
    transform: Matrix4.identity()
      ..translate(seeLeft ? 25.0 : 35.0, 0, 0),
    duration: Duration(seconds: 1),
    curve: Curves.fastOutSlowIn,
    child: ClipPath(
      clipper: SmileClipPath(),
      child: Container(
        width: 60,
        height: 40,
        color: Colors.yellow,
      ),
    ),
  ),
),

笑嘻嘻的嘴巴的裁剪類 SmileClipPath 代碼如下:

class SmileClipPath extends CustomClipper<Path> {
  @override
  Path getClip(Size size) {
    return Path()
      ..moveTo(0, 0)
      ..arcToPoint(
        Offset(size.width, 0),
        radius: Radius.circular(size.width * 0.55),
        clockwise: false,
      )
      ..arcToPoint(
        Offset(0, 0),
        radius: Radius.circular(size.width),
        clockwise: true,
      );
  }

  @override
  bool shouldReclip(covariant CustomClipper<Path> oldClipper) {
    return false;
  }
}

最后,控制狀態(tài)變量 seeLeft 的變化通過一個(gè)按鈕點(diǎn)擊觸發(fā)就好了。

floatingActionButton: FloatingActionButton(
  child: Icon(Icons.play_arrow, color: Colors.white),
  onPressed: () {
    setState(() {
      seeLeft = !seeLeft;
    });
  },
),

最終運(yùn)行效果如下,完整代碼已提交至:動(dòng)畫相關(guān)代碼。

Flutter怎么實(shí)現(xiàn)笑嘻嘻的動(dòng)態(tài)表情

關(guān)于“Flutter怎么實(shí)現(xiàn)笑嘻嘻的動(dòng)態(tài)表情”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí),可以關(guān)注億速云行業(yè)資訊頻道,小編每天都會(huì)為大家更新不同的知識(shí)點(diǎn)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI