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 直接安裝到