摘要:緊接上一篇的有側邊欄,這次我們向中加入上下頁,使之跟趨近主流大部分的信息布局套路,等不及看源碼的同學可以點擊進入我的倉庫下載代碼。子元素為類型的數組。頁的內容容器,其內放置頁的主體內容。
緊接上一篇的有側邊欄APP,這次我們向APP中加入上下Tab頁,使之跟趨近主流大部分APP的信息布局套路,等不及看源碼的同學可以點擊進入我的git倉庫下載代碼。
Tab關鍵元素TabController
這是Tab頁的控制器,用于定義Tab標簽和內容頁的坐標,還可配置標簽頁的切換動畫效果等。
TabController一般放入有狀態控件中使用,以適應標簽頁數量和內容有動態變化的場景,如果標簽頁在APP中是靜態固定的格局,則可以在無狀態控件中加入簡易版的DefaultTabController以提高運行效率,畢竟無狀態控件要比有狀態控件更省資源,運行效率更快。
TabBar
Tab頁的Title控件,切換Tab頁的入口,一般放到AppBar控件下使用,內部有*Title屬性。其子元素按水平橫向排列布局,如果需要縱向排列,請使用Column或ListView控件包裝一下。子元素為Tab類型的數組。
TabBarView
Tab頁的內容容器,其內放置Tab頁的主體內容。子元素可以是多個各種類型的控件。
Tab使用方法 有狀態控件搭配TabControllerTab頁的切換搭配了動畫,因此到State類上附加一個SingleTickerProviderStateMixin:
//定義有狀態控件 class HomePage extends StatefulWidget { @override _HomePageState createState() => new _HomePageState(); } //用于使用到了一點點的動畫效果,因此加入了SingleTickerProviderStateMixin class _HomePageState extends Statewith SingleTickerProviderStateMixin{ ... }
然后到有狀態控件的子類State中初始化控制器TabController:
@override void initState() { super.initState(); _tabController = new TabController( vsync: this, //動畫效果的異步處理,默認格式,背下來即可 length: 3 //需要控制的Tab頁數量 ); } //當整個頁面dispose時,記得把控制器也dispose掉,釋放內存 @override void dispose() { _tabController .dispose(); super.dispose(); }
然后到TabBar和TabBarView中的controller屬性中調用控制器_tabController
//標簽頁標題 new TabBar( tabs: [ //注意TabBar的子元素為Tab類型的數組 new Tab(icon: new Icon(Icons.directions_car)), new Tab(icon: new Icon(Icons.directions_transit)), new Tab(icon: new Icon(Icons.directions_bike)), ] //標簽頁內容區域 new TabBarView( children: [ new Icon(Icons.directions_car), new Icon(Icons.directions_transit), new Icon(Icons.directions_bike), ]
最后,我們把定義好的TabBar和TabBarView安放到需要的地方去,比如:
new Scaffold( appBar: new AppBar( backgroundColor: Colors.deepOrange, title: new Text("title"), ), .... body: new TabBarView( //TabBarView呈現內容,因此放到Scaffold的body中 controller: _bottomNavigation, //配置控制器 children: [ //注意順序與TabBar保持一直 new News(data: "參數值"), //上一篇定義好的子頁面 new TabPage2(), new TabPage3(), ] ), bottomNavigationBar: new Material( //為了適配主題風格,包一層Material實現風格套用 color: Colors.deepOrange, //底部導航欄主題顏色 child: new TabBar( //TabBar導航標簽,底部導航放到Scaffold的bottomNavigationBar中 controller: _bottomNavigation, //配置控制器 tabs: _bottomTabs, indicatorColor: Colors.white, //tab標簽的下劃線顏色 ), ) );無狀態控件搭配DefaultTabController
DefaultTabController要簡單很多,由于應用在無狀態控件中,使用DefaultTabController包裹需要用到Tab的頁面即可:
class TabPage3 extends StatelessWidget { @override Widget build(BuildContext context) { return new DefaultTabController( length: 3, child: new Scaffold( appBar: new AppBar( backgroundColor: Colors.orangeAccent, title: new TabBar( tabs: [ new Tab(icon: new Icon(Icons.directions_car)), new Tab(icon: new Icon(Icons.directions_transit)), new Tab(icon: new Icon(Icons.directions_bike)), ], indicatorColor: Colors.white, ), ), body: new TabBarView( children: [ new Icon(Icons.directions_car), new Icon(Icons.directions_transit), new Icon(Icons.directions_bike), ], ), ), ); } }
DefaultTabController和TabController的用法差異主要在控制器的定義上,TabBar和TabBarView的使用方法完全相同,通常上下Tab頁的標簽分別安放在Scaffold控件的appBar和bottomNavigationBar屬性上,然后我們把APP填充成下面這個樣式:
代碼結構如上圖所示,APP以底部Tab導航欄為主入口,底部每個Tab中又各自有自己的頂部次級Tab頁,因此我們把代碼結構整理一下:
_HomePageState是APP的主頁面HomePage的子類State
通過Scaffold底部的bottomNavigationBar屬性擺放TabBar,搭建Tab頁的標簽欄
放入Scaffold的body屬性放入TabBarView,TabBarView的children是三個外部dart文件定義的控件頁面
外部dart文件定義的控件頁面分別又有各自風格的Tab標簽頁
Tab頁的通用屬性可以提前定義到數組List中,在TabBar和TabBarView通過遍歷提取List的值創建子元素可以提高代碼的維護效率:
//在`StatefulWidget`控件中,可通過修改下面的數組,實現Tab頁的動態加載 final List使用獲取到的參數myTabs = [ new Tab(text: "Tab1"), new Tab(text: "Tab2"), new Tab(text: "Tab3"), new Tab(text: "Tab4"), new Tab(text: "Tab5"), new Tab(text: "Tab6"), new Tab(text: "Tab7"), new Tab(text: "Tab8"), new Tab(text: "Tab9"), new Tab(text: "Tab10"), new Tab(text: "Tab11"), ]; Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar( backgroundColor: Colors.orangeAccent, title: new TabBar( controller: _tabController, tabs: myTabs, //使用Tab類型的數組呈現Tab標簽 indicatorColor: Colors.white, isScrollable: true, ), ), body: new TabBarView( controller: _tabController, children: myTabs.map((Tab tab) { //遍歷List 類型的對象myTabs并提取其屬性值作為子控件的內容 return new Center(child: new Text(tab.text+" "+widget.data)); //使用參數值 }).toList(), ), ); }
由于StatelessWidget 和StatefulWidget的頁面構建不同,使用從外部獲取到的參數的方式也略有差異,在這里簡單總結下。
StatelessWidget 的獲參和用參方式
定義StatelessWidget 控件時,添加一個final類型的變量如pageText,用于為參數值預留空間,并在構造函數中加入參數值:
class SidebarPage extends StatelessWidget { final String pageText; //定義一個常量,用于保存跳轉進來獲取到的參數 SidebarPage(this.pageText); //構造函數,獲取參數 ... }
使用參數時直接引用即可:
Widget build(BuildContext context) { return new Scaffold( appBar: new AppBar(title: new Text(pageText),), //將參數當作頁面標題 body: new Center( child: new Text("pageText"), ), ); }
從外部傳入參數時,直接向構造函數中填入參數值即可:
Navigator.of(context).push(new MaterialPageRoute(builder: (BuildContext context) => new SidebarPage("First Page"))); //在new方法時調用控件的構造函數傳入參數值
StatefulWidget的獲參和用參方式
相比StatelessWidget 略復雜。定義構造函數時需要默認聲明key:
class TabPage1 extends StatefulWidget { const TabPage1({ Key key , this.data}) : super(key: key); //構造函數中增加參數 final String data; //為參數分配空間 @override _MyTabbedPageState createState() => new _MyTabbedPageState(); }
使用時,由于在State子類中實現具體的頁面內容,因此State子類使用父類TabPage1的參數時需要在參數名前增加一個widget關鍵字:
class _MyTabbedPageState extends State{ ... new Center(child: new Text(tab.text+" "+widget.data)); //使用參數值,需在參數名前增加widget前綴 ... }
從外部傳入參數時,需要聲明參數名:
new TabBarView controller: _bottomNavigation, children: [ new TabPage1(data: "參數值"), //new方法調用構造函數時,還需要聲明參數名稱 new TabPage2(), new TabPage3(), ] )
好勒,今天就講到這里,大家去下載我的git源碼試試效果吧,代碼中有附加的注釋,對一些控件屬性的特性也有多帶帶的描述,相信看完源碼之后,大家也可以自行實現效果了。
順便分享一個雷區,由于當初創建這個項目時,我使用命令flutter create [APPname1]的方式創建了這個項目,但我發現這個APPname1(代稱,并非真實名稱)不好聽,想把項目改名為APPname2,于是參考之前寫的安卓怎么打包?,把項目文件夾改名為APPname2,并非常任性的把項目目錄下的_androidappsrcmainAndroidManifest.xml_文件,把package和android:label都改成了APPname2,于是不出意料的悲催了,命令flutter fun報錯,無法啟動APP,還原配置之后,無法啟動APP,即便嘗試通過全文搜索APPname1,都按規定格式替換成APPname2,或者逆向改回去,都無法啟動APP,此時已是凌晨1點。。。妥妥的血淚史,所以鄭重的告誡大家:
不要在項目的各種配置文件中輕易改動項目名稱!不要在項目的各種配置文件中輕易改動項目名稱!不要在項目的各種配置文件中輕易改動項目名稱! 否則你就是下一個在電腦面前捶胸頓足的魚丸。什么?問我怎么恢復的?當然是托git的福。
感謝大家的支持,請關注我的Flutter圈子,多多投稿,也可以加入flutter 中文社區(官方QQ群:338252156)共同成長,謝謝大家~
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/93674.html
摘要:當我們搭建好了整個的頁面框架,現在我往頁里加點東西各種分類的新聞列表。由于需要請求外部數據,因此引入一個較為方便的庫。于是乎,在初始化對象時發起請求應該是個不錯的辦法具體是怎么初始化數據的,第三步會講到,踩了不少坑。 當我們搭建好了整個APP的頁面框架,現在我往Tab頁里加點東西:各種分類的新聞列表。也可以參考我的Git,上面有要點注釋。 showImg(https://segment...
摘要:前言最近比較熱門,但是成體系的文章并不多,前期避免不了踩坑我這篇文章主要介紹如何使用實現一個比較復雜的手勢交互,順便分享一下我在使用過程中遇到的一些小坑,減少大家入坑作者鏈接先睹為快本項目支持運行,效果如下對了,順便分享一下生成的小竅門,建 前言 Flutter最近比較熱門,但是Flutter成體系的文章并不多,前期避免不了踩坑;我這篇文章主要介紹如何使用Flutter實現一個比較復雜...
摘要:前言最近比較熱門,但是成體系的文章并不多,前期避免不了踩坑我這篇文章主要介紹如何使用實現一個比較復雜的手勢交互,順便分享一下我在使用過程中遇到的一些小坑,減少大家入坑作者鏈接先睹為快本項目支持運行,效果如下對了,順便分享一下生成的小竅門,建 前言 Flutter最近比較熱門,但是Flutter成體系的文章并不多,前期避免不了踩坑;我這篇文章主要介紹如何使用Flutter實現一個比較復雜...
閱讀 3120·2023-04-25 15:02
閱讀 2818·2021-11-23 09:51
閱讀 2034·2021-09-27 13:47
閱讀 1992·2021-09-13 10:33
閱讀 973·2019-08-30 15:54
閱讀 2646·2019-08-30 15:53
閱讀 2861·2019-08-29 13:58
閱讀 892·2019-08-29 13:54