flutter 通讯录
flutter 通讯录
工程仓库
国内的话需要梯子打开
https://www.dropbox.com/sh/u9s38957amql3yc/AABc3ncZd8L2gMtMAy83FKL0a?dl=0
如果不能下载的话请私信我
样式长这样
需求分析:
1、滑动会影响到右边的导航栏。
2、右边的导航栏具有点击和拖动的手势,位置点到的位置会影响到左边的list。
3、当list的导航栏的索引没有对应的list会选择最近的list。
4、当最后的list不占满的话,选倒数第二个list,若倒数第二个也不占满,以此类推上一个list。
需求没有说做停留索引,所以我没做了。
整体做法
页面
页面的话整体是个stack
。
占整个的是一个singleChildScrollview
,分两部分,一部分是头Container
,下面那部分是ListView
嵌套ListView
:目的是为了数据好处理。
嵌套一个导航栏:整体是Row
左边是指示器,位置是根据右边的选择来做判定,右边是一个嵌套了GestureDetector
的ListView
。GestureDetector
具有点击、滑动、取消点击的回调。
数据
创建一个长度为27的数组来存储高度(# + A~Z)。数据可能 B没有,那该位置就是上一个A的位置。当滑动的时候,根据offset
来判断当前的位置indexLocation
为右边的导航栏显示更新。
核心代码
整体的scrollview + 模拟数据
// 存储导航列表的高度位置瞄点List<double> scrollHeightList = [];// item高度double itemHeight = 60;// 导航item高度double sessionHeight = 38.5;// 当前选择item的位置int indexLocation = -1;// 最后占满屏幕的高度double lastHeight = 0;// 最后占满屏幕的位置int lastIndex = 0;// 标签页高度double firstItemHeight = 0;List<TeacherChooseList> teacherList = [];// 数据选择的字典Map chooseIndex = {'first': -1, 'second': -1};
在数据的创建时就要把高度给存在scrollHeightList
void createData() {List abcList = ['#','A','B','C','D','E','F'];abcList.forEach((element) {List<TeacherChooseModel> teacherItem = [];for(int i = 0; i < 5; i++) {TeacherChooseModel model = TeacherChooseModel('$element $i 中文 yingwen', false, '');teacherItem.add(model);}final TeacherChooseModel model = TeacherChooseModel('$element ddd', false, '一年级1班101');teacherItem.add(model);final TeacherChooseList chooseList = TeacherChooseList(element, teacherItem);teacherList.add(chooseList);});List<TeacherChooseList> dataList = teacherList;double textWidth = '文本文本文本文本文本文本文本文本文本文本'.paintWidthWithTextStyle(const TextStyle(fontSize: 12));double topItemHeight = 0;if(textWidth > (MediaQuery.of(widget.context).size.width - 30)) {topItemHeight = 33.5;}else {topItemHeight = 17;}firstItemHeight = topItemHeight + 52.5;double totalHeight = firstItemHeight;scrollHeightList.add(totalHeight);int wordIndex = 0;lastHeight += sessionHeight +itemHeight * dataList[dataList.length - 1].teacherItem.length;for(int i = 0; i < indexWord.length; i++) {for(int j = 1; j < dataList.length; j++) {if(dataList[j - 1].index == indexWord[i]) {if (j + 1 == (dataList.length)) {int dataIndex = j;print(MediaQuery.of(widget.context).size.height- firstItemHeight- MediaQuery.of(widget.context).padding.top- 64);while (lastHeight < (MediaQuery.of(widget.context).size.height- firstItemHeight- MediaQuery.of(widget.context).padding.top- 64)) {if(dataIndex >= 0) {lastHeight += sessionHeight +itemHeight * dataList[dataIndex].teacherItem.length;}dataIndex -= 1;if(lastIndex == 0) {lastIndex = wordIndex;}}}totalHeight += sessionHeight + itemHeight*dataList[j - 1].teacherItem.length;break;// }}}scrollHeightList.add(totalHeight);wordIndex += 1;}}
scrollview
的滑动监听
void _scrollListener() {final double offsetY = _scrollController.offset;setState(() {for(int i = 0; i < scrollHeightList.length; i ++) {if(offsetY < scrollHeightList[i]) {indexLocation = i - 1;break;}else {for (int i = 0; i < indexWord.length; i++) {if(indexWord[i] == teacherList.last.index) {indexLocation = i;break;}}}}});}
导航栏
需要传递的数据
List indexWord = ['#','A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'];
class TeacherChooseIndex extends StatefulWidget {final void Function(int index) indexBarCallBack;double totalHeight;int chooseIndex = -1;double firstItemHeight;TeacherChooseIndex({this.indexBarCallBack, this.totalHeight, this.chooseIndex, this.firstItemHeight});@overrideTeacherChooseIndexState createState() => TeacherChooseIndexState();
}
内部的数据
class TeacherChooseIndexState extends State<TeacherChooseIndex> {double _totalHeight = 0;double _indicatorY = 0.0;bool _indicatorHidden = true;String _indicatorText = 'A';double dragHeight = 0;double _firstItemHeight = 0;@overridevoid initState() {super.initState();_totalHeight = widget.totalHeight;dragHeight = 25*_totalHeight/27;_firstItemHeight = widget.firstItemHeight;}
滑动手势获取当前的index位置
int getIndexItem(BuildContext context,Offset globalPosition){//拿到当前盒子final RenderBox box = context.findRenderObject() as RenderBox;//拿到y值,当前位置到部件原点(部件左上角)的距离(x,y)var y = box.globalToLocal(globalPosition).dy;//算出字符高度final itemHeight = dragHeight/27;int index = y ~/itemHeight.clamp(0, indexWord.length-1) - 1;//~取整,设置取整范围clampif(index > 26) {index = 26;}if (index < 0) {index = 0;}print('${indexWord[index]}');return index;}
手势的操作
GestureDetector(onVerticalDragDown: (DragDownDetails details){final int index = getIndexItem(context, details.globalPosition);widget.indexBarCallBack(index);setState(() {widget.chooseIndex = index;_indicatorY = index * dragHeight/27;_indicatorText = indexWord[index];_indicatorHidden = false;//是否隐藏指示器});},onVerticalDragCancel: () {setState(() {_indicatorHidden = true; //是否隐藏指示器});},onVerticalDragEnd:(DragEndDetails details){setState(() {_indicatorHidden = true;//是否隐藏指示器});},onVerticalDragUpdate: (DragUpdateDetails details){final int index = getIndexItem(context, details.globalPosition);widget.indexBarCallBack(index);setState(() {widget.chooseIndex = index;_indicatorY = index * dragHeight/27;_indicatorText = indexWord[index];_indicatorHidden = false;//是否隐藏指示器});},child: Container(width:dragHeight/27,// color: AppColor.black,child: _getListView(context)),),
flutter 通讯录相关推荐
- Flutter (仿微信通讯录)按字母分组列表
再开发过程中我们经常会用到按字母顺序将名称惊醒分组,并且在列表最右侧有指示器,效果图如下.这个效果也是我参照一位大佬的博客才实现的,不过忘记了大佬博客的链接,还是很感谢这位大神的.下面是我自己整理的代 ...
- flutter 微信通讯录
Flutter 仿制微信通讯录效果,致效果如下: 有几个技术细节: 总体可滑动,少于屏幕长度也可滑动 对于数据的处理.昵称 拼音首字母排序, 右侧字母导航,点击/滑动:移动到指定位置 当点击/滑动 ...
- flutter 微信语言选择_Flutter 玩转微信——通讯录
概述 鄙人于闲暇之日,自学Flutter已有两月之久,古人曰:百闻不如一见,百见不如一试,特此利用生平之所学,实战微信以项目.Flutter,学语法之轻易,用组件之简单,源码开源,插件丰富.然一份代码 ...
- flutter 微信语言选择_#Flutter项目(3)之仿写微信通讯录界面
1 导航栏按钮的添加 导航栏 appBar 使用AppBar()方法创建:主要用到的控件属性如下: title:导航栏标题 /// The primary widget displayed in th ...
- android通讯录项目_Flutter高仿微信项目开源-具即时通讯IM功能
项目地址:https://github.com/fluttercandies/wechat_flutter wechat_flutter Flutter版本微信 效果图: 下载体验(Android): ...
- mvp 在 flutter 中的应用
在 Android 应用程序开发过程中,我们经常会用到一些所谓的架构方法,如:mvp,mvvm,clean等.之所以这些方法会被推崇是因为他们可以大大的解耦我们的代码的功能模块,让我们的代码在项目中后 ...
- flutter listview 滚动到底部_flutter实战项目,教你使用flutter打造仿微信app页面!...
flutter_wechat 源码地址:ding-zou/flutter-wechat A flutter app which clones wechat! 这是一个仿照微信样式基于flutter实现 ...
- flutter中使用图标(含自制图标库方案)
flutter中使用图标(含自定义图标图) 作者: jcLee95 邮箱 :291148484@163.com CSDN 主页:https://blog.csdn.net/qq_28550263?sp ...
- Flutter - 底部导航详解与案例示范
Flutter - 底部导航栏解析与示范 作者: jcLee95 邮箱 :291148484@163.com CSDN 主页:https://blog.csdn.net/qq_28550263?spm ...
最新文章
- js弹出一段html,html js 弹出层
- celery mysql flask_如何在Flask中创建Celery实例?
- Android EditText 修改提示字体的大小
- 支持javascript的博客汇总
- Miller Rabin算法:大质数判断
- 文本生成解码策略笔记-常见解码策略
- android(安卓)开源框架——六款【转】
- 课程作业练习 K均值聚类 python实现(最小误差平方和准则)
- 参数检验和非参数检验的区别
- 网上商城的功能模块架构设计之(一)
- c语言中数组怎么用乘法分配律,乘法分配律说课稿(5篇)(33页)-原创力文档
- java scavenge_JAVA Parallel Scavenge收集器
- java数字大小排序_怎么用java给数字排大小?
- 基于Python统计红楼梦中人物信息
- 微信小程序实现收货地址城市选择效果(添加收货地址)
- Verilog:【4】脉冲发生器(pulse_gen.sv)
- java用account类型定义两个变量_java 编程
- 单片机c语言篮球比分_单片机课程设计篮球计时计分器正文1
- linux内核内存屏障,从硬件引申出内存屏障,带你深入了解Linux内核RCU
- matlab符号对象