溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Flutter常用的布局和事件示例詳解

發(fā)布時(shí)間:2020-08-23 19:27:25 來源:腳本之家 閱讀:209 作者:JakePrim 欄目:移動(dòng)開發(fā)

Flutter 項(xiàng)目中常用的布局詳情,及封裝和使用,快速開發(fā)項(xiàng)目.

以及手勢事件和滾動(dòng)事件的使用

Scaffold 導(dǎo)航欄的實(shí)現(xiàn),有些路由頁可能會(huì)有抽屜菜單(Drawer)以及底部Tab導(dǎo)航菜單等

const Scaffold({
 Key key,
 this.appBar,//標(biāo)題欄
 this.body,//內(nèi)容
 this.floatingActionButton,//懸浮按鈕
 this.persistentFooterButtons,//底部持久化現(xiàn)實(shí)按鈕
 this.drawer,//側(cè)滑菜單左
 this.endDrawer,//側(cè)滑菜單右
 this.bottomNavigationBar,//底部導(dǎo)航
 this.backgroundColor,//背景顏色
 this.resizeToAvoidBottomPadding: true,//自動(dòng)適應(yīng)底部padding
 this.primary: true,//使用primary主色
 })

Flutter 中自帶的material樣式的標(biāo)題欄,首先看一下AppBar具有哪些屬性,代碼如下:

AppBar({
 Key key,
 this.leading,//主導(dǎo)Widget
 this.automaticallyImplyLeading: true,
 this.title,//標(biāo)題
 this.actions,//其他附加功能
 this.flexibleSpace,//伸縮空間,顯示在title上面
 this.bottom,//顯示在title下面
 this.elevation: 4.0,//陰影高度
 this.backgroundColor,//背景顏色
 this.brightness,//明暗模式
 this.iconTheme,//icon主題
 this.textTheme,//text主題
 this.primary: true,//是否是用primary
 this.centerTitle,//標(biāo)題是否居中
 this.titleSpacing: NavigationToolbar.kMiddleSpacing,//title與leading的間隔
 this.toolbarOpacity: 1.0,//title級文字透明度
 this.bottomOpacity: 1.0,//底部文字透明度
 })

懸浮button 屬性詳解

const FloatingActionButton({
 Key key,
 this.child,//button的顯示樣式
 this.tooltip,//提示,長按按鈕提示文字
 this.backgroundColor,//背景顏色
 this.heroTag: const _DefaultHeroTag(),//頁面切換動(dòng)畫Tag
 this.elevation: 6.0,//陰影
 this.highlightElevation: 12.0,//高亮陰影
 @required this.onPressed,//點(diǎn)擊事件
 this.mini: false//是否使用小圖標(biāo)
 })

底部導(dǎo)航欄BottomNavigationBar的實(shí)現(xiàn),與經(jīng)常搭配的PageView實(shí)現(xiàn)項(xiàng)目中常用的tab切換

Flutter常用的布局和事件示例詳解

Scaffold(
 body: PageView(
 controller: _controller,
 children: <Widget>[//page的頁面
 HomePage(),
 SearchPage(),
 TravelPage(),
 MinePage(),
 ],
 onPageChanged: (int index) {//滑動(dòng)page的監(jiān)聽
 setState(() {//改變tab狀態(tài)
 _controllerIndex = index;
 });
 },
 ),
 bottomNavigationBar: BottomNavigationBar(
 currentIndex: _controllerIndex, //當(dāng)前的index
 onTap: (index) {//點(diǎn)擊tab
 _controller.jumpToPage(index); //跳轉(zhuǎn)到具體的頁面
 //注意改變_controllerIndex的狀態(tài)
 setState(() {
 _controllerIndex = index;
 });
 },
 type: BottomNavigationBarType.fixed,//固定
 items: [//底部tab圖片、字體及顏色
 homeItem(),
 searchItem(),
 travelItem(),
 mineItem(),
 ]),
 );

BottomNavigationBarItem的實(shí)現(xiàn)

BottomNavigationBarItem mineItem() {
 return BottomNavigationBarItem(
 icon: Icon(
 //定義默認(rèn)狀態(tài)下的圖片以及顏色
 Icons.supervised_user_circle,
 color: _defaultColor,
 ),
 activeIcon: Icon(
 //定義選中狀態(tài)下的圖片以及顏色
 Icons.supervised_user_circle,
 color: _activityColor,
 ),
 title: Text(
 //定義文字
 '我的',
 style: TextStyle(
 color: _controllerIndex != 3 ? _defaultColor : _activityColor,
 ),
 ));
}

Container

Container({
 	Key key,
 	this.alignment,//內(nèi)部widget對齊方式
 this.padding,//內(nèi)邊距
 	Color color,//背景顏色,與decoration只能存在一個(gè)
 Decoration decoration,//背景裝飾,與decoration只能存在一個(gè)
 this.foregroundDecoration//前景裝飾,
 double width,//容器的寬
 	double height,//容器的高
 	BoxConstraints constraints//,
 	this.margin,//外邊距
 	this.transform,//傾斜
 	this.child,//子widget
})

