Flutter 通訊錄索引條完善及聊天數(shù)據(jù)配置

Flutter 工程版本兼容配置

我們這里主要完善索引條的功能及聊天列表數(shù)據(jù)的獲取,但是在這之前我們先講一下工程版本的配置問題。當(dāng)我們?cè)诠こ讨型先胍恍├系奈募a的時(shí)候可能會(huì)出現(xiàn)一些語(yǔ)法報(bào)錯(cuò)問題,可能的原因就是版本兼容的問題,我們可以在 pubspec.yaml 文件中配置 sdk 判斷的兼容范圍,然后點(diǎn)擊 Pub get。如果新建的工程建議是大于等于 2.12.0,因?yàn)?2.12.0 是一次大的更新,加入了空安全與值類型安全。

索引條功能完善

在上一篇中我們已經(jīng)可以獲取到點(diǎn)擊位置的索引字符,現(xiàn)在我們需要實(shí)現(xiàn)的功能是點(diǎn)擊索引字符滾動(dòng)到指定的位置,并且左邊添加指示器展示對(duì)應(yīng)的索引字符。下面我們把步驟進(jìn)行拆分介紹。

滾動(dòng)效果實(shí)現(xiàn)

索引條添加點(diǎn)擊回調(diào)方法

class IndexBar extends StatefulWidget {
  final void Function(String str)? indexBarCallBack;
  IndexBar({this.indexBarCallBack});
}

GestureDetector(
            onVerticalDragUpdate: (DragUpdateDetails details){
              final Function(String str) callBack = widget.indexBarCallBack as Function(String str);
              int index = _getIndex(context, details.globalPosition);
              callBack(INDEX_WORDS[index]);
            },

            // 索引條點(diǎn)擊
            onVerticalDragDown: (DragDownDetails details){
              final Function(String str) callBack = widget.indexBarCallBack as Function(String str);
              int index = _getIndex(context, details.globalPosition);
              callBack(INDEX_WORDS[index]);
            },
)
IndexBar(indexBarCallBack: (String str) {
              print(str);
          }),//懸浮的索引條

因?yàn)樗饕龡l是單獨(dú)定義的類,所以如果想讓外部的列表滾動(dòng)的話首先需要有一個(gè)回調(diào)方法,回調(diào)到外部。我們?cè)?IndexBar 類中添加了一個(gè) indexBarCallBack 回調(diào)方法,在點(diǎn)擊索引條的時(shí)候調(diào)用回調(diào)方法。

遍歷初始化索引字符對(duì)應(yīng)的偏移量

class _FriendsPageState extends State<FriendsPage> {
  final double _cellHeight = 54.5;
  final double _groupHeight = 30.0;
  final Map _groupOffsetMap = {

  };

  final List<Friends> _listDatas = [];
  ScrollController? _scrollController;
  @override
  void initState() {
    super.initState();
    //創(chuàng)建數(shù)據(jù)
    _listDatas..addAll(datas)..addAll(datas);
    //按首字母順序排序
    _listDatas.sort((Friends a, Friends b){
      return a.indexLetter.compareTo(b.indexLetter);
    });
    var _groupOffset = _cellHeight * _headerData.length;
    //循環(huán)計(jì)算,將每個(gè)組頭的位置放入到 _groupOffsetMap 字典中
    for (int i = 0; i < _listDatas.length; i++) {
      if (i < 1) {
        //第一個(gè) cell,一定有頭
        _groupOffsetMap.addAll({_listDatas[i].indexLetter : _groupOffset});
        //保存完了再加_groupOffset
        _groupOffset += _cellHeight + _groupHeight;
      } else if (_listDatas[i].indexLetter == _listDatas[i - 1]) {
        _groupOffset += _cellHeight;
      } else {
        _groupOffsetMap.addAll({_listDatas[i].indexLetter : _groupOffset});
        //保存完了再加_groupOffset
        _groupOffset += _cellHeight + _groupHeight;
      }
    }
  }

當(dāng)外部獲取到索引字符的時(shí)候就需要滾動(dòng)到對(duì)應(yīng)的偏移位置,這里我們用一個(gè) _groupOffsetMap 來存儲(chǔ)每個(gè)索引字符對(duì)應(yīng)的偏移位置,我們通過循環(huán)遍歷對(duì) _groupOffsetMap 進(jìn)行添加數(shù)據(jù)。

滾動(dòng)到對(duì)應(yīng)位置

