Flutter從零到∞學習筆記

  • 有狀態widget:StatefulWidget和無狀態widget:StatelessWidget 前者不須要實現Widget build(BuildContext context)。css

    具體的選擇取決於widget是否須要管理一些狀態python

  • 在Dart語言中使用下劃線前綴標識符,會強制其變成私有的。git

  • Icons.favorite Icons類裏面有不少默認圖標github

  • isOdd 是否奇數 2.isOdd -> false 1.isOdd -> trueweb

  • pushSaved 「」開頭的自動轉成私有(方法和變量)json

  • 導航欄添加按鈕和事件api

     @override

    Widget build(BuildContext context) {

      return new Scaffold(

        appBar: new AppBar(

          title: new Text('Startup Name Generator'),

          actions: <Widget>[

            // AppBar 添加一個按鈕 樣式爲list 事件是_pushSaved

            new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved)

          ],

        ),

        body: _buildSuggestions(),

      );

    }

    // tooltip 長時間按下的提示文字

    IconButton(icon: new Icon(Icons.search), tooltip: 'Search', onPressed: null) 

  

 

  1. 界面跳轉方法
    Navigator.of(context).push(

      new MaterialPageRoute(

          builder: (context) {

          },

      ),

    );

  

 

  1. 一行函數寫法
    // 多行

    void main() {

      runApp(

          new Center(

            child: new Text(

              'Hello, world!',

              textDirection: TextDirection.ltr,

            ),

          )

      )

    }

    // 一行

    void main() => runApp(new MyApp());

  

  1. // Material 是UI呈現的「一張紙」websocket

  2. 請確保在pubspec.yaml文件中,將flutter的值設置爲:uses-material-design: true。這容許咱們可使用一組預約義Material icons。網絡

  3. Row(橫向排列)和Column(縱向排列)app

    child: new Row(

      children: <Widget>[

        new ...,

        new ...,

        new ...,

      ],

    )

  

    child: new Column(

      children: <Widget>[

        new ...,

        new ...,

        new ...,

      ],

    ),

  

  1. cached_network_image 圖片佔位和淡入淡出

  2. push

    Navigator.push(

      context,

      new MaterialPageRoute(builder: (context) => new 新界面),

    );

    // 若是須要傳值:

    新界面({Key key, @required this.接收字段的名字}) : super(key: key);

    pop

    Navigator.pop(context);

  

  1. dio網絡請求 https://github.com/flutterchina/dio

  2. import 'dart:convert'; // package將響應內容轉化爲一個json Map

  3. // 使用fromJson工廠函數,將json Map 轉化爲一個Post對象

new Post.fromJson(json);

  

  1. future參數是一個異步的網絡請求

  2. import 'dart:io'; // 添加請求的headers

  3. // 長鏈接

import 'package:web_socket_channel/io.dart';

import 'package:multi_server_socket/multi_server_socket.dart';

  

  1. // 網絡請求
Future<Post> fetchPost() async {

  final response = await http.get('[http://jsonplaceholder.typicode.com/posts/1](http://jsonplaceholder.typicode.com/posts/1)');

  final responseJson = json.decode(response.body);

  return new Post.fromJson(responseJson);

}

// 請求添加headers

/*

Future<Post> fetchPost() async {

  final response = await http.get(

    '[https://jsonplaceholder.typicode.com/posts/1](https://jsonplaceholder.typicode.com/posts/1)',

    headers: {HttpHeaders.AUTHORIZATION: "Basic your_api_token_here"},

  );

  final json = jsonDecode(response.body);

  return new Post.fromJson(json);

}

*/

new FutureBuilder<Post>(

  future: fetchPost(),

  builder: (context, snapshot) {

    return new CircularProgressIndicator();

  }

)

  

 

  1. 長鏈接
// 鏈接長鏈接

