转载自北斗星_And大神的博客,未经原博主同意,禁止转载

前言

  目前移动市场上很多业务都需要开发Android/IOS两个端,开发成本比较高. Flutter 在跨端上凭借着性能优势关注量,使用度也持续上升.今天给大家分享在去年就写的一个Flutter版本的侧滑栏.

实现

先上一张实现效果图

SliderBar 实现
  侧边是一个支持手势滑动的SliderBar,一个自定义的StatefulWidget.可以观察到,当手势在侧边滑动时,中央显示选中的标签.

布局
  一个横向布局,里面放了一个元素。左边标签的容器尽量占满整个屏幕,右边固定宽度的一个列表(里面放需要展示的Label),代码如下:

new Row(mainAxisSize: MainAxisSize.min,crossAxisAlignment: CrossAxisAlignment.start,children: <Widget>[new Expanded(child: new Center(child: new Text(selectLabel,style:new TextStyle(color: Colors.orange, fontSize: 40.0)))),slide],);

手势数据处理

   Flutter 提供 手势处理类 GestureDetector,当手势开始滑动是更新中央Label显示,停止或者取消时,取消Label显示并把对应的数据填充到Label上.

new GestureDetector(behavior: HitTestBehavior.translucent,child: slideWidget,onPanStart: (event) {updateLabel(context, event.globalPosition);},onPanDown: (event) {updateLabel(context, event.globalPosition);},onVerticalDragUpdate: (event) {updateLabel(context, event.globalPosition);},onPanCancel: () {setState(() {selectLabel = '';});},onVerticalDragEnd: (event) {setState(() {selectLabel = '';});},);

遇到的问题以及解决方法:

GestureDetector 监听的手势很多,当注册 onVerticalDragUpdate 后,onPanUpdate 不在回调,解决方法:将onPanUpdate逻辑全部移入onVerticalDragUpdate,
onPanUp 未监听到手势抬起,解决方法:换用onPanCancel,onVerticalDragEnd方法监听
updateLabel,获取具体选中Label的index 公式为 index = dy / widgetHeight * labelList.length,其中dy 为 以控件起始点y的位置偏移量,widgetHeight为高度,
labelList.length为Label的长度,刷新数据逻辑如下:

void updateLabel(BuildContext context, Offset globalPosition) {var object = globalKey?.currentContext?.findRenderObject();var translation = object?.getTransformTo(null)?.getTranslation();int index = ((globalPosition.dy - translation.y - topMargin) /(globalKey.currentContext.size.height - topMargin) *widget.showList.length).toInt();if (index < widget.showList.length && index >= 0) {setState(() {selectLabel = widget.showList[index];if (widget.onChangeSelect != null) {widget.onChangeSelect(selectLabel);}});}}

其中,获取控件距离屏幕的距离方法为:

  var object = globalKey?.currentContext?.findRenderObject();var translation = object?.getTransformTo(null)?.getTranslation();

城市选择主界面实现

主布局

   采用了Flutter 的Stack布局(非常类似Android FrameLayout),下层是城市选择页面数据,上层盖了一层SliderBar

 new Scaffold(appBar: getAppBar(),body: new Stack(children: <Widget>[getShowContentView(),new SlideBar(cityListUtils.labelList, onChangeSelect)]));

UI的下层 使用 ListView.builder 根据item类型返回不同类型的Widget

Widget rightCity = new Container(color: AppColor.white,padding: EdgeInsets.only(right: 20.0),child: new ListView.builder(controller: scrollController,itemCount: cityListUtils.cityList.length,itemBuilder: (listContext, position) {var city = cityListUtils.cityList[position];if (city is CityModel) {return new GestureDetector(behavior: HitTestBehavior.translucent,child: new Container(decoration: new BoxDecoration(border: new Border.all(color: AppColor.bg1, width: 0.5)),height: 48.0,padding: EdgeInsets.only(left: 15.0),alignment: Alignment.centerLeft,child: new Text(city.name)),onTap:selectCity(city));} else if (city is CityLabel) {return new Container(width: MediaQuery.of(context).size.width,height: 20.0,padding: EdgeInsets.only(left: 15.0),child: new Text(city.keyLabel),color: AppColor.bg1,);}}));

