一区二区三区欧美日韩-一区二区三区欧美-一区二区三区免费在线视频-一区二区三区免费在线观看-久久精品店-久久精品第一页

歡迎您光臨深圳塔燈網絡科技有限公司!
電話圖標 余先生:13699882642

網站百科

為您解碼網站建設的點點滴滴

Flutter實戰詳解--高仿好奇心日報

發表日期:2019-01 文章編輯:小燈 瀏覽次數:1945

前言

最近Flutter一直比較火,我也它也是非常感興趣,看了下官網的基礎教程后我決定直接上手做一個App,一是這樣學的比較快印象更加深刻,二是可以記錄其中遇到的一些坑,幫助大家少走一些彎路.本篇文章我會盡可能詳細的講到每一個點上.

項目地址

Github,如果覺得不錯,歡迎Star

下載項目后報錯是因為沒有添加依賴,在pubspec.yaml文件中點擊Packages get下載依賴,有時候會在這里出現卡死的情況,可以配置一下環境變量,詳情請看修改Flutter環境變量.
先看看效果圖吧.

  • iOS效果圖


    iOS效果圖.gif
  • Android效果圖


    Android效果圖.gif

正題

怎么搭建Flutter環境我就不多說了,官網上講的很詳細,還沒有搭建開發環境的可以看看這個Flutter中文網.

1導航欄Tabbar