IOWebSocketChannel.connect('[ws://echo](ws://echo/).[websocket.org](http://websocket.org/)’)

// 接收消息

new StreamBuilder(

    stream: widget.channel.stream,

    builder: (context, snapshot) {

      return new Padding(

        child: new Text(snapshot.hasData ? '${snapshot.data}' : ''),

          padding: const EdgeInsets.symmetric(vertical: 20.0)

      );

    }

)

// 發送消息

widget.channel.sink.add(_textController.text);

// 關閉長鏈接

widget.channel.sink.close();

  

 

  1. 在Flutter中添加資源和圖片

https://flutterchina.club/assets-and-images/

  1. 標準widget:
Container

添加 padding, margins, borders, background color, 或將其餘裝飾添加到widget.

GridView

將 widgets 排列爲可滾動的網格.

ListView

將widget排列爲可滾動列表

Stack

將widget重疊在另外一個widget之上.

Material Components:

Card

將相關內容放到帶圓角和投影的盒子中。

ListTile

將最多3行文字,以及可選的行前和和行尾的圖標排成一行

  

  1. pubspec.yaml中添加字體 注意縮進對齊 注意縮進對齊 注意縮進對齊
-asset 路徑是與pubspec.yaml平級的文件路徑

flutter:

  # Include the Material Design fonts.

  uses-material-design: true

  fonts:

    - family: Rock Salt

      fonts:

        # [https://fonts.google.com/specimen/Rock+Salt](https://fonts.google.com/specimen/Rock+Salt)

      - asset: fonts/Arial-Unicode.ttf

    - family: VT323

      fonts:

        # [https://fonts.google.com/specimen/VT323](https://fonts.google.com/specimen/VT323)

        - asset: fonts/Arial-Unicode.ttf

    - family: Ewert

      fonts:

        # [https://fonts.google.com/specimen/Ewert](https://fonts.google.com/specimen/Ewert)

        - asset: fonts/Ewert-Regular.ttf

  

  1. 好比一個關閉按鈕在
new Row(mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[

  new FlatButton(onPressed: () {

  }, child: Icon(Icons.close))

],);

  

  1. 分割線



new Divider(color: Colors.lightBlue,)
  1. 自定義Icon



new Image.asset(「圖片路徑", width: 20.0, height: 20.0,)
  1. 按鈕寬高
00一、

new Padding(padding: new EdgeInsets.fromLTRB(48.0, 20.0, 48.0, 20.0),

  child: new Row(

    children: <Widget>[

      new Expanded(child:

        new RaisedButton(onPressed: (){

        },

          //設置控件的高度

          child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),

            child: new Text("登陸",

              style: TextStyle(color: Colors.white)

            ),

          ),

          color: Colors.brown,

        ),

      ),

    ],

  ),

),

00二、

new Container(

  width: MediaQuery.of(context).size.width - 48 * 2 ,

  padding: new EdgeInsets.only(top: 40.0),

  child: new RaisedButton(onPressed: (){

  },

    //設置控件的高度

    child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 10.0),

      child: new Text("登陸",

          style: TextStyle(color: Colors.white)

      ),

    ),

    color: Colors.brown,

  ),

),

00三、

Widget _bigButton(String text, double lSpace, double rSpace) {

  return new Container(

    width: MediaQuery.of(context).size.width - lSpace - rSpace,

    height: 48.0,

    margin: new EdgeInsets.only(left: lSpace, right: rSpace),

    color: Colors.white54,

    padding: new EdgeInsets.only(top: 0.0),

    child: new RaisedButton(onPressed: (){

      print(text);

    },

      child: new Padding(padding: new EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 0.0),

        child: new Text(text,

            style: TextStyle(color: Colors.white)

        ),

      ),

      color: Colors.brown,

    ),

  );

}

  

 

  1. 設備尺寸
MediaQuery.of(context).size.width

  

  1. 設備像素密度
MediaQuery.of(context).devicePixelRatio

  

  1. 狀態欄高度
MediaQuery.of(context).padding.top

  

  1. 擔憂鍵盤擋住控件,可使用 SingleChildScrollView,將SingleChildScrollView當作容器。

  2. 一個超級簡單界面

