您好,登錄后才能下訂單哦!
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切換
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à)值,謝謝大家對億速云的支持。
免責(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)容。