alignment: 內(nèi)部Widget對齊方式,左上對齊topLeft、垂直頂部對齊,水平居中對齊topCenter、右上topRight、垂直居中水平左對齊centerLeft、居中對齊center、垂直居中水平又對齊centerRight、底部左對齊bottomLeft、底部居中對齊bottomCenter、底部右對齊bottomRight

padding: 內(nèi)間距,子Widget距Container的距離。

color: 背景顏色

decoration: 背景裝飾

foregroundDecoration: 前景裝飾

width:容器的寬

height:容器的高

constraints:容器寬高的約束,容器最終的寬高最終都要受到約束中定義的寬高影響

margin:容器外部的間隔

transform: Matrix4變換

child:內(nèi)部子Widget

可以通過decoration裝飾器實(shí)現(xiàn)圓角和邊框,漸變等

decoration: BoxDecoration(
 border: Border(
 bottom:
 BorderSide(width: 1, color: Color(0xfff2f2f2))), //設(shè)置底部分割線
 ),
 borderRadius: BorderRadius.circular(12), //設(shè)置圓角
 gradient: LinearGradient(
 colors: [
 Color(0xffff4e63),
 Color(0xffff6cc9),
 ],
 begin: Alignment.centerLeft,
 end: Alignment.centerRight,
 ), //
 )

設(shè)置網(wǎng)絡(luò)圖片

Image.network(
 salesBoxModel.icon,
 fit: BoxFit.fill,
 height: 15,
 ),

設(shè)置行布局

Column({
 Key key,
 MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,//主軸X 排列方式
 MainAxisSize mainAxisSize = MainAxisSize.max,
 CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,//縱軸排列方式
 TextDirection textDirection,
 VerticalDirection verticalDirection = VerticalDirection.down,
 TextBaseline textBaseline,
 List<Widget> children = const <Widget>[],
 })

設(shè)置列布局

Row({
 Key key,
 MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
 MainAxisSize mainAxisSize = MainAxisSize.max,
 CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
 TextDirection textDirection,
 VerticalDirection verticalDirection = VerticalDirection.down,
 TextBaseline textBaseline,
 List<Widget> children = const <Widget>[],
 })

設(shè)置內(nèi)邊距Padding

Padding 也是一個(gè)Widget,它內(nèi)部可以包裹一個(gè)Widget

Padding(
 padding: EdgeInsets.only(top: 10),
 child: Text(
 model.title,
 style: TextStyle(
 fontSize: 14,
 color: Colors.white,
 ),
 ),
 )

設(shè)置寬度/高度撐滿父布局FractionallySizedBox

FractionallySizedBox({
 Key key,
 this.alignment = Alignment.center,
 this.widthFactor,//設(shè)置為1 則寬度撐滿父布局
 this.heightFactor,//設(shè)置為1 則高度撐滿父布局
 Widget child,//包裹的子Widget
 })

Expanded撐滿整個(gè)界面

Expanded({
 Key key,
 int flex = 1,
 @required Widget child,
 })

Stack 可以理解為棧布局,先放入的顯示在最下面,后放入的顯示在上面,跟Android中的ReaviteLayout相似

Stack({
 Key key,
 this.alignment: AlignmentDirectional.topStart,//對齊方式
 this.textDirection,
 this.fit: StackFit.loose,//是否按照父類寬高處理自己大小
 this.overflow: Overflow.clip,//溢出處理方式
 List<Widget> children: const <Widget>[],
 })

我們可以用Stack來實(shí)現(xiàn):請求網(wǎng)絡(luò)中的時(shí)候,顯示加載中的布局;請求網(wǎng)絡(luò)成功后,隱藏加載中的布局,顯示成功的布局.
自定義一個(gè)LoadingWidget,傳遞isLoading是否正在加載中,child加載成功后顯示的布局.這樣的好處就是我們可以在任何需要用到加載中的布局時(shí),直接使用,統(tǒng)一管理.使用setState來改變isLoading,來實(shí)現(xiàn)狀態(tài)的改變.

class LoadingWidget extends StatelessWidget {
 final bool isLoading;
 final bool cover;
 final Widget child;

 //required必須傳遞的參數(shù)
 const LoadingWidget(
 {Key key,
 @required this.isLoading,
 this.cover = false,
 @required this.child})
 : super(key: key);

 @override
 Widget build(BuildContext context) {
 return !cover
 ? !isLoading ? child : _loadingView
 : Stack(
 children: <Widget>[child, isLoading ? _loadingView : null],
 );
 }

 Widget get _loadingView {
 return Center(
 child: CircularProgressIndicator(), //圓形的進(jìn)度條
 );
 }
}

看一個(gè)簡單調(diào)用的例子.

class _HomePageState extends State<HomePage> {
bool isLoading = true;//默認(rèn)是加載中的狀態(tài)
 @override
 void initState() {
 super.initState();
 _handleRefresh();
 }