import 'package:flutter/material.dart';

class RegisterPage extends StatelessWidget {

  @override

  Widget build(BuildContext context) {

    return new Scaffold(

      backgroundColor: Colors.black,

      body: new RegisterWidget(),

    );

  }

}

class RegisterWidget extends StatefulWidget {

  RegisterWidgetState createState() => RegisterWidgetState();

}

class RegisterWidgetState extends State<RegisterWidget> {

  @override

  Widget build(BuildContext context) {

    return new Text("RegisterPage", style: TextStyle(color: Colors.white),);

  }

}

  

  1. Flutter 按鈕總結
· InkWell   // 純文字按鈕

· OutLineButton   // 邊框按鈕

· IconButton  // icon按鈕

· 

  

  1. import 'package:flutter/services.dart';
TextField

inputFormatters: <TextInputFormatter> [

  WhitelistingTextInputFormatter.digitsOnly,

],

  

 37 . 驗證碼按鈕

new Positioned(

    child: new Container(

      width: 80.0,

      height: 27.0,

      alignment: Alignment.center,

      decoration: new BoxDecoration(

        border: new Border.all(

          color: Colors.white,

          width: 1.0,

        ),

        borderRadius: new BorderRadius.circular(4.0),

      ),

      child: InkWell(

        child: _mText(_verifyStr, 12.0),

        onTap: () {

        },

      ),

    )

),

  

  1. 倒計時方法
@override

void dispose() {

  super.dispose();

  _cancelTimer();

}

_startTimer() {

  if (_verifyStr == '從新發送' || _verifyStr == '獲取驗證碼') {

    _seconds = 5;

    _timer = new Timer.periodic(new Duration(seconds: 1), (timer) {

      if (_seconds == 0) {

        _cancelTimer();

        return;

      }

      _seconds--;

      _verifyStr = '$_seconds(s)';

      setState(() {});

      if (_seconds == 0) {

        _verifyStr = '從新發送';

      }

    });

  }

}

_cancelTimer() {

  _timer?.cancel();

}

  

 

  1. 富文本拼接: 協議
Widget _protocolWidget() {

  return new Container(

    child: new Row(

      children: <Widget>[

        new GestureDetector(

          onTap: () {

            print("選擇");

          },

          child: Icon(Icons.add_alert, color: Colors.white),

        ),

        new Text.rich(

            new TextSpan(

                text: '我已閱讀並贊成',

                style: new TextStyle(

                  fontSize: 12.0,

                  color: Colors.grey[500],

                  fontWeight: FontWeight.w400,

                ),

                children: [

                  new TextSpan(

                    recognizer: new TapGestureRecognizer()

                      ..onTap = () {

                        print("《燎原用戶服務協議》");

                      },

                    text: "《燎原用戶服務協議》",

                    style: new TextStyle(

                      fontSize: 14.0,

                      color: Color(0XFFB57A36),

                      fontWeight: FontWeight.w400,

                    ),

                  )

                ]

            )

        ),

      ],

    )

  );

}

  

  1. 陰影、圓角
new Card(

  elevation: 4.0,

  shape: new RoundedRectangleBorder(

    borderRadius: BorderRadius.only(

      topLeft: Radius.circular(16.0),

      topRight: Radius.circular(16.0),

      bottomLeft: Radius.circular(12.0),

      bottomRight: Radius.circular(2.0),

    )

  ),

  child: new IconButton(icon: Icon(Icons.add), onPressed: () {

  }),

)

  

  1. YYTabbarWidget
import 'package:flutter/material.dart';

// with AutomaticKeepAliveClientMixin

class YYTabbarWidget extends StatefulWidget {

  List<Widget> tabItems = [];

  Widget title;

  List<Widget> tabViews = [];

  PageController pageController;

  final ValueChanged<int> onPageChanged;

  final Widget drawer;

  YYTabbarWidget({Key key,

    this.drawer,

    this.tabItems,

    this.title,

    this.tabViews,

    this.pageController,

    this.onPageChanged,

  }) : super(key: key);

