Flutter學習之旅

安裝/配置

請看官網:

遇到問題

配置創建第一工程過程中,可能會回到一步在卡在gradle這一步:

Running 'gradle assembleDebug

解決方案

語法

入口函數

方式一

main(){

}

方式二

void main(){

}

變量

dart是一門強大的腳步類語言,可以不預先定位變量的類型,會自動推斷類型
var s1 = ‘hello’
String s2 = ‘hello’
注:var後不要加類型,寫了類型就不要加var
類裏的變量加上下劃線(_)可以使之變爲私有的,如同private關鍵字

命名規則

  1. 變量命名必須有數字、字母、下劃線和美元符號($)組成
  2. 標識符開頭不能是數字
  3. 標識符不能是保留字和關鍵字
  4. 變量名字是區分大小寫的

常量

final(運行時變量)

開始可以不賦值,只賦值一次

const(編譯是變量)

值不變,一開始就賦值

數據類型(常用)

  1. Number(數值)
    int
    double
  2. String(字符)
    String,單引號,雙引號,三個單引號(適用於多行),三個雙引號(適用於多行)
    拼接使用+Strings1=hello;Strings2=world;Strings3=符號、+號,如 String s1 = 'hello'; String s2 = 'world'; String s3 = 's1 $s2’ //hello world
    String s4 = s1 + s2 //hello world
  3. Booleans
    bool
  4. List(數組)
    Dart中,數組是列表對象
  5. Maps(字典)
    map
    初始化方式一
    var map1 = {
    “key1”:“value1”,
    “key2”:“value2”,
    “key3”:“value3”
    }
    初始化方式二
    var map2 = new Map()
    map2[‘key1’] = ‘value1’;
    map2[‘key2’] = ‘value2’;
    map2[‘key3’] = ‘value3’;
    map2.keys;//獲取所有的key
    map.values;//獲取所有的value

類型判斷(is)

var s1 = ‘hello’;
if(s1 is String){
}

運算符(與java基本類似)

賦值運算符 = ??=

String s1;
s1 ??= ‘hello’;//表示如果s1爲空的話,把’hello’賦值給s1

for循環

  1. (var i = 0;i < length;i++){}
  2. for(var item in list){}
  3. list.forEach((value){});
  4. map.forEach((key,value){});
  5. newList = list.map((value){//返回原集合中個元素*2的組成新的集合
    return value * 2;
    })
  6. newList = list.where((value){//返回原集合中大於10的元素組成新的集合
    return value > 10;
    })
  7. newList = list.any((value){//判斷原集合中的元素是否有大於10的
    return value > 10;
    })
  8. newList = list.every((value){//判斷原集合中的元素是否都大於10
    return value > 10;
    })

函數(方法)

  1. 函數內部可以嵌套函數
  2. 可選參數使用中括號,如
void func(int a,[int b=1,int c]){} //其中,b,c爲可選參數

3.命名參數使用大括號,如

void func(int a,{int b,int c}){} //其中,b,c爲命名參數
調用
func(1,b=2,c=4)

閉包

概念:函數嵌套函數,嵌套的函數會調用外部函數的變量或參數,變量或參數不會被系統回收
寫法:函數嵌套函數,並return裏面的函數,這樣就形成閉包

?條件運算符(同kotlin),如:

Object ob;
ob?.toString()

as 類型轉換

is 類型判斷

… 級聯操作(連綴)

class User{
 int age;
 String name;
}
User user = new User();
user..age=10
     ..name="Tim";

初始化列表(執行構造函數前執行)

class User{
  int age;
  String name;
  User()in age=11,name='Tim'{
  }
}
class SubUser extend User{
	SubUser():supter(){}
}

複寫

@override可寫可不寫

類似多繼承(mixins)

class B{}
class C{}
class A with B,C{

}
注:使用mixins時,B、C類不能有構造函數,B、Clei不能繼承其他類

網絡請求

async: 讓方法變成一部

void test() async {}

await 等待異步方法執行完成