 Future<Null> _handleRefresh() async {
 try {
 HomeModel model = await HomeDao.fetch();
 setState(() {
 gridNavList = model.localNavList;
 girdModeList = model.gridNav;
 subNavList = model.subNavList;
 salesBoxModel = model.salesBox;
 bannerList = model.bannerList;
 isLoading = false;
 });
 } catch (e) {
 print(e.toString());
 setState(() {
 isLoading = false;
 });
 }
 return null;
 }
 
 @override
 Widget build(BuildContext context) {
 return Scaffold(
 backgroundColor: Color(0xfff2f2f2),
 body: LoadingWidget(//使用自定義的布局
 isLoading: isLoading,
 //加載成功后顯示的View
 child: Stack(
 .......
 )
 )
 );
 }
}

當(dāng)然,Stack還有很多其他的使用場景,可自行翻閱文檔Stack

IndexedStack

只不過IndexedStack只顯示指定位置的Widget,其他的位置的Widget不會(huì)顯示。

PageView 類似Android中的ViewPage組件,他還可以實(shí)現(xiàn)底部導(dǎo)航欄的效果
Flutter官網(wǎng)PageView

首先看一下PageView有哪些屬性,代碼如下:

PageView({
 Key key,
 this.scrollDirection = Axis.horizontal,
 this.reverse = false,
 PageController controller,
 this.physics,
 this.pageSnapping = true,
 this.onPageChanged,
 List<Widget> children = const <Widget>[],
 this.dragStartBehavior = DragStartBehavior.down,
 }) : controller = controller ?? _defaultPageController,
 childrenDelegate = SliverChildListDelegate(children),
 super(key: key);

來看一下各個(gè)屬性的意思

this.scrollDirection = Axis.horizontal,Axis.vertical//設(shè)置滾動(dòng)方向 橫向和豎向

pageSnapping true 帶有阻力的滑動(dòng),如果設(shè)置為false滑動(dòng)到哪就停止到哪

controller 頁面控制器,通過調(diào)用jumpToPage 實(shí)現(xiàn)頁面的跳轉(zhuǎn)

BottomNavigationBar

BottomNavigationBar({
 Key key,
 @required this.items,
 this.onTap,//點(diǎn)擊事件
 this.currentIndex = 0,//當(dāng)前的位置
 BottomNavigationBarType type,//底部固定和隱藏類型
 this.fixedColor,
 this.iconSize = 24.0,//圖片的大小
 })

final List<BottomNavigationBarItem> items;

BottomNavigationBarItem 定義底部的icon 選中的icon 文字

const BottomNavigationBarItem({
 @required this.icon,
 this.title,
 Widget activeIcon,
 this.backgroundColor,
 }) : activeIcon = activeIcon ?? icon,
 assert(icon != null);

底部固定

enum BottomNavigationBarType {
 /// The [BottomNavigationBar]'s [BottomNavigationBarItem]s have fixed width, always
 /// display their text labels, and do not shift when tapped.
 fixed,

 /// The location and size of the [BottomNavigationBar] [BottomNavigationBarItem]s
 /// animate and labels fade in when they are tapped. Only the selected item
 /// displays its text label.
 shifting,
}

手勢事件GestureDetector

GestureDetector 手勢監(jiān)聽,它可以包裹任何Widget并處理包裹Widget的點(diǎn)擊、滑動(dòng)、雙擊等事件,GestureDetector extends StatelessWidget 可以直接return Widget

來看一個(gè)Widget觸發(fā)點(diǎn)擊事件的例子

GestureDetector(
 onTap: () {
 CommonModel model = bannerList[index];
 Navigator.push(
 context,
 MaterialPageRoute(
 builder: (context) => WebView(
 url: model.url,
 title: model.title,
 statusBarColor: model.statusBarColor,
 hideAppBar: model.hideAppBar,
 )));
 },
 child: Image.network(bannerList[index].icon,
 fit: BoxFit.fill), //加載網(wǎng)絡(luò)圖片,
 );

另外關(guān)于其他的雙擊、滑動(dòng)等事件可自行翻閱文檔.GestureDetector

滾動(dòng)事件NotificationListener

NotificationListener 可用于監(jiān)聽所有Widget的滾動(dòng)事件,不管使用何種Widget都可以很方便的進(jìn)行處理

NotificationListener(
 //滾動(dòng)監(jiān)聽 list view
 onNotification: (scrollNotification) {
 //監(jiān)聽滾動(dòng)的距離ScrollUpdateNotification 滾動(dòng)時(shí)在進(jìn)行回調(diào)
 if (scrollNotification is ScrollUpdateNotification &&
 scrollNotification.depth == 0) {
 //只檢測listview的滾動(dòng)第0個(gè)元素widget時(shí)候才開始滾動(dòng)
 _scroll(scrollNotification.metrics.pixels);
 }
 },
 child: _buildListView,
 ),

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對億速云的支持。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI