入坑Flutter ,棄坑React-Native(簡單體驗) 頂 原 薦

前言

由於業務需要之前用react-native重寫了公司項目,中間碰到各種坑,莫名其妙紅屏,適配坑,頁面刷新坑,打包坑,熱更新坑.折磨了兩個月終於完成.年初就聽說了Flutter,看一下是用Google的Dart語言,據說是有望代替JavaScript這個一週完成的奇葩.咳咳,看了下國內鹹魚團隊已經在項目中使用了Flutter技術,這是他們的社區社區博文深入理解flutter的編譯原理與優化,想不到竟然如此強大.忍不住就參考官方文檔寫了個demo

Flutter官網

https://flutter.io/get-started/install/

克隆Flutter倉庫

git clone -b beta https://github.com/flutter/flutter.git

配置環境變量

export PUB_HOSTED_URL=https://pub.flutter-io.cn //國內用戶需要設置
export FLUTTER_STORAGE_BASE_URL=https://storage.flutter-io.cn //國內用戶需要設置
export PATH= flutter所在目錄/flutter/bin:$PATH

可直接將環境變量寫入~/.bash_profile文件中執行source $HOME/.bash_profile生效(如果未生效請重啓終端或電腦)

配置命令行工具sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer

安裝鏈接設備工具

brew update
brew install --HEAD libimobiledevice
brew install ideviceinstaller ios-deploy cocoapods
pod setup

VScode 配置

搜索dart code安裝dart 插件

image

快捷鍵 shift + command + p 輸入 ‘doctor’, 然後選擇 ‘Flutter: Run Flutter Doctor’ 驗證操作 image

同樣 shift + command + p 輸入 ‘flutter’, 然後選擇 ‘Flutter: New Project’ action 創建一個測試項目 vscode 底部展示附加設備 image

點擊Debug>Start Debugging即可運行項目

image

image

創建

按照之前的方法創建一個模板 shift + command + p 輸入 ‘flutter’, 然後選擇 ‘Flutter: New Project’ action

替換 lib/main.dart. 刪除lib / main.dart中的所有代碼,然後替換爲下面的代碼,它將在屏幕的中心顯示“Hello World”

//應用入口 
//main函數使用了(=>)符號, 這是Dart中單行函數或方法的簡寫
void main() => runApp(new DemoApp());

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          child: new Text('Royce and Owen'),
        ),
      ),
      
    );
  }
}

外部包使用

  • 您可以 在pub.dartlang.org上找到english_words軟件包以及其他許多開源軟件包 image
  • 將english_words添加到pubspec.yaml文件中(pubspec文件
  • 管理Flutter應用程序的assets(資源,如圖片、package等)) image
  • 在終端中運行flutter packages get安裝依賴
flutter packages get
Running "flutter packages get" in startup_first...           0.6s
  • 導入import 'package:english_words/english_words.dart';
  • 使用 English words 包生成文本來替換字符串“Hello World”.
  • 修改代碼
class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final wordPair = new WordPair.random();
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          child: new Text(wordPair.asUpperCase),
        ),
      ),
      
    );
  }
}

添加一個 有狀態的部件(Stateful widget)

Stateless widgets 是不可變的, 這意味着它們的屬性不能改變 - 所有的值都是最終的.

Stateful widgets 持有的狀態可能在widget生命週期中發生變化. 實現一個 stateful widget 至少需要兩個類:

  1. 一個 StatefulWidget類。
  2. 一個 State類。 StatefulWidget類本身是不變的,但是 State類在widget生命週期中始終存在.
  • 新建一個組件類RandomWords
  • 新建一個State組件類RandomWordsState
class RandomWordsState extends State<RandomWords> {
  @override
  Widget build(BuildContext context) {
    final wordPair = new WordPair.random();
    return new Text(wordPair.asPascalCase);
  }
}
class RandomWords extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
      // TODO: implement createState
      return new RandomWordsState();
    }
}
  • 修改代碼 final wordPair = new WordPair.random(); // 刪除此行

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
   
    return new MaterialApp(
      title: 'Welcome to Flutter',
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text('Welcome to Flutter'),
        ),
        body: new Center(
          child: new RandomWords(),
        ),
      ),
      
    );
  }
}

創建一個無限滾動ListView

擴展(繼承)RandomWordsState類,以生成並顯示單詞對列表。 當用戶滾動時,ListView中顯示的列表將無限增長

  1. 在RandomWordsState添加一個變量_suggestions(下劃線前綴標識符,會強制其變成私有的)
  2. 添加一個_biggerFont變量來孔子字體大小
  3. 新建_buildSuggestions()方法 顯示建議的單詞對
  4. 在RandomWordsState中添加一個_buildRow函數
  5. 更新RandomWordsState的build方法以使用_buildSuggestions()
  6. 更新MyApp的build方法
