目錄
- LinearLayout 在Flutter中等價於什麼(Android)?
- RelativeLayout 在Flutter中等價於什麼(Android)?
- 如何使用widget定義佈局屬性?
- 如何分層佈局?
- 如何設定佈局樣式?
- ScrollView在Flutter中等價於什麼?
- 誰是Flutter的列表元件?
- 如何知道點選了列表中哪個item?
- 如何動態更新ListView?
LinearLayout 在Flutter中等價於什麼(Android)?
在Android中,使用LinearLayout來使你的控制元件呈水平或垂直排列。在Flutter中,你可以使用Row或Column widget來實現相同的結果:
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Row One'),
Text('Row Two'),
Text('Row Three'),
Text('Row Four'),
],
);
}
複製程式碼
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text('Column One'),
Text('Column Two'),
Text('Column Three'),
Text('Column Four'),
],
);
}
複製程式碼
要了解有關構建線性佈局的更多資訊,可參考區貢獻的媒體文章Flutter For Android Developers : How to design LinearLayout in Flutter?。
RelativeLayout 在Flutter中等價於什麼(Android)?
RelativeLayout
用於使widget相對於彼此位置排列。在Flutter中,有幾種方法可以實現相同的結果
您可以通過使用Column
、Row
和Stack
的組合來實現RelativeLayout
的效果。您可以為widget建構函式指定相對於父元件的佈局規則。
推薦參考在StackOverflow上的一個在Flutter中構建RelativeLayout的例子。
如何使用widget定義佈局屬性?
在Flutter中,佈局主要由專門設計用於提供佈局的小部件定義,並結合控制元件widget及其樣式屬性。
例如, 列 和 行 widgets 控制一個陣列中的條目 並且 分別垂直和水平對齊它們。 Container widget 控制一個佈局的樣式和屬性, 並且 Center widget 負責居中它的子widget。
// Flutter
Center(
child: Column(
children: <Widget>[
Container(
color: Colors.red,
width: 100.0,
height: 100.0,
),
Container(
color: Colors.blue,
width: 100.0,
height: 100.0,
),
Container(
color: Colors.green,
width: 100.0,
height: 100.0,
),
],
),
)
複製程式碼
Flutter在其核心widget庫中提供了各種佈局小部件。 例如, Padding, Align, 和 Stack。
更多佈局widget可參考 Layout Widgets。
如何分層佈局?
在Android中,我們可以使用FrameLayout
佈局進行分層。
Flutter 使用Stack
widget 控制子widget在一層。 子widgets可以完全或者部分覆蓋基礎widgets。
Stack
控制元件將其子項相對於其框的邊緣定位。如果您只想重疊多個子視窗小部件,這個類很有用。
// Flutter
Stack(
alignment: const Alignment(0.6, 0.6),
children: <Widget>[
CircleAvatar(
backgroundImage: NetworkImage(
"https://avatars3.githubusercontent.com/u/14101776?v=4"),
),
Container(
decoration: BoxDecoration(
color: Colors.black45,
),
child: Text('Flutter'),
),
],
)
複製程式碼
上一個示例使用 Stack
覆蓋容器 (顯示其“Text”在半透明的黑色背景上) 在’CircleAvatar之上.
Stack偏移文字 使用
alignment屬性和
Alignment`定位。
如何設定佈局樣式?
Flutter有一套獨特的佈局系統,Padding
、Center
、Column
、Row
、等都是widget,另外元件也通常接受用於佈局樣式的構造引數:比如Text
widget可以使用TextStyle
屬性。如果要在多個位置使用相同的文字樣式, 你可以建立一個 TextStyle
類並將其應用於各個 Text
widgets。
// Flutter
var textStyle = TextStyle(fontSize: 32.0, color: Colors.cyan, fontWeight:
FontWeight.w600);
...
Center(
child: Column(
children: <Widget>[
Text(
'Sample text',
style: textStyle,
),
Padding(
padding: EdgeInsets.all(20.0),
child: Icon(Icons.lightbulb_outline,
size: 48.0, color: Colors.redAccent)
),
],
),
)
複製程式碼
ScrollView在Flutter中等價於什麼?
在Android中,ScrollView
允許您包含一個子控制元件,以便在使用者裝置的螢幕比控制元件內容小的情況下,使它們可以滾動。在Flutter中,最簡單的方法是使用ListView。但在Flutter中,一個ListView既是一個ScrollView,也是一個Android ListView。
在 iOS 中,你給 view 包裹上 ScrollView 來允許使用者在需要時滾動你的內容。在 Flutter 中,最簡單的方法是使用 ListView widget。它表現得既和 iOS 中的 ScrollView 一致,也能和 TableView 一致,因為你可以給它的 widget 做垂直排布:
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
Text('Row One'),
Text('Row Two'),
Text('Row Three'),
Text('Row Four'),
],
);
}
複製程式碼
更多關於在 Flutter 中如何排布 widget 的文件,請參閱 layout tutorial。
誰是Flutter的列表元件?
- 在 iOS 中,通常用
UITableView
或UICollectionView
來展示一個列表; - 在 Android 中,通常用
ListView
或RecyclerView
來展示一個列表; - 在 RN 中,通常用
FlatList
或SectionList
來展示一個列表;
在 Flutter 中,你可以用 ListView 來達到相似的實現:
import 'package:flutter/material.dart';
void main() {
runApp(SampleApp());
}
class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample App"),
),
body: ListView(children: _getListData()),
);
}
_getListData() {
List<Widget> widgets = [];
for (int i = 0; i < 100; i++) {
widgets.add(Padding(padding: EdgeInsets.all(10.0), child: Text("Row $i")));
}
return widgets;
}
}
複製程式碼
在Android ListView中,您可以建立一個介面卡,然後您可以將它傳遞給ListView,該介面卡將使用介面卡返回的內容來展示每一行,從上面程式碼中不難看出,在Flutter中沒有adapter的等價物,我們唯一要做的就是控制這個list中要展示的資料。
如何知道點選了列表中哪個item?
import 'package:flutter/material.dart';
void main() {
runApp(SampleApp());
}
class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample App"),
),
body: ListView(children: _getListData()),
);
}
_getListData() {
List<Widget> widgets = [];
for (int i = 0; i < 100; i++) {
widgets.add(GestureDetector(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text("Row $i"),
),
onTap: () {
print('row tapped');
},
));
}
return widgets;
}
}
複製程式碼
在上述程式碼中我們通過GestureDetector
來監聽item的點選事件。
如何動態更新ListView?
- 在 Android 中,改變列表資料後通過notifyDataSetChanged來更新列表;
- 在 iOS 中,你改變列表的資料,並通過 reloadData() 方法來通知 table 或是 collection view;
在 Flutter 中,如果你想通過 setState()
方法來更新 widget 列表,你會很快發現你的資料展示並沒有變化。這是因為當 setState()
被呼叫時,Flutter 渲染引擎會去檢查 widget 樹來檢視是否有什麼地方被改變了。當它得到你的 ListView
時,它會使用一個==
判斷,並且發現兩個 ListView 是相同的。沒有什麼東西是變了的,因此更新不是必須的。
一個更新 ListView
的簡單方法是,在 setState()
中建立一個新的 List
,並把舊 List
的資料拷貝給新的 list。雖然這樣很簡單,但當資料集很大時,並不推薦這樣做,來一起看個demo:
import 'package:flutter/material.dart';
void main() {
runApp(SampleApp());
}
class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List widgets = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 100; i++) {
widgets.add(getRow(i));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample App"),
),
body: ListView(children: widgets),
);
}
Widget getRow(int i) {
return GestureDetector(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text("Row $i"),
),
onTap: () {
setState(() {
widgets = List.from(widgets);
widgets.add(getRow(widgets.length + 1));
print('row $i');
});
},
);
}
}
複製程式碼
一個推薦的、高效的且有效的做法是,使用 ListView.Builder
來構建列表。這個方法在你想要構建動態列表,或是列表擁有大量資料時會非常好用:
import 'package:flutter/material.dart';
void main() {
runApp(SampleApp());
}
class SampleApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Sample App',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: SampleAppPage(),
);
}
}
class SampleAppPage extends StatefulWidget {
SampleAppPage({Key key}) : super(key: key);
@override
_SampleAppPageState createState() => _SampleAppPageState();
}
class _SampleAppPageState extends State<SampleAppPage> {
List widgets = [];
@override
void initState() {
super.initState();
for (int i = 0; i < 100; i++) {
widgets.add(getRow(i));
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Sample App"),
),
body: ListView.builder(
itemCount: widgets.length,
itemBuilder: (BuildContext context, int position) {
return getRow(position);
},
),
);
}
Widget getRow(int i) {
return GestureDetector(
child: Padding(
padding: EdgeInsets.all(10.0),
child: Text("Row $i"),
),
onTap: () {
setState(() {
widgets.add(getRow(widgets.length + 1));
print('row $i');
});
},
);
}
}
複製程式碼
與建立一個 “ListView” 不同,建立一個 ListView.builder
接受兩個主要引數:列表的初始長度,和一個 ItemBuilder 方法。
ItemBuilder 方法和 iOS的cellForItemAt
代理方法非常類似,它接受一個位置,並且返回在這個位置上你希望渲染的 cell。
最後,也是最重要的,注意 onTap()
函式裡並沒有重新建立一個 List
,而是 add
了一個 widget。