点击点事
按钮的点击事件,只需要设置 onPressed 参数就可以了:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
// 设置主题
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Title'),
),
body: HomeContent(),
),
theme: ThemeData(primarySwatch: Colors.yellow),
);
}
}
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return RaisedButton(
child: Text('click'),
onPressed: () => debugPrint('打印点击'),
);
}
}
任意控件的手势事件
跟 button 不同,大多数的控件没有手势事件监听函数可以设置,为了监听这些控件上的手势事件,我们需要使用另一个控件——GestureDetector(没错,它也是一个控件):
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
child: Text(
'你好 Flutter ',
style: TextStyle(
fontSize: 40.0,
color: Colors.blue,
),
),
onTap: () => debugPrint('onTap'), // 点击动作
onTapDown: (e) => debugPrint('onTapDown'),//按下
onTapUp: (e) => debugPrint('onTapUp'),
onTapCancel: () => debugPrint('onTapCancel'),
onDoubleTap: () => debugPrint('onDoubleTap'),
onLongPress: () => debugPrint('onLongPress'),
);
}
}
onTapDown:按下
onTap:点击动作
onTapUp:抬起
onTapCancel:前面触发了 onTapDown,但并没有完成一个 onTap 动作
onDoubleTap:双击
onLongPress:长按
onScaleStart, onScaleUpdate, onScaleEnd:缩放
onVerticalDragDown, onVerticalDragStart, onVerticalDragUpdate, onVerticalDragEnd, onVerticalDragCancel, onVerticalDragUpdate:在竖直方向上移动
onHorizontalDragDown, onHorizontalDragStart, onHorizontalDragUpdate, onHorizontalDragEnd, onHorizontalDragCancel, onHorizontalDragUpdate:在水平方向上移动
onPanDown, onPanStart, onPanUpdate, onPanEnd, onPanCancel:拖曳(水平、竖直方向上移动)
如果同时设置了 onVerticalXXX 和 onHorizontalXXX,在一个手势里,只有一个会触发(如果用户首先在水平方向移动,则整个过程只触发 onHorizontalUpdate;竖直方向的类似)
这里要说明的是,onVerticalXXX/onHorizontalXXX 和 onPanXXX 不能同时设置。如果同时需要水平、竖直方向的移动,使用 onPanXXX。
如果读者希望在用户点击的时候能够有个水波纹效果,可以使用 InkWell,它的用法跟 GestureDetector 类似,只是少了拖动相关的手势(毕竟,这个水波纹效果只有在点击的时候才有意义)
原始手势事件监听
GestureDetector 在绝大部分时候都能够满足我们的需求,如果真的满足不了,我们还可以使用最原始的 Listener 控件。
class HomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Listener(
child: Text('text'),
onPointerDown: (event) => print('onPointerDown'),
onPointerUp: (event) => print('onPointerUp'),
onPointerMove: (event) => print('onPointerMove'),
onPointerCancel: (event) => print('onPointerCancel'),
);
}
}
stack 结合 align 使用
image.pngclass LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Container(
height: 400,
width: 300,
color: Colors.blue,
child: Stack(
children: [
Align(
alignment: Alignment.topLeft,
child: Icon(
Icons.ac_unit_outlined,
color: Colors.white,
),
),
Align(
alignment: Alignment.center,
child: Icon(
Icons.home,
color: Colors.white,
),
),
Align(
alignment: Alignment.bottomRight,
child: Icon(
Icons.accessibility_new_sharp,
color: Colors.white,
),
),
],
),
));
}
}
stack 结合 Positioned 使用
image.pngclass LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: Container(
height: 400,
width: 300,
color: Colors.blue,
child: Stack(
children: [
Positioned(
top: 10,
left: 10,
child: Icon(
Icons.ac_unit_outlined,
color: Colors.white,
),
),
Positioned(
right: 10,
top: 10,
child: Icon(
Icons.home,
color: Colors.white,
),
),
Positioned(
bottom: 10,
left: 10,
child: Icon(
Icons.accessibility_new_sharp,
color: Colors.white,
),
),
],
),
));
}
}
Wrap 组件的使用
实现流式布局
image.pngclass LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 300,
height: 500,
color: Colors.pink,
child: Wrap(
direction: Axis.horizontal, //控制方向
spacing: 10, // 子节点间距
runSpacing: 10, // 行间距
runAlignment: WrapAlignment.end, // 显示在 Container 底部
children: [
MyButton("第一季,11111"),
MyButton("第二季"),
MyButton("第三季"),
MyButton("第四季"),
MyButton("第五季"),
MyButton("第六季"),
MyButton("第七季,22222222"),
MyButton("第八季"),
MyButton("第九季"),
MyButton("第十季"),
],
),
);
}
}
// 自定义 button
class MyButton extends StatelessWidget {
final String text;
const MyButton(this.text, {Key key}) : super(key: key);
@override
Widget build(BuildContext context) {
return RaisedButton(
textColor: Colors.blue,
child: Text(this.text),
onPressed: () {
debugPrint(this.text);
});
}
}
StatefulWidget 组件的使用
改变 Widget 状态
device-2021-09-25-170505.gif
// 有状态组件
class HomePage extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return HomePageState();
}
}
class HomePageState extends State<HomePage> {
int number = 0;
@override
Widget build(BuildContext context) {
return Column(
children: [
SizedBox(height: 10),
Chip(label: Text("${this.number}")),
RaisedButton( // 数量增加点击
onPressed: () {
setState(() { // 只有有状态组件里才有
this.number += 50;
});
print("数量:${this.number}");
},
child: Text("按钮"),
),
SizedBox(height: 10),
RaisedButton( // 归零点击
onPressed: () {
setState(() {
this.number = 0;
});
print("数量:${this.number}");
},
child: Text("清楚"),
),
],
);
}
}
StatefulWidget 组件的使用2
配合 list 的使用
device-2021-09-25-221823.gif
class HomePageState extends State<HomePage> {
List list = new List();
int count = 0;
@override
Widget build(BuildContext context) {
return ListView(
children: [
RaisedButton(
// 数量增加点击
onPressed: () {
setState(() {
count++;
this.list.add("条目-${this.count}");
});
},
child: Text(" 添加条目"),
),
RaisedButton(
// 数量增加点击
onPressed: () {
setState(() {
count=0;
this.list.clear();
});
},
child: Text(" 清楚条目"),
),
Column(
children: this.list.map((value) {
return ListTile(title: Text(value));
}).toList(),
),
],
);
}
}
BottomNavigationBar 组件的使用
被击底部 Tab 切换功能
device-2021-09-26-001713.gif// 有状态组件
class Tabs extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return TabsState();
}
}
class TabsState extends State<Tabs> {
int _currentIndex = 0;
List _pageList = [HomePage(), CategoryPage(), SettingPage()];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('FlutterDemo_Tab')),
body: this._pageList[this._currentIndex],
bottomNavigationBar: BottomNavigationBar(
currentIndex: this._currentIndex, // 设置索引值
onTap: (int index) { // 点击 tab 回调
setState(() {
this._currentIndex = index;
});
},
iconSize: 30.0, // 图标大小
fixedColor: Colors.green, // 选中的颜色
type: BottomNavigationBarType.fixed, // 布局类型
items: [
BottomNavigationBarItem(icon: Icon(Icons.home), label: ("首页")),
BottomNavigationBarItem(icon: Icon(Icons.category), label: ("分类")),
BottomNavigationBarItem(icon: Icon(Icons.settings), label: ("设置")),
],
));
}
}
普通路由
打开一个页面
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => FormPage(
title: "传递参数",
)));
关闭页面
Navigator.of(context).pop();
自定义路由
实现 routers 指定页面与自定义 路由地址的对应关系。
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter UX demo',
home: Tabs(),
routes: {
'/SearchPage': (context) => SearchPage(),
},
);
}
通过 Navigator.pushNamed() 传入自定义的路由名称
Navigator.pushNamed(context, '/SearchPage');
自定义路由传参
实现 onGenerateRoute
class MyApp extends StatelessWidget {
// 路由配置表
final routes = {
'/SearchPage': (context, {arguments}) => SearchPage(arguments: arguments),
};
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter UX demo',
home: Tabs(),
onGenerateRoute: (RouteSettings settings) { // 自定义路由传参的实现
// 统一处理
final name = settings.name;
final Function pageContentBuilder = this.routes[name];
if (pageContentBuilder != null && settings.arguments != null) {
final Route route = MaterialPageRoute(
builder: (context) => pageContentBuilder(context, arguments: settings.arguments));
return route;
} else {
final Route route = MaterialPageRoute(
builder: (context) => pageContentBuilder(context));
return route;
}
},
);
}
}
打开带参数的路由
Navigator.pushNamed(context, '/SearchPage',
arguments: {"id": 124});
接收参数的页面
class SearchPage extends StatelessWidget {
final arguments;
const SearchPage({this.arguments});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('搜索页面 ${arguments != null ? arguments['id'] : "0"}'),
// title: Text('搜索页面 ${this.arguments}'),
),
body: HomeContent(),
),
theme: ThemeData(primarySwatch: Colors.yellow),
);
}
}
网友评论