城市列表数据处理

   城市列表的数据格式如下

{"A":[{"name":"澳门","id":"***","fullWord":"aomen","first":"am","isShow":"true"}]}

数据解析使用到dart:convert包,调用json.decode(jsonStr)解析的数据为map,在将Map转为具体的实体,实体解析工具推荐使用开源工具自动生成模型文件 FlutterJsonBeanFactory
得到城市实体的解析Model如下:

import 'dart:convert' show json;class CityModel {String first;String fullWord;String id;String isShow;String name;bool isSelected = false;CityModel.fromParams({this.first, this.fullWord, this.id, this.isShow, this.name});factory CityModel(jsonStr) => jsonStr is String? CityModel.fromJson(json.decode(jsonStr)): CityModel.fromJson(jsonStr);CityModel.fromJson(jsonRes) {first = jsonRes['first'];fullWord = jsonRes['fullWord'];id = jsonRes['id'];isShow = jsonRes['isShow'];name = jsonRes['name'];}@overrideString toString() {return '{"first": ${first != null?'${json.encode(first)}':'null'},"fullWord": ${fullWord != null?'${json.encode(fullWord)}':'null'},"id": ${id != null?'${json.encode(id)}':'null'},"isShow": ${isShow != null?'${json.encode(isShow)}':'null'},"name": ${name != null?'${json.encode(name)}':'null'}}';}
}

将首字母,城市数据存入CityList里,并将首字母列表传入到SliderBar中,记录字母索引所在的位置

class CityListUtils {List cityList = [];List<String> labelList = [];Map<String, IndexPosition> mapKey = {};void parse(var map) {if (map is String) {map = json.decode(map);}Map mapList = map['destination'];int index = 0, labelPosition = 0;mapList.keys.forEach((key) {cityList.add(new CityLabel(key));labelList.add(key);mapKey[key] = new IndexPosition(labelPosition, index);labelPosition++;index++;for (var value in mapList[key]) {index++;cityList.add(new CityModel(value));};});}
}

联动处理
当滑动SliderBar时,应将城市列表滑到对应的位置,ListView 提供 ScrollController 去为ListView 添加监听及 Auto scroll ListView,
里面对应的有两个方法可以滑动,一个是带有动画 animateTo,一个不带有动画的滑动 jumpTo,此处使用不带有的方法,传递参数为
滑动的偏移量,实现如下

  OnChangeSelect onChangeSelect = (keyLabel) {IndexPosition index = cityListUtils.mapKey[keyLabel];scrollController.jumpTo(index.total * 48.0 - index.label * 28.0);};

其中 OnChangeSelect定义为

typedef OnChangeSelect(String keyLabel);

使用接口回调的方式将选中的key回传,并使用CityListUtils里存储的mapKey找到对应的首字母索引,计算出ListView应该滑动的偏移量

遇到的问题
计算的偏移量不准,导致滑动不能准确定位到首字母索引上。
原因:item 使用 Container布局 高度未限制,手动获取到的高度不准确
解决方法:使用固定的item高度