只有在使用async時,才能使用await

 getDataFromSever() async {
	var httpClient =new HttpClient();
	var uri = new Uri.http("http:xxxx");
	var request = await httpClient.getUrl(uri);
	var respone = await request.close();
	return respone.transForm(utf8.decoder).join();
}

第三方模塊

託管:統一託管在pub上,如

dev/packages
fluter-io
dartlang

flutter工程

目錄

在這裏插入圖片描述

程序入口

main(){
	runApp(myApp())
}
或
main() => runApp(myApp())

組件

Widget

對應Android中的View

MaterialApp

作爲Widget的頂層組件

home(主頁)

title(標題)

color(顏色)

theme(主題)

routes(路由,相當Activity)

Scaffold 是Meterial Design的佈局的基本實現

有以下幾個屬性

appBar

顯示在界面頂部的AppBar

body

當前界面所顯示的主要內容 Widget

drawer

抽屜菜單類型

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(
            '我是標題欄'
          ),
        ),
        body: MyCenter(),
      ),
      theme: ThemeData(
        primarySwatch:Colors.red //主題顏色
      ),
    );
  }

}

class MyCenter extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Center(
        child: Text(
          'hello',
          textDirection: TextDirection.ltr,
          style: TextStyle(
              color: Colors.red,
              fontSize: 32
          ),
        )
    );
  }
}

//class MyApp extends StatelessWidget {
//
//  @override
//  Widget build(BuildContext context) {
//    return new MaterialApp(
//      title: 'my First flutter',
//      home: new Scaffold(
//        appBar: new AppBar(
//          title: new Text('I am appBar 哈哈233'),
//        ),
//        body: new Center(
//          child: new Text('Hello World!!!2'),
//        ),
//      ),
//    );
//  }
//}

//void main() {
//  runApp(
//    new Center(
//      child: new Text(
//        'Hello, world!',
//        textDirection: TextDirection.ltr,
//      ),
//    ),
//  );
//}

Container(容器)

也是集成與StateLessWidget

Image

本地圖片 Image.asset

  1. 先在工程目錄下創建存放圖片的目錄,如:
    在這裏插入圖片描述
    images根目錄爲標準圖片
    images/2.0x爲2.0倍
    images/3.0x爲3.0倍
    以上三個目錄比配放置圖片
  2. 在pubspec.yaml配置該圖片路徑
assets:
    - images/bg.png
    - images/2.0x/bg.png
    - images/3.0x/bg.png
  1. 最後引用
Image.asset('images/bg.png');

網絡圖片 Image.network(picUrl)

圓角及圓形圖片

圓形

  1. 利用Container的borderRadius
Container(
      width: 400,
      height: 400,
      decoration: BoxDecoration(
          color: Colors.yellow,
//          borderRadius: BorderRadius.all(Radius.circular(60))
      borderRadius: BorderRadius.circular(60),
      image: DecorationImage(
        image: NetworkImage('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg'),
          fit: BoxFit.cover
      ))
  1. 利用Container的ClipOval屬性
child: ClipOval(
      child: Image.network(
        'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
        fit: BoxFit.cover,
      width: 300,
      height: 300,),
    ),

ListView

ListView內部不能嵌套ListView

ListView(
      padding: EdgeInsets.all(15.0),
      scrollDirection: Axis.vertical,
      children: <Widget>[
        ListTile(
          leading: Icon(Icons.ac_unit,color: Colors.red,size: 44,),
            trailing: Icon(Icons.ac_unit,color: Colors.red,size: 44,),
            title: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:'),
            subtitle: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:')
        ),
       //或者其他Widget
      ],
    );

ListView.builder

import 'package:flutter/material.dart';


class MyListView extends StatelessWidget {

  var list = new List();

  MyListView(){
    for(var i = 0;i < 20;i++){
      list.add('第$i條數據');
    }
  }

  @override
  Widget build(BuildContext context) {
//    return ListView(
//      padding: EdgeInsets.all(15.0),
//      scrollDirection: Axis.vertical,
//      children: _getStaticData(),
//    );
  return ListView.builder(
    itemCount: this.list.length,
    itemBuilder: (context,index){
      return ListTile(
        title: Text(this.list[index]),
      );
    }
  );
  }
}

List<Widget> _getStaticData(){
  return <Widget>[
    ListTile(
        leading: Icon(Icons.ac_unit,color: Colors.red,size: 44,),
        trailing: Icon(Icons.ac_unit,color: Colors.red,size: 44,),
        title: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:'),
        subtitle: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:')
    ),
    ListTile(
        leading: Icon(Icons.accessibility),
        title: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:'),
        subtitle: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:')
    ),
    ListTile(
        leading: Image.asset('images/bg.png',width: 44,height: 44,),
        title: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:'),
        subtitle: Text('要安裝並運行Flutter,您的開發環境必須滿足以下最低要求:')
    )
  ];
}



GridView

實現方式

GridView.count

GridView.count(
      scrollDirection: Axis.vertical,//方向
      crossAxisCount: 3, //一行幾列
      crossAxisSpacing: 8,//水平間隔
      mainAxisSpacing: 8,//垂直間隔
      children: _getStaticData(),
    )

GridView.builder

GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
          crossAxisCount: 3,
          crossAxisSpacing: 5,
          mainAxisSpacing: 5

    ),
    itemCount: this.list.length,
    itemBuilder: (context,index){
      return Container(
//        height: 120,
        child: Image.network(
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg",
          fit: BoxFit.cover),
      );
    }
  )