  _YYTabbarWidgetState createState() => _YYTabbarWidgetState(drawer, title, tabItems, tabViews, pageController, onPageChanged);

}

class _YYTabbarWidgetState extends State<YYTabbarWidget> with SingleTickerProviderStateMixin {

  final Widget _title;

  final List<Widget> _tabViews;

  final List<Widget> _tabItems;

  final ValueChanged<int> _onPageChanged;

  final Widget _drawer;

  _YYTabbarWidgetState(

      this._drawer,

      this._title,

      this._tabItems,

      this._tabViews,

      this._pageController,

      this._onPageChanged,

      ) : super();

  TabController _tabController;

  PageController _pageController;

  @override

  void initState() {

    super.initState();

    _tabController = new TabController(length: _tabItems.length, vsync: this);

  }

  @override

  void dispose() {

    _tabController.dispose();

    super.dispose();

  }

  _renderTab() {

    print(_tabItems);

    List<Widget> list = new List();

    for (int i = 0; i < _tabItems.length; i++) {

      list.add(new FlatButton(onPressed: () {

        print(i);

        _pageController.jumpTo(MediaQuery

            .of(context)

            .size

            .width * i);

      }, child: _tabItems[I],

      )

      );

    }

    return list;

  }

  @override

  Widget build(BuildContext context) {

    return new Scaffold(

      drawer: _drawer,

      appBar: new AppBar(

        title: _title,

      ),

      body: new PageView(

        controller: _pageController,

        children: _tabViews,

        onPageChanged: (index) {

          _tabController.animateTo(index);

          _onPageChanged?.call(index);

        },

    ),

      bottomNavigationBar: new Material(

        color: Colors.white,

        child: new TabBar(

          indicatorPadding: new EdgeInsets.only(top: 0.0),

          controller: _tabController,

          tabs: _renderTab(),

          indicatorColor: Colors.red,

        ),

      ),

    );

  }

}

  

 

  1. ListView 添加刷新,當數量少的時候不能滾動
physics: new AlwaysScrollableScrollPhysics(), // 讓ListView一直能夠滾動

  

  1. tabView切換 子界面都會調用initState
解決:AutomaticKeepAliveClientMixin

class HomePageState extends State<HomePage> with AutomaticKeepAliveClientMixin {

    @override

    bool get wantKeepAlive => true;

}

  

 

  1. 路有跳轉
///不帶參數的路由表跳轉

Navigator.pushNamed(context,routeName);

///跳轉新頁面而且替換,好比登陸頁跳轉主頁

Navigator.pushReplacementNamed(context,routeName);

///跳轉到新的路由,而且關閉給定路由的以前的全部頁面

Navigator.pushNamedAndRemoveUntil(context,'/calendar',ModalRoute.withName('/'));

///帶參數的路由跳轉,而且監聽返回

Navigator.push(context,newMaterialPageRoute(builder:(context)=>newNotifyPage())).then((res){

      ///獲取返回處理

    });

  

 

  1. flutter lib
cupertino_icons: ^0.1.2  #icon

flutter_spinkit: "^2.1.0"  # load more loading  import 'package:flutter_spinkit/flutter_spinkit.dart';

dio: x.x.x  #無網絡請求  import 'package:dio/dio.dart';

  

 

  1. dio網絡請求示例
_dioRequest() async {

  Dio dio = new Dio();

  Response response;

  try {

    String url;

    var params; // 請求參數

    Options options; // 配置:超時,請求頭,請求類型等

    response = await dio.request(url, data: params, options: options);

  } on DioError catch(e) {

    // 請求出錯時,返回一個DioError對象

  }

}

  

 

  1. build_runner的使用
一、在根目錄運行

二、一次性建立.g.dart文件 使用build 此時目錄內不能有.g.dart文件

三、watch是監聽 有model類的文件建立 自動建立.g.dart文件

flutter packages pub run build_runner build

flutter packages pub run build_runner watch
相關文章
相關標籤/搜索