Flutter 侧滑栏UI及城市选择UI的实现相关推荐

  1. html5 a-z字母排序,Mint UI实现A-Z字母排序的城市选择列表

    本文实例为大家分享了Mint Ul实现A-Z字母排序的城市选择列表的具体代码,供大家参考,具体内容如下 效果图如下: 项目文件存放路径图: 所有代码如下: import city from " ...

  2. 网游UI解决方案的选择(作者 鸣·铭)

    网游UI解决方案的选择作者 鸣·铭 转载请注明出自http://www.mobilegamebase.com 由于新项目动工,UI方面需要确定方向,所以最近纠结于各种解决方案的选择.以下是对各方案的比 ...

  3. 网游UI解决方案的选择

    网游UI解决方案的选择 作者 鸣·铭  转载请注明出自http://www.mobilegamebase.com 由于新项目动工,UI方面需要确定方向,所以最近纠结于各种解决方案的选择.以下是对各方案 ...

  4. 网游UI解决方案的选择(转)

    网游UI解决方案的选择作者 鸣·铭  转载请注明出自http://www.mobilegamebase.com 由于新项目动工,UI方面需要确定方向,所以最近纠结于各种解决方案的选择.以下是对各方案的 ...

  5. 网游UI解决方案的选择(CEGUI/MYGUI/Hikari/Scaleform/...)

    网游UI解决方案的选择 作者 鸣·铭 转载请注明出自http://www.mobilegamebase.com 由于新项目动工,UI方面需要确定方向,所以最近纠结于各种解决方案的选择.以下是对各方案的 ...

  6. autojs之大柒侧滑栏详解

    使用场景 解析 大柒 侧滑栏 效果展示 缘由 大柒做UI很棒, 以前他在群里分享过这个侧滑栏, 虽然一直没有能用到这个侧滑栏的机会, 但是还是想看看他怎么做的 autoj版本 代码讲解 布局 整体就是 ...

  7. 微信小程序手把手教你实现带字母索引的城市选择列表

    微信小程序手把手教你实现带字母索引的城市选择列表 前言 需求分析 左边可滑动列表 滑动列表UI实现 item点击事件 右边带字母的索引条 索引条从上到下分别是定位和26个大写字母 索引条响应触摸和点击 ...

  8. 第四十四课:jQuery UI和jQuery easy UI

    jQuery UI是jQuery官方提供的功能效果和UI样式.作为官方出的东西,它一直没有被人们看重,一是它没有datagrid,tree等UI库必备的东西,二是它修改太过频繁,体积庞大.其实它所有以 ...

  9. 独立完成一个城市选择组件(阿里前端题目,内附知识点、思路)

    借用了两个久经考验的轮子:fastClick和better-scroll,介意可以就此打住.本文绝对原创,手打,思路清晰,知识不难,不适合大佬观看,谢谢. 首先说一下,我不是阿里的人,也没去阿里面试过 ...

最新文章

  1. go通过thrift连接hbase_关于thrift协议改进畅想
  2. 简单理解kafka---入门
  3. Struts2-拦截器原理
  4. 剑指Offer 从尾到头打印链表
  5. 博客网站源代码_详解SEO布词以及网站排名优化技巧
  6. [结构力学] 几何构造分析的技巧
  7. Linux 小知识翻译 - 「/proc 文件夹」
  8. C#多线程之线程池篇2
  9. mysql 单向自动同步_mysql单向自动同步
  10. java中的io系统详解[转]
  11. java多线程调度_Java多线程:生命周期,实现与调度
  12. conda SSL错误
  13. word如何拆分表格
  14. 纯前端语言编写音乐播放器
  15. Django - Celery使用及介绍
  16. 保险保费基本计算规则
  17. Win10浏览器闪退问题解决(所有类型的浏览器都会发生闪退、包括chrome、firefox)
  18. mysql插入数据时如果有相同数据就不插入或者替换
  19. 软件工程——成本效益分析
  20. 当人工智能变成美妆博主……

热门文章

  1. qrc路径_Windows下 Qt 资源文件(.qrc)文件 的 编写与应用
  2. 经验分享:SEO新手面对新网站应该如何去优化
  3. Q4财报过后,为何说兰亭集势迎来“价值拐点”?
  4. 资源帖丨从推荐算法到前端开发,这是字节跳动技术Leader们最中意的40项学习资源
  5. unity中的动态绑定、赋值等
  6. FOC——12.MOS管电路及选型
  7. 10.8上海交大PMP每日一题
  8. 郁闷的出纳员(splay, 树状数组可做)
  9. 【TIOBE 2月编程语言排行榜新鲜出炉!Python获1.77%增长率!】
  10. 编程题009--按之字形顺序打印二叉树--niuke