Flower_gift 簡單的Flutter實戰app(四)

0001.jpg
項目git地址:flower_gift
tabBar-分類界面:

效果:


11324.gif
頭部搜索欄的搭建:
//頂部搜索框;
  Widget _buildSearchBar(){
    return Container(
              margin: EdgeInsets.symmetric(horizontal: 10.0,vertical: 8.0),
              decoration: BoxDecoration(
                 color: Colors.black12,
                 borderRadius: BorderRadius.all(Radius.circular(22.0)),
              ),
              child: Row(
                 crossAxisAlignment: CrossAxisAlignment.start,
                 children: <Widget>[
                    Expanded(
                      flex: 1,
                      child: Container(
                        padding: EdgeInsets.symmetric(horizontal: 8.0),
                        child: TextFormField(
                            decoration: InputDecoration(
                                border: InputBorder.none,
                                hintText: "請輸入關鍵字",
                                hintStyle: TextStyle(
                                  color: Colors.black
                                ),
                                icon: Icon(Icons.search,color:Colors.black)
                            ),
                          ),
                      ) 
                      
                    ),
                    
                 ],
              ),
    );
  }

使用:

 return Scaffold(
        appBar: AppBar(
           backgroundColor: Colors.white,
           title: _buildSearchBar()
        ),
        body: ...

這里就是說,開始我以為這個Scaffold的title屬性只能是這個Text組件控制這個導航欄title.原來這個也是完全可以自定義的。

body布局部分:
 body: FutureBuilder(
            future: _getCategoryPage(context),
            builder: (context,snapshot){
              if(snapshot.hasData){
                return Container(
                    color: Colors.white,
                    child: Row(
                        children: <Widget>[
                          Expanded(
                            flex: 2,
                            child: CategoryLeftNav()
                          ),
                          Expanded(
                            flex: 5,
                            child: CategoryRightCategory()
                          )
                        ],
                      ),  
                );  
              }else{
                return Center(
                  child: Text("暫無數據"),
                );
              }
            },
        ),


 
  //網絡請求
   Future _getCategoryPage(BuildContext context) async{
     await Provide.value<CategoryPageProvide>(context).getCategoryPageData();
     return "完成加載....";
  }

整體布局我把這個作為左右兩部分吧,所以這個就直接用Row,然后里面嵌套這個Expanded組件,用flex來控制所占寬度比。

左邊導航欄
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../model/categoryPage_model_entity.dart';
import 'package:provide/provide.dart';
import '../../provide/categoryPage_provide.dart';

class CategoryLeftNav extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return Provide<CategoryPageProvide>(
        builder: (context,child,val){
          var categoryPageModelEntity = val.categoryModelEntity;
          return  Container(
            decoration: BoxDecoration(
              border: Border(
                right: BorderSide(
                    color: Colors.black12,
                    width: 1.0,
                    style: BorderStyle.solid
                )
              )
            ),
            child: ListView.builder(
              itemCount: categoryPageModelEntity.categorys.length,
              itemBuilder:(context,index){
                  return Container(
                      color: Colors.white,
                      child: InkWell(
                          //設置點擊閃爍那一下的文字顏色
                          splashColor: Colors.redAccent.withOpacity(0.5),
                          onTap: (){
                             Provide.value<CategoryPageProvide>(context).switchCategory(index);
                          },
                          child: Column(
                            children: <Widget>[
                              SizedBox(height: 15.0,),
                                Container(
                                  alignment: Alignment.center,
                                  padding: const EdgeInsets.symmetric(vertical: 4.0),
                                  decoration: (Provide.value<CategoryPageProvide>(context).currentIndex == index) ?  BoxDecoration(
                                      border: Border(
                                          left: BorderSide(
                                            color: Colors.orange,
                                            width: 3.0,
                                            style: BorderStyle.solid
                                          )
                                      )
                                    ) : null,
                                    child: Text(
                                        categoryPageModelEntity.categorys[index].type,
                                        style: TextStyle(fontSize: 18.0),
                                      ),
                              ),
                              SizedBox(height: 15.0,),
                              
                            ],
                          ) 
                        
                          
                      )
                      
                  );
              },
            ),
            
        );
      }
   );
  }
}

這個布局就比較簡單的,主要就是利用Provide來管理了當前點擊的分類項,然后左邊的指示條我就直接用的這個邊框來做的。

右邊分類布局部分:
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../model/categoryPage_model_entity.dart';
import 'package:provide/provide.dart';
import '../../provide/categoryPage_provide.dart';

class CategoryRightCategory extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Provide<CategoryPageProvide>(
        builder: (context,child,val){
           var currentIndex = Provide.value<CategoryPageProvide>(context).currentIndex;
           var categoryModelCategory = val.categoryModelEntity.categorys[currentIndex];
           var categoryBanners = categoryModelCategory.categoryBanner;
           var areasItem = categoryModelCategory.areas[0];//默認只做第一排的商品分類詳情了
           var head = areasItem.head;//看看是否有頭部標題欄
           var contents = areasItem.contents;
           return Container(
              child:ListView(
                
                   children: <Widget>[
                      _buildTopBanner(context, categoryModelCategory.banner),
                    (categoryBanners != null) ? _buildCategoryBanner(context, categoryBanners) : SizedBox(height: 1.0,),
                    (head != null) ? _buildTitle(head) : SizedBox(height: 1.0,),
                    Divider(),
                    _buildCategoryShow(context, contents),
                   ],
                 
              )
             
           );
        },
    );
    
  }

  //頂部banner
  Widget _buildTopBanner(BuildContext context,CategoryModelCategorysBanner banner){
      return Padding(
         padding: const EdgeInsets.symmetric(horizontal: 10.0, vertical: 10.0),
         child: Container(
            height: MediaQuery.of(context).size.height / 7,
            child: Image.network(banner.imageUrl,fit:BoxFit.fill,),
         ), 
      );
   }

   //分類banner -- 需要判斷顯示否
   Widget _buildCategoryBanner(BuildContext context,List<CategoryModelCategorysCategorybanner> categoryBanners){
      return Padding(
        padding: const EdgeInsets.symmetric(horizontal: 10.0),
        child: Container(
           height: MediaQuery.of(context).size.height / 7,
           child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: _categoryBanners(context, categoryBanners)
           ),
        ),
      );
   }
   List<Widget> _categoryBanners(BuildContext context, List<CategoryModelCategorysCategorybanner> categoryBanners){
       List<Widget> list = new List();
        for(var i = 0; i < categoryBanners.length; i++){
          list.add(
              Container(
                width: (MediaQuery.of(context).size.width / 7 * 5  - 40.0)/3,
                child: Image.network(categoryBanners[i].imageUrl,fit:BoxFit.fill),
              )
              
          ); 
     }
     return list;
   }
 
   //標題欄
   Widget _buildTitle(dynamic head){
      return Padding(
        padding: const EdgeInsets.symmetric(horizontal: 10.0,vertical: 5.0),
        child: Row(
           mainAxisAlignment: MainAxisAlignment.spaceBetween,
           children: <Widget>[
              Text(head["Title"]),
              Text(head["UrlDesc"])
           ],
        ),
      );

   }
  //分類展示
   Widget _buildCategoryShow(BuildContext context,List<CategoryModelCategorysAreasContent> contents){
     return Padding(
            padding: const EdgeInsets.symmetric(horizontal: 10.0),
            child: Wrap(
               alignment: WrapAlignment.spaceBetween,
               children: _categoryShow(context, contents)
            ),
        
     );
     
   }
   //分類展示遍歷
   List<Widget> _categoryShow(BuildContext context,List<CategoryModelCategorysAreasContent> contents){
       List<Widget> list = new List();
        for(var i = 0; i < contents.length; i++){
          list.add(
              Container(
                //  height:  MediaQuery.of(context).size.height / 7 + 20.0,
                 width:  (MediaQuery.of(context).size.width / 7 * 5 - 30.0)/3,
                 child: Column(
                     mainAxisAlignment: MainAxisAlignment.center,
                     children: <Widget>[
                        SizedBox(height:25.0),
                       (contents[i].text != null) ? CircleAvatar(
                           child: Image.network(contents[i].imageUrl),
                        ) : Padding(
                           padding: const EdgeInsets.symmetric(horizontal: 5.0),
                           child:Image.network(contents[i].imageUrl),
                        ),
                        SizedBox(height: 15.0,),
                        (contents[i].text != null) ? Text(
                          contents[i].text
                        ) : SizedBox(height: 1.0,),
                         
                     ],

                 ),
              )
              
          ); 
     }
     return list;
   }
}

這邊布局也是比較簡單的,主要就是考慮這個數據是否為null,來確定顯示哪一部分。

結尾:這個頁面的分類項點擊的邏輯還沒做,這個路由的配置就利用首頁來做就好了,具體的分類列表項布局還算簡單,就是其中的邏輯比較雜。其次這個搜索邏輯也沒有做,看后面有時間補上。商品詳情頁
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,663評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,125評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,506評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,614評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,402評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,934評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,021評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,168評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,690評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,596評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,784評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,288評論 5 357
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,027評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,404評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,662評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,398評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,743評論 2 370

推薦閱讀更多精彩內容