猜猜微信啪一啪是怎麼用Flutter實現的?

CrazyQ1發表於2020-06-18

猜猜微信啪一啪是怎麼用Flutter實現的?

推薦學習專案

最近這個啪一啪效果挺火的啊

猜猜微信啪一啪是怎麼用Flutter實現的?
群裡經常有人啪;

介紹

其實之前我就雙擊過頭像,但並沒任何效果,估計是當時把這個啪一啪訊息隱藏了的,最近才放出來的,剛好看到,才開始實現。

關於進度

目前只是先把具體的效果實現,估計過幾天你看wechat_flutter專案的時候就有啪一啪訊息體了,我的思路是新增訊息體封裝,或者把原有的進行修改,比如說文字訊息體自定義下內容,然後顯示的時候判斷即可;

處理方式【本段來自Android_ZzT】

咋們儘量處理的跟微信官方客戶端一模一樣

暴力連續 「啪一啪」

連續一直雙擊頭像會發現,只有第一次會傳送資訊,剩下的雙擊只會觸發客戶端行為「頭像抖動」,是做了防爆處理的。大概過 10s 左右後恢復,可以再次觸發

斷網下「啪一啪」

斷網情況下,雙擊頭像,會發現,自己先能看到 「拍一拍」,然後過了一段時間後,會出現「因網路原因,對方可能不知道你拍了他」。這就證明是先走客戶端的渲染邏輯,然後再發的網路請求,網路不好的情況下應該會經過重試過程,如果最終還是失敗,則顯示網路原因失敗的字樣

啪自己

雙擊自己頭像,會顯示「你拍了拍自己」,只是雙擊使用者資訊是自己的情況下這樣顯示,這沒什麼特別的,但是請求失敗情況下的文案沒太能對上,仍然顯示的是「對方可能不知道你拍了他」,猜測這個文案是寫在客戶端的,可能要改的話又得更新版本嘍

實現

其實主要用了一個動畫,然後使用TweenSequence進行多組補間動畫

 TweenSequence<double>([
      //使用TweenSequence進行多組補間動畫
      TweenSequenceItem<double>(tween: Tween(begin: 0, end: 10), weight: 1),
      TweenSequenceItem<double>(tween: Tween(begin: 10, end: 0), weight: 1),
      TweenSequenceItem<double>(tween: Tween(begin: 0, end: -10), weight: 1),
      TweenSequenceItem<double>(tween: Tween(begin: -10, end: 0), weight: 1),
    ])
複製程式碼

然後封裝成了個動畫元件,元件呼叫了Transform來進行轉動;

封裝的那個元件繼承了AnimatedWidget,然後呼叫了super把自定義的listenable 傳了進去,


class AnimateWidget extends AnimatedWidget {
  final Widget child;

  AnimateWidget({Animation<double> animation, this.child})
      : super(listenable: animation);

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    var result = Transform(
      transform: Matrix4.rotationZ(animation.value * pi / 180),
      alignment: Alignment.bottomCenter,
      child: new ClipRRect(
        borderRadius: BorderRadius.all(Radius.circular(5)),
        child: this.child,
      ),
    );
    return result;
  }
}
複製程式碼

也算是非常簡單。

程式碼所在位置

封裝之後的程式碼所在

/wechat_flutter/lib/ui/view/shake_view.dart

然後專案中頭像呼叫啪一啪的地方在

/wechat_flutter/lib/ui/message_view/msg_avatar.dart

大家可以去看下具體是怎麼呼叫和封裝的;

封裝後的程式碼

import 'dart:math';

import 'package:flutter/material.dart';

/// 封裝之後的拍一拍
class ShakeView extends StatefulWidget {
  final Widget child;

  ShakeView({
    this.child,
  });

  _ShakeViewState createState() => _ShakeViewState();
}

class _ShakeViewState extends State<ShakeView>
    with SingleTickerProviderStateMixin {
  Animation<double> animation;
  AnimationController controller;

  initState() {
    super.initState();

    controller = AnimationController(
        duration: const Duration(milliseconds: 500), vsync: this);
    animation = TweenSequence<double>([
      //使用TweenSequence進行多組補間動畫
      TweenSequenceItem<double>(tween: Tween(begin: 0, end: 10), weight: 1),
      TweenSequenceItem<double>(tween: Tween(begin: 10, end: 0), weight: 1),
      TweenSequenceItem<double>(tween: Tween(begin: 0, end: -10), weight: 1),
      TweenSequenceItem<double>(tween: Tween(begin: -10, end: 0), weight: 1),
    ]).animate(controller);
    controller.forward();
  }

  Widget build(BuildContext context) {
    return AnimateWidget(animation: animation, child: widget.child);
  }

  dispose() {
    controller.dispose();
    super.dispose();
  }
}

class AnimateWidget extends AnimatedWidget {
  final Widget child;

  AnimateWidget({Animation<double> animation, this.child})
      : super(listenable: animation);

  @override
  Widget build(BuildContext context) {
    final Animation<double> animation = listenable;
    var result = Transform(
      transform: Matrix4.rotationZ(animation.value * pi / 180),
      alignment: Alignment.bottomCenter,
      child: new ClipRRect(
        borderRadius: BorderRadius.all(Radius.circular(5)),
        child: this.child,
      ),
    );
    return result;
  }
}
複製程式碼

呼叫例子

這個child就是你要啪一啪之後抖動的widget內容

new ShakeView(
    child: new Image.network(
    'url',
    height: 50,
     width: 50,
     fit: BoxFit.cover,
   ),
)
複製程式碼

專案地址

聯絡我

Flutter交流QQ群:874592746

Flutter交流微信群:

猜猜微信啪一啪是怎麼用Flutter實現的?

相關文章