flutter初體驗之編寫的第一個flutter app
阿新 • • 發佈:2022-03-23
隨著flutter環境的搭建成功,我趁熱打鐵照著教程做起了第一個app的demo
這個教程分兩步,
第一步
我還是跟他(https://flutter.cn/docs/get-started/codelab)一步步下來,感覺挺有收穫的,編碼習慣,編碼語法之類的;專案也正常執行起來,沒有問題:
第二步
- 像列表新增圖示
- 新增互動
- 導航到新頁面
- 使用themes修改UI
Widget _buildRow(WordPair pair) { final bool alreadySaved = _saved.contains(pair); return new ListTile( title:在使用每個元件UI的時候 都要 new 一下,常規程式碼邏輯中是直接使用的如下new Text( pair.asPascalCase, style: _biggerFont, ), trailing: new Icon( // 新增程式碼開始 ... alreadySaved ? Icons.favorite : Icons.favorite_border, color: alreadySaved ? Colors.red : null, ), // ... 新增程式碼結束 );}
body: ListView.builder( padding: const EdgeInsets.all(導致跟著教程編寫的時候一直報錯,於是我去掉了 new 的關鍵字之後,重啟了服務,列表中新增圖示的功能實現了,如下圖 但是這裡沒有互動 完整程式碼16.0), itemBuilder: /*1*/ (context,i){ if(i.isOdd) return const Divider(); /*2*/ final index = i ~/2; /*3*/ if(index >= _suggestions.length){ _suggestions.addAll(generateWordPairs().take(10));/*4*/ } return ListTile( title: Text( _suggestions[index].asPascalCase, style: _biggerFont, ) ); } ),// /*1*/ 對於每個建議的單詞對都會呼叫一次 itemBuilder,然後將單詞對新增到 ListTile 行中。在偶數行,該函式會為單詞對新增一個 ListTile row,在奇數行,該函式會新增一個分割線的 widget,來分隔相鄰的詞對。注意,在小螢幕上,分割線看起來可能比較吃力。 // /*2*/ 在 ListView 裡的每一行之前,新增一個 1 畫素高的分隔線 widget。 // /*3*/ 語法 i ~/ 2 表示 i 除以 2,但返回值是整型(向下取整),比如 i 為:1, 2, 3, 4, 5 時,結果為 0, 1, 1, 2, 2,這個可以計算出 ListView 中減去分隔線後的實際單詞對數量。 // /*4*/ 如果是建議列表中最後一個單詞對,接著再生成 10 個單詞對,然後新增到建議列表。 // 對於每一個單詞對,_buildSuggestions() 都會呼叫一次 _buildRow()。這個函式在 ListTile 中顯示每個新詞對,這使你在下一步中可以生成更漂亮的顯示行,詳見本 codelab 的第二部分。
import 'package:english_words/english_words.dart'; import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class RandomWords extends StatefulWidget{ const RandomWords({Key? key}): super(key:key); @override _RandomWordsState createState()=> _RandomWordsState(); } class _RandomWordsState extends State<RandomWords>{ final List<WordPair> _suggestions = <WordPair>[]; final Set<WordPair> _saved = new Set<WordPair>(); final TextStyle _biggerFont = const TextStyle(fontSize: 18.0); // 3 導航到新頁面 void _pushSaved(){ Navigator.of(context).push( MaterialPageRoute<void>( builder: (BuildContext context){ final Iterable<ListTile> titls = _saved.map( (WordPair pair){ return ListTile( title: Text( pair.asPascalCase, style: _biggerFont, ) ); } ); final List<Widget> divided = ListTile.divideTiles( context: context, tiles: titls, ).toList(); return Scaffold( appBar: AppBar( title: const Text('saved name is huYe'), ), body: ListView(children: divided), ); } ) ); } @override Widget build(BuildContext context){ return Scaffold( appBar: AppBar( title: const Text('Startup Name Cenerator'), actions: <Widget>[ IconButton(onPressed: _pushSaved, icon: const Icon(Icons.list)) ], ), body: _buildSuggestions() ); } Widget _buildSuggestions() { return ListView.builder( padding: const EdgeInsets.all(16.0), itemBuilder: (BuildContext _context, int i) { if (i.isOdd) { return const Divider(); } final int index = i ~/ 2; if (index >= _suggestions.length) { _suggestions.addAll(generateWordPairs().take(10)); } return _buildRow(_suggestions[index]); }); } // 2.1 新增圖示 Widget _buildRow(WordPair wp){ final bool alreadySaved = _saved.contains(wp); return ListTile( title: Text( wp.asPascalCase, style: _biggerFont, ), trailing: Icon( alreadySaved? Icons.favorite : Icons.favorite_border, color: alreadySaved? Colors.red : null, ), // 2.2 新增互動 onTap: (){ setState(() {//在 Flutter 的響應式風格的框架中,呼叫 setState() 會為 State 物件觸發 build() 方法,從而導致對 UI 的更新 if(alreadySaved){ _saved.remove(wp); }else{ _saved.add(wp); } }); }, ); } } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); // This widget is the root of your application. @override Widget build(BuildContext context) { // 這裡自己用了const 程式碼報錯,應該用final return MaterialApp( title: 'Startup Name Generators', home: const RandomWords(), theme: ThemeData( primaryColor: Colors.red // 不論如何設定都無效(後續補充這的原因) ), );