line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>這是一個系列,通過8篇文章幫助大家建立起 Flutter 的知識體系,建議大家好好閱讀並收藏起來。本篇文章我們先介紹 Flutter 裡一些常用的 UI 控制元件,然後藉助官網提供的兩個 demo 把所學的控制元件知識實際使用起來。 color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>基本控制元件 color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>Widget color: inherit;
line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>Widget 分為兩種,一種是無狀態的,叫 StatelessWidget,它只能用來展示資訊,不能有動作(使用者互動);另一種是有狀態的,叫 StatefulWidget,這種 Widget 可以通過改變狀態使得 UI 發生變化,它可以包含使用者互動。
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
FooWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
//
...
}
}
複製程式碼
line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>StatefulWidget 用起來麻煩一些,他還需要一個 State:
class
BarWidget
extends
StatefulWidget
{
@override
State
createState()
{
return
_BarWidgetState();
}
}
class
_BarWidgetState
extends
State<
BarWidget>
{
@override
Widget
build(BuildContext
context)
{
//
...
}
}
複製程式碼
color: inherit;line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>從 BarWidget 的實現來看,好像跟前面使用 StatelessWidget 沒有什麼區別,都是在 build 方法裡面返回一個 Widget,只是 stateful widget 把這個方法挪到了 State 裡面。實際上,兩者的區別非常大。stateless widget 整個生命週期裡都不會改變,所以 build 方法只會執行一次。而 stateful widget 只要狀態改變,就會呼叫 build 方法重新建立 UI。
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
BarWidget
extends
StatefulWidget
{
State
createState()
{
return
_BarWidgetState();
}
}
class
_BarWidgetState
extends
State<
BarWidget>
{
var
i
=
0;
Widget
build(BuildContext
context)
{
return
Row(
children:
<
Widget>
[
Text('i
=
$i'),
RaisedButton(
onPressed:
()
{
setState(()
{
++i;
});
},
child:
Text('click'),
)
],
);
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>文字
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Text("Put
your
text
here");
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Text(
"Put
your
text
here",
style:
TextStyle(
color:
Colors.blue,
fontSize:
16.0,
fontWeight:
FontWeight.bold
),
);
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>圖片
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">Image.asset(name);
Image.file(file);
Image.memory(bytes);
Image.network(src);
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Image.network(
"http://www.example.com/xxx.png",
width:
200.0,
height:
150.0,
);
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>按鈕
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
var
flatBtn
=
FlatButton(
onPressed:
()
=>
print('FlatButton
pressed'),
child:
Text('BUTTON'),
);
var
raisedButton
=
RaisedButton(
onPressed:
()
=>
print('RaisedButton
pressed'),
child:
Text('BUTTON'),
);
return
raisedButton;
}
}
複製程式碼
line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>注意,由於我們只是在按鈕點選的時候列印一個字串,這裡使用 StatelessWidget 是沒有問題的。但如果有其他 UI 動作(比如彈出一個 dialog,則必須使用 StatefulWidget)。 color: inherit;
line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>FlatButton: margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“>flat-button color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“>raised-button color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>文字輸入框
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
MessageForm
extends
StatefulWidget
{
State
createState()
{
return
_MessageFormState();
}
}
class
_MessageFormState
extends
State<
MessageForm>
{
var
editController
=
TextEditingController();
Widget
build(BuildContext
context)
{
//
Row、Expand
都是用於佈局的控制元件,這裡可以先忽略它們
return
Row(
children:
<
Widget>
[
Expanded(
child:
TextField(
controller:
editController,
),
),
RaisedButton(
child:
Text("click"),
onPressed:
()
=>
print('text
inputted:
${editController.text
}'),
)
],
);
}
void
dispose()
{
super.dispose();
//
手動呼叫
controller
的
dispose
方法以釋放資源
editController.dispose();
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>顯示彈框
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
_MessageFormState
extends
State<
MessageForm>
{
var
editController
=
TextEditingController();
Widget
build(BuildContext
context)
{
return
Row(
children:
<
Widget>
[
Expanded(
child:
TextField(
controller:
editController,
),
),
RaisedButton(
child:
Text("click"),
onPressed:
()
{
showDialog(
//
第一個
context
是引數名,第二個
context
是
State
的成員變數
context:
context,
builder:
(_)
{
return
AlertDialog(
//
dialog
的內容
content:
Text(editController.text),
//
actions
設定
dialog
的按鈕
actions:
<
Widget>
[
FlatButton(
child:
Text('OK'),
//
使用者點選按鈕後,關閉彈框
onPressed:
()
=>
Navigator.pop(context),
)
],
);
}
);
}
)
],
);
}
void
dispose()
{
super.dispose();
editController.dispose();
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>最簡單的佈局——Container、Padding 和 Center: color: inherit;
line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>控制元件 Container 可以讓我們設定一個控制元件的尺寸、背景、margin 等:
class
TestWidget
extends
StatelessWidget
{
@override
Widget
build(BuildContext
context)
{
return
Container(
child:
Text('text'),
padding:
EdgeInsets.all(8.0),
margin:
EdgeInsets.all(4.0),
width:
80.0,
decoration:
BoxDecoration(
//
背景色
color:
Colors.grey,
//
圓角
borderRadius:
BorderRadius.circular(5.0),
),
);
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Padding(
padding:
EdgeInsets.all(8.0),
child:
Text('text'),
);
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Container(
padding:
EdgeInsets.all(8.0),
margin:
EdgeInsets.all(4.0),
width:
200.0,
height:
200.0,
decoration:
BoxDecoration(
//
背景色
color:
Colors.grey,
//
圓角
borderRadius:
BorderRadius.circular(5.0),
),
//
把文字放在
Container
的中間
child:
Center(
child:
Text('text'),
),
);
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>水平、豎直佈局和 Expand
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Row(
//
只有一個子元素的
widget,一般使用
child
引數來設定;Row
可以包含多個子控制元件,
//
對應的則是
children。
children:
<
Widget>
[
Text('text1'),
Text('text2'),
Text('text3'),
Text('text4'),
],
);
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Column(
children:
<
Widget>
[
Text('text1'),
Text('text2'),
Text('text3'),
Text('text4'),
],
);
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
MessageForm
extends
StatefulWidget
{
State
createState()
{
return
_MessageFormState();
}
}
class
_MessageFormState
extends
State<
MessageForm>
{
var
editController
=
TextEditingController();
Widget
build(BuildContext
context)
{
return
Row(
children:
<
Widget>
[
//
佔滿一行裡除
RaisedButton
外的所有空間
Expanded(
child:
TextField(
controller:
editController,
),
),
RaisedButton(
child:
Text("click"),
onPressed:
()
=>
print('text
inputted:
${editController.text
}'),
)
],
);
}
void
dispose()
{
super.dispose();
editController.dispose();
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Row(
children:
<
Widget>
[
Expanded(
//
佔一行的
2/3
flex:
2,
child:
RaisedButton(child:
Text('btn1'),),
),
Expanded(
//
佔一行的
1/3
flex:
1,
child:
RaisedButton(child:
Text('btn2'),),
),
],
);
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>Stack 佈局
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Stack(
children:
<
Widget>
[
Text('foobar'),
Text('barfoo'),
],
);
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
TestWidget
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
return
Stack(
//
Aligment
的取值範圍為
[-1,
1],Stack
中心為
(0,
0),
//
這裡設定為
(-0.5,
-0.5)
後,可以讓文字對齊到
Container
的
1/4
處
alignment:
const
Alignment(-0.5,
-0.5),
children:
<
Widget>
[
Container(
width:
200.0,
height:
200.0,
color:
Colors.blue,
),
Text('foobar'),
],
);
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“>screenshot-stack color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>示例一 color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“>lakes-diagram color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>展示圖片
line-height: inherit;
margin: 0px;
padding: 0px;
margin-bottom: 0.5em;
“> color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
margin-bottom: 0.5em;
“>
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">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
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">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/lake.jpg
複製程式碼
line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
margin-top: 0px;
“>現在,我們可以把這張圖片展示出來了:
void
main()
{
runApp(MyApp());
}
class
MyApp
extends
StatelessWidget
{
@override
Widget
build(BuildContext
context)
{
return
MaterialApp(
title:
'Flutter
UI
basic
1',
home:
Scaffold(
appBar:
AppBar(
title:
Text('Top
Lakes'),
),
body:
Image.asset(
'images/lake.jpg',
width:
600.0,
height:
240.0,
//
cover
類似於
Android
開發中的
centerCrop,其他一些型別,讀者可以檢視
//
https://docs.flutter.io/flutter/painting/BoxFit-class.html
fit:
BoxFit.cover,
)
),
);
}
}
複製程式碼
color: inherit;line-height: inherit;
margin: 0px;
padding: 0px;
font-weight: bold;
“>強烈建議在遇到不熟悉的 API 時翻一翻文件,並在文件中找到 demo 所使用的 API。我們的例子不可能覆蓋所有的 API,通過這種方式熟悉文件後,讀者就可以根據文件實現出自己想要的效果。不妨就從 Image 開始吧,在 color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>佈局 color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“>
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
_TitleSection
extends
StatelessWidget
{
final
String
title;
final
String
subtitle;
final
int
starCount;
_TitleSection(this.title,
this.subtitle,
this.starCount);
Widget
build(BuildContext
context)
{
//
為了給
title
section
加上
padding,這裡我們給內容套一個
Container
return
Container(
//
設定上下左右的
padding
都是
32。類似的還有
EdgeInsets.only/symmetric
等
padding:
EdgeInsets.all(32.0),
child:
Row(
children:
<
Widget>
[
//
這裡為了讓標題佔滿螢幕寬度的剩餘空間,用
Expanded
把標題包了起來
Expanded(
//
再次提醒讀者,Expanded
只能包含一個子元素,使用的引數名是
child。接下來,
//
為了在豎直方向放兩個標題,加入一個
Column。
child:
Column(
//
Column
是豎直方向的,cross
為交叉的意思,也就是說,這裡設定的是水平方向
//
的對齊。在水平方向,我們讓文字對齊到
start(讀者可以修改為
end
看看效果)
crossAxisAlignment:
CrossAxisAlignment.start,
children:
<
Widget>
[
//
聰明的你,這個時候肯定知道為什麼突然加入一個
Container
了。
//
跟前面一樣,只是為了設定一個
padding
Container(
padding:
const
EdgeInsets.only(bottom:
8.0),
child:
Text(
title,
style:
TextStyle(fontWeight:
FontWeight.bold),
),
),
Text(
subtitle,
style:
TextStyle(color:
Colors.grey[500]),
)
],
),
),
//
這裡是
Row
的第二個子元素,下面這兩個就沒用太多值得說的東西了。
Icon(
Icons.star,
color:
Colors.red[500],
),
Text(starCount.toString())
],
),
);
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>對齊 color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“>
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">Widget
_buildButtonColumn(BuildContext
context,
IconData
icon,
String
label)
{
final
color
=
Theme.of(context).primaryColor;
return
Column(
//
main
axis
跟我們前面提到的
cross
axis
相對應,對
Column
來說,指的就是豎直方向。
//
在放置完子控制元件後,螢幕上可能還會有一些剩餘的空間(free
space),min
表示儘量少佔用
//
free
space;類似於
Android
的
wrap_content。
//
對應的,還有
MainAxisSize.max
mainAxisSize:
MainAxisSize.min,
//
沿著
main
axis
居中放置
mainAxisAlignment:
MainAxisAlignment.center,
children:
<
Widget>
[
Icon(icon,
color:
color),
Container(
margin:
const
EdgeInsets.only(top:
8.0),
child:
Text(
label,
style:
TextStyle(
fontSize:
12.0,
fontWeight:
FontWeight.w400,
color:
color,
),
),
)
],
);
}
class
MyApp
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
//...
Widget
buttonSection
=
Container(
child:
Row(
//
沿水平方向平均放置
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children:
[
_buildButtonColumn(context,
Icons.call,
'CALL'),
_buildButtonColumn(context,
Icons.near_me,
'ROUTE'),
_buildButtonColumn(context,
Icons.share,
'SHARE'),
],
),
);
//...
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“> color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“>全部放到一起
class
MyApp
extends
StatelessWidget
{
@override
Widget
build(BuildContext
context)
{
final
titleSection
=
_TitleSection(
'Oeschinen
Lake
Campground',
'Kandersteg,
Switzerland',
41);
final
buttonSection
=
...;
final
textSection
=
Container(
padding:
const
EdgeInsets.all(32.0),
child:
Text(
'''
Lake
Oeschinen
lies
at
the
foot
of
the
Blüemlisalp
in
the
Bernese
Alps.
Situated
1,578
meters
above
sea
level,
it
is
one
of
the
larger
Alpine
Lakes.
A
gondola
ride
from
Kandersteg,
followed
by
a
half-hour
walk
through
pastures
and
pine
forest,
leads
you
to
the
lake,
which
warms
to
20
degrees
Celsius
in
the
summer.
Activities
enjoyed
here
include
rowing,
and
riding
the
summer
toboggan
run.
''',
softWrap:
true,
),
);
return
MaterialApp(
title:
'Flutter
UI
basic
1',
home:
Scaffold(
appBar:
AppBar(
title:
Text('Top
Lakes'),
),
//
由於我們的內容可能會超出螢幕的長度,這裡把內容都放到
ListView
裡。
//
除了這種用法,ListView
也可以像我們在
Android
原生開發中使用
ListView
那樣,
//
根據資料動態生成一個個
item。這個我們在下一節再來學習
body:
ListView(
children:
<
Widget>
[
Image.asset(
'images/lake.jpg',
width:
600.0,
height:
240.0,
//
cover
類似於
Android
開發中的
centerCrop,其他一些型別,讀者可以檢視
//
https://docs.flutter.io/flutter/painting/BoxFit-class.html
fit:
BoxFit.cover,
),
titleSection,
buttonSection,
textSection
],
),
)
);
}
}
}
複製程式碼
color: inherit;line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“>
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">git
clone
https://github.com/Jekton/flutter_demo.git
cd
flutter_demo
git
checkout
ui-basic1
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“>示例二 color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“> color: inherit;
line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>首先給資料建模:
enum
BuildingType
{
theater,
restaurant
}
class
Building
{
final
BuildingType
type;
final
String
title;
final
String
address;
Building(this.type,
this.title,
this.address);
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
ItemView
extends
StatelessWidget
{
final
int
position;
final
Building
building;
ItemView(this.position,
this.building);
Widget
build(BuildContext
context)
{
final
icon
=
Icon(
building.type
==
BuildingType.restaurant
?
Icons.restaurant
:
Icons.theaters,
color:
Colors.blue[500]);
final
widget
=
Row(
children:
<
Widget>
[
Container(
margin:
EdgeInsets.all(16.0),
child:
icon,
),
Expanded(
child:
Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children:
<
Widget>
[
Text(
building.title,
style:
TextStyle(
fontSize:
20.0,
fontWeight:
FontWeight.w500,
)
),
Text(building.address)
],
),
)
],
);
return
widget;
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">class
BuildingListView
extends
StatelessWidget
{
final
List<
Building>
buildings;
BuildingListView(this.buildings);
Widget
build(BuildContext
context)
{
//
ListView.builder
可以按需生成子控制元件
return
ListView.builder(
itemCount:
buildings.length,
itemBuilder:
(context,
index)
{
return
new
ItemView(index,
buildings[index]);
}
);
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">//
定義一個回撥介面
typedef
OnItemClickListener
=
void
Function(int
position);
class
ItemView
extends
StatelessWidget
{
final
int
position;
final
Building
building;
final
OnItemClickListener
listener;
//
這裡的
listener
會從
ListView
那邊傳過來
ItemView(this.position,
this.building,
this.listener);
Widget
build(BuildContext
context)
{
final
widget
=
...;
//
一般來說,為了監聽手勢事件,我們使用
GestureDetector。但這裡為了在點選的時候有個
//
水波紋效果,使用的是
InkWell。
return
InkWell(
onTap:
()
=>
listener(position),
child:
widget
);
}
}
class
BuildingListView
extends
StatelessWidget
{
final
List<
Building>
buildings;
final
OnItemClickListener
listener;
//
這是對外介面。外部通過建構函式傳入資料和
listener
BuildingListView(this.buildings,
this.listener);
Widget
build(BuildContext
context)
{
return
ListView.builder(
itemCount:
buildings.length,
itemBuilder:
(context,
index)
{
return
new
ItemView(index,
buildings[index],
listener);
}
);
}
}
複製程式碼
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">void
main()
{
runApp(MyApp());
}
class
MyApp
extends
StatelessWidget
{
Widget
build(BuildContext
context)
{
final
buildings
=
[
Building(BuildingType.theater,
'CineArts
at
the
Empire',
'85
W
Portal
Ave'),
Building(BuildingType.theater,
'The
Castro
Theater',
'429
Castro
St'),
Building(BuildingType.theater,
'Alamo
Drafthouse
Cinema',
'2550
Mission
St'),
Building(BuildingType.theater,
'Roxie
Theater',
'3117
16th
St'),
Building(BuildingType.theater,
'United
Artists
Stonestown
Twin',
'501
Buckingham
Way'),
Building(BuildingType.theater,
'AMC
Metreon
16',
'135
4th
St
#3000'),
Building(BuildingType.restaurant,
'K\'s
Kitchen',
'1923
Ocean
Ave'),
Building(BuildingType.restaurant,
'Chaiya
Thai
Restaurant',
'72
Claremont
Blvd'),
Building(BuildingType.restaurant,
'La
Ciccia',
'291
30th
St'),
//
double
一下
Building(BuildingType.theater,
'CineArts
at
the
Empire',
'85
W
Portal
Ave'),
Building(BuildingType.theater,
'The
Castro
Theater',
'429
Castro
St'),
Building(BuildingType.theater,
'Alamo
Drafthouse
Cinema',
'2550
Mission
St'),
Building(BuildingType.theater,
'Roxie
Theater',
'3117
16th
St'),
Building(BuildingType.theater,
'United
Artists
Stonestown
Twin',
'501
Buckingham
Way'),
Building(BuildingType.theater,
'AMC
Metreon
16',
'135
4th
St
#3000'),
Building(BuildingType.restaurant,
'K\'s
Kitchen',
'1923
Ocean
Ave'),
Building(BuildingType.restaurant,
'Chaiya
Thai
Restaurant',
'72
Claremont
Blvd'),
Building(BuildingType.restaurant,
'La
Ciccia',
'291
30th
St'),
];
return
MaterialApp(
title:
'ListView
demo',
home:
Scaffold(
appBar:
AppBar(
title:
Text('Buildings'),
),
body:
BuildingListView(buildings,
(index)
=>
debugPrint('item
$index
clicked'))
),
);
}
}
複製程式碼
line-height: inherit;
margin: 0px;
padding: 0px;
“> margin: 0px;
padding: 0px;
margin-top: 10px;
text-align: center;
color: rgb(153, 153, 153);
font-size: 0.7em;
“>
color: inherit;
line-height: inherit;
margin: 0px;
padding: 0px;
">git
clone
https://github.com/Jekton/flutter_demo.git
cd
flutter_demo
git
checkout
ui-basic2
複製程式碼
推薦閱讀
Flutter學習指南:熟悉Dart語言
Flutter學習指南:編寫第一個應用
Flutter學習指南:開發環境搭建
line-height: inherit;
padding: 0px;
margin: 1.5em 0px;
“>https://juejin.im/post/5bd54b7be51d456c430e35f6