From 75d2c6e34289f6729b4ef25a9a470330358d6f58 Mon Sep 17 00:00:00 2001 From: tanghongliang Date: Fri, 21 Sep 2018 23:24:48 +0800 Subject: [PATCH] IndexBar,SuspensionWidget --- .gitignore | 1 + README.md | 2 + assets/data/china.json | 1111 ++++++++++++++++++++ lib/main.dart | 7 +- lib/routes/index.dart | 3 +- lib/routes/index_suspension.dart | 328 ++++++ lib/widgets/page_scaffold.dart | 9 + package_src/lib/flukit.dart | 2 + package_src/lib/src/index_bar.dart | 250 +++++ package_src/lib/src/suspension_widget.dart | 238 +++++ package_src/pubspec.lock | 377 ------- pubspec.lock | 391 ------- pubspec.yaml | 4 + 13 files changed, 1949 insertions(+), 774 deletions(-) create mode 100644 assets/data/china.json create mode 100644 lib/routes/index_suspension.dart create mode 100644 package_src/lib/src/index_bar.dart create mode 100644 package_src/lib/src/suspension_widget.dart delete mode 100644 package_src/pubspec.lock delete mode 100644 pubspec.lock diff --git a/.gitignore b/.gitignore index 43b5f44..c85378d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ .packages .pub/ .idea/ +pubspec.lock build/ diff --git a/README.md b/README.md index 6676950..9c542c3 100644 --- a/README.md +++ b/README.md @@ -39,5 +39,7 @@ If you add a new widget,please follow these rules: - ScaleView - Swiper - AnimatedRotationBox +- IndexBar +- SuspensionWidget diff --git a/assets/data/china.json b/assets/data/china.json new file mode 100644 index 0000000..197384e --- /dev/null +++ b/assets/data/china.json @@ -0,0 +1,1111 @@ +{ + "china": [ + { + "name": "北京市" + }, + { + "name": "天津市" + }, + { + "name": "石家庄市" + }, + { + "name": "唐山市" + }, + { + "name": "秦皇岛市" + }, + { + "name": "邯郸市" + }, + { + "name": "邢台市" + }, + { + "name": "保定市" + }, + { + "name": "张家口市" + }, + { + "name": "承德市" + }, + { + "name": "沧州市" + }, + { + "name": "廊坊市" + }, + { + "name": "衡水市" + }, + { + "name": "太原市" + }, + { + "name": "大同市" + }, + { + "name": "阳泉市" + }, + { + "name": "长治市" + }, + { + "name": "晋城市" + }, + { + "name": "朔州市" + }, + { + "name": "晋中市" + }, + { + "name": "运城市" + }, + { + "name": "忻州市" + }, + { + "name": "临汾市" + }, + { + "name": "吕梁市" + }, + { + "name": "呼和浩特市" + }, + { + "name": "包头市" + }, + { + "name": "乌海市" + }, + { + "name": "赤峰市" + }, + { + "name": "通辽市" + }, + { + "name": "鄂尔多斯市" + }, + { + "name": "呼伦贝尔市" + }, + { + "name": "巴彦淖尔市" + }, + { + "name": "乌兰察布市" + }, + { + "name": "兴安盟" + }, + { + "name": "锡林郭勒盟" + }, + { + "name": "阿拉善盟" + }, + { + "name": "沈阳市" + }, + { + "name": "大连市" + }, + { + "name": "鞍山市" + }, + { + "name": "抚顺市" + }, + { + "name": "本溪市" + }, + { + "name": "丹东市" + }, + { + "name": "锦州市" + }, + { + "name": "营口市" + }, + { + "name": "阜新市" + }, + { + "name": "辽阳市" + }, + { + "name": "盘锦市" + }, + { + "name": "铁岭市" + }, + { + "name": "朝阳市" + }, + { + "name": "葫芦岛市" + }, + { + "name": "长春市" + }, + { + "name": "吉林市" + }, + { + "name": "四平市" + }, + { + "name": "辽源市" + }, + { + "name": "通化市" + }, + { + "name": "白山市" + }, + { + "name": "松原市" + }, + { + "name": "白城市" + }, + { + "name": "延边朝鲜族自治州" + }, + { + "name": "哈尔滨市" + }, + { + "name": "齐齐哈尔市" + }, + { + "name": "鸡西市" + }, + { + "name": "鹤岗市" + }, + { + "name": "双鸭山市" + }, + { + "name": "大庆市" + }, + { + "name": "伊春市" + }, + { + "name": "佳木斯市" + }, + { + "name": "七台河市" + }, + { + "name": "牡丹江市" + }, + { + "name": "黑河市" + }, + { + "name": "绥化市" + }, + { + "name": "大兴安岭地区" + }, + { + "name": "上海市" + }, + { + "name": "南京市" + }, + { + "name": "无锡市" + }, + { + "name": "徐州市" + }, + { + "name": "常州市" + }, + { + "name": "苏州市" + }, + { + "name": "南通市" + }, + { + "name": "连云港市" + }, + { + "name": "淮安市" + }, + { + "name": "盐城市" + }, + { + "name": "扬州市" + }, + { + "name": "镇江市" + }, + { + "name": "泰州市" + }, + { + "name": "宿迁市" + }, + { + "name": "杭州市" + }, + { + "name": "宁波市" + }, + { + "name": "温州市" + }, + { + "name": "嘉兴市" + }, + { + "name": "湖州市" + }, + { + "name": "绍兴市" + }, + { + "name": "金华市" + }, + { + "name": "衢州市" + }, + { + "name": "舟山市" + }, + { + "name": "台州市" + }, + { + "name": "丽水市" + }, + { + "name": "合肥市" + }, + { + "name": "芜湖市" + }, + { + "name": "蚌埠市" + }, + { + "name": "淮南市" + }, + { + "name": "马鞍山市" + }, + { + "name": "淮北市" + }, + { + "name": "铜陵市" + }, + { + "name": "安庆市" + }, + { + "name": "黄山市" + }, + { + "name": "滁州市" + }, + { + "name": "阜阳市" + }, + { + "name": "宿州市" + }, + { + "name": "巢湖市" + }, + { + "name": "六安市" + }, + { + "name": "亳州市" + }, + { + "name": "池州市" + }, + { + "name": "宣城市" + }, + { + "name": "福州市" + }, + { + "name": "厦门市" + }, + { + "name": "莆田市" + }, + { + "name": "三明市" + }, + { + "name": "泉州市" + }, + { + "name": "漳州市" + }, + { + "name": "南平市" + }, + { + "name": "龙岩市" + }, + { + "name": "宁德市" + }, + { + "name": "南昌市" + }, + { + "name": "景德镇市" + }, + { + "name": "萍乡市" + }, + { + "name": "九江市" + }, + { + "name": "新余市" + }, + { + "name": "鹰潭市" + }, + { + "name": "赣州市" + }, + { + "name": "吉安市" + }, + { + "name": "宜春市" + }, + { + "name": "抚州市" + }, + { + "name": "上饶市" + }, + { + "name": "济南市" + }, + { + "name": "青岛市" + }, + { + "name": "淄博市" + }, + { + "name": "枣庄市" + }, + { + "name": "东营市" + }, + { + "name": "烟台市" + }, + { + "name": "潍坊市" + }, + { + "name": "济宁市" + }, + { + "name": "泰安市" + }, + { + "name": "威海市" + }, + { + "name": "日照市" + }, + { + "name": "莱芜市" + }, + { + "name": "临沂市" + }, + { + "name": "德州市" + }, + { + "name": "聊城市" + }, + { + "name": "滨州市" + }, + { + "name": "菏泽市" + }, + { + "name": "郑州市" + }, + { + "name": "开封市" + }, + { + "name": "洛阳市" + }, + { + "name": "平顶山市" + }, + { + "name": "安阳市" + }, + { + "name": "鹤壁市" + }, + { + "name": "新乡市" + }, + { + "name": "焦作市" + }, + { + "name": "濮阳市" + }, + { + "name": "许昌市" + }, + { + "name": "漯河市" + }, + { + "name": "三门峡市" + }, + { + "name": "南阳市" + }, + { + "name": "商丘市" + }, + { + "name": "信阳市" + }, + { + "name": "周口市" + }, + { + "name": "驻马店市" + }, + { + "name": "武汉市" + }, + { + "name": "黄石市" + }, + { + "name": "十堰市" + }, + { + "name": "宜昌市" + }, + { + "name": "襄樊市" + }, + { + "name": "鄂州市" + }, + { + "name": "荆门市" + }, + { + "name": "孝感市" + }, + { + "name": "荆州市" + }, + { + "name": "黄冈市" + }, + { + "name": "咸宁市" + }, + { + "name": "随州市" + }, + { + "name": "恩施土家族苗族自治州" + }, + { + "name": "仙桃市" + }, + { + "name": "潜江市" + }, + { + "name": "天门市" + }, + { + "name": "神农架林区" + }, + { + "name": "长沙市" + }, + { + "name": "株洲市" + }, + { + "name": "湘潭市" + }, + { + "name": "衡阳市" + }, + { + "name": "邵阳市" + }, + { + "name": "岳阳市" + }, + { + "name": "常德市" + }, + { + "name": "张家界市" + }, + { + "name": "益阳市" + }, + { + "name": "郴州市" + }, + { + "name": "永州市" + }, + { + "name": "怀化市" + }, + { + "name": "娄底市" + }, + { + "name": "湘西土家族苗族自治州" + }, + { + "name": "广州市" + }, + { + "name": "韶关市" + }, + { + "name": "深圳市" + }, + { + "name": "珠海市" + }, + { + "name": "汕头市" + }, + { + "name": "佛山市" + }, + { + "name": "江门市" + }, + { + "name": "湛江市" + }, + { + "name": "茂名市" + }, + { + "name": "肇庆市" + }, + { + "name": "惠州市" + }, + { + "name": "梅州市" + }, + { + "name": "汕尾市" + }, + { + "name": "河源市" + }, + { + "name": "阳江市" + }, + { + "name": "清远市" + }, + { + "name": "东莞市" + }, + { + "name": "中山市" + }, + { + "name": "潮州市" + }, + { + "name": "揭阳市" + }, + { + "name": "云浮市" + }, + { + "name": "南宁市" + }, + { + "name": "柳州市" + }, + { + "name": "桂林市" + }, + { + "name": "梧州市" + }, + { + "name": "北海市" + }, + { + "name": "防城港市" + }, + { + "name": "钦州市" + }, + { + "name": "贵港市" + }, + { + "name": "玉林市" + }, + { + "name": "百色市" + }, + { + "name": "贺州市" + }, + { + "name": "河池市" + }, + { + "name": "来宾市" + }, + { + "name": "崇左市" + }, + { + "name": "海口市" + }, + { + "name": "三亚市" + }, + { + "name": "重庆市" + }, + { + "name": "成都市" + }, + { + "name": "自贡市" + }, + { + "name": "攀枝花市" + }, + { + "name": "泸州市" + }, + { + "name": "德阳市" + }, + { + "name": "绵阳市" + }, + { + "name": "广元市" + }, + { + "name": "遂宁市" + }, + { + "name": "内江市" + }, + { + "name": "乐山市" + }, + { + "name": "南充市" + }, + { + "name": "眉山市" + }, + { + "name": "宜宾市" + }, + { + "name": "广安市" + }, + { + "name": "达州市" + }, + { + "name": "雅安市" + }, + { + "name": "巴中市" + }, + { + "name": "资阳市" + }, + { + "name": "阿坝藏族羌族自治州" + }, + { + "name": "甘孜藏族自治州" + }, + { + "name": "凉山彝族自治州" + }, + { + "name": "贵阳市" + }, + { + "name": "六盘水市" + }, + { + "name": "遵义市" + }, + { + "name": "安顺市" + }, + { + "name": "铜仁市" + }, + { + "name": "黔西南布依族苗族自治州" + }, + { + "name": "毕节市" + }, + { + "name": "黔东南苗族侗族自治州" + }, + { + "name": "黔南布依族苗族自治州" + }, + { + "name": "昆明市" + }, + { + "name": "曲靖市" + }, + { + "name": "玉溪市" + }, + { + "name": "保山市" + }, + { + "name": "昭通市" + }, + { + "name": "丽江市" + }, + { + "name": "思茅市" + }, + { + "name": "临沧市" + }, + { + "name": "楚雄彝族自治州" + }, + { + "name": "红河哈尼族彝族自治州" + }, + { + "name": "文山壮族苗族自治州" + }, + { + "name": "西双版纳傣族自治州" + }, + { + "name": "大理白族自治州" + }, + { + "name": "德宏傣族景颇族自治州" + }, + { + "name": "怒江傈僳族自治州" + }, + { + "name": "迪庆藏族自治州" + }, + { + "name": "拉萨市" + }, + { + "name": "昌都地区" + }, + { + "name": "山南地区" + }, + { + "name": "日喀则地区" + }, + { + "name": "那曲地区" + }, + { + "name": "阿里地区" + }, + { + "name": "林芝地区" + }, + { + "name": "西安市" + }, + { + "name": "铜川市" + }, + { + "name": "宝鸡市" + }, + { + "name": "咸阳市" + }, + { + "name": "渭南市" + }, + { + "name": "延安市" + }, + { + "name": "汉中市" + }, + { + "name": "榆林市" + }, + { + "name": "安康市" + }, + { + "name": "商洛市" + }, + { + "name": "兰州市" + }, + { + "name": "嘉峪关市" + }, + { + "name": "金昌市" + }, + { + "name": "白银市" + }, + { + "name": "天水市" + }, + { + "name": "武威市" + }, + { + "name": "张掖市" + }, + { + "name": "平凉市" + }, + { + "name": "酒泉市" + }, + { + "name": "庆阳市" + }, + { + "name": "定西市" + }, + { + "name": "陇南市" + }, + { + "name": "临夏回族自治州" + }, + { + "name": "甘南藏族自治州" + }, + { + "name": "西宁市" + }, + { + "name": "海东地区" + }, + { + "name": "海北藏族自治州" + }, + { + "name": "黄南藏族自治州" + }, + { + "name": "海南藏族自治州" + }, + { + "name": "果洛藏族自治州" + }, + { + "name": "玉树藏族自治州" + }, + { + "name": "海西蒙古族藏族自治州" + }, + { + "name": "银川市" + }, + { + "name": "石嘴山市" + }, + { + "name": "吴忠市" + }, + { + "name": "固原市" + }, + { + "name": "中卫市" + }, + { + "name": "乌鲁木齐市" + }, + { + "name": "克拉玛依市" + }, + { + "name": "吐鲁番地区" + }, + { + "name": "哈密地区" + }, + { + "name": "昌吉回族自治州" + }, + { + "name": "博尔塔拉蒙古自治州" + }, + { + "name": "巴音郭楞蒙古自治州" + }, + { + "name": "阿克苏地区" + }, + { + "name": "克孜勒苏柯尔克孜自治州" + }, + { + "name": "喀什地区" + }, + { + "name": "和田地区" + }, + { + "name": "伊犁哈萨克" + }, + { + "name": "塔城地区" + }, + { + "name": "阿勒泰地区" + }, + { + "name": "石河子市" + }, + { + "name": "阿拉尔市" + }, + { + "name": "图木舒克市" + }, + { + "name": "五家渠市" + }, + { + "name": "台北" + }, + { + "name": "高雄" + }, + { + "name": "基隆" + }, + { + "name": "台中" + }, + { + "name": "台南" + }, + { + "name": "新竹" + }, + { + "name": "嘉义" + }, + { + "name": "宜兰" + }, + { + "name": "桃园" + }, + { + "name": "苗栗" + }, + { + "name": "彰化" + }, + { + "name": "南投" + }, + { + "name": "云林" + }, + { + "name": "屏东" + }, + { + "name": "台东" + }, + { + "name": "花莲" + }, + { + "name": "澎湖" + }, + { + "name": "香港岛" + }, + { + "name": "九龙" + }, + { + "name": "新界" + }, + { + "name": "澳门半岛" + }, + { + "name": "氹仔岛" + }, + { + "name": "路环岛" + }, + { + "name": "路氹城" + } + ] +} diff --git a/lib/main.dart b/lib/main.dart index f1f588c..99294db 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -26,7 +26,6 @@ class MyHomePage extends StatefulWidget { } class _MyHomePageState extends State { - @override Widget build(BuildContext context) { return Scaffold( @@ -37,9 +36,7 @@ class _MyHomePageState extends State { PageInfo("Swiper", (ctx) => SwiperRoute()), PageInfo("Swiper Style", (ctx) => SwiperStyleRoute()), PageInfo("Photo View", (ctx) => PhotoViewRoute()), - ]) - ); + PageInfo("IndexBar & SuspensionWidget", (ctx) => IndexSuspensionRoute()), + ])); } } - - diff --git a/lib/routes/index.dart b/lib/routes/index.dart index 6742ed0..3433103 100644 --- a/lib/routes/index.dart +++ b/lib/routes/index.dart @@ -2,4 +2,5 @@ export 'quick_scrollbar.dart'; export 'pull_refresh.dart'; export 'swiper.dart'; export 'photo_view.dart'; -export 'swiper_control.dart'; \ No newline at end of file +export 'swiper_control.dart'; +export 'index_suspension.dart'; \ No newline at end of file diff --git a/lib/routes/index_suspension.dart b/lib/routes/index_suspension.dart new file mode 100644 index 0000000..d4673d0 --- /dev/null +++ b/lib/routes/index_suspension.dart @@ -0,0 +1,328 @@ +import 'dart:convert'; + +import 'package:flukit/flukit.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lpinyin/lpinyin.dart'; + +class CityBean extends BaseIndexBean { + String name; + + CityBean({ + this.name, + baseIndexTag, + baseIndexPinyin, + isShowSuspension, + }) : super( + baseIndexName: name, + baseIndexTag: baseIndexTag, + baseIndexPinyin: baseIndexPinyin, + isShowSuspension: isShowSuspension); + + CityBean.fromJson(Map json) + : name = json['name'] == null ? "" : json['name']; + + Map toJson() => { + 'name': name, + 'baseIndexName': baseIndexName, + 'baseIndexTag': baseIndexTag, + 'baseIndexPinyin': baseIndexPinyin, + 'isShowSuspension': isShowSuspension + }; + + @override + String toString() { + return "CityBean {" + " \"name\":\"" + name + "\"" + '}'; + } +} + +class PinYinUtils { + ///获取拼音并排序 + static void sortListByLetter(List list) { + if (list == null || list.isEmpty) return; + for (int i = 0, length = list.length; i < length; i++) { + String pinyin = PinyinHelper.convertToPinyinStringWithoutException( + list[i].baseIndexName); + list[i].baseIndexPinyin = pinyin; + String tag = pinyin.substring(0, 1).toUpperCase(); + if (new RegExp("[A-Z]").hasMatch(tag)) { + list[i].baseIndexTag = tag; + } else { + list[i].baseIndexTag = "#"; + } + } + SuspensionUtil.sortSuspensionList(list); + } +} + +class IndexSuspensionRoute extends StatefulWidget { + @override + State createState() { + return new _IndexSuspensionRouteState(); + } +} + +class _IndexSuspensionRouteState extends State { + List _cityList = new List(); + List _hotCityList = new List(); + List _indexTagList = new List(); + + Map _suspensionSectionMap = new Map(); + + ScrollController _scrollController; + int _suspensionHeight = 40; + int _itemHeight = 50; + String _suspensionTag = ""; + + bool _isShowIndexBarHint = false; + String _indexBarHint = ""; + + @override + void initState() { + super.initState(); + + _scrollController = new ScrollController(); + + _hotCityList.add(new CityBean(name: "北京市", baseIndexTag: "★ 热门城市")); + _hotCityList.add(new CityBean(name: "广州市", baseIndexTag: "★ 热门城市")); + _hotCityList.add(new CityBean(name: "成都市", baseIndexTag: "★ 热门城市")); + _hotCityList.add(new CityBean(name: "深圳市", baseIndexTag: "★ 热门城市")); + _hotCityList.add(new CityBean(name: "杭州市", baseIndexTag: "★ 热门城市")); + _hotCityList.add(new CityBean(name: "武汉市", baseIndexTag: "★ 热门城市")); + + loadData(); +// new Future.delayed(new Duration(milliseconds: 500), () { +// loadData(); +// }); + } + + void loadData() async { + rootBundle.loadString('assets/data/china.json').then((value) { + List cityList = new List(); + Map countyMap = json.decode(value); + List list = countyMap['china']; + list.forEach((value) { + cityList.add(new CityBean(name: value['name'])); + }); + + showData(cityList); + }); + } + + void showData(List cityList) { + PinYinUtils.sortListByLetter(cityList); + + setState(() { + _cityList.addAll(_hotCityList); + _cityList.addAll(cityList); + + _indexTagList.clear(); + _indexTagList.add("★"); + _indexTagList.addAll(SuspensionUtil.getRealIndexDataList(cityList)); + + SuspensionUtil.buildShowSuspensionTag(_cityList); + _suspensionTag = _cityList.isEmpty ? "" : _cityList[0].baseIndexTag; + }); + } + + void _onIBarTouchCallback(IndexModel model) { + setState(() { + _indexBarHint = model.currentTag; + _isShowIndexBarHint = model.isTouchDown; + + String current = model.currentTag; + if (current == "★") { + current = "★ 热门城市"; + } + int offset = _suspensionSectionMap[current]; + if (offset != null) { + _scrollController.jumpTo(offset.toDouble()); + } + }); + } + + void _onSusTagChangeCallBack(String tag) { + setState(() { + _suspensionTag = tag; + }); + } + + void _onSusSectionCallBack(Map map) { + _suspensionSectionMap = map; + } + + Widget _buildListItem(int index) { + CityBean model = _cityList[index]; + return new Column( + children: [ + new Offstage( + offstage: !(model.isShowSuspension == true), + child: new Container( + alignment: Alignment.centerLeft, + height: _suspensionHeight.toDouble(), + color: Color(0xfff3f4f5), + padding: const EdgeInsets.only(left: 15.0), + child: new Text( + model.baseIndexTag, + style: new TextStyle(fontSize: 14.0, color: Color(0xff999999)), + )), + ), + new InkWell( + onTap: () { + print("OnItemClick: " + model.toString()); + }, + child: new Container( + height: _itemHeight.toDouble(), + alignment: Alignment.centerLeft, + child: new Padding( + padding: const EdgeInsets.only(left: 15.0), + child: new Text( + model.name, + style: new TextStyle(color: Color(0xff333333), fontSize: 14.0), + ), + ), + decoration: new BoxDecoration( + color: Colors.white, + border: new Border( + bottom: + new BorderSide(color: Color(0xfff5f5f5), width: 0.33))), + ), + ) + ], + ); + } + + @override + Widget build(BuildContext context) { + return new Material( + color: Colors.transparent, + child: new Column( + children: [ + new Container( + color: Colors.white, + child: new Row( + children: [ + new Expanded( + child: new Padding( + padding: const EdgeInsets.only(left: 10.0, right: 10.0), + child: new TextField( + autofocus: false, + style: new TextStyle( + fontSize: 14.0, color: Color(0XFF333333)), + decoration: new InputDecoration( + border: InputBorder.none, + hintText: '城市中文名或拼音', + hintStyle: new TextStyle( + fontSize: 14.0, color: Color(0XFFcccccc))), + ), + )), + new Container( + width: 0.33, + height: 14.0, + color: Color(0XFFEFEFEF), + ), + new InkWell( + onTap: () { + Navigator.pop(context); + }, + child: new Padding( + padding: const EdgeInsets.all(8.0), + child: new Text( + "取消", + style: new TextStyle( + color: Color(0xFF999999), fontSize: 14.0), + ), + ), + ) + ], + ), + ), + new Expanded( + child: new Card( + color: Colors.white, + margin: const EdgeInsets.only( + left: 10.0, top: 10.0, right: 10.0, bottom: 0.0), + shape: const RoundedRectangleBorder( + borderRadius: + const BorderRadius.all(const Radius.circular(2.0)), + ), + child: new Column( + children: [ + new Container( + alignment: Alignment.centerLeft, + padding: const EdgeInsets.only(left: 15.0), + height: 50.0, + child: new Text( + "当前城市:成都市", + style: new TextStyle( + fontSize: 14.0, color: Color(0xff333333)), + ), + ), + new Expanded( + flex: 1, + child: new Container( + child: new Stack( + children: [ + new SuspensionWidget(_cityList, + contentWidget: new ListView.builder( + controller: _scrollController, + shrinkWrap: true, + itemCount: _cityList.length, + itemBuilder: + (BuildContext context, int index) { + return _buildListItem(index); + }), + suspensionWidget: new Container( + height: 40.0, + padding: const EdgeInsets.only(left: 15.0), + color: Color(0xfff3f4f5), + alignment: Alignment.centerLeft, + child: new Text( + '$_suspensionTag', + softWrap: false, + style: new TextStyle( + fontSize: 14.0, + color: Color(0xff999999)), + )), + controller: _scrollController, + suspensionHeight: _suspensionHeight, + itemHeight: _itemHeight, + onSusTagChangeCallBack: _onSusTagChangeCallBack, + onSusSectionCallBack: _onSusSectionCallBack), + new Align( + alignment: Alignment.centerRight, + child: new IndexBar( + indexData: _indexTagList, + touchDownColor: Color(0x7DF7F7F7), + onIBarTouchCallback: _onIBarTouchCallback), + ), + new Offstage( + offstage: !_isShowIndexBarHint, + child: new Center( + child: new Card( + color: Color(0xFF262626), + child: new Container( + alignment: Alignment.center, + width: 72.0, + height: 72.0, + child: new Text( + '$_indexBarHint', + textAlign: TextAlign.center, + style: new TextStyle( + fontSize: 32.0, + color: Colors.white), + ), + ), + ), + )) + ], + ), + )) + ], + ), + )), + ], + )); + } +} diff --git a/lib/widgets/page_scaffold.dart b/lib/widgets/page_scaffold.dart index 0f19f3c..3862059 100644 --- a/lib/widgets/page_scaffold.dart +++ b/lib/widgets/page_scaffold.dart @@ -1,3 +1,4 @@ +import 'package:flukitdemo/routes/index_suspension.dart'; import 'package:flutter/material.dart'; class PageScaffold extends StatelessWidget { @@ -36,6 +37,14 @@ class ListPage extends StatelessWidget { } void _openPage(BuildContext context,PageInfo page) { + if (page.title == "IndexBar & SuspensionWidget") { + showDialog( + context: context, + barrierDismissible: false, + builder: (BuildContext context) => new IndexSuspensionRoute(), + ); + return; + } Navigator.push(context, MaterialPageRoute(builder: (context) { if (!page.withScaffold) { return page.builder(context); diff --git a/package_src/lib/flukit.dart b/package_src/lib/flukit.dart index 15dc1ef..f25cedc 100644 --- a/package_src/lib/flukit.dart +++ b/package_src/lib/flukit.dart @@ -4,3 +4,5 @@ export 'src/pull_refresh.dart'; export 'src/after_layout.dart'; export 'src/swiper.dart'; export 'src/scale_view.dart'; +export 'src/index_bar.dart'; +export 'src/suspension_widget.dart'; \ No newline at end of file diff --git a/package_src/lib/src/index_bar.dart b/package_src/lib/src/index_bar.dart new file mode 100644 index 0000000..24655d1 --- /dev/null +++ b/package_src/lib/src/index_bar.dart @@ -0,0 +1,250 @@ +import 'package:flutter/material.dart'; + +///IndexBar touch callback IndexModel. +typedef void IndexBarTouchCallback(IndexModel model); + +///IndexModel. +class IndexModel { + String currentTag; //current touch tag. + int position; //current touch position. + bool isTouchDown; //is touch down. + + IndexModel({this.currentTag, this.position, this.isTouchDown}); +} + +///Default Index data. +const List INDEX_DATA_DEF = const [ + "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", + "#" +]; + +/// a letter list IndexBar. +class IndexBar extends StatefulWidget { + ///index data. + final List indexData; + + ///IndexBar width(def:30). + final int iBarWidth; + + ///IndexBar item height(def:16). + final int iBarItemHeight; + + ///IndexBar text style. + final TextStyle textStyle; + + ///IndexBar touch down color. + final Color touchDownColor; + + ///Item touch callback. + final IndexBarTouchCallback onIBarTouchCallback; + + IndexBar( + {Key key, + this.indexData: INDEX_DATA_DEF, + this.iBarWidth: 30, + this.iBarItemHeight: 16, + this.textStyle, + this.touchDownColor: Colors.transparent, + @required this.onIBarTouchCallback}) + : assert(onIBarTouchCallback != null), + super(key: key); + + @override + State createState() { + return new IndexBarState(); + } +} + +class IndexBarState extends State { + bool _isTouchDown = false; + + void _onIBarTouchCallback(IndexModel model) { + _isTouchDown = model.isTouchDown; + if (widget.onIBarTouchCallback != null) widget.onIBarTouchCallback(model); + } + + @override + Widget build(BuildContext context) { + return new Container( + alignment: Alignment.center, + color: _isTouchDown ? widget.touchDownColor : Colors.transparent, + width: widget.iBarWidth.toDouble(), + height: double.infinity, + child: new BaseIndexBar( + indexData: widget.indexData, + iBarWidth: widget.iBarWidth, + iBarItemHeight: widget.iBarItemHeight, + textStyle: widget.textStyle, + onIBarTouchCallback: _onIBarTouchCallback, + ), + ); + } +} + +/// Base IndexBar. +class BaseIndexBar extends StatefulWidget { + ///index data. + final List indexData; + + ///IndexBar width(def:30). + final int iBarWidth; + + ///IndexBar item height(def:16). + final int iBarItemHeight; + + ///IndexBar text style. + final TextStyle textStyle; + + ///Item touch callback. + final IndexBarTouchCallback onIBarTouchCallback; + + BaseIndexBar( + {Key key, + this.indexData: INDEX_DATA_DEF, + this.iBarWidth: 30, + this.iBarItemHeight: 16, + this.textStyle, + @required this.onIBarTouchCallback}) + : assert(onIBarTouchCallback != null), + super(key: key); + + @override + State createState() { + return new BaseIndexBarState(); + } +} + +class BaseIndexBarState extends State { + List _indexData = new List(); + List _indexWidgetList = new List(); + List _indexSectionList = new List(); + int _widgetTop = -1; + int _lastIndex = 0; + bool _widgetTopChange = false; + + IndexModel _indexModel = new IndexModel(); + + ///get index. + int _getIndex(int offset) { + for (int i = 0, length = _indexSectionList.length; i < length - 1; i++) { + int a = _indexSectionList[i]; + int b = _indexSectionList[i + 1]; + if (offset >= a && offset < b) { + return i; + } + } + return -1; + } + + ///two list is equal. + bool _twoListIsEqual(List listA, List listB) { + if (listA == listB) return true; + if (listA == null || listB == null) return false; + int length = listA.length; + if (length != listB.length) return false; + for (int i = 0; i < length; i++) { + if (!listA.contains(listB[i])) { + return false; + } + } + return true; + } + + @override + Widget build(BuildContext context) { + if (!_twoListIsEqual(_indexData, widget.indexData)) { + _widgetTopChange = true; + + _indexData.clear(); + if (widget.indexData != null) _indexData.addAll(widget.indexData); + + _indexSectionList.clear(); + _indexWidgetList.clear(); + + _indexSectionList.add(0); + int tempHeight = 0; + _indexData.forEach((value) { + tempHeight = tempHeight + widget.iBarItemHeight; + _indexSectionList.add(tempHeight); + _indexWidgetList.add(new SizedBox( + width: widget.iBarWidth.toDouble(), + height: widget.iBarItemHeight.toDouble(), + child: new Text( + value, + textAlign: TextAlign.center, + style: widget.textStyle == null + ? new TextStyle(fontSize: 10.0, color: Color(0xFF666666)) + : widget.textStyle, + ), + )); + }); + } + + return new GestureDetector( + onVerticalDragDown: (DragDownDetails details) { + if (_widgetTop == -1 || _widgetTopChange) { + _widgetTopChange = false; + RenderBox box = context.findRenderObject(); + Offset topLeftPosition = box.localToGlobal(Offset.zero); + _widgetTop = topLeftPosition.dy.toInt(); + } + int offset = details.globalPosition.dy.toInt() - _widgetTop; + int index = _getIndex(offset); + if (index != -1) { + _lastIndex = index; + _indexModel.position = index; + _indexModel.currentTag = _indexData[index]; + _indexModel.isTouchDown = true; + if (widget.onIBarTouchCallback != null) + widget.onIBarTouchCallback(_indexModel); + } + }, + onVerticalDragUpdate: (DragUpdateDetails details) { + int offset = details.globalPosition.dy.toInt() - _widgetTop; + int index = _getIndex(offset); + if (index != -1 && _lastIndex != index) { + _lastIndex = index; + _indexModel.position = index; + _indexModel.currentTag = _indexData[index]; + _indexModel.isTouchDown = true; + if (widget.onIBarTouchCallback != null) + widget.onIBarTouchCallback(_indexModel); + } + }, + onVerticalDragEnd: (DragEndDetails details) { + _indexModel.isTouchDown = false; + if (widget.onIBarTouchCallback != null) + widget.onIBarTouchCallback(_indexModel); + }, + child: new Column( + mainAxisSize: MainAxisSize.min, + children: _indexWidgetList, + ), + ); + } +} diff --git a/package_src/lib/src/suspension_widget.dart b/package_src/lib/src/suspension_widget.dart new file mode 100644 index 0000000..bab2e14 --- /dev/null +++ b/package_src/lib/src/suspension_widget.dart @@ -0,0 +1,238 @@ +import 'package:flutter/material.dart'; + +///base index bean. +class BaseIndexBean implements ISuspensionBean { + String baseIndexName; + String baseIndexTag; + String baseIndexPinyin; + bool isShowSuspension; + + BaseIndexBean( + {this.baseIndexTag, + this.baseIndexPinyin, + this.baseIndexName, + this.isShowSuspension}); + + @override + String getSuspensionTag() { + return baseIndexTag; + } +} + +///ISuspension Bean. +abstract class ISuspensionBean { + String getSuspensionTag(); //Suspension Tag +} + +///on sus tag change callback. +typedef void OnSusTagChangeCallBack(String tag); + +///on all sus section callback(map: Used to scroll the list to the specified tag location). +typedef void OnSusSectionCallBack(Map map); + +///Suspension Widget.Currently only supports fixed height items! +class SuspensionWidget extends StatefulWidget { + ///with ISuspensionBean Data + final List mData; + + ///content widget(must contain ListView). + final Widget contentWidget; + + ///suspension widget. + final Widget suspensionWidget; + + ///ListView ScrollController. + final ScrollController controller; + + ///suspension widget Height. + final int suspensionHeight; + + ///item Height. + final int itemHeight; + + ///on sus tag change callback. + final OnSusTagChangeCallBack onSusTagChangeCallBack; + + ///on sus section callback. + final OnSusSectionCallBack onSusSectionCallBack; + + SuspensionWidget(this.mData, + {Key key, + @required this.contentWidget, + @required this.suspensionWidget, + @required this.controller, + this.suspensionHeight: 40, + this.itemHeight: 50, + this.onSusTagChangeCallBack, + this.onSusSectionCallBack}) + : assert(contentWidget != null), + assert(suspensionWidget != null), + assert(controller != null), + super(key: key); + + @override + State createState() { + return new _SuspensionWidgetState(); + } +} + +class _SuspensionWidgetState extends State { + List _mData = new List(); + + double _widgetWidth = 0.0; + int _suspensionTop = 0; + + int _lastIndex; + int _suSectionListLength; + + List _suspensionSectionList = new List(); + Map _suspensionSectionMap = new Map(); + + @override + void initState() { + super.initState(); + widget.controller.addListener(() { + int offset = widget.controller.offset.toInt(); + int _index = getIndex(offset); + if (_index != -1 && _lastIndex != _index) { + _lastIndex = _index; + if (widget.onSusTagChangeCallBack != null) { + widget.onSusTagChangeCallBack( + _suspensionSectionMap.keys.toList()[_index]); + } + } + }); + } + + int getIndex(int offset) { + for (int i = 0; i < _suSectionListLength - 1; i++) { + int space = _suspensionSectionList[i + 1] - offset; + if (space > 0 && space < widget.suspensionHeight) { + space = space - widget.suspensionHeight; + } else { + space = 0; + } + if (_suspensionTop != space) { + setState(() { + _suspensionTop = space; + }); + } + int a = _suspensionSectionList[i]; + int b = _suspensionSectionList[i + 1]; + if (offset >= a && offset < b) { + return i; + } + if (offset >= _suspensionSectionList[_suSectionListLength - 1]) { + return _suSectionListLength - 1; + } + } + return -1; + } + + ///two list is equal. + bool _twoListIsEqual(List listA, List listB) { + if (listA == listB) return true; + if (listA == null || listB == null) return false; + int length = listA.length; + if (length != listB.length) return false; + for (int i = 0; i < length; i++) { + if (!listA.contains(listB[i])) { + return false; + } + } + return true; + } + + @override + Widget build(BuildContext context) { + if (_widgetWidth == 0.0) { + RenderBox box = context.findRenderObject(); + if (box != null && box.semanticBounds != null) { + _widgetWidth = box.semanticBounds.width; + } + } + + if (!_twoListIsEqual(_mData, widget.mData)) { + _mData.clear(); + if (widget.mData != null) _mData.addAll(widget.mData); + _suspensionSectionMap.clear(); + + int temp = 0; + String tag; + for (int i = 0, length = _mData.length; i < length; i++) { + ISuspensionBean bean = _mData[i]; + if (tag != bean.getSuspensionTag()) { + tag = bean.getSuspensionTag(); + _suspensionSectionMap.putIfAbsent(tag, () => temp); + temp = temp + widget.suspensionHeight + widget.itemHeight; + } else { + temp = temp + widget.itemHeight; + } + } + + _suspensionSectionList.clear(); + _suspensionSectionList.addAll(_suspensionSectionMap.values); + _suSectionListLength = _suspensionSectionList.length; + + if (widget.onSusSectionCallBack != null) { + widget.onSusSectionCallBack(_suspensionSectionMap); + } + } + + return new Stack(children: [ + widget.contentWidget, + new Positioned( + top: _suspensionTop.toDouble(), + width: _widgetWidth, + child: widget.suspensionWidget) + ]); + } +} + +///Suspension Util. +class SuspensionUtil { + ///sort list by suspension tag. + static void sortSuspensionList(List list) { + if (list == null || list.isEmpty) return; + list.sort((a, b) { + if (a.getSuspensionTag() == "@" || b.getSuspensionTag() == "#") { + return -1; + } else if (a.getSuspensionTag() == "#" || b.getSuspensionTag() == "@") { + return 1; + } else { + return a.getSuspensionTag().compareTo(b.getSuspensionTag()); + } + }); + } + + ///get real index data list by suspension tag. + static List getRealIndexDataList(List list) { + List indexData = new List(); + if (list != null && list.isNotEmpty) { + String tempTag; + for (int i = 0, length = list.length; i < length; i++) { + String tag = list[i].getSuspensionTag(); + if (tempTag != tag) { + indexData.add(tag); + tempTag = tag; + } + } + } + return indexData; + } + + ///build is show suspension tag. + static void buildShowSuspensionTag(List list) { + if (list == null || list.isEmpty) return; + String tempTag; + for (int i = 0, length = list.length; i < length; i++) { + String tag = list[i].baseIndexTag; + if (tempTag != tag) { + tempTag = tag; + list[i].isShowSuspension = true; + } else { + list[i].isShowSuspension = false; + } + } + } +} diff --git a/package_src/pubspec.lock b/package_src/pubspec.lock deleted file mode 100644 index ebee08c..0000000 --- a/package_src/pubspec.lock +++ /dev/null @@ -1,377 +0,0 @@ -# Generated by pub -# See https://www.dartlang.org/tools/pub/glossary#lockfile -packages: - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.32.4" - args: - dependency: transitive - description: - name: args - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.5.0" - async: - dependency: transitive - description: - name: async - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.8" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.4" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.14.11" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.2" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.6" - csslib: - dependency: transitive - description: - name: csslib - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.14.5" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - front_end: - dependency: transitive - description: - name: front_end - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.1.4" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.7" - html: - dependency: transitive - description: - name: html - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.13.3+3" - http: - dependency: transitive - description: - name: http - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.11.3+17" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.5" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.flutter-io.cn" - source: hosted - version: "3.1.3" - io: - dependency: transitive - description: - name: io - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.3.3" - js: - dependency: transitive - description: - name: js - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.6.1+1" - json_rpc_2: - dependency: transitive - description: - name: json_rpc_2 - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.9" - kernel: - dependency: transitive - description: - name: kernel - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.3.4" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.11.3+2" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.12.3+1" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.6" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.6+2" - multi_server_socket: - dependency: transitive - description: - name: multi_server_socket - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.2" - node_preamble: - dependency: transitive - description: - name: node_preamble - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.4.4" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.5" - package_resolver: - dependency: transitive - description: - name: package_resolver - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.4" - path: - dependency: transitive - description: - name: path - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.6.2" - plugin: - dependency: transitive - description: - name: plugin - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.0+3" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.3.6" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.4.2" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.0+1" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.7.3+3" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.4" - shelf_static: - dependency: transitive - description: - name: shelf_static - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.8" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.2+4" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.5" - source_maps: - dependency: transitive - description: - name: source_maps - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.10.7" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.4.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.9.3" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.6.8" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.4" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.1" - test: - dependency: transitive - description: - name: test - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.3.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.6" - utf: - dependency: transitive - description: - name: utf - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.0+5" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.8" - vm_service_client: - dependency: transitive - description: - name: vm_service_client - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.6" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.7+10" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.9" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.1.15" -sdks: - dart: ">=2.0.0-dev.68.0 <3.0.0" diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index 0b4c2cc..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,391 +0,0 @@ -# Generated by pub -# See https://www.dartlang.org/tools/pub/glossary#lockfile -packages: - analyzer: - dependency: transitive - description: - name: analyzer - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.32.4" - args: - dependency: transitive - description: - name: args - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.5.0" - async: - dependency: transitive - description: - name: async - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.8" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.4" - charcode: - dependency: transitive - description: - name: charcode - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.2" - collection: - dependency: transitive - description: - name: collection - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.14.11" - convert: - dependency: transitive - description: - name: convert - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.2" - crypto: - dependency: transitive - description: - name: crypto - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.6" - csslib: - dependency: transitive - description: - name: csslib - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.14.5" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.1.2" - flukit: - dependency: "direct main" - description: - path: package_src - relative: true - source: path - version: "0.0.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - front_end: - dependency: transitive - description: - name: front_end - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.1.4" - glob: - dependency: transitive - description: - name: glob - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.7" - html: - dependency: transitive - description: - name: html - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.13.3+3" - http: - dependency: transitive - description: - name: http - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.11.3+17" - http_multi_server: - dependency: transitive - description: - name: http_multi_server - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.5" - http_parser: - dependency: transitive - description: - name: http_parser - url: "https://pub.flutter-io.cn" - source: hosted - version: "3.1.3" - io: - dependency: transitive - description: - name: io - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.3.3" - js: - dependency: transitive - description: - name: js - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.6.1+1" - json_rpc_2: - dependency: transitive - description: - name: json_rpc_2 - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.9" - kernel: - dependency: transitive - description: - name: kernel - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.3.4" - logging: - dependency: transitive - description: - name: logging - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.11.3+2" - matcher: - dependency: transitive - description: - name: matcher - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.12.3+1" - meta: - dependency: transitive - description: - name: meta - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.6" - mime: - dependency: transitive - description: - name: mime - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.6+2" - multi_server_socket: - dependency: transitive - description: - name: multi_server_socket - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.2" - node_preamble: - dependency: transitive - description: - name: node_preamble - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.4.4" - package_config: - dependency: transitive - description: - name: package_config - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.5" - package_resolver: - dependency: transitive - description: - name: package_resolver - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.4" - path: - dependency: transitive - description: - name: path - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.6.2" - plugin: - dependency: transitive - description: - name: plugin - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.0+3" - pool: - dependency: transitive - description: - name: pool - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.3.6" - pub_semver: - dependency: transitive - description: - name: pub_semver - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.4.2" - quiver: - dependency: transitive - description: - name: quiver - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.0+1" - shelf: - dependency: transitive - description: - name: shelf - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.7.3+3" - shelf_packages_handler: - dependency: transitive - description: - name: shelf_packages_handler - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.4" - shelf_static: - dependency: transitive - description: - name: shelf_static - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.8" - shelf_web_socket: - dependency: transitive - description: - name: shelf_web_socket - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.2+4" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.99" - source_map_stack_trace: - dependency: transitive - description: - name: source_map_stack_trace - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.5" - source_maps: - dependency: transitive - description: - name: source_maps - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.10.7" - source_span: - dependency: transitive - description: - name: source_span - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.4.1" - stack_trace: - dependency: transitive - description: - name: stack_trace - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.9.3" - stream_channel: - dependency: transitive - description: - name: stream_channel - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.6.8" - string_scanner: - dependency: transitive - description: - name: string_scanner - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.4" - term_glyph: - dependency: transitive - description: - name: term_glyph - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.1" - test: - dependency: transitive - description: - name: test - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.3.0" - typed_data: - dependency: transitive - description: - name: typed_data - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.1.6" - utf: - dependency: transitive - description: - name: utf - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.0+5" - vector_math: - dependency: transitive - description: - name: vector_math - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.0.8" - vm_service_client: - dependency: transitive - description: - name: vm_service_client - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.2.6" - watcher: - dependency: transitive - description: - name: watcher - url: "https://pub.flutter-io.cn" - source: hosted - version: "0.9.7+10" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.flutter-io.cn" - source: hosted - version: "1.0.9" - yaml: - dependency: transitive - description: - name: yaml - url: "https://pub.flutter-io.cn" - source: hosted - version: "2.1.15" -sdks: - dart: ">=2.0.0-dev.68.0 <3.0.0" diff --git a/pubspec.yaml b/pubspec.yaml index ea6cba3..fd04a7e 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,6 +21,7 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^0.1.2 + lpinyin: ^1.0.6 dev_dependencies: flutter_test: @@ -47,6 +48,9 @@ flutter: - images/cat.jpg - images/horse.jpg - images/road.jpg + + - assets/data/china.json + # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg