Flutter开发之Widget布局和页面导航
一、水平布局Row
Row控件可以分为非灵活排列和灵活排列两种,灵活的可以在外边加入Expanded使用
两者混用:
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // TODO: implement build return MaterialApp( title: '', home: new Scaffold( appBar: new AppBar(title: new Text('hello row')), body: new Row( children: <Widget>[ Expanded( //灵活使用 child: new RaisedButton( onPressed: () {}, color: Colors.blue, child: new Text('Blue Button'), )), new RaisedButton( onPressed: () {}, color: Colors.green, child: new Text('Green Button'), ), ], ), ), ); } }
二、垂直布局Column
对齐方式:
-
main轴: 比如Row组件,那水平就是主轴。比如Column组件,那垂直就是主轴。
- cross轴:比如Row组件,那垂直就是副轴。比如Columu组件,那水平就是副轴。
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { // TODO: implement build return MaterialApp( title: '', home: new Scaffold( appBar: new AppBar(title: new Text('hello Column')), body: new Center( child: new Column( crossAxisAlignment: CrossAxisAlignment.center, //副轴对齐方式 mainAxisAlignment: MainAxisAlignment.center, //主轴对齐方式 children: <Widget>[ new Text('君不见黄河之水天上来,', style: TextStyle( color: Colors.black, fontSize: 30.0, )), new Text('东流到海不复还,', style: TextStyle( color: Colors.redAccent, fontSize: 30.0, )), ], ), ), ), ); } }
三、层叠布局Stack
alignment属性:控制层叠的位置
alignment: const FractionalOffset(dx,dy) dx、dy 为0~1
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { var stack = new Stack( alignment: const FractionalOffset(0.5, 0.8), children: <Widget>[ new CircleAvatar( backgroundImage: new NetworkImage('https://profile.csdnimg.cn/0/5/2/1_jyd0124'), radius: 100.0, ), new Container( decoration: BoxDecoration( color: Colors.cyan, ), child: new Text('blog_jyd0124'), padding: EdgeInsets.all(5.0), ), ], ); // TODO: implement build return MaterialApp( title: '', home: new Scaffold( appBar: new AppBar(title: new Text('hello Stack')), body: new Center(child: stack), ), ); } }
说明:CircleAvatar组件经常用来作头像,radius属性可以设置图片的弧度
Stack布局高级用法:Positioned(层叠定位组件)用于层叠多个组件
var stack = new Stack( //alignment: const FractionalOffset(0.5, 0.8), children: <Widget>[ new CircleAvatar( backgroundImage: new NetworkImage('https://profile.csdnimg.cn/0/5/2/1_jyd0124'), radius: 100.0, ), new Positioned( bottom: 20.0, left: 60.0, child: new Container( decoration: BoxDecoration( color: Colors.cyan, ), child: new Text('blog_jyd0124'), padding: EdgeInsets.all(5.0), )), ], );
四、卡片布局Card
import 'package:flutter/material.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { var card = new Card( child: new Column( children: <Widget>[ ListTile( title: new Text('成都市',style:TextStyle(fontWeight:FontWeight.w100)), subtitle: new Text('QQ:150048****'), leading: new Icon(Icons.account_balance,color: Colors.blue,), ), ListTile( title: new Text('西安市',style:TextStyle(fontWeight:FontWeight.w100)), subtitle: new Text('QQ:150048****'), leading: new Icon(Icons.account_balance,color: Colors.blue,), ), ListTile( title: new Text('兰州市',style:TextStyle(fontWeight:FontWeight.w100)), subtitle: new Text('QQ:150048****'), leading: new Icon(Icons.account_balance,color: Colors.blue,), ), ], ) ); // TODO: implement build return MaterialApp( title: '', home: new Scaffold( appBar: new AppBar(title: new Text('hello Column')), body: new Center(child: card), ), ); } }
五、页面的导航和返回
1.RaisedButton按钮组件
两个常用属性:
- child:可以放入容器,图标,文字
- onPressed:事件的响应,一般调用
Navigator
组件
2.Navigator组件
- Navigator.push() =====跳转到下一个页面,接受两个参数一个是上下文context,另一个是要跳转的函数。
- Navigator.pop() =====返回到上一个页面,接受一个context(上下文)参数
import 'package:flutter/material.dart'; void main() => runApp(MaterialApp( title: '导航演示', home: new FirstScreen(), )); class FirstScreen extends StatelessWidget { @override Widget build(BuildContext context) { // TODO: implement build return Scaffold( appBar: AppBar( title: Text(''), ), body: Center( child: RaisedButton( child: Text('跳转'), onPressed: () { Navigator.push( context, MaterialPageRoute( builder: (context) => new SecondScreen(), )); }), ), ); } } class SecondScreen extends StatelessWidget { @override Widget build(BuildContext context) { // TODO: implement build return Scaffold( body: new Scaffold( appBar: new AppBar(title: new Text('跳转完成')), body: new Center( child: RaisedButton( child: Text('返回'), onPressed: () { Navigator.pop(context); }, )), ), ); } }
六、导航参数的传递和接收
import 'package:flutter/material.dart'; class Product { String title; String description; Product(this.title, this.description); } void main() { runApp(MaterialApp( title: '导航的数据传递和接受', home: ProductList( products: List.generate(20, (i) => Product('商品 $i', '这是一个商品详情,编号为 $i'))), )); } class ProductList extends StatelessWidget { final List<Product> products; ProductList({Key key, @required this.products}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('商品列表'), ), body: ListView.builder( itemCount: products.length, itemBuilder: (context, index) { return ListTile( title: Text(products[index].title), onTap: () { Navigator.push( context, MaterialPageRoute( builder: (context) => ProductDetail(product: products[index]))); }, ); }), ); } } class ProductDetail extends StatelessWidget { final Product product; ProductDetail({Key key, @required this.product}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('${product.title}')), body: Center( child: Text('${product.description}'), ), ); } }
- 小技巧 :Android Studio 中输入stless可以自动生成StatelessWidget,但在VSCode中,需先安装Awesome Flutter snippets插件,然后输入stlss;
七、页面跳转并返回数据
1.异步请求与等待
使用async...await
2.SnackBar
显示提示信息的一个控件,会自动隐藏,SnackBar是以Scaffold的showSnackBar()方法来进行显示的;
3.返回数据
Navigator.pop()带第二个参数就可以
import 'package:flutter/material.dart'; void main() { runApp(MaterialApp( title: '页面跳转返回数据', home: FirstPage(), )); } class FirstPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('得到一个数字')), body: Center( child: RouteButton(), ), ); } } class RouteButton extends StatelessWidget { @override Widget build(BuildContext context) { return RaisedButton( onPressed: () { navigateToNumber(context); }, child: Text('Get'), ); } navigateToNumber(BuildContext context) async { //async是启用异步方法 final result = await Navigator.push( //等待 context, MaterialPageRoute(builder: (context) => Number())); Scaffold.of(context).showSnackBar(SnackBar(content: Text('$result'))); } } class Number extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('我是你找的数')), body: Center( child: Column( children: <Widget>[ RaisedButton( child: Text('两位数'), onPressed: () { Navigator.pop(context, '两位数:98'); }, ), RaisedButton( child: Text('三位数'), onPressed: () { Navigator.pop(context, '三位数:124'); }, ), ], ), ), ); } }
八、静态资源和项目图片的处理
在pubspec.yaml文件中声明资源文件
测试:
import 'package:flutter/material.dart'; void main()=>runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return Container( child: Image.asset('images/csdn.jpg'), ); } }
九、客户端打包(Android)
1. 配置APP的图片的目录 /android/app/src/main/res/
2.配置APP的名称、图标和系统权限的目录 /android/app/src/main/AndroidManifest.xml
3.生成keystore
<1> flutter doctor -v 命令找到keytool.exe的位置
<2>cd进入这个目录,然后执行下面命令就会在D盘下面有一个jks的文件
keytool -genkey -v -keystore D:\key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias key
<3>到项目目录下的android文件夹下,创建一个名为key.properties的文件,并打开粘贴下面的代码
storePassword=<password from previous step> //输入上一步创建KEY时输入的 密钥库 密码 keyPassword=<password from previous step> //输入上一步创建KEY时输入的 密钥 密码 keyAlias=key storeFile=<E:/key.jks> //key.jks的存放路径
4.配置key注册
<1>进入项目目录的/android/app/build.gradle文件,在android{这一行前面,加入如下代码
def keystorePropertiesFile = rootProject.file("key.properties") def keystoreProperties = new Properties() keystoreProperties.load(new FileInputStream(keystorePropertiesFile))
<2>把如下代码进行替换
替换成的代码:
signingConfigs { release { keyAlias keystoreProperties['keyAlias'] keyPassword keystoreProperties['keyPassword'] storeFile file(keystoreProperties['storeFile']) storePassword keystoreProperties['storePassword'] } } buildTypes { release { signingConfig signingConfigs.release } }
5.生成apk
在终端输入 flutter build apk,这时候打包成功,可在build\app\outputs\apk\release\找到
然后在终端输入flutter install 直接安装到