  ScrollController? _scrollController;
  @override
  void initState() {
    super.initState();
    _scrollController = ScrollController();
}
child: ListView.builder(itemBuilder: _itemForRow, controller: _scrollController, itemCount: _headerData.length + _listDatas.length,)
if(_groupOffsetMap[str] != null) {
              print(str);
              _scrollController!.animateTo(_groupOffsetMap[str], duration: Duration(microseconds: 100), curve: Curves.elasticIn);
            }

在源碼中我們可以看到有一個(gè) controller 屬性,可以用來控制列表的滾動(dòng)。我們定義一個(gè) _scrollController 屬性,在 initState 方法中進(jìn)行初始化,并且在 ListView 初始化的時(shí)候賦值給 controller 屬性,并且在回調(diào)方法中滾動(dòng)到對(duì)應(yīng)位置。duration 代表滾動(dòng)時(shí)長(zhǎng),curve 代表滾動(dòng)的動(dòng)畫效果,大家可以自己選擇動(dòng)畫類型。

添加左邊指示器

我們的指示器是添加在索引條上的,所以所以條的布局方式我們采用 Row 部件,并在 children 添加指示器部件跟原來的索引條部件,整體采用左右結(jié)構(gòu)。

Container(
            alignment: Alignment(0, _indicatorY),
            width: 100,
            child: _indicatorHidden ? null : Stack(
              alignment: Alignment(-0.2, 0),
              children: [
                Image(image: AssetImage('images/氣泡.png'), width: 60,),
                Text(
                  _indicatorText,
                  style: TextStyle(
                    fontSize: 35, color: Colors.white,
                  ),
                )
              ],
            ),
          )

指示器部件我們采用的是一張圖片,并在上面加上文字。這里我們定義了三個(gè)變量, _indicatorY 代表豎軸方向的偏移比例系數(shù),_indicatorHidden 代表是否顯示,_indicatorText 代表顯示的文字,也就是索引字符。

GestureDetector(
            onVerticalDragUpdate: (DragUpdateDetails details){
              int index = _getIndex(context, details.globalPosition);
              callBack(INDEX_WORDS[index]);
              setState(() {
                _indicatorY = 2.2 / INDEX_WORDS.length * index - 1.1;
                _indicatorText = INDEX_WORDS[index];
                _indicatorHidden = false;
              });
            },
            // 索引條點(diǎn)擊
            onVerticalDragDown: (DragDownDetails details){
              int index = _getIndex(context, details.globalPosition);
              callBack(INDEX_WORDS[index]);
              setState(() {
                _indicatorY = 2.2 / INDEX_WORDS.length * index - 1.1;
                _indicatorText = INDEX_WORDS[index];
                _indicatorHidden = false;
              });
            },
// 索引條點(diǎn)擊取消
            onVerticalDragEnd: (DragEndDetails details){
              setState(() {
                _indicatorHidden = true;
              });
            },
)

我們?cè)邳c(diǎn)擊方法與取消方法中分別設(shè)置這三方變量的值,然后調(diào)用 setState 方法,刷新指示器的位置,顯示的文字及是否隱藏狀態(tài)。

聊天列表數(shù)據(jù)的配置及接口請(qǐng)求

聊天列表數(shù)據(jù)配置

這里給大家推薦一個(gè) api 倉(cāng)庫(kù) RAP,大家可以自己注冊(cè)一個(gè)賬號(hào),并配置接口名稱及返回的數(shù)據(jù)。這里我們定義了聊天列表的接口 /api/chat/list,并且配置了數(shù)據(jù),這里我配置的比較簡(jiǎn)單,就三個(gè)屬性 imageUrl、name、name。這里初始值配置的時(shí)候 @cname 代表隨機(jī)生成中文名稱,@cparagraph 代表隨機(jī)生成 message 內(nèi)容。頭像 imageUrl 我們還要借助一個(gè)網(wǎng)站 randomuser 可以隨機(jī)生成假的用戶信息數(shù)據(jù)。

這里我們只用到頭像鏈接地址就可以了,但是這里有一個(gè)規(guī)律,例如我們將頭像鏈接中的 75 改為別的數(shù)字,就會(huì)顯示別的頭像圖片,所以接口文檔中頭像鏈接我們是這樣配置的 ,https://randomuser.me/api/portraits/women/@natural(20,100).jpg,其中 @natural(20,100) 代表隨機(jī)生成 20100 之間的數(shù)據(jù)。

網(wǎng)絡(luò)常用三方庫(kù)

這里給大家推薦一個(gè)網(wǎng)站 pub.dev,作用類似 github,我們可以在上面搜索一下開源的 flutter 三方庫(kù)。網(wǎng)絡(luò)請(qǐng)求的話目前使用比較多的三方庫(kù)是 httpdio。這里我們先使用 http 進(jìn)行網(wǎng)絡(luò)請(qǐng)求演示,這個(gè)三方庫(kù)是 flutter 官方發(fā)布的。

三方庫(kù)配置

在三方庫(kù)詳情頁(yè)點(diǎn)擊復(fù)制按鈕,在 pubspec.yaml 文件中進(jìn)行配置,點(diǎn)擊 Pub get 按鈕進(jìn)行集成。

網(wǎng)絡(luò)請(qǐng)求示例

 @override
  void initState() {
    super.initState();
    //獲取網(wǎng)絡(luò)數(shù)據(jù)
    _getDatas();
  }
  _getDatas() async {
    final url = Uri.parse('http://rap2api.taobao.org/app/mock/294394/api/chat/list');
    final response = await http.get(url);
    print(response);
  }

這里需要注意的是需要先導(dǎo)入頭文件 import 'package:http/http.dart' as http;,async 代表異步執(zhí)行,await 代表等待請(qǐng)求完成才往下執(zhí)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容