420 Views
April 11, 25
スライド概要
YOUTRUST x Omiai Flutter LT会
https://connpass.com/event/346334/
で発表したスライドです。
アニメーションは再生されません。
気になる方は、スライド内 QR コードを Web ブラウザで開いて、触ってみてください。
Android Engineer at Kyash Inc.
マッチングアプリでよく見る、 左スワイプでスキップ、 右スワイプでいいね!を送る UI を Flutter で作る。 YOUTRUST x Omiai Flutter LT会 1
自己紹介 ● ● 高田 晴彦 @tfandkusu ○ ● ● ● Qiita/Zenn/note/GitHub/X 株式会社Omiai Flutter / Android エンジニア スプラトゥーンが好き 2
今回作った Flutter アプリ マッチングアプリで よく見る 左スワイプでスキップ 右スワイプでいいね! を送るUI https://skip-or-like.web.app/ 今回解説するアプリの Flutter on the web 版 3
Tinder が発祥 https://skip-or-like.web.app/ Tinder の AppStore より引用 今回解説するアプリの Flutter on the web 版 4
pub.dev を Tinder で検索 5つ以上の該当 UI を実現するパッケージ ● ● ● ● ● flutter_card_swiper appinio_swiper swipable_stack tcard stacked_list_carousel https://skip-or-like.web.app/ flutter_card_swiper の pub.dev ページよ り引用 今回解説するアプリの Flutter on the web 版 5
Omiai は Flutter リプレイス中 学習 細かい調整 https://skip-or-like.web.app/ 今回解説するアプリの Flutter on the web 版 ※ 調査、検討段階であり、リリースは決定していません。 6
今回の説明範囲 7
今回の説明範囲 1/3 縦方向ドラッグで カードが上下に動く 8
今回の説明範囲 2/3 横方向ドラッグで カードが傾く 9
今回の説明範囲 3/3 ドラッグをやめると カードがアニメーションで 元に戻る 10
作り方の解説 11
ドラッグ操作を受け取る GestureDetector Widget をドラッグ操作できる範囲の親 Widget にする。 GestureDetector( /* 他パラメータは次スライドで解説 */ behavior: HitTestBehavior.translucent /* 透明部分もドラッグ範囲とする */, child: /* ドラッグ操作できる範囲の Widget */ ) 12
ドラッグ操作を受け取る onPanStart パラメータでドラッグ開始座標を受け取る。 GestureDetector( onPanStart: (details) { final startDragX = details.localPosition.dx; final startDragY = details.localPosition.dy; }, /* 他パラメータは別スライドで解説 */ ) 13
ドラッグ操作を受け取る onPanUpdate パラメータでドラッグ中の最新座標を取得する。 GestureDetector( onPanUpdate: (details) { final dragX = details.localPosition.dx; final dragY = details.localPosition.dy; }, /* 他パラメータは別スライドで解説 */ ) 14
ドラッグ操作を受け取る onPanEnd パラメータは指を離してドラッグ操作が終了したら呼ばれる。 GestureDetector( onPanEnd: (details) { }, /* 他パラメータは別スライドで解説 */ ) 15
ドラッグ操作によるカード移動と傾きを保持するデータクラスを freezed で作成 @freezed abstract class CardAppearance with _$CardAppearance { const factory CardAppearance({ required double offsetY /* 縦方向のカード移動ピクセル数*/, required double angle /* 傾き(ラジアン) */, }) = _CardAppearance; } 16
Widget に移動と傾きを適用 final cardAppearance = ref.watch(cardAppearanceNotifierProvider); final matrix = Matrix4.translationValues(0, cardAppearance.offsetY, 0) /* 平行移動の行列 */ * /* 行列の積で合成 */ Matrix4.rotationZ(cardAppearance.angle) /* 回転の行列 */; return Transform( origin: Offset(width / 2, height) /* 回転の中心は最下部中央 */, transform: matrix, child: /* カードの Widget */, ); 17
ドラッグ操作に合わせて Notifer の state を更新 state = CardAppearance( // 縦方向のドラッグ量 = 現在Y - ドラッグ開始Y。 offsetY: dragY - startDragY, // 傾きは atan2 関数で求める。 angle: atan2(dragX - startDragX, height), ) dragX - startDragX height atan(dragX - startDragX / height) 横方向ドラッグ量 ドラッグ範囲の高さ angle 18
これでドラッグ操作に合わせて、カードが縦方向に移動および傾くようになった 19
指を離したときに戻るアニメーションの作り方 20
TweenAnimationBuilder Widget を使う TweenAnimationBuilder<CardAppearance>( tween: CardAppearanceTween( /* このクラスは次のスライドで解説 */ begin: animationBeginCardAppearance /* 開始の値 */, end: CardAppearance(offsetY: 0, angle: 0) /* 終了の値(初期位置) */, ), duration: Duration(milliseconds: 300), /* アニメーション時間 */ child: /* アニメーション対象 Widget */, builder: (context, cardAppearance, child) => /* Transform Widget でアニメーション中に変化する値を適用して返却 */, ) 21
Tween クラスを継承
class CardAppearanceTween extends Tween<CardAppearance> {
CardAppearanceTween({required super.begin, required super.end});
@override
CardAppearance lerp(double t) {
// t がアニメーションが進むごとに0から1になめらかに増えてくるので
// それに伴い begin から end に寄せる。
return CardAppearance(
offsetY: begin!.offsetY + (end!.offsetY - begin!.offsetY) * t,
angle: begin!.angle + (end!.angle - begin!.angle) * t,
);
}
}
22
指を離したときに戻るアニメーションも完成 23
まとめ ● ● ● マッチングアプリでよく見る、左スワイプでスキップ、右スワイプでいいね!を送 る UI の作り方の一部を解説。 お相手のカードに対して平行移動と回転を与えている。 移動と回転を組み合わせたアニメーションは TweenAnimationBuilder を使うこ と実現できる。 24
実装方法は一例 他にこのような実装方法がある等、ありましたら、懇親会等で教えて頂けると幸いで す。 25
今回話せなかったこと ● ● ● 素早くカードを飛ばす Fling 操作の対応 素早く操作したときも破綻無くアニメーションをする 一定以上ドラッグしたときに、スキップ、いいねを確定させるアニメーション 26
サンプルコード https://github.com/tfandkusu/skip_like_flutter 27
ありがとうございました。 28