項(xiàng)目案例 -- StatelessWidget
- 案例代碼如下:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage(),
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("商品列表"),
),
body: SFContentBody(),
);
}
}
class SFContentBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: [
SFProductItem("Apple1","MacBook1","https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fdl.bbs.9game.cn%2Fattachments%2Fforum%2F201507%2F29%2F154250no2g2zqiuiqvaiku.jpg&refer=http%3A%2F%2Fdl.bbs.9game.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637072364&t=07974f838e1b49ecdecaba22f4af4fa2"),
SFProductItem("Apple2","MacBook2","https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fdl.bbs.9game.cn%2Fattachments%2Fforum%2F201507%2F29%2F154250no2g2zqiuiqvaiku.jpg&refer=http%3A%2F%2Fdl.bbs.9game.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637072364&t=07974f838e1b49ecdecaba22f4af4fa2"),
SFProductItem("Apple3","MacBook3","https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fdl.bbs.9game.cn%2Fattachments%2Fforum%2F201507%2F29%2F154250no2g2zqiuiqvaiku.jpg&refer=http%3A%2F%2Fdl.bbs.9game.cn&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1637072364&t=07974f838e1b49ecdecaba22f4af4fa2"),
],
);
}
}
class SFProductItem extends StatelessWidget {
final String title;
final String desc;
final String imageUrl;
final titleStyle = TextStyle(fontSize: 25,color: Colors.orange);
final descStyle = TextStyle(fontSize: 20,color: Colors.green);
//自定義構(gòu)造函數(shù)
SFProductItem(this.title,this.desc,this.imageUrl);
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(8), //設(shè)置內(nèi)邊距
decoration: BoxDecoration(
border: Border.all(
width: 5, //設(shè)置邊框的寬度
color: Colors.purple //設(shè)置邊框的額顏色
)
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(title,style: titleStyle),
SizedBox(height: 8),//設(shè)置間距
Text(desc,style: descStyle),
SizedBox(height: 8),
Image.network(imageUrl)
],
),
);
}
}
- 效果如下所示:
- 給widget添加Container的快捷鍵
Alt + Enter
- widget之間
設(shè)置間距
使用SizedBox(height: 8)
項(xiàng)目案例 -- StatefulWidget
-
StatefulWidget
最大的特點(diǎn)是:StatefulWidget
通過創(chuàng)建狀態(tài)類_SFHomeContentState
墙基,來管理自己的狀態(tài)數(shù)據(jù)棒妨; - 案例代碼如下:
import 'package:flutter/material.dart';
import 'package:flutter/cupertino.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("商品列表")
),
body: SFHomeContent("上面是一個(gè)簡單的計(jì)數(shù)器")
);
}
}
class SFHomeContent extends StatefulWidget {
final String message;
SFHomeContent(this.message);
@override
State<StatefulWidget> createState() {
return _SFHomeContentState();
}
}
//
class _SFHomeContentState extends State<SFHomeContent>{
var _counter = 0;
@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_getButtons(),
Text("當(dāng)前計(jì)數(shù): $_counter",style: TextStyle(fontSize: 20)),
Text("${widget.message}",style: TextStyle(fontSize: 18))
],
),
);
}
Widget _getButtons(){
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
child: Text("+",style: TextStyle(fontSize: 20,color: Colors.white)),
color: Colors.pink,
onPressed: (){
print("點(diǎn)擊+");
setState(() {
_counter++;
});
},
),
RaisedButton(
child: Text("-",style: TextStyle(fontSize: 20,color: Colors.white)),
color: Colors.purple,
onPressed: (){
print("點(diǎn)擊-");
setState(() {
_counter--;
});
},
)
],
);
}
}
-
class _SFHomeContentState extends State<SFHomeContent>
蠢络,Widget _getButtons()
類名與方法名之前加下劃線
表明屬于私有的限煞; -
class _SFHomeContentState extends State<SFHomeContent>
:_SFHomeContentState
狀態(tài)用來管理SFHomeContent
這個(gè)widget的狀態(tài)數(shù)據(jù)的,即_SFHomeContentState
會(huì)綁定SFHomeContent
融涣,_SFHomeContentState
中能通過widget屬性
訪問SFHomeContent
中的內(nèi)容稀颁; - 代碼運(yùn)行效果:
StatefulWidget生命周期
- 所謂生命周期是指:目標(biāo)組件從創(chuàng)建到銷毀的整個(gè)過程肢藐,監(jiān)聽組件的生命周期以便在不同的時(shí)期執(zhí)行不同的邏輯吹菱;
- Flutter組件的生命周期:
-
StatelessWidget
可以由父widget直接傳入值,調(diào)用build
方法來創(chuàng)建彭则,整個(gè)過程非常簡單鳍刷,其生命周期,主要關(guān)注構(gòu)造函數(shù)
與build
方法俯抖; -
StatefulWidget
需要通過State
來管理其狀態(tài)數(shù)據(jù)输瓜,并且監(jiān)聽狀態(tài)的改變重新build整個(gè)widget;
-
-
StatefulWidget
生命周期的過程如下圖所示:
- 1.執(zhí)行
StatefulWidget
的構(gòu)造函數(shù)芬萍; - 2.執(zhí)行
StatefulWidget
的createState
方法尤揣,創(chuàng)建一個(gè)維護(hù)StatefulWidget
的State
對(duì)象; - 3.執(zhí)行
State
的構(gòu)造方法柬祠; - 4.執(zhí)行
initState
方法北戏,我們通常在此方法中執(zhí)行一些數(shù)據(jù)初始化
操作,或者發(fā)送網(wǎng)絡(luò)請(qǐng)求
漫蛔; - 5.
didChangeDependencies
方法嗜愈,在下面兩種情況下會(huì)調(diào)用:- 調(diào)用
initState
時(shí)會(huì)調(diào)用旧蛾; - 從其他對(duì)象中依賴一些數(shù)據(jù)發(fā)生改變時(shí),比如InheritedWidget蠕嫁;
- 調(diào)用
- 6.執(zhí)行
build
方法锨天,渲染widget樹; - 7.當(dāng) 當(dāng)前的widget不再使用時(shí)剃毒,會(huì)調(diào)用
dispose
方法進(jìn)行銷毀病袄; - 8.手動(dòng)調(diào)用
setState
方法,會(huì)根據(jù)最新的狀態(tài)數(shù)據(jù)來重新調(diào)用build
方法赘阀,構(gòu)建對(duì)應(yīng)的widget益缠; - 9.執(zhí)行
didUpdateWidget
方法是在父widget觸發(fā)重建rebuild時(shí),系統(tǒng)會(huì)調(diào)用didUpdateWidget
方法纤壁; - 代碼案例驗(yàn)證:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("商品列表")
),
body: SFHomeContent("上面是一個(gè)簡單的計(jì)數(shù)器")
);
}
}
class SFHomeContent extends StatefulWidget {
final String message;
SFHomeContent(this.message){
print("SFHomeContent 構(gòu)造方法");
}
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
class _SFHomeContentState extends State<SFHomeContent>{
var _counter = 0;
_SFHomeContentState(){
print("_SFHomeContentState 構(gòu)造方法");
}
@override
void initState() {
super.initState();
print("_SFHomeContentState initState");
}
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
RaisedButton(
child: Text("+",style: TextStyle(fontSize: 25,color: Colors.white)),
color: Colors.pinkAccent,
onPressed: (){
setState(() {
_counter++;
});
},
),
Text("${widget.message}",style: TextStyle(fontSize: 18))
],
),
);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
print("_SFHomeContentState didChangeDependencies");
}
@override
void didUpdateWidget(SFHomeContent oldWidget) {
super.didUpdateWidget(oldWidget);
print("_SFHomeContentState didUpdateWidget");
}
-
@override
void dispose() {
super.dispose();
print("_SFHomeContentState dispose");
}
}
- 執(zhí)行結(jié)果如下:
-
StatefulWidget
生命周期復(fù)雜版的過程如下圖所示:
mounded
時(shí)State內(nèi)部設(shè)置的一個(gè)屬性左刽,不需要我們手動(dòng)進(jìn)行修改的,其主要作用是記錄widget
對(duì)應(yīng)的element
是否為空酌媒;dirty state
含義是臟的state欠痴,它實(shí)際是來標(biāo)記Element
的,標(biāo)記為dirty的Element會(huì)等待下一次的重繪檢查秒咨,強(qiáng)制調(diào)用build方法
來構(gòu)建我們的widget喇辽;clean state
含義是干凈的state,它表示當(dāng)前build出來的widget雨席,下一次重繪檢查不需要重新build菩咨;
Flutter的編程范式
- 命令式編程:就是一步步給計(jì)算機(jī)命令,告訴它我們想做什么事情陡厘;
- 聲明式編程:通常是描述目標(biāo)的性質(zhì)抽米,依賴哪些狀態(tài),并且當(dāng)依賴的狀態(tài)發(fā)生改變時(shí)糙置,我們通過某些方式通知目標(biāo)做出響應(yīng)云茸,聲明式編程是依賴框架的;
- Flutter采用的是聲明式編程谤饭;
- 命令式編程的代碼案例:
final text = new Text();
var title = "Hello World";
text.setContent(title); //主動(dòng)設(shè)置title
- 聲明式編程的代碼案例:
var title = "Hello World";
Text(title); //告訴Text內(nèi)部顯示的是title
基礎(chǔ)Widget
文本W(wǎng)idget
- 在Flutter中使用
Text
組件來顯示文本标捺;
普通文本
-
控制文本布局的參數(shù)
:在構(gòu)造函數(shù)中;-
textAlign
:文本的對(duì)齊方式揉抵; -
textDirection
:文本的排版方向亡容; -
maxLines
:最大顯示行數(shù); -
overflow
:文本的截?cái)嘁?guī)則冤今;
-
-
控制文本樣式的參數(shù)
:在構(gòu)造函數(shù)的參數(shù)style
中闺兢;-
fontSize
:文本大小戏罢; -
color
:文本顏色列敲; -
fontFamily
:設(shè)置字體阱佛; -
shaow
:文本陰影;
-
- 案例代碼:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("基礎(chǔ)widget")
),
body: SFHomeContent()
);
}
}
class SFHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
class _SFHomeContentState extends State<SFHomeContent>{
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return TextDemo();
}
}
class TextDemo extends StatelessWidget {
const TextDemo({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(
"基礎(chǔ)widget \ndasd has發(fā)哈就困了打算看是的撒 \n但是開發(fā)雙卡雙待",
textAlign: TextAlign.center,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 30,
color: Colors.red,
fontWeight: FontWeight.bold,
fontFamily: 'Courier'
),
);
}
}
富文本
- 富文本使用
Text.rich
戴而,其中必選參數(shù)傳入InlineSpan
凑术,是一個(gè)抽象類,我們需要傳入其子類即可所意,其子類有:-
TextSpan
:顯示文本的淮逊; -
WidgetSpan
:顯示圖片的; placeholderSpace
-
- 案例代碼如下:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("基礎(chǔ)widget")
),
body: SFHomeContent()
);
}
}
class SFHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
class _SFHomeContentState extends State<SFHomeContent>{
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return TextRichDemo();
}
}
class TextRichDemo extends StatelessWidget {
const TextRichDemo({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text.rich(
TextSpan(
children: [
TextSpan(text: "Hello World!!", style: TextStyle(fontSize: 20,color: Colors.green)),
TextSpan(text: "Hello iOS!!", style: TextStyle(fontSize: 20,color: Colors.red)),
WidgetSpan(child: Icon(Icons.favorite,color: Colors.red)),
TextSpan(text: "Hello Flutter!!", style: TextStyle(fontSize: 25,color: Colors.orange))
]
)
);
}
}
按鈕Widget
- 常見的按鈕類型有:
- RaisedButton
- FlatButton
- OutlineButton
- FloatingActionButton
RaisedButton
-
RaisedButton
是帶有一定圓角和陰影以及灰色背景的按鈕扶踊,并且在點(diǎn)擊的時(shí)候有動(dòng)畫效果泄鹏,其構(gòu)造函數(shù)如下:
class RaisedButton extends MaterialButton {
/// Create a filled button.
///
/// The [autofocus] and [clipBehavior] arguments must not be null.
/// Additionally, [elevation], [hoverElevation], [focusElevation],
/// [highlightElevation], and [disabledElevation] must be non-negative, if
/// specified.
const RaisedButton({
Key key,
@required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged,
MouseCursor mouseCursor,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
Brightness colorBrightness,
double elevation,
double focusElevation,
double hoverElevation,
double highlightElevation,
double disabledElevation,
EdgeInsetsGeometry padding,
VisualDensity visualDensity,
ShapeBorder shape,
Clip clipBehavior = Clip.none,
FocusNode focusNode,
bool autofocus = false,
MaterialTapTargetSize materialTapTargetSize,
Duration animationDuration,
Widget child,
})
FlatButton
-
FlatButton
:默認(rèn)沒有背景顏色,不帶陰影秧耗,高亮狀態(tài)下有背景备籽,構(gòu)造函數(shù)如下:
class FlatButton extends MaterialButton {
/// Create a simple text button.
///
/// The [autofocus] and [clipBehavior] arguments must not be null.
const FlatButton({
Key key,
@required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged,
MouseCursor mouseCursor,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color disabledColor,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
Brightness colorBrightness,
EdgeInsetsGeometry padding,
VisualDensity visualDensity,
ShapeBorder shape,
Clip clipBehavior = Clip.none,
FocusNode focusNode,
bool autofocus = false,
MaterialTapTargetSize materialTapTargetSize,
@required Widget child,
})
OutlineButton
-
OutlineButton
:帶有邊框的按鈕,構(gòu)造函數(shù)如下:
class OutlineButton extends MaterialButton {
/// Create an outline button.
///
/// The [highlightElevation] argument must be null or a positive value
/// and the [autofocus] and [clipBehavior] arguments must not be null.
const OutlineButton({
Key key,
@required VoidCallback onPressed,
VoidCallback onLongPress,
MouseCursor mouseCursor,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Color color,
Color focusColor,
Color hoverColor,
Color highlightColor,
Color splashColor,
double highlightElevation,
this.borderSide,
this.disabledBorderColor,
this.highlightedBorderColor,
EdgeInsetsGeometry padding,
VisualDensity visualDensity,
ShapeBorder shape,
Clip clipBehavior = Clip.none,
FocusNode focusNode,
bool autofocus = false,
Widget child,
})
FloatingActionButton
-
FloatingActionButton
:懸浮按鈕分井,構(gòu)造函數(shù)如下:
class FloatingActionButton extends StatelessWidget {
/// Creates a circular floating action button.
///
/// The [mini] and [clipBehavior] arguments must not be null. Additionally,
/// [elevation], [highlightElevation], and [disabledElevation] (if specified)
/// must be non-negative.
const FloatingActionButton({
Key key,
this.child,
this.tooltip,
this.foregroundColor,
this.backgroundColor,
this.focusColor,
this.hoverColor,
this.splashColor,
this.heroTag = const _DefaultHeroTag(),
this.elevation,
this.focusElevation,
this.hoverElevation,
this.highlightElevation,
this.disabledElevation,
@required this.onPressed,
this.mouseCursor,
this.mini = false,
this.shape,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
this.materialTapTargetSize,
this.isExtended = false,
})
- 案例代碼:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("基礎(chǔ)widget")
),
body: SFHomeContent()
);
}
}
class SFHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
class _SFHomeContentState extends State<SFHomeContent>{
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return ButtonWidget();
}
}
class ButtonWidget extends StatelessWidget {
const ButtonWidget({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Column(
children: [
RaisedButton(
child: Text("RaisedButton"),
textColor: Colors.white,
onPressed: (){
print("RaisedButton click");
},
),
FlatButton(
child: Text("FlatButton"),
onPressed: (){
print("FlatButton click");
},
),
OutlineButton(
child: Text("OutlineButton"),
onPressed: (){
print("OutlineButton click");
},
),
FloatingActionButton(
child: Icon(Icons.add),
onPressed: (){
print("FloatingActionButton click");
},
),
//自定義button
FlatButton(
color: Colors.green,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8)
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.favorite,color: Colors.red),
Text("喜歡作者")
],
),
onPressed: (){
print("FlatButton");
},
)
],
);
}
}
- 執(zhí)行結(jié)果如下圖所示:
-
ShapeBorder
:設(shè)置邊框车猬,是一個(gè)抽象類,其常用子類為RoundedRectangleBorder
- 1.默認(rèn)情況下Button上下會(huì)有一定的間距尺锚,可通過
materialTapTargetSize
屬性珠闰,去除間距; - 2.Button在沒有文本的情況下瘫辩,會(huì)顯示默認(rèn)尺寸大小伏嗜,可通過
ButtonTheme
屬性,自定義任意尺寸大蟹パ帷承绸; - 3.可通過
padding
屬性,去除內(nèi)容邊距挣轨; - 案例代碼:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("基礎(chǔ)widget")
),
body: SFHomeContent()
);
}
}
class SFHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
//`ButtonTheme`屬性军熏,自定義任意尺寸大小
//通過`padding`屬性,去除內(nèi)容邊距
class _SFHomeContentState extends State<SFHomeContent>{
final imageUrl = "";
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return Column(
children: [
ButtonTheme(
minWidth: 30,
height: 15,
child: FlatButton(
color: Colors.red,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
child: Text("FlatButton"),
textColor: Colors.white,
padding: EdgeInsets.all(0),
onPressed: (){
print("click FlatButton");
},
),
)
],
);
}
}
class ButtonExtra01 extends StatelessWidget {
const ButtonExtra01({
Key key,
}) : super(key: key);
//`materialTapTargetSize`屬性刃唐,去除間距
@override
Widget build(BuildContext context) {
return Column(
children: [
FlatButton(
color: Colors.red,
child: Text("FlatButton"),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Colors.white,
onPressed: (){
print("click FlatButton");
},
),
FlatButton(
color: Colors.red,
child: Text("FlatButton"),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
textColor: Colors.white,
onPressed: (){
print("click FlatButton");
},
)
],
);
}
}
圖片Widget
- Image:圖片組件,其構(gòu)造函數(shù)如下:
class Image extends StatefulWidget {
/// Creates a widget that displays an image.
///
/// To show an image from the network or from an asset bundle, consider using
/// [new Image.network] and [new Image.asset] respectively.
///
/// The [image], [alignment], [repeat], and [matchTextDirection] arguments
/// must not be null.
///
/// Either the [width] and [height] arguments should be specified, or the
/// widget should be placed in a context that sets tight layout constraints.
/// Otherwise, the image dimensions will change as the image is loaded, which
/// will result in ugly layout changes.
///
/// Use [filterQuality] to change the quality when scaling an image.
/// Use the [FilterQuality.low] quality setting to scale the image,
/// which corresponds to bilinear interpolation, rather than the default
/// [FilterQuality.none] which corresponds to nearest-neighbor.
///
/// If [excludeFromSemantics] is true, then [semanticLabel] will be ignored.
const Image({
Key key,
@required this.image,
this.frameBuilder,
this.loadingBuilder,
this.errorBuilder,
this.semanticLabel,
this.excludeFromSemantics = false,
this.width,
this.height,
this.color,
this.colorBlendMode,
this.fit,
this.alignment = Alignment.center,
this.repeat = ImageRepeat.noRepeat,
this.centerSlice,
this.matchTextDirection = false,
this.gaplessPlayback = false,
this.isAntiAlias = false,
this.filterQuality = FilterQuality.low,
})
-
@required this.image
:必選參數(shù)界轩,參數(shù)類型為ImageProvider
是一個(gè)抽象類画饥,常見子類有:NetworkImage
與AssetImage
NetworkImage加載網(wǎng)絡(luò)圖片
- 案例代碼如下:
class NetWorkImage extends StatelessWidget {
const NetWorkImage({
Key key,
@required this.imageUrl,
}) : super(key: key);
final String imageUrl;
@override
Widget build(BuildContext context) {
return Image(
image: NetworkImage(imageUrl),
width: 200,
height: 200,
fit: BoxFit.fill,
alignment: Alignment.bottomLeft,
repeat: ImageRepeat.repeatY,
);
}
}
-
fit
:圖片的顯示模式,等價(jià)于OC中的contentMode
-
alignment
:圖片的對(duì)齊方式浊猾; -
repeat
:當(dāng)圖片未填充滿控件時(shí)抖甘,可設(shè)置重復(fù)填充;
AssetImage加載本地圖片
- 首先在Flutter項(xiàng)目中引入圖片資源葫慎;
- 然后在
pub spec.yaml
文件中進(jìn)行配置衔彻,然后執(zhí)行flutter pub get
命令薇宠; - 最后使用圖片;
- 流程如下:
- 代碼案例:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("基礎(chǔ)widget")
),
body: SFHomeContent()
);
}
}
class SFHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
class _SFHomeContentState extends State<SFHomeContent>{
final imageUrl = "";
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return Image(
image: AssetImage("asset/images/180.png"),
);
}
}
- 案例代碼:
class ImageExtra extends StatelessWidget {
const ImageExtra({
Key key,
@required this.imageUrl,
}) : super(key: key);
final String imageUrl;
@override
Widget build(BuildContext context) {
return FadeInImage(
placeholder: AssetImage("asset/images/180.png"), //設(shè)置占位圖
image: NetworkImage(imageUrl),//設(shè)置網(wǎng)絡(luò)圖片
fadeOutDuration: Duration(milliseconds: 1),//淡入淡出的動(dòng)畫效果
fadeInDuration: Duration(milliseconds: 1),
);
}
}
-
placeholder
屬性可設(shè)置占位圖片艰额;
Icon圖標(biāo)
- 1.Icon可設(shè)置字體圖片與圖片圖標(biāo)澄港;
- 2.字體圖片與圖片圖標(biāo)是矢量圖,放大不會(huì)失真柄沮;
- 3.圖標(biāo)可設(shè)置顏色回梧;
- 案例代碼:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("基礎(chǔ)widget")
),
body: SFHomeContent()
);
}
}
class SFHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
class _SFHomeContentState extends State<SFHomeContent>{
final imageUrl = "";
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
//1.Icon可設(shè)置字體圖片與圖片圖標(biāo)
//2.字體圖片與圖片圖標(biāo)是矢量圖,放大不會(huì)失真
//3.圖標(biāo)可設(shè)置顏色
//4.下面三種寫法等價(jià)
return Icon(Icons.pets,size: 200,color: Colors.red);
// return Icon(IconData(0xe91d, fontFamily: 'MaterialIcons'),size: 200,color: Colors.red);
// return Text("\ue91d",style: TextStyle(fontSize: 100,fontFamily: 'MaterialIcons',color: Colors.red));
}
}
輸入框Widget -- TextField
- TextField的構(gòu)造函數(shù):
class TextField extends StatefulWidget {
/// Creates a Material Design text field.
///
/// If [decoration] is non-null (which is the default), the text field requires
/// one of its ancestors to be a [Material] widget.
///
/// To remove the decoration entirely (including the extra padding introduced
/// by the decoration to save space for the labels), set the [decoration] to
/// null.
///
/// The [maxLines] property can be set to null to remove the restriction on
/// the number of lines. By default, it is one, meaning this is a single-line
/// text field. [maxLines] must not be zero.
///
/// The [maxLength] property is set to null by default, which means the
/// number of characters allowed in the text field is not restricted. If
/// [maxLength] is set a character counter will be displayed below the
/// field showing how many characters have been entered. If the value is
/// set to a positive integer it will also display the maximum allowed
/// number of characters to be entered. If the value is set to
/// [TextField.noMaxLength] then only the current length is displayed.
///
/// After [maxLength] characters have been input, additional input
/// is ignored, unless [maxLengthEnforced] is set to false. The text field
/// enforces the length with a [LengthLimitingTextInputFormatter], which is
/// evaluated after the supplied [inputFormatters], if any. The [maxLength]
/// value must be either null or greater than zero.
///
/// If [maxLengthEnforced] is set to false, then more than [maxLength]
/// characters may be entered, and the error counter and divider will
/// switch to the [decoration.errorStyle] when the limit is exceeded.
///
/// The text cursor is not shown if [showCursor] is false or if [showCursor]
/// is null (the default) and [readOnly] is true.
///
/// The [selectionHeightStyle] and [selectionWidthStyle] properties allow
/// changing the shape of the selection highlighting. These properties default
/// to [ui.BoxHeightStyle.tight] and [ui.BoxWidthStyle.tight] respectively and
/// must not be null.
///
/// The [textAlign], [autofocus], [obscureText], [readOnly], [autocorrect],
/// [maxLengthEnforced], [scrollPadding], [maxLines], [maxLength],
/// [selectionHeightStyle], [selectionWidthStyle], and [enableSuggestions]
/// arguments must not be null.
///
/// See also:
///
/// * [maxLength], which discusses the precise meaning of "number of
/// characters" and how it may differ from the intuitive meaning.
const TextField({
Key key,
this.controller,
this.focusNode,
this.decoration = const InputDecoration(),
TextInputType keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
this.style,
this.strutStyle,
this.textAlign = TextAlign.start,
this.textAlignVertical,
this.textDirection,
this.readOnly = false,
ToolbarOptions toolbarOptions,
this.showCursor,
this.autofocus = false,
this.obscuringCharacter = '?',
this.obscureText = false,
this.autocorrect = true,
SmartDashesType smartDashesType,
SmartQuotesType smartQuotesType,
this.enableSuggestions = true,
this.maxLines = 1,
this.minLines,
this.expands = false,
this.maxLength,
this.maxLengthEnforced = true,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.inputFormatters,
this.enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
this.selectionHeightStyle = ui.BoxHeightStyle.tight,
this.selectionWidthStyle = ui.BoxWidthStyle.tight,
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection = true,
this.onTap,
this.mouseCursor,
this.buildCounter,
this.scrollController,
this.scrollPhysics,
this.autofillHints,
})
- 案例代碼如下:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: SFHomePage()
);
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("基礎(chǔ)widget")
),
body: SFHomeContent()
);
}
}
class SFHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
class _SFHomeContentState extends State<SFHomeContent>{
final usernameTextEditController = TextEditingController();
final passwordTextEditController = TextEditingController();
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return Theme(
data: ThemeData(
primaryColor: Colors.red
),
child: Padding(
padding: EdgeInsets.all(8.0),
child:Column(
children: [
TextField(
controller: usernameTextEditController,
decoration: InputDecoration(
labelText: "username",
icon: Icon(Icons.people),
hintText: "請(qǐng)輸入用戶名",
border: OutlineInputBorder(),
filled: true,
fillColor: Colors.red[100],
),
onChanged: (value){
print("onChanged:$value");
},
onSubmitted: (value){
print("onSubmitted:$value");
},
),
SizedBox(height: 10),
TextField(
controller: passwordTextEditController,
decoration: InputDecoration(
labelText: "password",
icon: Icon(Icons.lock),
hintText: "請(qǐng)輸入密碼",
border: InputBorder.none,
filled: true,
fillColor: Colors.red[100],
),
onChanged: (value){
print("onChanged:$value");
},
onSubmitted: (value){
print("onSubmitted:$value");
},
),
SizedBox(height: 20),
Container(
width: 300,
height: 35,
child: FlatButton(
child: Text("登 錄",style: TextStyle(fontSize: 20,color: Colors.white)),
color: Colors.blue,
onPressed: (){
print("login");
final username = usernameTextEditController.text;
final password = passwordTextEditController.text;
print("username = $username,password = $password");
},
),
)
],
)
)
);
}
}
- 運(yùn)行結(jié)果如下:
-
Theme
:設(shè)置整個(gè)UI的主題風(fēng)格祖搓; - 給目標(biāo)組件
設(shè)置寬高
狱意,通常是在目標(biāo)組件外面再包裝一層Container
,然后設(shè)置width
與height
屬性拯欧; -
onChanged
:監(jiān)聽輸入框文本變化的回調(diào)详囤; -
onSubmitted
:監(jiān)聽輸入框提交時(shí)的回調(diào); - 在登錄按鈕的點(diǎn)擊回調(diào)中镐作,獲取輸入框的文本是通過給輸入框綁定一個(gè)
TextEditingController
藏姐,然后通過TextEditingController.text
獲取輸入框的文本;
單子布局組件
- 常見的單子布局組件有:Align滑肉,Center包各,Padding,Container
Align組件
- Align:即對(duì)齊;
- Center組件:是繼承自Align組件的靶庙,本質(zhì)上Align與Center等價(jià)问畅;
- 案例代碼如下:
class _SFHomeContentState extends State<SFHomeContent>{
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return Container(
color: Colors.red,
child: Align(
child: Icon(Icons.pets,size: 50),
alignment: Alignment(0,0),
widthFactor: 5,
heightFactor: 3,
),
);
}
}
- Align默認(rèn)占據(jù)整個(gè)屏幕大小六荒;
- widthFactor與heightFactor 是child的尺寸的倍數(shù)大小 作為Align的尺寸大谢つ贰;
Padding組件
- Padding:主要用來設(shè)置子Widget到父Widget的邊距掏击;
- 其構(gòu)造函數(shù):
const Padding({
Key key,
@required this.padding,
Widget child,
})
- 案例代碼:
class _SFHomeContentState extends State<SFHomeContent>{
@override
Widget build(BuildContext context) {
print("_SFHomeContentState build");
return Column(
children: [
Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Text("日你啊滿滿的個(gè)單",style: TextStyle(fontSize: 20,backgroundColor: Colors.red)),
),
Padding(
padding: const EdgeInsets.only(bottom: 5),
child: Text("日你啊滿滿的個(gè)單",style: TextStyle(fontSize: 20,backgroundColor: Colors.red)),
),
Text("日你啊滿滿的個(gè)單",style: TextStyle(fontSize: 20,backgroundColor: Colors.red))
],
);
}
}
Container組件
- Container:顧名思義為容器組件卵皂,
- 其構(gòu)造函數(shù)如下:
Container({
Key key,
this.alignment,
this.padding,
this.color,
this.decoration,
this.foregroundDecoration,
double width,
double height,
BoxConstraints constraints,
this.margin,
this.transform,
this.child,
this.clipBehavior = Clip.none,
})
- 案例代碼:
class _SFHomeContentState extends State<SFHomeContent>{
@override
Widget build(BuildContext context) {
return Container(
// color: Colors.red,
width: 200,
height: 200,
child: Text("這是一個(gè)文本",style: TextStyle(color: Colors.white),),
alignment: Alignment(0,0),
padding: EdgeInsets.all(20),
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
color: Colors.red,
border: Border.all(
width: 5,
color: Colors.purple
),
borderRadius: BorderRadius.circular(100),
boxShadow: [
BoxShadow(color: Colors.orange,offset: Offset(10,10),spreadRadius: 5,blurRadius: 10),
BoxShadow(color: Colors.blue,offset: Offset(-10,10),spreadRadius: 5,blurRadius: 10)
]
),
);
}
}
-
padding
:設(shè)置容器內(nèi)間距; -
margin
:設(shè)置容器外間距砚亭; -
decoration
:設(shè)置裝飾灯变,內(nèi)部包含邊框,圓角捅膘,陰影等等添祸; - 效果圖:
多子布局組件
- 常見的多子布局組件有:Flex,Row寻仗,Column
Flex組件
- Row組件與Column組件都是繼承自Flex組件刃泌;
- 主軸:mainAxis即主方向的軸;
- 交叉軸:crosssAxis
Row組件
Row的主軸方向?yàn)椋核椒较颍徊孑S為豎直方向耙替;
-
Row在主軸方向即
水平方向
上占據(jù)比較大的空間
亚侠;- 若在水平方向上希望包裹內(nèi)容,那么設(shè)置
mainAxisSize = min
俗扇;
- 若在水平方向上希望包裹內(nèi)容,那么設(shè)置
Row在交叉軸方向即
豎直方向
上包裹內(nèi)容
硝烂;-
mainAxisAlignment
:主軸方向上的對(duì)齊方式-
start
:主軸的開始位置依次擺放元素; -
end
:主軸的結(jié)束位置依次擺放元素狐援; -
center
:主軸中心點(diǎn)對(duì)齊钢坦; -
spaceBetween
:左右間距為0,其他元素之間間距平分啥酱; -
spaceAround
:左右間距是其他元素之間間距的一半爹凹; -
spaceEvenly
:所有間距平分;
-
-
crossAxisAlignment
:交叉方向上的對(duì)齊方式-
start
:交叉軸的開始位置依次擺放元素镶殷; -
end
:交叉軸的結(jié)束位置依次擺放元素禾酱; -
center
:交叉軸中心點(diǎn)對(duì)齊; -
textBaseline
:基線對(duì)齊(必須有文本內(nèi)容才有效果)绘趋; -
stretch
:將所有子元素颤陶,拉伸到最大;
-
案例代碼:mainAxisSize = min
class _SFHomeContentState extends State<SFHomeContent>{
@override
Widget build(BuildContext context) {
return RaisedButton(
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Icon(Icons.bug_report),
Text("bug")
],
),
);
}
}
- 案例代碼:
class RowDemo extends StatelessWidget {
const RowDemo({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
textBaseline: TextBaseline.alphabetic,
children: [
Container(width: 80,height: 60,color: Colors.red),
Container(width: 80,height: 80,color: Colors.green),
Container(width: 80,height: 100,color: Colors.blue),
Container(width: 80,height: 120,color: Colors.orange),
],
);
}
}
Flexible與Expanded
-
Flexible
:空間拉伸與收縮陷遮,占滿空間滓走; -
Expanded
:空間拉伸與收縮,占滿空間帽馋,與Flexible
效果等價(jià)搅方,區(qū)別在與使用Expanded
不用再設(shè)置fit: FlexFit.tight
,因?yàn)?code>Expanded在內(nèi)部已經(jīng)設(shè)置了绽族,所以其使用更廣姨涡; - 空間剩余時(shí),會(huì)進(jìn)行拉伸占滿剩余空間吧慢;
- 空間不足時(shí)涛漂,會(huì)收縮子widget,占滿空間检诗;
class RowDemo2 extends StatelessWidget {
const RowDemo2({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
textBaseline: TextBaseline.alphabetic,
children: [
Flexible(
child: Container(width: 80,height: 60,color: Colors.red),
fit: FlexFit.tight,
),
Expanded(
child: Container(width: 80,height: 80,color: Colors.green),
),
Container(width: 80,height: 100,color: Colors.blue),
Container(width: 80,height: 120,color: Colors.orange),
],
);
}
}
這里補(bǔ)充個(gè)小知識(shí)點(diǎn):
如果children中出現(xiàn)2個(gè)Flexible或者Expand匈仗,那么剩余空間會(huì)根據(jù)兩個(gè)Expand的Flex比例來填充,如果沒有設(shè)置Flex逢慌,那么默認(rèn)的Flex值為1
Column組件
- Column的主軸方向?yàn)椋贺Q直方向悠轩,交叉軸為水平方向;
- 與Row組件類似涕癣,只是子組件在主軸方向即豎直方向上排列哗蜈;
Stack組件
- 在開發(fā)中,我們多個(gè)組件可能需要
重疊顯示
坠韩,在Android中使用Frame布局實(shí)現(xiàn)距潘,而在Flutter中我們需要使用層疊布局Stack
來實(shí)現(xiàn); - 內(nèi)部子組件默認(rèn)從左上角開始排布只搁;
- Stack默認(rèn)的大小是包裹內(nèi)容的尺寸大幸舯取;
- 參數(shù)alignment:表示從什么位置開始排布所有的子組件氢惋;
- 參數(shù)fit:expand表示將所有子組件拉伸到最大洞翩;
- 參數(shù)overflow:對(duì)于超出父組件區(qū)域的子組件的處理
- flip:超出部分被裁減;
- visible:超出部分依然顯示焰望; - 案例代碼:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: SFHomePage());
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("基礎(chǔ)widget")), body: SFHomeContent());
}
}
class SFHomeContent extends StatefulWidget {
@override
State<StatefulWidget> createState() {
print("createState");
return _SFHomeContentState();
}
}
class _SFHomeContentState extends State<SFHomeContent> {
@override
Widget build(BuildContext context) {
return StackDemo1();
}
}
class StackDemo2 extends StatelessWidget {
const StackDemo2({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
Container(
height: 200,
child: Image.asset("asset/images/180.png", fit: BoxFit.fill),
width: double.infinity),
Positioned(
child: Container(
child: Row(
children: [
Text("這是一行文本", style: TextStyle(fontSize: 17, color: Colors.white)),
IconButton(icon: Icon(Icons.favorite),color: Colors.white,onPressed: (){
})
],
mainAxisAlignment: MainAxisAlignment.spaceBetween,
),
color: Color.fromARGB(150, 0, 0, 0),
width: double.infinity,
padding: EdgeInsets.symmetric(horizontal: 8),
),
left: 0,
right: 0,
bottom: 0,
)
],
);
}
}
class StackDemo1 extends StatelessWidget {
const StackDemo1({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Stack(
children: [
Image.asset("asset/images/180.png"),
Positioned(
child: Container(
width: 100,
height: 100,
color: Colors.green,
),
right: 0,
),
Positioned(
child: Text("推客圖標(biāo)", style: TextStyle(fontSize: 20)),
left: 0,
)
],
alignment: AlignmentDirectional.bottomStart,
overflow: Overflow.visible,
);
}
}
- StackDemo1與StackDemo2的效果圖如下:
- 滾動(dòng)組件有
ListView
骚亿,GridView
,Sliver
ListView
- ListView創(chuàng)建的方式通常有三種熊赖,分別為
ListView()
来屠,ListView.builder()
,ListView.separated()
ListView創(chuàng)建方式
- 第一種方式:
ListView()
- 案例代碼:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: SFHomePage());
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("基礎(chǔ)widget")), body: SFHomeContent());
}
}
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
scrollDirection: Axis.vertical,
itemExtent: 100,//設(shè)置Item的高度
children: List.generate(100, (index) {
return ListTile(
leading: Icon(Icons.people),
trailing: Icon(Icons.delete),
title: Text("聯(lián)系人${index+1}"),
subtitle: Text("聯(lián)系人電話號(hào)碼:19991604555"),
);
}),
);
}
}
-
ListTile
組件就是ListView的Item震鹉; -
itemExtent
:設(shè)置Item的高度俱笛; - 效果圖如下:
通過
ListView()
創(chuàng)建,會(huì)一次性創(chuàng)建100個(gè)Item传趾,這樣性能比較差迎膜,其適用于Item個(gè)數(shù)確定,且數(shù)量較少的情況下才會(huì)采用浆兰;第二種方式:
ListView.builder()
ListView.builder()
不會(huì)一次性創(chuàng)建所有Item磕仅,而是需要展示的Item才會(huì)去創(chuàng)建,性能較好镊讼;案例代碼如下:
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: 100,
itemExtent: 50,
itemBuilder: (BuildContext ctx, int index){
return Text("Hello World!!! ${index}",style: TextStyle(fontSize: 20),);
}
);
}
}
- 第三種方式:
ListView.separated()
- 案例代碼如下:
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView.separated(
itemBuilder: (BuildContext ctx, int index){
return Text("Hello World!!! ${index}",style: TextStyle(fontSize: 20),);
},
//分割線
separatorBuilder: (BuildContext ctx,int index){
return Divider(color: Colors.red,indent: 20,endIndent: 20,thickness: 5);
},
itemCount: 100
);
}
}
-
itemBuilder
:創(chuàng)建Item宽涌; -
separatorBuilder
:創(chuàng)建分割線;
GridView
- GridView的創(chuàng)建方式有:
GridView()
蝶棋,GridView.builder()
- 案例代碼一:
GridView()
+SliverGridDelegateWithFixedCrossAxisCount
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GridView(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 1.5,
crossAxisSpacing: 8,
mainAxisSpacing: 8
),
children:
List.generate(100, (index) {
return Container(
color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256), Random().nextInt(256)),
);
}),
);
}
}
-
SliverGridDelegateWithFixedCrossAxisCount
:交叉軸方向上item數(shù)量固定卸亮,其寬度根據(jù)屏幕的寬度與item的數(shù)量進(jìn)行計(jì)算;-
crossAxisCount
:item的個(gè)數(shù)玩裙; -
childAspectRatio
:item的寬高比兼贸; -
crossAxisSpacing
:交叉軸方向上 item之間的間距; -
mainAxisSpacing
:主軸方向上 item之間的間距吃溅;
-
案例代碼二:
GridView()
+SliverGridDelegateWithMaxCrossAxisExtent
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GridView(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 220,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 1.5
),
children: List.generate(100, (index) {
return Container(
color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256),Random().nextInt(256)),
);
})
);
}
}
-
SliverGridDelegateWithMaxCrossAxisExtent
:交叉軸方向上的設(shè)置item寬度溶诞,個(gè)數(shù)不固定;-
maxCrossAxisExtent
:item的最大寬度决侈;
-
案例代碼三:
GridView.builder()
+SliverGridDelegateWithFixedCrossAxisCount
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
crossAxisSpacing: 8,
mainAxisSpacing: 8
),
itemBuilder: (BuildContext ctx,int index){
return Container(
color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256),Random().nextInt(256)),
);
}
);
}
}
Slivers -- CustomScrollView
CustomScrollView
:自定義滾動(dòng)組件螺垢,需要傳入Slivers
即Sliver數(shù)組,我們知道ListView
與GridView
都是繼承自BoxScrollView
,而BoxScrollView
是一個(gè)抽象類枉圃,從源碼來看ListView
與GridView
在察創(chuàng)建的過程中都需要執(zhí)行buildSlivers
方法功茴,其內(nèi)部調(diào)用buildChildLayout
方法,這是一個(gè)抽象方法孽亲,分別由ListView
與GridView
來實(shí)現(xiàn)坎穿,最終提供一個(gè)Sliver數(shù)組
,其中ListView
提供的Sliver為SliverFixedExtentList
返劲,GridView
提供的Sliver為SliverGrid
案例代碼:單個(gè)Sliver
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: SFHomePage());
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("基礎(chǔ)widget")),
body: SFHomeContent());
}
}
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return SliverDemo1();
}
}
class SliverDemo1 extends StatelessWidget {
const SliverDemo1({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverSafeArea(
sliver: SliverPadding(
padding: EdgeInsets.all(8),
sliver: SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 1.5
),
delegate: SliverChildBuilderDelegate(
(BuildContext ctx,int index){
return Container(
color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256),Random().nextInt(256)),
);
},
childCount: 100
),
),
),
)
],
);
}
}
自定義CustomScrollView玲昧,需傳入Slivers數(shù)組,這里傳入的Sliver為
SliverGrid
篮绿;參數(shù)
gridDelegate
:是提供布局信息孵延;參數(shù)
delegate
:是提供item組件,類型為SliverChildDelegate
亲配;-
SliverChildDelegate是抽象類隙袁,其作用是用來創(chuàng)建滾動(dòng)組件的item,其有兩個(gè)子類分別為
SliverChildListDelegate
與SliverChildBuilderDelegate
-
SliverChildListDelegate
:性能較差弃榨,item一次性創(chuàng)建所有菩收; -
SliverChildBuilderDelegate
:性能較好,創(chuàng)建需要展示的item鲸睛;
-
-
SafeArea
與SliverSafeArea
的區(qū)別:- SafeArea:安全區(qū)域娜饵,讓目標(biāo)組件在安全區(qū)域內(nèi)顯示;
- SliverSafeArea:給Sliver設(shè)置安全區(qū)域官辈,且在滾動(dòng)時(shí)可以在非安全區(qū)域內(nèi)滾動(dòng)箱舞,而SafeArea不可以;
SliverPadding
:是Sliver自己的設(shè)置內(nèi)邊距的組件拳亿;案例代碼:多個(gè)Sliver
import 'dart:math';
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: SFHomePage());
}
}
class SFHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
// appBar: AppBar(title: Text("基礎(chǔ)widget")),
body: SFHomeContent());
}
}
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return CustomScrollView(
slivers: [
SliverAppBar(
pinned: true,
expandedHeight: 200,
flexibleSpace: FlexibleSpaceBar(
title: Text("Hello World!!",style: TextStyle(fontSize: 25),),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 2.5
),
delegate: SliverChildBuilderDelegate(
(BuildContext ctx,int index){
return Container(
color: Color.fromARGB(255, Random().nextInt(256), Random().nextInt(256),Random().nextInt(256)),
);
},
childCount: 10
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext ctx,int index){
return ListTile(
leading: Icon(Icons.people),
title: Text("聯(lián)系人$index"),
);
},
childCount: 20
),
)
],
);
}
}
-
slivers
數(shù)組中傳入了SliverAppBar
晴股,SliverGrid
與SliverList
三種類型的Sliver,效果如下:
滾動(dòng)組件的監(jiān)聽
- 滾動(dòng)組件的監(jiān)聽通常有兩種方式肺魁,分別為
controller
與NotificationListener
controller監(jiān)聽
- 可以設(shè)置默認(rèn)值offset电湘;
- 監(jiān)聽滾動(dòng),也可以監(jiān)聽滾動(dòng)的位置鹅经;
- 案例代碼:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: SFHomePage());
}
}
class SFHomePage extends StatefulWidget {
@override
_SFHomePageState createState() => _SFHomePageState();
}
class _SFHomePageState extends State<SFHomePage> {
ScrollController controller = ScrollController(initialScrollOffset: 300);
bool isShowFloatButton = false;
@override
void initState() {
super.initState();
controller.addListener(() {
print("監(jiān)聽到滾動(dòng): ${controller.offset}");
setState(() {
isShowFloatButton = controller.offset >= 1000;
});
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("基礎(chǔ)widget")),
body: SFHomeContent(controller),
floatingActionButton: isShowFloatButton ? FloatingActionButton(
child: Icon(Icons.arrow_upward),
onPressed: (){
controller.animateTo(0, duration: Duration(seconds: 1), curve: Curves.easeIn);
},
) : null,
);
}
}
class SFHomeContent extends StatelessWidget {
final ScrollController controller;
SFHomeContent(this.controller);
@override
Widget build(BuildContext context) {
return ListView.builder(
controller: controller,
itemBuilder: (BuildContext ctx, int index) {
return ListTile(
leading: Icon(Icons.people),
title: Text("聯(lián)系人$index"),
);
},
itemCount: 100,
);
}
}
- 右下角懸浮按鈕寂呛,當(dāng)前滾動(dòng)偏移量>=1000時(shí)顯示;
NotificationListener監(jiān)聽
- 案例代碼:
import 'package:flutter/material.dart';
void main() => runApp(SFMyApp());
class SFMyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(home: SFHomePage());
}
}
class SFHomePage extends StatefulWidget {
@override
_SFHomePageState createState() => _SFHomePageState();
}
class _SFHomePageState extends State<SFHomePage> {
bool isShowFloatButton = false;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("基礎(chǔ)widget")),
body: SFHomeContent(),
floatingActionButton: isShowFloatButton
? FloatingActionButton(
child: Icon(Icons.arrow_upward),
onPressed: () {
},
)
: null,
);
}
}
class SFHomeContent extends StatelessWidget {
@override
Widget build(BuildContext context) {
return NotificationListener(
onNotification: (ScrollNotification notification){
if(notification is ScrollStartNotification){
print("開始滾動(dòng)");
}else if (notification is ScrollUpdateNotification){
print("正在滾動(dòng) -- 總區(qū)域:${notification.metrics.maxScrollExtent} 當(dāng)前位置: ${notification.metrics.pixels}");
}else if (notification is ScrollEndNotification){
print("結(jié)束滾動(dòng)");
}
return true;
},
child: ListView.builder(
itemBuilder: (BuildContext ctx, int index) {
return ListTile(
leading: Icon(Icons.people),
title: Text("聯(lián)系人$index"),
);
},
itemCount: 100,
),
);
}
}
總結(jié)
現(xiàn)在對(duì)以上出現(xiàn)的所有Widget做一個(gè)總結(jié)瘾晃,主要針對(duì)繼承關(guān)系:
-
以
StatelessWidget
為中心的Widget組件有如下:
-
以
StatefulWidget
為中心的Widget組件有如下:
-
以
RenderObjectWidget
為中心的Widget組件有如下: