前言
上篇關於Flutter的文章總結了下標籤+導航的專案模式的搭建,具體的有需要的可以去看看Flutter分類的文章,這篇文章我們簡單的總結一下關於Flutter本地檔案引用以及簡單的自定義List的使用,我們先總結本地圖片的引用。今天這篇文章的具體的UI效果如下:
引用本地圖片
我們沒有使用到的我們暫時先不提,等後面慢慢補充進去,比如說網路圖片的顯示等等,我們現總結一下關於本地圖片的使用,具體的我們需要下面幾步:
1、建立檔案匯入資源
Flutter的檔案資源需要我們建立一個檔案去管理,我們可以定義一個images的檔案,當然這個名字不是固定的但需要留意下它的檔案等級,它裡面還可以裝別的其他資原始檔,你要叫Resource也可以的。然後不管是做Android的還是iOS的都知道我們的圖片資源是分2x和3x的,所以我們在你建立的檔案下面再建立一個2.0x和3.0x的資料夾分別存放相應倍數的圖片資源。如下圖:
2、不是說直接匯入就能直接使用的,還需要處理一下 pubspec.yaml檔案,具體的改動如下面所示:
# The following section is specific to Flutter. flutter: # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in # the material Icons class. uses-material-design: true # To add assets to your application, add an assets section, like this: # assets: # - images/a_dot_burr.jpeg # - images/a_dot_ham.jpeg # An image asset can refer to one or more resolution-specific "variants", see # https://flutter.dev/assets-and-images/#resolution-aware. # For details regarding adding assets from package dependencies, see # https://flutter.dev/assets-and-images/#from-packages # To add custom fonts to your application, add a fonts section here, # in this "flutter" section. Each entry in this list should have a # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: # fonts: # - family: Schyler # fonts: # - asset: fonts/Schyler-Regular.ttf # - asset: fonts/Schyler-Italic.ttf # style: italic # - family: Trajan Pro # fonts: # - asset: fonts/TrajanPro.ttf # - asset: fonts/TrajanPro_Bold.ttf # weight: 700 # # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages #### 圖片資源 assets: - images/icon_header.png - images/icon_heath.png - images/icon_village.png - images/mine_train.png
前面我們說的資料夾名字不是固定的,繫結使用的的就是assets,這裡其實你理解成圖片在專案中的層級位置就可以了。看上面Flutter給的註釋資訊,我們完全可以在匯入別的資訊,如 fonts等等。
3、現在可以直接使用了,它的使用還是相對比較簡單的,我們直接上程式碼,需要注意的點是使用的時候需要的是圖片全程,記得帶上字尾。
Image.asset( "images/icon_header.png", width: 20, height: 20, )
實現上面我的頁面
上面的實現我們需要簡單的瞭解幾個相應的控制元件,我們一個一個的介紹一下先,最後就可以出來我們前面的我的頁面的UI了。
1、InkWell 它是一個效果控制元件 ,點選有潑墨的水波的效果 ,經常和Material+顏色透明一起使用。
2、Row 水平元件,首先一點是不管是我們現在說的Row還是我們後面說的 Column只能在繼承與StatelessWidget或者StatefullWidget的Widget中使用。
Row({ Key key, MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, MainAxisSize mainAxisSize = MainAxisSize.max, CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, TextDirection textDirection, VerticalDirection verticalDirection = VerticalDirection.down, TextBaseline textBaseline = TextBaseline.alphabetic, List<Widget> children = const <Widget>[], }) : super( children: children, key: key, direction: Axis.horizontal, mainAxisAlignment: mainAxisAlignment, mainAxisSize: mainAxisSize, crossAxisAlignment: crossAxisAlignment, textDirection: textDirection, verticalDirection: verticalDirection, textBaseline: textBaseline, );
它就這麼一個構造方法,還是相對比較簡單的,首先它是不能滾動的,但是它可以靈活佈局,如果要讓某個子元件填充滿剩餘剩餘空間,可以在 children 中使用 Expanded 元件,children 這個屬性看上面的原始碼我們知道,它是一個 Widget 陣列,這個我們在後面會使用到。具體的它裡面的 Expanded 元件我們下面總結,現不在這裡細說。
它裡面的屬性還是相對比較簡單的,可以自己瞭解學習一下。我們接著看下面的元件。
3、Column
上面說的是水平的,那這個肯定就是豎直的了,其實它倆挺像的,也都是最基礎的。我們把它初始化方法放出來對比一下,對比一下前面的Row:
Column({ Key key, MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, MainAxisSize mainAxisSize = MainAxisSize.max, CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, TextDirection textDirection, VerticalDirection verticalDirection = VerticalDirection.down, TextBaseline textBaseline, List<Widget> children = const <Widget>[], }) : super( children: children, key: key, direction: Axis.vertical, mainAxisAlignment: mainAxisAlignment, mainAxisSize: mainAxisSize, crossAxisAlignment: crossAxisAlignment, textDirection: textDirection, verticalDirection: verticalDirection, textBaseline: textBaseline, ); }
4、Expanded
這個我們也需要說說的,因為我們的Row和Column都需要Expanded,其實它也是比較簡單的:
class Expanded extends Flexible { /// Creates a widget that expands a child of a [Row], [Column], or [Flex] /// so that the child fills the available space along the flex widget's /// main axis. const Expanded({ Key key, int flex = 1, @required Widget child, }) : super(key: key, flex: flex, fit: FlexFit.tight, child: child); }
我們就需要了解兩個引數一個 flex 和一個 child,child我們就不多說了,比較簡單,flex 按照一個比例理解,比如兩個Expanded , 並排需要控制它們的寬度比例,就可以使用這個屬性。這些我們在下面的程式碼使用中都有體現的。我們程式碼中細說。
我們看具體的程式碼,理解了上面大概說的,這個程式碼就相對比較簡單了,我們先看看頂部的頭部我們是怎樣定義的:
class MineHeader extends StatelessWidget { String userHeaderImage; String userName; /// 這裡定義了就可以在外面使用這個方法進行初始化 MineHeader(this.userHeaderImage, this.userName); @override Widget build(BuildContext context) { return Container( color: Colors.orange, height: 100, /// 水平佈局 /// 在Row中使用Expanded的時候,無法指定Expanded中的子元件的寬度width,但可以指定其高度height。 /// 同理,在Column中使用Expanded的時候, /// 無法指定Expanded中的子元件的高度height,可以指定寬度width。 child: Row( children: <Widget>[ Expanded( flex: 1, child: Container( padding: EdgeInsets.only(left: 15), child: Image.asset( userHeaderImage, width: 50, height: 50, ), ), ), Expanded( flex: 5, child: Container( padding: EdgeInsets.only(left: 15), child: Text( userName, /// 18號 藍色 加粗 style: TextStyle( fontSize: 18, color: Colors.white, fontWeight: FontWeight.bold), ), ), ), ], ), ); } }
需要我們注意的點我們都在上面程式碼註釋中基本上都說了,接下來我們我們看看下面列表的程式碼:
class MineItemWidget extends StatelessWidget { String imageName; String title; @required VoidCallback onTap; MineItemWidget(this.imageName, this.title, {this.onTap}); @override Widget build(BuildContext context) { return Container( /// 子檢視 顏色容器 child: Column( children: <Widget>[ /// Container( height: 53, child: _mineItem(imageName, title), ), Container( color: Color(0xffeaeaea), constraints: BoxConstraints.expand(height: 1.0), ), ], ), ); } Widget _mineItem(String imageName, String title) { return InkWell( onTap: () { this.onTap(); }, child: Row( /// children: <Widget>[ Expanded( flex: 1, child: Container( padding: EdgeInsets.only(left: 15), child: Image.asset( imageName, width: 20, height: 20, ), ), ), Expanded( flex: 6, child: Container( padding: EdgeInsets.only(left: 15), child: Text( title, style: TextStyle(fontSize: 16), ), ), ), ], ), ); } }
最後就是把它倆寫到我們的 MinePage ,MinePage的程式碼如下:
class MinePage extends StatefulWidget { MinePage({Key key}) : super(key: key); @override _MinePageState createState() => _MinePageState(); } class _MinePageState extends State<MinePage> { @override Widget build(BuildContext context) { return Scaffold( appBar: new AppBar( title: Text("我的"), backgroundColor: Colors.orange, elevation: 0, // 去掉Appbar底部陰影 ), body: ListView( children: <Widget>[ /// 頭部的View MineHeader("images/icon_header.png", "張旭旭旭旭啊"), /// 線 _listViewLine, MineItemWidget("images/icon_heath.png", "我的健康", onTap: () { /// 跳轉到檢視按鈕內容介面 Navigator.push( context, MaterialPageRoute(builder: (context) => MineCustomButton()), ); }), MineItemWidget("images/icon_village.png", "我的旅行", onTap: () { print('我的旅行'); }), _listViewLine, MineItemWidget("images/mine_train.png", "我的家鄉", onTap: () { print('我的家鄉'); }), ], ), ); } /// 分割線 Widget get _listViewLine { return Container( color: Color(0xffeaeaea), height: 6, ); } }
這樣整個一個基本的效果就出來了,如最開始我們給的那張圖效果一樣。打算在後面一篇文章中再說說我們常見到一些元件,按鈕,輸入框,進度條等等的。
參考文章: