Flutter學習及實戰分享 [復制鏈接]

2019-6-16 17:06
慕涵盛華 閱讀:252 評論:0 贊:2
Tag:  

先看一下最終實現的效果:

圖片描述

簡介

Flutter是Google發布的一個用于創建跨平臺、高性能移動應用的框架。它沒有使用原生控件,而是實現了一個自繪引擎,使用自身的布局、繪制系統。開發Flutter應用使用的是Dart語言

一.Dart語法

Dart語言跟Java或者Kotlin的語法使用上差不多,下面就快速介紹一下Flutter開發中常用到的不同之處:

變量

Dart聲明基本類型的變量可以使用var來接收任意類型的變量,一旦賦值類型就不能改變,也可以使用具體的類型來聲明。

var i = 10; //一旦賦值類型就確定了,以后的類型就不能改變了。
int j = 10;

使用dynamic或Object來聲明任意類型的對象類型。

函數

1.函數簡寫:

void main() => runApp(MyApp());
等價于
void main(){
  runApp(MyApp());
}

如果函數體只有一個表達式,可以使用=>來代替{}

2.可選命名參數
使用{param1, param2, …},用于指定命名參數。

//定義
void setData(int id,{String name,int count}){
    ......
}
//使用
setData(1);
setData(1,name: "慕涵盛華");
setData(1,name: "慕涵盛華",count: 2)

可選命名參數在Flutter中使用非常多。

修飾符

Dart里沒有private/protected/public等權限修飾符,但是要實現private,只需要將需要修飾的字段或者方法,加上:"_"

//前綴帶_的變量或者方法表示是類私有的變量或者方法。
int _count = 0; 
void _setCount(int count){
   _count  = count;
}
//使用
_setData(1);

異步支持

Dart類庫有非常多的返回Future或者Stream對象的函數。 這些函數被稱為異步函數:它們只會在設置好一些耗時操作之后返回,比如像 IO操作。而不是等到這個操作完成。

使用關鍵字async和await來異步編程。

//異步方法
void _getData() async {
    //等待返回結果
    final response = await http.get(URL_HOME_FIND_DETAIL_LIST);
    debugPrint("獲取的數據為:${response.body}");
};

以上介紹這些語法都是在Flutter開發中經常使用的,其他語法的用法跟Java或者Kotlin基本一樣了。

二.Flutter工程目錄

創建類型

圖片描述

從上圖中我們可以看出使用AndroidStudio創建Flutter項目是有4中類型,每一種類型的用處下面都給出了說明。這里說一下Flutter ApplicationFlutter Module,這兩種工程目錄下都包含Android和Ios工程目錄,但是Flutter Module;類型下的這兩個工程目錄是隱藏式的。

目錄結構

圖片描述

具體看一下pubspec.yaml文件的內容:

name: flutter_eyepetizer
description: A new Flutter module.
#應用或包的版本號
version: 1.0.0+1

environment:
  sdk: ">=2.1.0 <3.0.0"

#Flutter應用依賴
dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.2
  dio: ^2.1.0
  http: ^0.12.0
  video_player: 0.10.0+2

#開發環境依賴的工具包
dev_dependencies:
  flutter_test:
    sdk: flutter

#flutter相關的配置選項
flutter:
  uses-material-design: true
  #配置本地圖片
  assets:
    - images/ic_action_search.png
    - images/ic_tab_strip_icon_category.png
    - images/ic_tab_strip_icon_category_selected.png
    - images/ic_tab_strip_icon_feed.png
    - images/ic_tab_strip_icon_feed_selected.png
    - images/ic_tab_strip_icon_follow.png
    - images/ic_tab_strip_icon_follow_selected.png
    - images/ic_tab_strip_icon_profile.png
    - images/ic_tab_strip_icon_profile_selected.png
    - images/ic_home_public.png

  module:
    androidPackage: com.gfd.flutter_eyepetizer
    iosBundleIdentifier: com.gfd.flutterEyepetizer

Flutter的依賴使用的是pub倉庫

三.Widget簡介

Flutter中幾乎所有的對象都是一個Widget,與原生開發中“控件”不同的是,Flutter中的widget的概念更廣泛,它不僅可以表示UI元素,也可以表示一些功能性的組件如:用于手勢檢測的 GestureDetector widget、用于應用主題數據傳遞的Theme等等。而原生開發中的控件通常只是指UI元素。

Widget的功能是“描述一個UI元素的配置數據,它就是說,Widget其實并不是表示最終繪制在設備屏幕上的顯示元素,而只是顯示元素的一個配置數據。實際上,Flutter中真正代表屏幕上顯示元素的類是Element,也就是說Widget只是描述Element的一個配置。并且一個Widget可以對應多個Element,這是因為同一個Widget對象可以被添加到UI樹的不同部分,而真正渲染時,UI樹的每一個Widget節點都會對應一個Element對象。

四.常用Widget介紹

1.布局類

線性布局Row和Column

Row相當于Android中LinearLayout設置為android:orientation="horizontal"
Column相當于Android中LinearLayout設置為android:orientation="vertical"

Row(
    //對于Row來說:主軸為水平方向,縱軸的垂直方向
    mainAxisAlignment: MainAxisAlignment.center,//主軸的對其方式
    crossAxisAlignment: CrossAxisAlignment.center,//縱軸的對其方式
    textDirection: TextDirection.ltr,//水平方向上的布局順序:從left to right
    verticalDirection: VerticalDirection.down,//垂直方向上的對齊方式 :從上到下
    children: <Widget>[
        Text("子控件1"),
        Text("子控件2")
    ],
);

彈性布局

彈性布局允許子widget按照一定比例來分配父容器空間,類似Android中的android:layout_weightFlutter中的彈性布局主要通過FlexExpanded來配合實現。

//Row和Column都繼承自Flex,參數基本相同,所以能使用Flex的地方一定可以使用Row或Column。
Flex(
    direction: Axis.horizontal,
    children: <Widget>[
    Expanded(
        flex: 1, //比例 相當于LinearLayout中的android:layout_weight = 1
        child: Container(height: 32.0, color: Colors.blue)),
    Expanded(
        flex: 2,

        child: Container(height: 32.0, color: Colors.green))
    ],
)

Spacer是對Expanded的一個包裝,功能是占用指定比例的空間。

Spacer(
    flex: 1,
),
//Spacer內部實現
new Expanded(
  flex: flex,
  child: const SizedBox(
    height: 0.0,
    width: 0.0,
  ),
);

流式布局

在使用Row或者Colum時,如果子Widget超出屏幕范圍,則會報溢出錯誤:

圖片描述

上圖表示的是右邊溢出部分報錯。這是因為Row默認只有一行,如果超出屏幕不會折行。而流式布局在超出屏幕顯示范圍會自動換行。Flutter中通過WrapFlow來支持流式布局。類似Android中的FlexboxLayout.
Wrap:

Wrap(
    //主軸方向
    direction: Axis.horizontal,
    //主軸方向間距
    spacing: 8.0,
    //縱軸方向間距
    runSpacing: 4.0,
    //沿主軸方向靠左對齊
    alignment: WrapAlignment.start,
    children: <Widget>[
    Chip(
        label: Text("慕涵盛華"),
        avatar: CircleAvatar(
            backgroundColor: Colors.blue, child: Text("A"))),
    Chip(
        label: Text("慕涵盛華"),
        avatar: CircleAvatar(
            backgroundColor: Colors.blue, child: Text("B"))),
    Chip(
        label: Text("慕涵盛華"),
        avatar: CircleAvatar(
            backgroundColor: Colors.blue, child: Text("C"))),
    Chip(
        label: Text("慕涵盛華"),
        avatar: CircleAvatar(
            backgroundColor: Colors.blue, child: Text("D"))),
    Chip(
        label: Text("慕涵盛華"),
        avatar: CircleAvatar(
            backgroundColor: Colors.blue, child: Text("E"))),
    ],
);

圖片描述

Flow
一般很少會使用Flow,因為其過于復雜,需要自己實現子Widget的位置轉換,Flow主要用于一些需要自定義布局策略或性能要求較高的場景。

層疊布局

層疊布局Android中的幀布局:FrameLayout類似。Flutter中使用StackPositioned來實現層疊布局Stack允許子Widget堆疊,而Positioned可以給子Widget定位(根據Stack的四個角)。

////通過ConstrainedBox來確保Stack占滿屏幕
ConstrainedBox(
  constraints: BoxConstraints.expand(),
  child: Stack(
    //決定沒有定位的子Widget如何去適應Stack的大小。
    // StackFit.loose:使用子widget的大小,StackFit.expand:擴伸到Stack的大小。
    fit: StackFit.loose,
    alignment:Alignment.center,//指定未定位widget的對齊方式
    children: <Widget>[
      Container(
        width: 32.0,
        height: 32.0,
        color: Colors.blue,
      ),
      Positioned(
        top: 10, 
        left: 10,
        child: Text("慕涵盛華"))
    ],
  ),
));

2.容器類

容器類Widget布局類Widget都作用于其子Widget,不同的是:

  • 布局類Widget一般都需要接收一個Widget數組(children),而容器類Widget一般只需要接受一個子Widget(child)

  • 布局類Widget是按照一定的排列方式來對其子Widget進行排列,而容器類Widget一般只是包裝其子Widget,對其添加一些修飾或限制。

Padding

Padding可以給其子Widget添加內間距,類似Android布局屬性中的android:layout_paddingXXX

Padding(
    //only:指定方向上的間距
    padding: EdgeInsets.only(left: 10,top: 10),
    //padding: EdgeInsets.all(10), 四個方向的間距
    //padding: EdgeInsets.fromLTRB(10, 10, 5, 8), 一次為 l t r b
    //padding: EdgeInsets.symmetric(horizontal: 8), 左右的距離
    child: Text("慕涵盛華"),
)

布局限制類容器:ConstrainedBox和SizedBox

ConstrainedBox:對子widget添加額外的約束

ConstrainedBox(
    //constraints:約束
    constraints: BoxConstraints(
        minWidth: double.infinity, //寬度盡可能大
        maxHeight: 50.0 //最大高度為50像素
        ),
    child: Container(
      color: Colors.blue,
    )
);

SizedBox:用于給子Widget指定固定的寬高

SizedBox(
    width: 50,
    height: 50,
    //child屬性可以不設置,可以用來設置間距
    child: Container(
      color: Colors.blue,
    ),
);

裝飾容器:DecoratedBox

可以在其子Widget繪制前后繪制一個裝飾如背景、邊框、漸變等。

DecoratedBox(
    //decoration:裝飾
    decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(4.0), //圓角
        gradient: LinearGradient(//背景漸變
            colors: [Colors.red, Colors.orange[700]]), 
        boxShadow: [ //陰影
          BoxShadow(
              color: Colors.black54,
              offset: Offset(2.0, 2.0),
              blurRadius: 4.0)
        ]),
    child: Padding(
        padding: EdgeInsets.symmetric(vertical: 18, horizontal: 80),
        child: Text("Login",style: TextStyle(color: Colors.white))
);

圖片描述

變換:Transform

Transform可以在其子Widget繪制時對其應用一個矩陣變換,實現平移、縮放、旋轉等效果。

Container(
    color: Colors.black,
    child: new Transform(
    alignment: Alignment.topRight, //相對于坐標系原點的對齊方式
     // Transform.translate(offset: Offset(-20.0, -5.0) : 平移 
     //Transform.rotate 旋轉
    transform: new Matrix4.skewY(0.3), //矩陣變換:沿Y軸傾斜0.3弧度
    child: new Container(
      padding: const EdgeInsets.all(8.0),
      color: Colors.deepOrange,
      child: const Text('慕涵盛華'),
    ),
    ),
);

Container

Container通過組合多種Widget來實現復雜強大的功能。

Container({
  this.alignment,
  this.padding, //容器內補白,屬于decoration的裝飾范圍
  Color color, // 背景色
  Decoration decoration, // 背景裝飾
  Decoration foregroundDecoration, //前景裝飾
  double width,//容器的寬度
  double height, //容器的高度
  BoxConstraints constraints, //容器大小的限制條件
  this.margin,//容器外補白,不屬于decoration的裝飾范圍
  this.transform, //變換
  this.child,
})

3.Material Design風格Widget

在大多數應用首頁中頂部包含一個標題欄,底部包含一個底部導航等。Flutter Material庫提供了一個Scaffold Widget,它是一個路由頁的骨架,可以非常容易的拼裝出一個完整的頁面。類似下面這種頁面:

圖片描述

Scaffold:

Scaffold({
    Key key,
    this.appBar, : AppBar 類似Android中的ActionBar
    this.body,
    this.floatingActionButton,
    this.floatingActionButtonLocation,
    this.floatingActionButtonAnimator,
    this.persistentFooterButtons,
    this.drawer,  ://Drawer:抽屜菜單
    this.endDrawer,
    this.bottomNavigationBar, :頁面底部導航欄
    this.bottomSheet,
    this.backgroundColor,
    this.resizeToAvoidBottomPadding,
    this.resizeToAvoidBottomInset,
    this.primary = true,
    this.drawerDragStartBehavior = DragStartBehavior.start,
    this.extendBody = false,
  })

使用示例:

//TabBar必須有一個TabController
DefaultTabController(
  length: 4,//tab數量
  child: Scaffold(
    backgroundColor: Colors.white,
    appBar: AppBar(
      title: Text("圖片列表"),
      elevation: 0.0,
      //左側圖標
      leading: IconButton(
          icon: Icon(Icons.menu), onPressed: () => debugPrint("按鈕點擊")),
      //右側圖標(可以指定多個)
      actions: <Widget>[
        IconButton(
            icon: Icon(Icons.search),
            tooltip: "搜索按鈕",
            onPressed: () => debugPrint("搜索按鈕被點擊")),
        IconButton(
            icon: Icon(Icons.more_horiz),
            tooltip: "搜索按鈕",
            onPressed: () => debugPrint("更多按鈕被點擊")),
      ],
      //頂部導航Tab 具體顯示的內容與TabBarView對應
      bottom: TabBar(
          indicatorColor: Colors.white,
          indicatorSize: TabBarIndicatorSize.tab,
          indicatorWeight: 2.0,
          tabs: <Widget>[
            Tab(icon: Icon(Icons.local_florist)),
            Tab(icon: Icon(Icons.change_history)),
            Tab(icon: Icon(Icons.directions_bike)),
            Tab(icon: Icon(Icons.call_missed))
          ]),
    ),
    body: TabBarView(children: <Widget>[
      NavigationDemo(),
      SliverDemo(),
      GridViewDemo(),
      PageViewDemo2()
    ]),
    drawer: DrawerDemo(),
    bottomNavigationBar: BottomNavigationBarDemo(),
  ),
)

4.可滑動Widget

SingleChildScrollView

類似于Android中的ScrollView

SingleChildScrollView({
  this.scrollDirection = Axis.vertical, //滾動方向,默認是垂直方向
  this.reverse = false,  //是否反向滑動
  this.padding, 
  bool primary,  //是夠使用默認的ScrollController
  this.physics, 
  this.controller, //ScrollController
  this.child,
})

ListView和GirdView

類似Android中的列表控件。

CustomScrollView,Sliver

類似Android中的CoordinatorLayout + AppBarLayout + CollapsingToolbarLayout

五.實戰

效果圖:

圖片描述

圖片描述

圖片描述

代碼:
https://github.com/guofudong/flutter_eyepetizer


我來說兩句
您需要登錄后才可以評論 登錄 | 立即注冊
facelist
所有評論(0)

領先的中文移動開發者社區
18620764416
7*24全天服務
意見反饋:[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )

黑龙江彩票网