在Flutter中自定義組件其實(shí)就是一個(gè)類(lèi),都需要繼承StatelessWidget
或者StatefulWidget
.
StatelessWidget
是無(wú)狀態(tài)組件,狀態(tài)不可改變,我們可以看做為初識(shí)狀態(tài)后一直保持原樣,無(wú)法通過(guò)改變數(shù)據(jù)再次重新渲染組件.
StatefulWidget
是有狀態(tài)組件,持有的狀態(tài)可能在widget
生命周期發(fā)生改變,也可以理解為,如果我們?cè)陧?yè)面上需要數(shù)據(jù)反復(fù)渲染的話(huà),就需要用到這個(gè)有狀態(tài)組件.
StatefulWidget
首先我們先用一個(gè)demo
來(lái)理解一下StatefulWidget
有狀態(tài)組件:
- 創(chuàng)建一個(gè)
LayoutDemo
類(lèi)繼承StatefulWidget
有狀態(tài)組件,StatefulWidget
是一個(gè)抽象類(lèi) -
StatefulWidget
抽象類(lèi)里面有一個(gè)抽象方法createState()
,我們必須要實(shí)現(xiàn)這個(gè)抽象方法 - 在抽象方法中調(diào)用我們自己定義的
_LayoutDemoState
類(lèi) -
_LayoutDemoState
類(lèi)需要繼承State
- 實(shí)現(xiàn)
_LayoutDemoState
的build
方法,返回一個(gè)widget
,這個(gè)widget
才是我們需要實(shí)現(xiàn)的組件內(nèi)容
下面我們通過(guò)每次點(diǎn)擊按鈕進(jìn)行計(jì)數(shù)的頁(yè)面功能來(lái)理解StatefulWidget
import "package:flutter/material.dart";
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Container(
child: MaterialApp(
title: 'belineApp',
home: Scaffold(
appBar: AppBar(
title: Text('Wrap'),
),
body: LayoutDemo()
)
)
);
}
}
//- 自定義有狀態(tài)組件
class LayoutDemo extends StatefulWidget {
LayoutDemo({Key key}) : super(key: key);
_LayoutDemoState createState() => _LayoutDemoState();
}
class _LayoutDemoState extends State<LayoutDemo> {
int countNum = 0;
@override
Widget build(BuildContext context) {
return Column(
children: <Widget>[
Chip(
label: Text('${this.countNum}'),
),
SizedBox(height:20),
RaisedButton(
child: Text('按鈕'),
onPressed: () {
//- setState 方法只有在有狀態(tài)組件中才有
setState(() {
this.countNum++;
});
},
)
],
);
}
}
頁(yè)面功能效果
image.png
根據(jù)上面的demo,我們?cè)賹?shí)現(xiàn)一個(gè)功能需求:
- 新增數(shù)據(jù)功能,給空的
listview
組件添加listTile
并且每條數(shù)據(jù)顯示對(duì)應(yīng)的編號(hào) -
實(shí)現(xiàn)數(shù)據(jù)清空功能,并清空編號(hào)
效果:
image.png
代碼如下:
import "package:flutter/material.dart";
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Container(
child: MaterialApp(
title: 'belineApp',
home: Scaffold(
appBar: AppBar(
title: Text('StatefulWidget'),
),
body: HomePage()
)
)
);
}
}
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List list =new List(); //- 定義一個(gè)數(shù)組變量來(lái)裝新增的內(nèi)容
int countNum = 0; //- 用于記住數(shù)量
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
Column(
children: this.list.map((value){ //- 通過(guò)遍歷數(shù)組返回ListTile組件
return ListTile(
title: Text(value)
);
}).toList(), //- 由于map方法返回的不是一個(gè)數(shù)組,所以我們需要調(diào)用toList()方法轉(zhuǎn)換成數(shù)組
),
SizedBox(height:20),
RaisedButton(
child: Text('新增數(shù)據(jù)'),
onPressed: () {
setState(() {
this.countNum++;
this.list.add('新增數(shù)據(jù)第${this.countNum}條'); //- 調(diào)用數(shù)組的add方法,添加一個(gè)str內(nèi)容在數(shù)組中
});
},
),
RaisedButton(
child: Text('清空'),
onPressed: (){ //- 清空功能按鈕
setState(() {
this.countNum = 0;
this.list = [];
});
},
)
],
);
}
}
下面部分為個(gè)人練習(xí):
- 引入dio組件(網(wǎng)絡(luò)請(qǐng)求)
- 通過(guò)請(qǐng)求的數(shù)據(jù)進(jìn)行頁(yè)面渲染
-
圖文列表中,如果沒(méi)有圖片,用一張暫無(wú)圖片代替
頁(yè)面效果:
image.png
代碼:
import "package:flutter/material.dart";
import "package:dio/dio.dart";
void main() => runApp(MyApp());
class MyApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Container(
child: MaterialApp(
title: 'belineApp',
home: Scaffold(
appBar: AppBar(
title: Text('StatefulWidget'),
),
body: HomePage()
)
)
);
}
}
getHttp() async {
try {
Response response = await Dio().get("http://rap2.taobao.org:38080/app/mock/228170/datalist");
return response;
// print(response);
} catch (e) {
print(e);
}
}
class HomePage extends StatefulWidget {
HomePage({Key key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
List list =new List(); //- 定義一個(gè)數(shù)組變量來(lái)裝新增的內(nèi)容
int countNum = 0; //- 用于記住數(shù)量
@override
Widget build(BuildContext context) {
return ListView(
children: <Widget>[
Column(
children: this.list.map((value){ //- 通過(guò)遍歷數(shù)組返回ListTile組件
return Container(
decoration: BoxDecoration(
border: Border.all(color: Color(0xFFFF0000), width: 0.5)
),
child: ListTile(
leading: Container(
decoration: new BoxDecoration(
image: new DecorationImage(
image: new NetworkImage('https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=3956878071,2257649761&fm=26&gp=0.jpg'), // 設(shè)置一個(gè)暫無(wú)圖片的背景
fit: BoxFit.fill // 填滿(mǎn)
),
),
child: Image.network(value['coverOneToOne'], width:100.0,height:100.0, fit:BoxFit.cover),
),
title: Text(value['title']),
subtitle: Text(value['summary']),
)
);
}).toList(), //- 由于map方法返回的不是一個(gè)數(shù)組,所以我們需要調(diào)用toList()方法轉(zhuǎn)換成數(shù)組
),
SizedBox(height:20),
RaisedButton(
child: Text('新增數(shù)據(jù)'),
onPressed: () {
getHttp().then((res){
print(res.data['datas']);
setState(() {
this.list = res.data['datas'];
});
});
},
),
RaisedButton(
child: Text('清空'),
onPressed: (){ //- 清空功能按鈕
setState(() {
// this.countNum = 0;
this.list = [];
});
},
)
],
);
}
}