FlutterはWeChatアドレスブックのカスタムナビゲーションバーを模倣します

一緒に書く習慣をつけましょう!「ナゲッツデイリーニュープラン・4月アップデートチャレンジ」に参加して4日目です。クリックしてイベントの詳細をご覧ください

たとえば、一部のページでは、連絡先や都市を選択するときに、必要なオプションをすばやく見つける必要があります。通常、WeChatアドレスブックの右側にあるナビゲーションバーのような機能が必要です。これはすばやく実行できます。 AからZまでの位置にあります。この記事この記事では、WeChatアドレスブックと同じ機能を自分たちで実装します。

  • キーポイント:ジェスチャポジショニングスライディング、リストポジショニング、ジェスチャ、リストリンケージ。

データを準備するには、まずナビゲーションディレクトリデータを準備する必要があります。

List<String> _az = [
  "☆",
  "A",  "B", "C",  "D",
  "E",  "F",  "G", "H",
  "I",  "G",  "K", "L", 
  "M",  "N",  "O", "P",
  "Q",  "R",  "S", "T",
  "U",  "V", "W",  "X", 
  "Y", "Z", 
];
复制代码

次に、リストデータ、リストデータを背景で並べ替えることができます。背景で並べ替えられない場合は、自分で並べ替えて組み立てることもできます。ここでは、プラグインを使用して、中国語に従ってピンインのイニシャルを取得します。文字、そして私たちは自分たちでこのデータを行うことができます。

lpinyin: ^2.0.3
复制代码

データ形式:NameBeanは文字のリストに対応します。これは、正式なリストデータを格納する形式です。

class NameBean {
  String? initial;// 字母导航
  List<Name>? nameList;// 内容列表

  NameBean({
    this.initial,
    this.nameList,
  });
}

/// name : "老李"

/// 这里我只放了一个name字段,以后扩展内容只需在这里新增字段就好了
class Name {
  String? name;

  Name({
    this.name,
  });
}
复制代码

次に、最初にナビゲーションバーを作成しましょう:
実装のアイデア:ナビゲーションバーはリストリストです。クリック、スライド、リリースの相互作用は異なります。さまざまな相互作用に従って実装します。ここでは、公式のGestureDetectorコンポーネントを使用します。ジェスチャ認識に使用されます。各アイテムの高さを修正し、ジェスチャの相互作用によって返される位置データを介して目的のディレクトリを返します。たとえば、各ディレクトリの高さは20に設定されています。
ナビゲーションバーコード:クリックまたは移動すると、選択したディレクトリにプレス効果があります。

GestureDetector(
  child: Container(
      margin: EdgeInsetsDirectional.only(top: 40),
      width: 40,
      // 导航条
      child: ListView.builder(
        physics: NeverScrollableScrollPhysics(),
        shrinkWrap: true,
        itemBuilder: (context, index) {
          return SizedBox(
            height: 20,
            // 这里做了一个按压或移动滑动的触发效果
            child: Container(
              alignment: Alignment.center,
              decoration: BoxDecoration(
                  color:
                      currentIndex == index ? Colors.redAccent : null,
                  shape: BoxShape.circle),
              child: Text(
                _az[index],
                style: TextStyle(
                  color: currentIndex == index
                      ? Colors.white
                      : Colors.black87,
                ),
              ),
            ),
          );
        },
        itemCount: _az.length,
      )),
      //手指按下触发 竖着划就用onVertica XXX回调
  onVerticalDragDown: (DragDownDetails e) {
    //打印手指按下的位置(相对于屏幕)
    int i = e.localPosition.dy ~/ 20;
    // _scrollController.jumpTo(index: i);
    setState(() {
      currentIndex = i;
    });
  },
  //手指滑动时会触发此回调
  onVerticalDragUpdate: (DragUpdateDetails e) {
    //用户手指滑动时,更新偏移
    int i = e.localPosition.dy ~/ 20;
    _az.length;
    if (i >= 0 && i <= _az.length - 1) {
      if (i != currentIndex) {
        setState(() {
        // 当前选中的index 默认-1
          currentIndex = i;
        });
        print("滑动 ${_az[i]}");
       
       
      }
    }
  },
  // 手指抬起
  onTapUp: (e) {
    // 手指抬起
    setState(() {
      currentIndex = -1;
    });
  },
  // 移动取消
  onVerticalDragEnd: (e) {
    // 移动取消
    setState(() {
      currentIndex = -1;
    });
  },
)
复制代码

次に、WeChatがスワイプしているときにジェスチャーで移動する文字拡大バブルがあることがわかります。
実装アイデア:バブルとナビゲーションバーを並べて、ジェスチャーの位置に応じて上マージンを更新できます。ナビゲーションバーの各アイテムの高さが固定されているため、スライド距離の高さを計算できます。スライド位置に応じた上部。ここのバブルは、UIに背景画像をカットさせることも、キャンバスを使用して自分で描画することもできます。
バブル描画のソースコード:現在、コンポーネントの描画を学んでいますが、ちなみに描画しました。最高ではないかもしれませんが、重要ではありません〜今日の焦点はそうではありません~~~

@override
void paint(Canvas canvas, Size size) {
  // 原点移到左下角
  canvas.translate(size.width / 2, size.height / 2);
  Paint paint = Paint()
    ..color = Colors.redAccent
    ..strokeWidth = 2
    ..style = PaintingStyle.fill;

  Path path = Path();
  // 绘制文字
  path.lineTo(0, -size.width / 2);
  // path.conicTo(33, -28, 20, 0, 1);

  path.arcToPoint(Offset(size.width / 2, 0),
      radius: Radius.circular(size.width / 2),
      largeArc: true,
      clockwise: true);
  path.close();
  var bounds = path.getBounds();
  canvas.save();
  canvas.translate(-bounds.width / 2, bounds.height / 2);
  canvas.rotate(pi * 1.2);
  canvas.drawPath(path, paint);
  canvas.restore();
  // 绘制文字
  var textPainter = TextPainter(
      text: TextSpan(
          text: text,
          style: TextStyle(
            fontSize: 24,
            foreground: Paint()
              ..style = PaintingStyle.fill
              ..color = Colors.white,
          )),
      textAlign: TextAlign.center,
      textDirection: TextDirection.ltr);
  textPainter.layout();
  canvas.translate(-size.width, -size.height / 2);
  textPainter.paint(canvas, Offset(-size.width / 2.4, size.height / 1.2));
}
复制代码

ナビゲーションバーとバブルが完成しました。次のステップは非常に簡単です。ListViewを使用してコンテンツを入力することはできません。ここでは、公式のプラグインが必要です。scrollable_positioned_list: ^0.2.3これを使用して特定のアイテムの位置を特定し、 listナビゲーションバーにリンクされています。
コンテンツコード:

ScrollablePositionedList.builder(
  physics: BouncingScrollPhysics(),
  itemScrollController: _scrollController,
  itemBuilder: (context, index) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.min,
      children: [
        Container(
          padding: EdgeInsetsDirectional.only(start: 10),
          child: Text(dataList[index].initial ?? ""),
          color: Colors.grey.shade300,
          height: 30,
          width: double.infinity,
          alignment: Alignment.centerLeft,
        ),
        Container(
          padding: EdgeInsetsDirectional.only(start: 15),
          child: ListView.builder(
            // 禁用滑动事件
            physics: NeverScrollableScrollPhysics(),
            shrinkWrap: true,
            itemBuilder: (context, cityIndex) {
              return InkWell(
                child: Container(
                  height: 40,
                  child: Column(
                    children: [
                      Expanded(
                        child: Container(
                          child: Text(dataList[index]
                                  .nameList?[cityIndex]
                                  .name ??
                              ""),
                          alignment: Alignment.centerLeft,
                        ),
                      ),
                      Divider(
                        height: 0.5,
                      )
                    ],
                  ),
                ),
                onTap: () {},
              );
            },
            itemCount: dataList[index].nameList?.length,
          ),
        )
      ],
    );
  },
  itemCount: dataList.length,
)
复制代码

ScrollablePositionedListの使用法は、特定のアイテムを見つけることができるもう1つのメソッドがあることを除いて、基本的にListViewの使用法と同じです。

_scrollController.jumpTo(index: i);
复制代码

最終的な効果を見てみましょう。データの繰り返しは無視してください...データを手動で入力するのは面倒です。何もわからない場合は、コミュニケーションをとることができます。

0f353b0b-5595-4dc6-b6d5-5020c080b378.gif

  • 概要:このコンポーネントを通じて、Flutterのジェスチャインタラクション操作を簡単に理解できます。ジェスチャ認識を通じて、多くの興味深いコンポーネントを実現できます。特に、描画とアニメーションの組み合わせにより、非常に興味深いインタラクションを作成できます。すべてのインタラクションの最下層は、ジェスチャによるものです。 。識別が完了したら、ソースコードを調べて、共有する時間があります〜

おすすめ

転載: juejin.im/post/7083806995085525006