- 原文地址:Flutter Getting Started: Tutorial 5 Grid
- 原文做者:Alok Gupta
- 譯文出自:掘金翻譯計劃
- 本文永久連接:github.com/xitu/gold-m…
- 譯者:YueYong
Flutter GridView
幾乎與 ListView
相同,只是它提供了與 ListView
單向視圖的 2D 視圖比較。同時它也是移動應用開發中很是受歡迎的小部件。若是你不相信我,那就舉個例子,打開你手機中的任何一個電子商務應用,它確定是依賴於 ListView
或 GridView
來顯示數據的。html
Amazon 移動應用程序利用網格顯示數據前端
另外一個是 PayTM,它是印度流行的在線錢包服務應用之一,它普遍使用網格佈局來顯示不一樣的產品android
本文的最終目的是實現相似的界面:ios
可是,若是你注意到上面的圖像,那是橫屏模式下的。因此我將在本文中作如下的事情,當應用程序處於豎屏模式時,移動 APP 將在 ListView
中顯示項目,當它處於橫屏模式時,將會在網格中每行顯示3個條目。我還經過在單獨的類中移動 gridview 來實現建立自定義窗口小部件。git
我將以我以前的文章爲基礎 Flutter Getting Started: Tutorial 4 ListView,我已經建立了基於 ListView 的應用程序,這裏是初始項目結構和初始UI。github
這是咱們開始構建的初始代碼後端
class HomePage extends StatelessWidget {
final List<City> _allCities = City.allCities();
HomePage() {}
final GlobalKey scaffoldKey = new GlobalKey();
@override
Widget build(BuildContext context) {
return new Scaffold(
key: scaffoldKey,
appBar: new AppBar(
title: new Text(
"Cites around world",
style: new TextStyle(
fontSize: 18.0,
fontWeight: FontWeight.bold,
color: Colors.black87),
),
),
body: new Padding(
padding: EdgeInsets.fromLTRB(0.0, 10.0, 0.0, 0.0),
child: getHomePageBody(context)));
}
getHomePageBody(BuildContext context) {
return ListView.builder(
itemCount: _allCities.length,
itemBuilder: _getListItemUI,
padding: EdgeInsets.all(0.0),
);
}
Widget _getListItemUI(BuildContext context, int index,
{double imgwidth: 100.0}) {
return new Card(
child: new Column(
children: <Widget>[
new ListTile(
leading: new Image.asset(
"assets/" + _allCities[index].image,
fit: BoxFit.fitHeight,
width: imgwidth,
),
title: new Text(
_allCities[index].name,
style: new TextStyle(fontSize: 14.0, fontWeight: FontWeight.bold),
),
subtitle: new Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Text(_allCities[index].country,
style: new TextStyle(
fontSize: 13.0, fontWeight: FontWeight.normal)),
new Text('Population: ${_allCities[index].population}',
style: new TextStyle(
fontSize: 11.0, fontWeight: FontWeight.normal)),
]),
onTap: () {
_showSnackBar(context, _allCities[index]);
},
)
],
));
}
_showSnackBar(BuildContext context, City item) {
final SnackBar objSnackbar = new SnackBar(
content: new Text("${item.name} is a city in ${item.country}"),
backgroundColor: Colors.amber,
);
Scaffold.of(context).showSnackBar(objSnackbar);
}
}
複製代碼
在開始實際任務以前,讓我簡要介紹一下我上面作過的事情bash
ListView.builder
建立了簡單的 ListView
,它能夠靈活地建立無限的 listitem 視圖,由於它只調用那些能夠在屏幕上顯示的項目的回調函數。SnackBar
。如今開始咱們的工做,正如我以前提到的,咱們將把新的 widget 重構爲不一樣的類,以保持咱們的代碼模塊化並提升代碼的可讀性。所以,在 lib
文件夾下建立一個新的文件夾,並添加新的 DART 文件 mygridview.dart
。app
添加文件後,首先經過 'package:flutter/material.dart'
導入 material 組件,而後添加 MyGridView
類來繼承咱們最喜歡的 StatelessWidget
並複寫 Build
函數,代碼以下所示less
import 'package:flutter/material.dart';
import 'package:flutter5_gridlist/model/city.dart';
class MyGridView extends StatelessWidget {
final List<City> allCities;
MyGridView({Key key, this.allCities}) : super(key: key);
@override
Widget build(BuildContext context) {
return null;
}
}
複製代碼
我如今添加基本的 GridView 只顯示城市名稱,因此我將在重寫的 Build 函數中添加如下代碼
@override
Widget build(BuildContext context) {
return GridView.count(
crossAxisCount: 3,
padding: EdgeInsets.all(16.0),
childAspectRatio: 8.0,
children: _getGridViewItems(context),
);
}
_getGridViewItems(BuildContext context){
List<Widget> allWidgets = new List<Widget>();
for (int i = 0; i < allCities.length; i++) {
var widget = new Text(allCities[i].name);
allWidgets.add(widget);
};
return allWidgets;
}
複製代碼
對上述代碼的解釋
GridView.count
方法將爲應用程序提供 GridView 小部件crossAxisCount
屬性用於讓移動應用程序知道咱們想要顯示每行的項目數children
屬性將包含您但願在加載頁面時顯示的全部小部件childAspectRatio
,它是每一個子節點的橫軸與主軸範圍的比率,由於我顯示的是名稱,因此我統一設置爲 8.0,以便減小兩個圖塊之間的邊距這是UI的樣子
如今咱們來改變 UI 讓其相似於咱們看到的 ListView。在這裏我建立了一個新的函數,它將以 Card 的形式發送 City 類
// Create individual item
_getGridItemUI(BuildContext context, City item) {
return new InkWell(
onTap: () {
_showSnackBar(context, item);
},
child: new Card(
child: new Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
new Image.asset(
"assets/" + item.image,
fit: BoxFit.fill,
),
new Expanded(
child: new Center(
child: new Column(
children: <Widget>[
new SizedBox(height: 8.0),
new Text(
item.name,
style: new TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
new Text(item.country),
new Text('Population: ${item.population}')
],
)))
],
),
elevation: 2.0,
margin: EdgeInsets.all(5.0),
));
}
複製代碼
上述代碼的解釋
Inkwell
類,由於 Card 類不直接支持手勢,因此我把它包裝在 InkWell 類中,利用它的 onTap
事件替換 SnackBarListView
的卡片,但未指定寬度childAspectRatio
從 8.0 更改成 8.0/9.0,由於咱們須要更多的高度。若是沒有忘記的話,在開始作程序時我就說過,我將在縱向方向上顯示 ListView
,在橫向方向上顯示 GridView
,爲了實現它咱們須要 MediaQuery
類來識別方向。不管什麼時候更改方向,你均可以決定哪些代碼應該被調用,也就是說,即便你傾斜移動窗口都會調用 Build
函數,小部件也都會從新繪製。因此在 homepage.dart
類中咱們將使用如下函數來處理 Orientation 更改的問題
getHomePageBody(BuildContext context) {
if (MediaQuery.of(context).orientation == Orientation.portrait)
return ListView.builder(
itemCount: _allCities.length,
itemBuilder: _getListItemUI,
padding: EdgeInsets.all(0.0),
);
else
return new MyGridView(allCities: _allCities);
}
複製代碼
所以,最終的 UI 將是這樣的
本教程結束
請仔細閱讀這些文章。它可能會給你一個你真正須要的指引:
若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。
掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。