flutter一文通4
程序员文章站
2022-05-30 17:37:29
...
flutter图标库:http://fluttericon.com/
一. ClipOval椭圆组件
使被包裹的子组件椭圆化
ClipOval(
child: Image.network("https://timgsa.baidu.com/timg68"),
),
二. ClipRRect 圆角矩形
使被包裹的子组件圆角矩形化
ClipRRect(
borderRadius: BorderRadius.circular(16),
child: Image.network("https://timgsa.baidu.com/timg68"),
),
三. form表单
form也是一个组件,与它配套的是可以提交内容的组件,比如:
- TextFormField
提交过程很繁琐:
- 提前声明一个GlobalKey,用来绑定form
GlobalKey<FormState> formGlobalKey = GlobalKey();
- 给form的key属性绑定这个GlobalKey
- 在配套组件中注册提交事件
onSaved: (value){}
- 在提交按钮中用GlobalKey找到form,并调用它的
formGlobalKey.currentState.save();
这样,在按钮点击时,表单会触发与它配套的组件的onSaved: (value){}
方法,并将他们的值传给这个方法
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Scaffold(
appBar: AppBar(
title: Text("data"),
),
body: Login(),
),
);
}
}
class Login extends StatefulWidget {
@override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
String username;
String password;
GlobalKey<FormState> formGlobalKey = GlobalKey();
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10),
child: Form(
key: formGlobalKey,
child: Column(
children: <Widget>[
TextFormField(
decoration: InputDecoration(
icon: Icon(Icons.people), labelText: 'USERs'),
onSaved: (value) {
setState(() {
print(value);
this.username = value;
});
},
),
TextFormField(
decoration: InputDecoration(
icon: Icon(Icons.lock), labelText: 'password'),
obscureText: true,
onSaved: (value) {
setState(() {
print(value);
this.password = value;
});
},
),
RaisedButton(
child: Container(
width: double.infinity,
alignment: Alignment.center,
child: Text(
"login",
style: TextStyle(color: Colors.white),
),
),
color: Colors.green,
onPressed: () {
setState(() {
print("OK");
formGlobalKey.currentState.save();
});
})
],
)),
);
}
}
四. 表单验证器
我们想验证表单里的内容输入的合法性,这需要:
- 在form配套子组件中添加属性validator
validator属性里面如何设置?
validator属性里要传入一个函数,这个函数默认接收value参数,可以对value做一些判断,如果合规就return null,如果不合规就return一个字符串错误提示
validator: (value) {
if (value.length == 0) {
return "密码不能为空";
}
return null;
},
- 在提交按钮中触发
formGlobalKey.currentState.validate();
五. 表单自动验证
很简单,在form配套子组件中添加属性autovalidate: true,
同时,可以省略在提交按钮中触发formGlobalKey.currentState.validate();
这一步了
六. 主题设置
一个APP我们往往要求色调统一等全局性设置,这些设置都被放在了根组件MaterialApp的theme
属性里.
主题数据里的设置非常非常多,而且全都是跟颜色 动画等APP风格有关的设置
例,设置方法:
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(),
theme: ThemeData(primaryColor: Colors.green),
);
}
}
七. 底部导航栏
- 底部导航栏BottomNavigationBar里面要放至少两个BottomNavigationBarItem,而且每个BottomNavigationBarItem必须有title
- BottomNavigationBar有一个关键属性currentIndex,此属性传入数字,传入几第几个标签就会标记为按下
- BottomNavigationBar有一个ontap事件,事件会在点击BottomNavigationBarItem时触发,事件默认传入一个参数value, 其指代的是被点击的BottomNavigationBarItem的index
- 底栏切换时,脚手架的home也随之切换,实现的方式是:把所有要显示的内容放在列表中,用elementAt(_selectedIndex)来切换
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
static const String _title = 'Flutter Code Sample';
@override
Widget build(BuildContext context) {
return MaterialApp(
title: _title,
home: MyStatefulWidget(),
theme: ThemeData(primaryColor: Colors.green),
);
}
}
class MyStatefulWidget extends StatefulWidget {
MyStatefulWidget({Key key}) : super(key: key);
@override
_MyStatefulWidgetState createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
int _selectedIndex = 0;
static const TextStyle optionStyle =
TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
static const List<Widget> _widgetOptions = <Widget>[
Text(
'Index 0: Home',
style: optionStyle,
),
Text(
'Index 1: Business',
style: optionStyle,
),
Text(
'Index 2: School',
style: optionStyle,
),
];
void _onItemTapped(int index) {
setState(() {
_selectedIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('BottomNavigationBar Sample'),
),
body: Center(
child: _widgetOptions.elementAt(_selectedIndex),
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
title: Text('首页'),
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
title: Text('分类'),
),
BottomNavigationBarItem(
icon: Icon(Icons.school),
title: Text('我的'),
),
],
currentIndex: _selectedIndex,
onTap: _onItemTapped,
),
);
}
}
八. 封装一个自己的组件
建立一个文件 如:components/my_bottom_bar.dart
import 'package:flutter/material.dart';
class MyBottomBar extends BottomNavigationBarItem{
MyBottomBar(String name,Icon icon,Icon activeIcon):super(
icon: icon,
activeIcon:activeIcon,
title:Text(name)
);
}
引用时:
import './components/my_bottom_bar.dart';
九. 导航条配合神器 IndexedStack组件
IndexedStack会根据index选择自己要显示的子组件
import 'package:flutter/material.dart';
class MyBottomNavBar extends StatefulWidget {
@override
_MyBottomNavBarState createState() => _MyBottomNavBarState();
}
class _MyBottomNavBarState extends State<MyBottomNavBar> {
int _currentIndex=0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("底部导航栏"),),
body: IndexedStack(
index: _currentIndex,
children: <Widget>[
Text("首页"),
Text("商店页"),
],
),
bottomNavigationBar: BottomNavigationBar(
currentIndex: _currentIndex,
items: [
BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("home")),
BottomNavigationBarItem(icon: Icon(Icons.shop),title: Text("shop")),
],
onTap: (index){
setState(() {
_currentIndex=index;
});
},
),
);
}
}
十. 状态组件中状态管理器如何拿到组件的变量
使用widget.xxx
import 'package:flutter/material.dart';
class EachView extends StatefulWidget {
final String _title;
EachView(this._title);
@override
_EachViewState createState() => _EachViewState();
}
class _EachViewState extends State<EachView> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget._title)),
body: Center(
child: Text(widget._title),
),
);
}
}
十一. 搜索框
先看效果:
import 'package:flutter/material.dart';
import './asset.dart'; //数据本应该是数据库提供的 这里我们写了个假数据文件假扮.
class SearchBarDemo extends StatefulWidget {
@override
_SearchBarDemoState createState() => _SearchBarDemoState();
}
class _SearchBarDemoState extends State<SearchBarDemo> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("搜索DEMO"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.search),
onPressed: () {
//点击搜索按钮后会调用原生showSearch方法显示SearchBarDelegate搜索条
showSearch(context: context, delegate: SearchBarDelegate());
})
],
),
);
}
}
class SearchBarDelegate extends SearchDelegate<String> {
@override
List<Widget> buildActions(BuildContext context) {
//重写bulidActions 构造搜索动作区域 就是后面的X 这个重构基本不会变
return [IconButton(icon: Icon(Icons.clear), onPressed: () => query = "")];
}
@override
Widget buildLeading(BuildContext context) {
//重写buildLeading 构造搜索头部区域 就是前面的⬅ 这个重构基本不会变
return IconButton(
icon: AnimatedIcon(
icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
onPressed: () => close(context, null));
}
@override
Widget buildResults(BuildContext context) {
//重写buildResults 构造搜索结果区域, 这里写的是搜索按钮按下后的逻辑
return Container(
width: 400.0,
height: 200.0,
child: Card(
//点击搜索后可以显示列表清单\特等结果等, 这里是假装搜索到一个卡片.
color: Colors.indigo,
child: Text(
'这里是假装的搜索$query 得到的结果!!最好做成一个列表,通过点击跳转到想去的页面',
style: TextStyle(color: Colors.white, fontSize: 20),
textAlign: TextAlign.center,
),
),
);
}
@override
Widget buildSuggestions(BuildContext context) {
//重写buildSuggestions 构造搜索提示区域
final suggestionList = query.isEmpty //搜索提示列表数据
? recentSuggest //最近搜索, 数据应来源于服务器
: searchList
.where((input) => input.startsWith(query))
.toList(); //数据应来源于服务器
//重写buildSuggestions 构造搜索提示
return ListView.builder(
//生成提示列表
itemBuilder: (context, index) => ListTile(
//返回列表瓦片
title: RichText(
text: TextSpan(
//严格匹配的加粗部分
text: suggestionList[index].substring(0, query.length),
style: TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
children: [
TextSpan(
//未严格匹配到的部分
text: suggestionList[index].substring(query.length),
style: TextStyle(color: Colors.grey))
]),
),
onTap: () {
print(query);
Scaffold.of(context).removeCurrentSnackBar();
Scaffold.of(context).showSnackBar(SnackBar(
content: Text("一个建议选项被点了,可能要跳转到对应的页面了"),
));
},
),
itemCount: suggestionList.length);
}
}
十二. 闪屏页面 //启动加载页
import 'package:flutter/material.dart';
import './home_page.dart';
class SplashScreen extends StatefulWidget {
@override
_SplashScreenState createState() => _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen>
with SingleTickerProviderStateMixin { //为了动画效果混合这个类SingleTickerProviderStateMixin
AnimationController _controller; //动画控制器
Animation _animation; //动画过程
@override
void initState() {
//重写初始化方法
super.initState();
_controller = AnimationController( //初始化动画控制器
vsync: this, duration: Duration(milliseconds: 3000));
_animation = Tween(begin: 0.0, end: 1.0).animate(_controller); //初始化动画过程
_animation.addStatusListener((status) { //监听动画状态变化
if (status == AnimationStatus.completed) { //当动画状态变为AnimationStatus.completed时,发生跳转
Navigator.of(context).pushAndRemoveUntil(
MaterialPageRoute(builder: (context) => MyHomePage()), //跳转到MyHomePage页面
(router) => router == null); //固定写法
}
});
_controller.forward(); //播放动画
}
@override
void dispose() {
//重写销毁方法
_controller.dispose(); //销毁动画控制器
super.dispose();
}
@override
Widget build(BuildContext context) {
return FadeTransition( //返回一个淡入动画
opacity: _animation, //该动画的透明度关联至上面创立的动画过程_animation身上
child: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1587370522470&di=e0ba28a377b1d9d18a5589579af3a35a&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201611%2F27%2F20161127000843_zLhCx.jpeg",
scale: 2.0,
fit: BoxFit.cover,
),
);
}
}
十三. 右滑返回
实现这个效果,我们引用了另一套UI框架cupertino.这套风格接近IOS风格.
import 'package:flutter/cupertino.dart'; //引用的是另一套UI风格:cupertino
class RightBackDemo extends StatelessWidget {
//第二页,里面有个卡布奇诺按钮, 按下返回第一页
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Center(
child: Container(
height: 100,
width: 100,
color: CupertinoColors.activeBlue,
child: CupertinoButton(
child: Icon(CupertinoIcons.add),
onPressed: () {
Navigator.push(context,
CupertinoPageRoute(builder: (BuildContext context) {
return FirstPage();
}));
}),
)));
}
}
class FirstPage extends StatelessWidget {
//第一页,只是一个普通的页面
@override
Widget build(BuildContext context) {
return CupertinoPageScaffold(
child: Center(
child: Container(
child: CupertinoButton(
child: Text('next page'),
onPressed: () {
Navigator.push(context,
CupertinoPageRoute(builder: (BuildContext context) {
return RightBackDemo();
}));
}),
),
),
);
}
}
十四. tooltip 轻提示
tooltip常常用在图片 按钮上,做小型提示.
import 'package:flutter/material.dart';
class TooltipDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("tooltip")),
body: Center(
child: Tooltip(
message: '不要乱点',
preferBelow:true,
child: Image.network(
"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1587630407426&di=dc83b562a13e8f2f870dc19b5dc4fe05&imgtype=0&src=http%3A%2F%2Fattachments.gfan.com%2Fforum%2F201803%2F23%2F1849303zhiwhlvviwplm5l.jpg",
),
),
),
);
}
}