class RandomWords extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new RandomWordsState();
  }
}
class RandomWordsState extends State<RandomWords> {
  final _suggestions = <WordPair>[];
  final _biggerFont =
      const TextStyle(fontSize: 18.0, color: Color.fromARGB(1, 234, 111, 22));

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
          title: new Text('StartUp'),
        ),
        body: _buildSuggestions());
  }

  Widget _buildSuggestions() {
    return new ListView.builder(
        padding: const EdgeInsets.all(16.0),
        // 對於每個建議的單詞對都會調用一次itemBuilder,然後將單詞對添加到ListTile行中
        // 在偶數行,該函數會爲單詞對添加一個ListTile row.
        // 在奇數行,該行書湖添加一個分割線widget,來分隔相鄰的詞對。
        // 注意,在小屏幕上,分割線看起來可能比較吃力。
        itemBuilder: (context, i) {
          // 在每一列之前,添加一個1像素高的分隔線widget
          if (i.isOdd) return new Divider();
          // 語法 "i ~/ 2" 表示i除以2,但返回值是整形(向下取整),比如i爲:1, 2, 3, 4, 5
          // 時,結果爲0, 1, 1, 2, 2, 這可以計算出ListView中減去分隔線後的實際單詞對數量
          final index = i ~/ 2;
          if (index >= _suggestions.length) {
            _suggestions.addAll(generateWordPairs().take(10));
          }
          return _buildRow(_suggestions[index]);
        });
  }

  Widget _buildRow(WordPair pair) {
    return new ListTile(
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
    );
  }
}

添加交互

  1. 添加一個 _saved Set(集合) 到RandomWordsState。這個集合存儲用戶喜歡(收藏)的單詞對
  2. 在 _buildRow 方法中添加 alreadySaved來檢查確保單詞對還沒有添加到收藏夾中。
  3. 同時在 _buildRow()中, 添加一個心形 ❤️ 圖標到 ListTiles以啓用收藏功能
  4. 在 _buildRow中讓心形❤️圖標變得可以點擊。如果單詞條目已經添加到收藏夾中, 再次點擊它將其從收藏夾中刪除。當心形❤️圖標被點擊時,函數調用setState()通知框架狀態已經改變。
Widget _buildRow(WordPair pair) {
    //判斷是否收藏
    final bool alreadySaved = _saved.contains(pair);
    return new ListTile(
      title: new Text(
        pair.asPascalCase,
        style: _biggerFont,
      ),
      subtitle: new Text('哈哈哈'),
      trailing: new Icon(
        alreadySaved ? Icons.favorite : Icons.favorite_border,
        color: alreadySaved ? Colors.red : null,
      ),
      onTap: () {
        setState(() {
          if (alreadySaved) {
            _saved.remove(pair);
          } else {
            _saved.add(pair);
          }
        });
      },
    );
  }

導航到新頁面

在Flutter中,導航器管理應用程序的路由棧。將路由推入(push)到導航器的棧中,將會顯示更新爲該路由頁面。 從導航器的棧中彈出(pop)路由,將顯示返回到前一個路由。這點類似iOS的導航機制

  1. 給AppBar的actions屬性添加一個按鈕子組件,由於是複數用 <Widget>[]包裝
  2. 當用戶點擊導航欄中的列表圖標時,建立一個路由並將其推入到導航管理器棧中。此操作會切換頁面以顯示新路由在MaterialPageRoute的builder屬性中構建,builder是一個匿名函數。
 @override
  Widget build(BuildContext context) {
    return new Scaffold(
        appBar: new AppBar(
        actions: <Widget>[
          new IconButton(icon: new Icon(Icons.list), onPressed: _pushSaved)
        ],
          title: new Text('嘿嘿嘿',
              style: const TextStyle(
                  fontSize: 18.0, color: Color.fromRGBO(150, 22, 123, 1.0))),
        ),
        body: _buildSuggestions());
  }
  void _pushSaved() {
    Navigator.of(context).push(new MaterialPageRoute(builder: (context) {
      //便利以保存的單詞 創建tile 或者叫(cell,item)
      final tiles = _saved.map((pair) {
        return new ListTile(
          title: new Text(
            pair.asPascalCase,
            style: _biggerFont,
          ),
        );
      });
      final divided =
          ListTile.divideTiles(context: context, tiles: tiles).toList();
          //返回一個新頁面
      return new Scaffold(
        appBar: new AppBar(
          title: new Text('saved Suggestions'),
        ),
        body: new ListView(children: divided),
      );
    }));
  }

效果

image

image

使用主題更改UI

創建ThemeData來定義theme

class DemoApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Startup Name Generator',
      //主題
      theme: new ThemeData(
        primaryColor: Colors.orange,
      ),
      home: new RandomWords(),
    );
  }
}

ThemeData提供相當多的屬性,自定義程度相當高了,不愧是基於OpenGL構建的UI,比起RN自由度高了很多
Material library中的 Colors類也提供了許多可以使用的顏色常量例如Colors.green,Color.fromRGBO(255, 111, 233, 1.0)

部分屬性介紹
accentColor → Color 控件的前景色(旋鈕、文本、覆蓋邊緣效果等)。
accentColorBrightness → Brightness 
dividerColor → Color 分隔符和彈窗分隔符的顏色,也用於ListTiles和DataTables的行之間
primaryColor → Color 應用程序主要部分的背景顏色(工具欄,標籤欄等)

以上第一flutterdemo完成.
Dart語法非常類似JS,相比較RN但少了</>更加易懂,擁類似state狀態機,熱加載速度很快,C++底層,基於OpenGL,強大的API和文檔支持.

代碼地址https://gitee.com/Royce_he/flutter_demo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章