這里我用到了DefaultTabController這個控件,使用DefaultTabController包裹需要用到Tab的頁面即可,它的child為Scaffold,Scaffold有個appBar屬性,在AppBar中設置具體的樣式,大家看代碼會更加清楚.相關注釋也都寫上了.

 home: new DefaultTabController( length: titleList.length, child: new Scaffold( appBar: new AppBar( elevation: 0.0,//導航欄下面那根線 title: new TabBar( isScrollable: false,//是否可滑動 unselectedLabelColor: Colors.black26,//未選中按鈕顏色 labelColor: Colors.black,//選中按鈕顏色 labelStyle: TextStyle(fontSize: 18),//文字樣式 indicatorSize: TabBarIndicatorSize.label,//滑動的寬度是根據內容來適應,還是與整塊那么大(label表示根據內容來適應) indicatorWeight: 4.0,//滑塊高度 indicatorColor: Colors.yellow,//滑動顏色 indicatorPadding: EdgeInsets.only(bottom: 1),//與底部距離為1 tabs: titleList.map((String text) {//tabs表示具體的內容,是一個數組 return new Tab( text: text, ); }).toList(), ), ), //body表示具體展示的內容 body:TabBarView(children: [News(url: 'http://app3.qdaily.com/app3/homes/index_v2/'),News(url: 'http://app3.qdaily.com/app3/papers/index/')]) , ), ), 

大家也可以看看官網的示例Flutter官網示例

2. 不同樣式的item

  • 樣式一



    這種布局的大概結構如下


注意這里圖片是緊貼著右邊屏幕的,所以這里需要用到Expanded控件,用于自動填充子控件.

  • 樣式二



    這個樣式的控件布局就很簡單了,結構如下


  • 樣式三



    這個和樣式二差不多,只不過最上面多了一塊.

這里需要注意的是,那個你猜這個圖片是堆疊在整個大圖上面的,所以需要用到Stack這個控件,其中Stack中有個屬性const FractionalOffset(double dx, double dy)用于表示子控件相對于父控件的位置

  • 樣式四



    這種樣式稍微復雜一點,結構如下


3數據抓取

用青花瓷抓取了好奇心數據.青花瓷使用教程

image.png
簡單分析一下,has_more表示是否可以加載更多,last_key用于上拉加載的時候請求用的,feeds就是每一條數據,banners就是輪播圖的信息,columns就是橫向滾動的ListView的相關數據,這個后面講.接下來就做json序列化相關的了.

4.Json序列化

首先在pubspec.yaml中導入

dependencies:
json_annotation: ^2.0.0
dev_dependencies:
build_runner: ^1.0.0
json_serializable: ^2.0.0

創建一個model.dart文件
引入文件

import 'package:json_annotation/json_annotation.dart';
part 'model.g.dart';

其中這個model.g.dart等會兒會自動生成.這里需要掌握兩個知識點

1.@JsonSerializable() 這是表示告訴編譯器這個類是需要生成Model類的
2,@JsonKey 由于服務器返回的部分數據名稱在Dart語言中是不被允許的,比如has_more,Dart中命名不能出現下劃線,所以就需要用到@JsonKey來告訴編譯器這個參數對于json中的哪個字段

@JsonSerializable() class Feed { String image; int type; @JsonKey(name: 'index_type') int indexType; Post post; @JsonKey(name: 'news_list') List<News> newsList; Feed(this.image,this.type,this.post,this.indexType,this.newsList); factory Feed.fromJson(Map<String,dynamic> json) => _$FeedFromJson(json); Map<String, dynamic> toJson() => _$FeedToJson(this); } 

好了,寫完后會報錯,因為FeedFromJsonFeedToJson沒有找到,這個時候在控制到輸入flutter packages pub run build_runner build指令后會自動生成一個moded.g.dart文件,于是在網絡請求下來數據后就可以用Feed feed = Feed.fromJson(data)這個方法來將Json中數據轉換保存在Feed這個實例中了.在model類中還有些復雜的Json嵌套,但是也都很簡單,大家看一眼應該就會了,哈哈.JSON和序列化具體教程

5.輪播圖

Flutter中的輪播圖我用到了Fluuter_Swiper這個組件,這里設置小圓點屬性的時候稍微麻煩了點,網上好像也沒有講到,我這里講一下.
首先要創建DotSwiperPaginationBuilder

 DotSwiperPaginationBuilder builder = DotSwiperPaginationBuilder( color: Colors.white,//未選中圓點顏色 activeColor: Colors.yellow,//選中圓點顏色 size:7,//未選中大小 activeSize: 7,//選中圓點大小 space: 5//圓點間距 ); 

然后在Swiper中的pagination屬性中設置它

pagination: new SwiperPagination( builder: builder, ), 
  1. 網絡請求
    首先,展示頁面要繼承自StatefulWidget,因為需要動態更新數據和列表.
    網絡請求插件我用的Dio,非常好用.
    initState方法中請求數據表示剛加載頁面的時候進行網絡請求,請求數據方法如下
void getData()async{ if (lastKey == '0'){ dataList = [];//下拉刷新的時候將DataList制空 } Dio dio = new Dio(); Response response = await dio.get("$url$lastKey.json"); Reslut reslut = Reslut.fromJson(response.data); if(!reslut.response.hasMore){ return;//如果沒有數據就不繼續了 } if(reslut.response.columns != null) { columnList = reslut.response.columns; } lastKey = reslut.response.lastKey;//更新lastkey setState(() { if (reslut.response.banners != null){ banners = reslut.response.banners;//給輪播圖賦值 } dataList.addAll(reslut.response.feeds);//給數據源賦值 }); } 

因為用到了setState()方法,所以在該方法中改變了的數據會對其相應的地方進行刷新,比如設置了ListView的itemCount個數為dataList.length,如果在SetState方法中dataList.length改變了,那么ListView的itemCount樹也會自動改變并刷新ListView.

7. 上拉刷新與加載

Flutter中有RefreshIndicator用于下拉刷新,它有個onRefresh閉包方法,表示下拉的時候執行的方法,一般用于網絡請求.onRefresh方法如下

 Future<void> _handleRefresh() { final Completer<void> completer = Completer<void>(); Timer(const Duration(seconds: 1), () { completer.complete(); }); return completer.future.then<void>((_) { lastKey = '0'; getData(); }); } 

下拉加載的話需要初始化一個ScrollController,將它設為ListView的controller,并對其進行監聽,當滑動到最底部的時候進行網絡請求.

@override void initState() { url = widget.url; getData(); _scrollController.addListener(() { ///判斷當前滑動位置是不是到達底部,觸發加載更多回調 if (_scrollController.position.pixels == _scrollController.position.maxScrollExtent) { getData(); } }); } final ScrollController _scrollController = new ScrollController(); 

上拉加載loading框用到了flutter_spinkit插件,提供了大量的加載樣式.


代碼如下

///上拉加載更多 Widget _buildProgressIndicator() { ///是否需要顯示上拉加載更多的loading Widget bottomWidget = new Row(mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ ///loading框 new SpinKitThreeBounce(color: Color(0xFF24292E)), new Container( width: 5.0, ), ]); return new Padding( padding: const EdgeInsets.all(20.0), child: new Center( child: bottomWidget, ), ); } 

8. ListView賦值

由于最上面有一個輪播圖,最下面有加載框,所以ListView的itemCount個數為dataList.length+2,又因為每個item之間都有一個淺灰色的風格線,所以需要用到ListView.separated,具體代碼如下:

 Widget build(BuildContext context) { return RefreshIndicator( onRefresh:(()=> _handleRefresh()), color: Colors.yellow,//刷新控件的顏色 child: ListView.separated( physics: const AlwaysScrollableScrollPhysics(), itemCount: _getListCount(),//item個數 controller: _scrollController,//用于監聽是否滑到最底部 itemBuilder: (context,index){ if(index == 0){ return SwiperWidget(context, banners);//如果是第一個,則展示banner }else if(index < dataList.length + 1){ return WidgetUtils.GetListWidget(context, dataList[index - 1]);//展示數據 }else { return _buildProgressIndicator();//展示加載loading框 } }, separatorBuilder: (context,idx){//分割線 return Container( height: 5, color: Color.fromARGB(50,183, 187, 197), ); }, ), ); } 

9. ListView嵌套橫向滑動ListView

這種的話也稍微復雜一點,有兩種樣式.并且到滑到最右邊的時候可以繼續請求并加載數據.




首先來分析一下數據



這個colunmns就是橫向滑動列表的重要數據.

里面的id是請求參數,show_type表示列表的樣式,location表示插入的位置.而且通過抓取接口發現,當橫向列表快要展示出來的時候,才會去請求橫向列表的具體接口.

那么思路就很清晰了,在請求獲得數據后遍歷colunmns,根據每個colunmn的location插入一個Map,如下

data.insert(colunm.location,{'id':colunm.id,'showType':colunm.showType}); 

,再創建一個ColumnsListWidget類,繼承自StatefulWidget,是一個新item,在滑動到該列表的位置的時候,會將該Map數據傳給ColumnsListWidget,這個時候ColumnsListWidget就會加載數據并展示出來了,滑到最右邊的時候加載和滑到最底部加載的方法一樣,就不多說了.具體可以查看源碼,關鍵代碼如下:

static Widget GetListWidget(BuildContext context, dynamic data) { Widget widget; if(data.runtimeType == Feed) { if (data.indexType != null) { widget = NewsListWidget(context, data); } else if (data.type == 2) { widget = ListImageTop(context, data); } else if (data.type == 0) { widget = ActivityWidget(context, data); } else if (data.type == 1) { widget = ListImageRight(context, data); } }else{ widget = ColumnsListWidget(id: data['id'],showType: data['showType'],); } 

1.橫向ListView外需要用Flexible包裹,Flexible組件可以使Row、Column、Flex等子組件在主軸方向有填充可用空間的能力(例如,Row在水平方向,Column在垂直方向),但是它與Expanded組件不同,它不強制子組件填充可用空間。
2.ListView初始位置用到padding: new EdgeInsets.symmetric(horizontal: 12.0),用padding: EdgeInsets.only(left: 12)的話會讓ListView和最左邊一直有條線

10.webview加載復雜的Html字段


獲取到網頁詳情的數據發現是Html字段,并且其中的css是url地址,試了很多Flutter加載Html的插件發現樣式都不正確,最后決定使用原生和Flutter混編,這時候發現flutter_webview_plugin這個插件是使用原生網頁的,不過它只支持加載url,于是就需要做一些修改.

  • iOS
    FlutterWebviewPlugin.m文件中的- (void)navigate:(FlutterMethodCall*)call方法中的最后一排,將[self.webview loadRequest:request]方法改為[self.webview loadHTMLString:url baseURL:nil]
  • Android
    WebViewManager.java文件中webView.loadUrl(url)方法改為webView.loadData(url, "text/html", "UTF-8"),以及下面那排的void reloadUrl(String url) { webView.loadUrl(url); }改為void reloadUrl(String url) { webView.loadData(url, "text/html", "UTF-8"); }
    由于服務器端返回的Html中的css和js文件地址是/assets/app3開頭的,所以需要替換成絕對路徑,所以要用到這個方法htmlBody.replaceAll( '/assets/app3','http://app3.qdaily.com/assets/app3')
    好了,這下就可以呈現出漂亮的網頁了.

11.ListView嵌套GridView

在點擊橫向滑動列表的總標題的時候,會進入到相關欄目的詳情頁,如圖



這個ListView包含上下兩部分.上面這部分為:



結構如下

下面就是一個GridView,不過有時候下面會是ListView,根據shouwType字段來判斷,GridView的代碼如下:

Widget ColumnsDetailTypeTwo(BuildContext context,List<Feed> feesList){ return GridView.count( physics: NeverScrollableScrollPhysics(), crossAxisCount: 2, shrinkWrap: true, mainAxisSpacing: 10.0, crossAxisSpacing: 15.0, childAspectRatio: 0.612, padding: new EdgeInsets.symmetric(horizontal: 20.0), children: feesList.map((Feed feed) { returnColumnsTypeTwoTile(context, feed); }).toList()); } 

其中 childAspectRatio表示寬高比.

圓角頭像需要用到
CircleAvatar(backgroundImage:NetworkImage(url),),這個控件

總結

做了這個項目最大的感受就是界面布局是真的很方便很簡單,因為做了一遍對很多知識點也理解的更深了.如果覺得有幫助到你的話,希望可以給個 Star

項目地址

Github


本頁內容由塔燈網絡科技有限公司通過網絡收集編輯所得,所有資料僅供用戶學習參考,本站不擁有所有權,如您認為本網頁中由涉嫌抄襲的內容,請及時與我們聯系,并提供相關證據,工作人員會在5工作日內聯系您,一經查實,本站立刻刪除侵權內容。本文鏈接:http://www.junxiaosheng.cn/17689.html
相關APP開發
 八年  行業經驗

多一份參考,總有益處

聯系深圳網站公司塔燈網絡,免費獲得網站建設方案及報價

咨詢相關問題或預約面談,可以通過以下方式與我們聯系

業務熱線:余經理:13699882642

Copyright ? 2013-2018 Tadeng NetWork Technology Co., LTD. All Rights Reserved.    

主站蜘蛛池模板: 精品久久久久久电影网| 十分钟免费观看高清视频大全| 抽插性奴中出乳精内射| 亚洲人成伊人成综合网久久久| 欧美成人国产| 娇妻让壮男弄的流白浆| 东北老妇xxxxhd| 99re久久这里只有精品| 亚洲中文字幕国产综合| 天天综合亚洲综合网站| 欧美AAAA片免费播放观看| 久久re这里精品在线视频7| 国产精品久久久久久日本| AV色蜜桃一区二区三区| 在线观看qvod| 亚洲精品无码葡京AV天堂| 深夜释放自己在线观看| 欧美亚洲日韩国产在线在线| 久久久久久久久久综合情日本| 国产精品自在在线午夜精品| 扒开老师大腿猛进AAA片| 2224x最新网站| 在线观看国产亚洲| 艳照门在线播放| 亚洲精品成人AV在线观看爽翻| 神马伦理不卡午夜电影| 日本免费一本天堂在线| 欧美 日韩 亚洲 在线| 麻豆啊传媒app黄版破解免费| 激情办公室| 黑人开嫩苞| 红尘影院手机在线观看| 国产亚洲美女精品久久久2020| 国产99九九久久无码熟妇| 动漫美女被爆挤奶歪歪漫画| yy8090理论三级在线看| 99婷婷久久精品国产一区二区| 69精品国产人妻蜜桃国产毛片| 中文字幕亚洲无线码在线| 伊人久久综合成人亚洲| 医生含着我的奶边摸边做|