Flutter for 定位布局
-先看效果图
1.自定义数据源 (随便添加了几个)
import 'package:flutter/material.dart';
class RegionVo {
String sectionKey;
String name;
RegionVo({@required this.sectionKey,this.name});
}
List regionDataSource = [
new RegionVo(
sectionKey: 'A',
name: '阿拉善',
),
new RegionVo(
sectionKey: 'A',
name: '安庆市',
),
new RegionVo(
sectionKey: 'A',
name: '安阳市',
),
new RegionVo(
sectionKey: 'B',
name: '北京',
),
new RegionVo(
sectionKey: 'B',
name: '包头市',
),
new RegionVo(
sectionKey: 'C',
name: '承德市',
),
new RegionVo(
sectionKey: 'C',
name: '沧州市',
),
new RegionVo(
sectionKey: 'C',
name: '池州',
),
new RegionVo(
sectionKey: 'C',
name: '长阳',
),
new RegionVo(
sectionKey: 'D',
name: '德州',
),
new RegionVo(
sectionKey: 'D',
name: '达州',
),
new RegionVo(
sectionKey: 'D',
name: '定西市',
),
];
2.自定义一个header项
import 'package:flutter/material.dart';
import '../Common/touch_callback.dart';
class RegionHeader extends StatelessWidget {
final String title;
RegionHeader({Key key, @required this.title});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border(
bottom: BorderSide(width: 0.5, color: Colors.grey[100]))),
height: 64.0,
child: TouchCallBack(
onPressed: (){},
isfeed: true,
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: EdgeInsets.only(left: 12.0, right: 12.0),
child: Image.asset(
'images/location.png',
width: 32,
height: 32,
),
),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title),
],
)),
],
),
));
}
}
3.自定义一个item项
import 'package:flutter/material.dart';
import './region_data.dart';
class RegionItem extends StatelessWidget {
final RegionVo item;
final String titleName;
RegionItem({this.item, this.titleName});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Colors.white,
border:
Border(bottom: BorderSide(width: 0.5, color: Color(0xFFd9d9d9)))),
height: 52.0,
child: FlatButton(
onPressed: () {},
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(
margin: const EdgeInsets.only(left: 12.0),
// color: Colors.grey,
child: Text(
titleName == null ? item.name ?? '暂时' : titleName,
style: TextStyle(fontSize: 18.0, color: Colors.black),
),
)
],
),
),
);
}
}
4.接下来就是自定义一个列表项(构建三个builder 给外部调用)
import 'package:flutter/material.dart';
import 'package:region/region/region_data.dart';
class RegionList extends StatefulWidget {
final List items;
final IndexedWidgetBuilder headerBuild;
final IndexedWidgetBuilder sectionBuild;
final IndexedWidgetBuilder itemsBuild;
RegionList({
Key key,
@required this.items,
this.headerBuild,
@required this.sectionBuild,
@required this.itemsBuild
}) : super(key: key);
@override
RegionListState createState() => new RegionListState();
}
class RegionListState extends State implements SectionInderxer {
Color _pressColor = Colors.transparent;
final ScrollController _scrollController = new ScrollController();
bool _onNotification(ScrollNotification notification) {
return true;
}
_isShowHeader(index) {
if (index == 0 && widget.headerBuild != null) {
return Offstage(
offstage: false,
child: widget.headerBuild(context, index),
);
}
return Container();
}
bool _shouldShowSectionHeader(index) {
if (index < 0) {
return false;
}
if (index == 0) {
return false;
}
if (index != 0 &&
widget.items[index].sectionKey != widget.items[index - 1].sectionKey) {
return false;
}
return true;
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: [
NotificationListener(
onNotification: _onNotification,
child: ListView.builder(
controller: _scrollController,
physics: const AlwaysScrollableScrollPhysics(),
itemCount: widget.items.length,
itemBuilder: (BuildContext context, int index) {
return Container(
alignment: Alignment.centerLeft,
child: Column(
children: [
_isShowHeader(index),
Offstage(
//当offstage为false时 显示
offstage: _shouldShowSectionHeader(index),
child: widget.sectionBuild(context, index)),
Column(
children: [
widget.itemsBuild(context, index),
],
)
],
),
);
},
),
),
//排序字母
Positioned(
top: MediaQuery.of(context).size.height * 0.25,
right: 0.0,
child: Container(
alignment: Alignment.center,
height: MediaQuery.of(context).size.height * 0.5,
width: 32.0,
color: _pressColor,
child: GestureDetector(
onTapDown: (TapDownDetails t) {
setState(() {
_pressColor = Colors.grey;
});
},
onTapUp: (TapUpDetails t) {
setState(() {
_pressColor = Colors.transparent;
});
},
onVerticalDragStart: (DragStartDetails details) {
//开始垂直滑动
setState(() {
_pressColor = Colors.grey;
});
},
onVerticalDragEnd: (DragEndDetails details) {
setState(() {
_pressColor = Colors.transparent;
});
},
onVerticalDragUpdate: (DragUpdateDetails details) {
//手指垂直滑动时
setState(() {});
},
child: ListView.builder(
controller: ScrollController(),
itemCount: siderBarKey.length,
itemBuilder: (BuildContext context, int index) {
return Container(
alignment: Alignment.center,
height: 17.0,
child: Text(siderBarKey[index]),
);
},
),
),
),
)
],
),
);
}
listScrollTopPosition(int index) {
for (var i = 0; i < widget.items.length; i++) {
if (siderBarKey[index] == "*" || siderBarKey[index] == "^") {
_scrollController.jumpTo(0.0);
setState(() {});
return -1;
} else if (widget.items[i].sectionKey == siderBarKey[index]) {
return i;
}
}
return -1;
}
}
abstract class SectionInderxer {
listScrollTopPosition(int index);
}
const siderBarKey = [
"*",
"^",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"Z",
];
5.最后把上面3个自定义模块 结合数据源进行组装
import 'package:flutter/material.dart';
import 'package:region/region/region_data.dart';
import 'package:region/region/region_header.dart';
import 'package:region/region/region_item.dart';
import 'package:region/region/region_list.dart';
class Regions extends StatefulWidget {
@override
RegionState createState() => new RegionState();
}
class RegionState extends State {
@override
Widget build(BuildContext context) {
return Scaffold(
body: RegionList(
items: regionDataSource,
headerBuild: (BuildContext context, int index) {
return Container(
child: RegionHeader(
title: '宁波',
),
);
},
itemsBuild: (BuildContext context, int index) {
return Container(
color: Colors.white,
alignment: Alignment.centerLeft,
child: RegionItem(item: regionDataSource[index]),
);
},
sectionBuild: (BuildContext context, int index){
return Container(
height: 22.0,
padding: const EdgeInsets.only(left: 14.0),
color: Colors.grey[100],
alignment: Alignment.centerLeft,
child: Text(
regionDataSource[index].sectionKey,
style: TextStyle(fontSize: 12.0,color: Colors.black87),
),
);
},
),
);
}
}
6.最后显示一下
-main.dart
import 'package:flutter/material.dart';
import 'package:region/loading.dart';
import './app.dart';
void main()=> runApp(MaterialApp(
debugShowCheckedModeBanner: false,
title: 'weChat',
theme: mDefaultTheme,
routes: {
"app":(BuildContext context) => new App(),
},
home: new LoadingPage(),
));
final ThemeData mDefaultTheme = new ThemeData(
primaryColor: Color(0xff303030),
scaffoldBackgroundColor: Color(0xFFebebeb),
cardColor: Color(0xff393a3f),
);
-loading.dart
import 'package:flutter/material.dart';
import 'dart:async';
class LoadingPage extends StatefulWidget {
@override
_LoadingState createState() => new _LoadingState();
}
class _LoadingState extends State {
@override
void initState() {
super.initState();
new Future.delayed(Duration(seconds: 1),(){
Navigator.of(context).pushReplacementNamed("app");
});
}
@override
Widget build(BuildContext context) {
return new Container(
child:Image.asset("images/loading.jpg"),
);
}
}
-app.dart
import 'package:flutter/material.dart';
import 'package:region/region/region.dart';
class App extends StatefulWidget {
@override
MainState createState() => MainState();
}
class MainState extends State {
_cusAppBar() {
return AppBar(
title: Text('定位'),
actions: [
GestureDetector(
onTap: () {
Navigator.pushNamed(context, 'search');
},
child: Icon(
Icons.search,
),
),
Padding(
padding: const EdgeInsets.only(left: 20.0, right: 20.0),
child: GestureDetector(
onTap: () async {
showMenu(
color: Colors.white,
context: context,
position: RelativeRect.fromLTRB(500.0, 86.0, 25.0, 0.0),
items: [
new PopupMenuItem(
value: 'value01', child: new Text('Item One')),
new PopupMenuDivider(height: 1.0),
new PopupMenuItem(
value: 'value02', child: new Text('Item Two')),
new PopupMenuDivider(height: 1.0),
new PopupMenuItem(
value: 'value03', child: new Text('Item Three')),
new PopupMenuDivider(height: 1.0),
new PopupMenuItem(
value: 'value04', child: new Text('I am Item Four'))
],
);
},
child: Icon(Icons.add_circle),
),
)
],
flexibleSpace: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [Colors.cyan, Colors.blue, Colors.blueAccent],
),
),
),
);
}
Regions region = new Regions();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: _cusAppBar(),
body: region,
);
}
}