Padding、 Row Column、Expanded

Padding–間距組件

Row–水平組件

Row(
        mainAxisAlignment: MainAxisAlignment.end,//主軸(水平)排列方式
        children: <Widget>[
          Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            width: 50,
            height: 50,),
          Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            width: 50,
            height: 50,),
          Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            width: 50,
            height: 50,),
          Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            width: 50,
            height: 50,)
        ],
      )

Column–垂直組件

Column(
        mainAxisAlignment: MainAxisAlignment.end,//主軸(垂直)排列方式
        children: <Widget>[
          Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            width: 50,
            height: 50,),
          Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            width: 50,
            height: 50,),
          Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            width: 50,
            height: 50,),
          Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            width: 50,
            height: 50,)
        ],
      )

Expanded

類似web中的flex佈局

Row(
      children: <Widget>[
        Expanded(
          flex: 2,
          child: Image.network(
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
            fit: BoxFit.cover,
            height: 100,),
        ),
        Expanded(
            flex: 1,
            child: Image.network(
          'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
          fit: BoxFit.cover,
          height: 100,)
        )],
    )

Stack

頁面層疊組件,類似於RelativeLayout佈局
屬性

alignment 配置所有子元素顯示的位置

 Stack(
        children: <Widget>[
          Align( //相對位置
            alignment: Alignment(0,0.5),//(0.0)爲中心
            child: Icon(Icons.home,size:60,color: Colors.red),
          ),
          Align(
            alignment: Alignment.bottomLeft,
            child: Icon(Icons.save,size:60,color: Colors.yellow),
          ),
          Positioned(//絕對位置)
            left: 0,//左上角
//            top: 0,
//            right: 0,
            bottom: 100,
            child: Icon(Icons.settings,size:60,color: Colors.yellow),
          )
        ],
      )

注意:(0.0)爲中心

position

children 子組件

Positioned(//絕對位置)
            left: 0,//左上角
//            top: 0,
//            right: 0,
            bottom: 100,
            child: Icon(Icons.settings,size:60,color: Colors.yellow),
          )
Container(
      height: 400,
      width: 400,
      color: Colors.blue,
      alignment: Alignment(0,1),
      child: new Stack(
        children: <Widget>[
          Align( //相對位置
            alignment: Alignment(0,0.5),//(0.0)爲中心
            child: Icon(Icons.home,size:60,color: Colors.red),
          ),
          Align(
            alignment: Alignment.bottomLeft,
            child: Icon(Icons.save,size:60,color: Colors.yellow),
          ),
          Positioned(//絕對位置)
            left: 0,//左上角
//            top: 0,
//            right: 0,
            bottom: 100,
            child: Icon(Icons.settings,size:60,color: Colors.yellow),
          )
        ],
      ),
    )

AspectRadio、Card

AspectRadio

作用:可以設置調整child子元素的寬高比

AspectRatio(
        aspectRatio: 2/1,//寬/高
        child: Container(
          color: Colors.blue
        ),
    )

Card

屬性

  1. margin 外邊距
  2. child 子組件
  3. shape 卡片的陰影效果,默認是圓角的長方形
Card(
          margin: EdgeInsets.all(10),
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20))),
          child: Column(
            children: <Widget>[
              AspectRatio(
                aspectRatio: 16/9,
                child: Image.network(
                    'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg',
                    fit: BoxFit.cover),
              ),
              ListTile(
                leading: CircleAvatar(
                  backgroundImage: NetworkImage("https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1581422031471&di=df2254ecbc97fc0cae3396a670511021&imgtype=0&src=http%3A%2F%2Fimg2018.cnblogs.com%2Fblog%2F1762823%2F201911%2F1762823-20191104112732371-1699453123.jpg"),
                ),
                title: Text('name'),
                subtitle: Text('subContent'),
              )
            ],
          )
        )

RaisedButton

child

onPressed

Wrap

實現流佈局,相對於FloxBoxLayout

import 'package:first_flutter_app/MyRaisedButton.dart';
import 'package:flutter/material.dart';

class MyWrap extends StatelessWidget {

  var list = new List();

  MyWrap(){
    for(var i = 0;i < 20;i++){
      list.add('第$i條數據');
    }
  }

  @override
  Widget build(BuildContext context) {
    return Wrap(
      direction: Axis.horizontal,//方向
        spacing: 5,//主軸間距
        runSpacing: 5,//副軸間距
        alignment: WrapAlignment.center,//主軸方向對其方式
      children: _getWidgets()
    );
  }

  List<Widget> _getWidgets(){
    return list.map((value) {
      return MyRaisedButton(value);
    }).toList();
  }
}

StatefulWidget

有狀態組件

關鍵點

  1. MyWidget 繼承 StatefulWidget
  2. 並繼承State
  3. 改變狀態是,在state類裏調用setState函數
import 'package:flutter/material.dart';

class MySatefulWidget extends StatefulWidget {

  @override
  _MySatefulWidgetState createState() {
    return _MySatefulWidgetState();
  }

}

class _MySatefulWidgetState extends State<MySatefulWidget>{

  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        SizedBox(
          height: 10,
        ),
        Text('Hi ${this.count}'),
        SizedBox(
          height: 10,
        ),
        RaisedButton(
          child: Text('click'),
          onPressed: (){
            setState(() {
              this.count++;
            });
          },
        )
      ],
    );
  }

}

BottomNavigationBar

自定義底部導航條
屬於Scaffold
常見屬性

  1. items 底部導航條按鈕組合(List)
  2. iconSize
  3. currentIndex
  4. onTap 選中變化回調的函數
  5. fixedColor 選中的顏色,如果不設置,默認跟主題顏色一樣
  6. type
    1).BottomNavigationBar.fixed
    2).BottomNavigationBar.shifting
Scaffold(
        appBar: AppBar(
          title: Text('我是標題欄'),
        ),
        body: this._pages[this._currentIndex],
        bottomNavigationBar:BottomNavigationBar(
          currentIndex: this._currentIndex,
          iconSize: 22.0,//icon大小
          fixedColor:Colors.blue, //選中的顏色,如果不設置,默認跟主題顏色一樣
          type: BottomNavigationBarType.fixed, //解決多個tabItem時,不顯示的配置
          onTap: (int index) {
            setState(() {
              this._currentIndex = index;
            });
          },
          items: [
        BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('首頁')
        ),
        BottomNavigationBarItem(
            icon: Icon(Icons.message),
            title: Text('消息')
        ),
        BottomNavigationBarItem(
            icon: Icon(Icons.departure_board),
            title: Text('發現')
        ),
        BottomNavigationBarItem(
            icon: Icon(Icons.people),
            title: Text('我的')
        ),
//        BottomNavigationBarItem(
//            icon: Image.asset('/images/bg.png'),
//            title: Text('發現')
//        )
      ],
    ))

路由

也就是頁面跳轉,通過navigator來管理路由導航,並提供了堆棧的管理方法,如,Navigator.push()–跳轉下一級,Navigator.pop(),返回上一級

配置方式

基本路由

跳轉

RaisedButton(
          child: Text("去搜索"),
          onPressed: (){
            Navigator.of(context).push(
              MaterialPageRoute(
                builder: (context) => SearchPage()//目標頁
              )
            );
          },
        )

返回

Navigator.of(context).pop()

命名路由

定義在MaterialApp裏,相當於Android的manifest文件裏配置的Activity

調用步驟

  1. 先在MaterialApp註冊頁面信息
MaterialApp(
     //註冊裏一個搜索,一個設置頁面
      routes: {
        '/search':(context) => SearchPage(),
        '/setting':(context) => SettingPage(),
      },
    )
  1. 在點擊跳轉的時候執行
Navigator.pushNamed(context, "/search");
或
Navigator.pushNamed(context, "/setting");

傳值

//配置頁面,類似Androd裏Manifest.xml配置的Activity
final _routes = {
  '/search':(context,{arguments}) => SearchPage(arguments: arguments,),
  '/setting':(context,{arguments}) => SettingPage(arguments: arguments)
};

//傳值固定配置函數
Route onGenerateRoute(RouteSettings settings) {
  final String name = settings.name;//點擊跳轉是輸入的name//Navigator.pushNamed(context, "/search");name爲"/search"
  final Function pageBuilder = _routes[name];//跳轉的函數//(context,{arguments}) => SearchPage(arguments: arguments,)
  if (pageBuilder != null) {
    if (settings.arguments != null) {
      // 如果透傳了參數
      return MaterialPageRoute(
          builder: (context) =>
              pageBuilder(context, arguments: settings.arguments));
    } else {
      // 沒有透傳參數
      return MaterialPageRoute(builder: (context) => pageBuilder(context));
    }
  }
  return null;
}

路由替換

頁面1→頁面2→頁面3 點擊返回到→頁面1,
在頁面2點擊跳轉的時候,執行以下跳轉方法

Navigator.pushReplacementNamed(conext,name)

返回根路由

//相當於跳轉到根頁面,然後把之前的棧清空
            Navigator.pushAndRemoveUntil(
                context,
                MaterialPageRoute(builder: (context) => RootPage()),
                (route) => route = null);

跳轉方式

  1. 路由直接跳轉到下一個頁面Navigator.pushNamed(context,"/nextPage");
    2. 跳轉的下一個頁面,替換當前的頁面Navigator.of(context).pushReplacementNamed('/nextPage')
    3. 返回上一個頁面 Navigator.of(context).pop()
    4. 返回到指定的頁面(指定的頁面必須已經在棧裏)
    Navigator.of(context).popUntil(ModalRoute.withName(MyRoute.TABS))
    5. 跳轉新頁面並清空堆棧路由或者返回指定的路由Navigator.of(context).pushAndRemoveUntil( new MaterialPageRoute(builder: (context) => new MyTextFiled()), (route) => route == null //rootRoute()指定返回的路由 );

AppBar

頂部導航

屬性

屬性 描述
leading 標題前的一個控件,通常首頁顯示應用的logo,其他頁面顯示返回鍵
title 標題
actions 通常使用IconButton表示,可以放置按鈕組
buttom 通常放tabBar,標題下面顯示一個Tab 導航欄
comTheme 圖標樣式
titleTheme 文字樣式
centerTitle 標題是否居中顯示
backgroundColor 背景欄顏色
Scaffold(
      appBar: AppBar(
        title: Text('myAppbar'),
        centerTitle: true,//標題是否居中
        backgroundColor: Colors.black,
//        leading: Icon(Icons.accessibility),//標題左邊,沒有點擊事件的
        leading: IconButton(
          icon: Icon(Icons.beach_access),
          onPressed: () {
            Navigator.pop(context);
          },
        ), //標題左邊,有點擊事件的
        actions: <Widget>[ //導航右側圖標
          Icon(Icons.settings),
          Icon(Icons.departure_board)
        ],
      ),
      body: Center(
        child: Text('內容'),
      ),
    )

AppBar裏的TabBar

常見屬性

屬性 描述
tabs 顯示的標籤內容,一般用Tab對象,也可以用其他Widget
controller TabController對象
isScrollable 是否可以滾動
indicatorColor 指示器(下劃線)顏色
indicatorSize 指示器長度
label 選擇文字的顏色

在這裏插入圖片描述

DefaultTabController(
        length: 2,
        child: Scaffold(
          appBar: AppBar(
            bottom: TabBar(
              tabs: <Widget>[
                Tab(text: '熱門',),
                Tab(text: '推薦',),
              ],
            ),
            title: Text('myAppbar'),
            centerTitle: true,//標題是否居中
            backgroundColor: Colors.black,
//        leading: Icon(Icons.accessibility),//標題左邊,沒有點擊事件的
            leading: IconButton(
              icon: Icon(Icons.beach_access),
              onPressed: () {
                Navigator.pop(context);
              },
            ), //標題左邊,有點擊事件的
            actions: <Widget>[ //導航右側圖標
              Icon(Icons.settings),
              Icon(Icons.departure_board)
            ],
          ),
          body: TabBarView(
            children: <Widget>[
              Text('熱門內容'),
              Text('推薦內容')
            ],
          ),
        ),
      )

切換

  1. 代碼配置
body: TabBarView(
            children: <Widget>[
              Text('熱門內容'),
              Text('推薦內容')
            ],
          ),

2.TabContoller

import 'package:flutter/material.dart';

class MyTabBarCtrlPage extends StatefulWidget {

  @override
  State<StatefulWidget> createState() {
    return _MyTabBarCtrlPageState();
  }
}

class _MyTabBarCtrlPageState extends State<MyTabBarCtrlPage> with SingleTickerProviderStateMixin{

  TabController _tabController;

  @override
  void initState() {
    super.initState();
    _tabController = TabController(
        vsync:this,
        length:3
    );
    _tabController.addListener(() {
      print('index= ${_tabController.index}');
    });
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('MyTabBarCtrlPage'),
        bottom: TabBar(
          controller: this._tabController,//注意,必須要加
          tabs: <Widget>[
            Tab(text: '熱門'),
            Tab(text: '推薦'),
            Tab(text: '更多')
          ],
        ),
      ),
      body: TabBarView(
        controller: this._tabController,//注意,必須要加
        children: <Widget>[
          Center(
            child: Text('熱門內容'),
          ),
          Center(
            child: Text('推薦內容'),
          ),
          Center(
            child: Text('更多內容'),
          )
        ],
      ),
    );
  }
}

Drawer

抽屜組價、側邊欄

左側欄

Drawer()

右側欄

endDrawer()

側欄普通頭部

DrawerHeader

側欄用戶頭部

UserAccountsDrawerHeader()

caffold(
      appBar: AppBar(
        title: Text('MyDrawer'),
      ),
      body: Center(
        child: Text('內容'),
      ),
      drawer: Drawer(
          child: Column(
            children: <Widget>[
              DrawerHeader(
                child: Text('左側標題'),
              ),
              Divider(),
              Text('左側邊欄內容'),
            ],
          )
      ),
      endDrawer: Drawer(
        child: Center(
          child: Text('右側邊欄內容'),
        ),
      ),
    )

按鈕組件

名稱 描述
RaisedButton 凸起按鈕
FlatButton 扁平化按鈕
OutlineButton 線框按鈕
IconButton 圖標按鈕
ButtonBar 按鈕組
FlatingActionButton 浮動按鈕

在這裏插入圖片描述

表單

TextFiled

文本框組件(Editext)

TextField(
          obscureText: true,//密碼框
          maxLines: 1,
          decoration: InputDecoration(
            icon: Icon(Icons.people),
            hintText: '請輸入內容',
            labelText: '用戶名',//顯示在輸入框左上角
            border: OutlineInputBorder(),//變邊框的
          ),
        )

獲取TextFiled裏的值

監聽onChanged()方法

TextField(
//              obscureText: true,//密碼框
              maxLines: 1,
              decoration: InputDecoration(
                icon: Icon(Icons.people),
                hintText: '請輸入內容',
                labelText: '用戶名',//顯示在輸入框左上角
                border: OutlineInputBorder(),//變邊框的
              ),
              onChanged: (value){
                 
              },
            )

CheckBox

Checkbox(
              value: this._checkFlag,
              onChanged: (value) {
                setState(() {
                  this._checkFlag = value;
                });
              },
              activeColor: Colors.yellow,//選擇的顏色
            )

CheckBoxListTile

在這裏插入圖片描述

CheckboxListTile(
              value: this._checkFlag,
              title: Text('標題'),
              subtitle: Text('內容'),
              secondary: Icon(Icons.settings),//左側加圖片
              onChanged: (value) {
                setState(() {
                  this._checkFlag = value;
                });
              },
            )

Radio

Radio(
              value: 1,
              onChanged: (v){
                setState(() {
                  this._radioValue = v;
                });
              },
              groupValue: this._radioValue,//radio組選擇的值
            )

RadioListTile

類似RadioListTile的用法

本地化語言設置

  1. 引入依賴
    在pubspec.yaml文件中配置
dependencies:
  flutter_localizations:
    sdk: flutter
  1. 在入口處
MaterialApp(
      //配置本地化
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate
      ],
      supportedLocales: [
        const Locale('zh', 'CH'),
        const Locale('en', 'US')
      ],
      )

日期組件

官方控件

日期

showDatePicker(
        context: context,
        initialDate: _nowDate,
        firstDate: DateTime(1970),
        lastDate: DateTime(2021)
    ).then((result){

    })

時間

showTimePicker(
        context: context,
        initialTime: TimeOfDay.now()
    ).then((result){

    });

Swiper(第三方輪播圖組件)

輪播圖組件

new Swiper(
          itemCount: 3,
        itemBuilder: (BuildContext context,int index){
            return Image.network(
              'https://ss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=2628977794,1833531909&fm=26&gp=0.jpg',
              fit: BoxFit.cover,);
        },
        pagination: SwiperPagination(),//指示器(點下。。。)
        control: SwiperControl(),//配置左右箭頭
      ),
    )

AlertDialog

在這裏插入圖片描述

showDialog(
              context: context,
              builder: (context) {
                return AlertDialog(
                  title: Text('標題'),
                  content: Text('內容'),
                  actions: <Widget>[
                    FlatButton(
                      child: Text('取消'),
                      onPressed: (){
                        Navigator.pop(context);
                      },
                    ),
                    FlatButton(
                      child: Text('確定'),
                      onPressed: (){
                        Navigator.pop(context);
                      },
                    ),
                  ],
                )

SimpleDialog

在這裏插入圖片描述

showDialog(
              context: context,
              builder: (context) {
                return SimpleDialog(
                  title: Text('標題'),
                  children: <Widget>[
                    SimpleDialogOption(
                      child: Text('option 1'),
                      onPressed: (){},
                    ),
                    SimpleDialogOption(
                      child: Text('option 2'),
                      onPressed: (){},
                    ),
                    SimpleDialogOption(
                      child: Text('option 3'),
                      onPressed: (){
                        Navigator.pop(context,'3');//其中參數'3'可以當結果返回
                      },
                    ),
                  ],
                );

ShowBottomSheet

在這裏插入圖片描述

showModalBottomSheet(
            context: context,
            builder: (context){
              return Container(
                height: 160,
                child: Column(
                  children: <Widget>[
                    Text('選項一'),
                    Divider(),
                    Text('選項二'),
                    Divider(),
                    Text('選項三'),
                    Divider(),
                    Text('選項四'),
                  ],
                ),
              );
            },
          );

Toast(FlutterToast)

第三方庫

 Fluttertoast.showToast(
              msg: 'hello toast',
            toastLength: Toast.LENGTH_SHORT,
            gravity: ToastGravity.CENTER,
            backgroundColor: Colors.black,
            timeInSecForIos: 1,// only iOS
            textColor: Colors.white,
            fontSize: 15,
          );

自定義Dialog

步驟

  1. 寫一個組件extend Dialog
import 'package:flutter/material.dart';

class MyCustomDialog extends Dialog{

  @override
  Widget build(BuildContext context) {
    return Material(//注意點
      type: MaterialType.transparency,//設置透明
      child: Center(
        child: Container(
          height: 180,
          width: 320,
          color: Colors.white,
            child: Text('自定義dialog'),
        )
      )
    );
  }
}
  1. 調用的地方
showDialog(
	 context: context,
     builder: (context){
     	return MyCustomDialog(); //此處
 	}
);

網絡請求

Json數據與Map類型的轉換

需要引入 import ‘dart:convert’

Map轉Json字符串

Map map = {
      '年齡':'21',
      '性別':'男',
      '地址':'xxxx',
    };
String jsonStr = json.encode(map);
print('jsonStr= $jsonStr');

Json.encode(Map)

Json字符串轉Map

Json.decode(jsonStr)

String jsonStr2 = '{"年齡":"21","性別":"男","地址":"xxxx"}';
Map map2= json.decode(jsonStr2);
print('map2[年齡]= ${map2["年齡"]}');

get請求

String url = 'https://suggest.taobao.com/sug?code=utf-8&q=%E5%8D%AB%E8%A1%A3';
    http.Response respone = await http.get(url);//異步請求
    print('http_code= ${respone.statusCode}');
    if (respone.statusCode == 200) {
      print('http_body= ${respone.body}');
      setState(() {
        this._result = respone.body;
      });
      Map map = convert.jsonDecode(respone.body);//轉換爲map
    }

post請求

print('http_getData');
    String url = 'https://suggest.taobao.com/sug?code=utf-8&q=%E5%8D%AB%E8%A1%A3';
    http.Response respone = await http.post(url,body:this._map);//異步請求
    print('http_code= ${respone.statusCode}');
    if (respone.statusCode == 200) {
      print('http_body= ${respone.body}');
      setState(() {
        this._result = respone.body;
      });
      Map map = convert.jsonDecode(respone.body);//轉換爲map
    }

Flutter與原生的混合集成

主要有以下兩種

源碼集成 AAR(andriod),framework(iOS)集成
優點 1. 簡單快捷 2. 和原生交互較多或需要依賴原生的數據環境時,使用該方式調試方便 1. 不影響原生項目 2. 不參與Flutter開發的人員處於無感狀態 3. 無需對先原生環境做修改
缺點 1. 團隊所有人需要安裝Flutter環境 2. 需要對現在編譯發佈體現做修改 1. 複雜度較高 2. 與原生調試不是很方便

源碼集成

  1. 在原APP Native工程項目裏,添加flutter_module
  2. 安裝flutter相關開發插件

AAR集成

  1. 創建單獨的flutter工程並創建flutter_module
  2. 開發完成,打包成aar
    執行flutter builde aar完成後,控制檯會提示配置以下信息
1. Open <host>/app/build.gradle
  2. Ensure you have the repositories configured, otherwise add them:

      repositories {
        maven {
            url '/Users/wangpingtao/yuxun/exitApp/flutter_module/build/host/outputs/repo' //new
        }
        maven {
            url 'http://download.flutter.io' //new
        }
      }

  3. Make the host app depend on the Flutter module:

    dependencies {
      debugImplementation 'exit.wpt.com.flutter_module:flutter_debug:1.0 //new
      profileImplementation 'exit.wpt.com.flutter_module:flutter_profile:1.0 //new
      releaseImplementation 'exit.wpt.com.flutter_module:flutter_release:1.0 //new
    }


  4. Add the `profile` build type:

    android {
      buildTypes {
        profile { //new
          initWith debug //new
        } //new
      }
    }
  1. 在app/build.gralde文件配置aar相關信息:配置aar相關信息
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章