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阅读 156,907评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,546评论 1 289
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,705评论 0 238
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,624评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,940评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,371评论 1 210
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,672评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,396评论 0 195
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,069评论 1 238
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,350评论 2 242
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,876评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,243评论 2 251
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,847评论 3 231
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,004评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,755评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,378评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,266评论 2 259

推荐阅读更多精彩内容