Flower_gift 簡單的Flutter實(shí)戰(zhàn)app(五)

ed94bbb1f573dd5dcd00505fab7cfb72.png

商品詳情頁完成--看看效果:

1111.gif

商品詳情頁布局

商品詳情頁一般都是這個商城app中布局最多的一個界面慷暂,也是各種交互比較多的界面,整整寫了一天才寫完(其實(shí)還沒完帕涌,后面有些無關(guān)緊要的圖片就沒有寫了)
還是一點(diǎn)來吧

首先是路由配置和數(shù)據(jù)獲取

路由配置:

Handler detailsHandler = Handler(
   handlerFunc: (BuildContext context,Map<String,List<String>> params){
      String itemCode = params["itemCode"].first;//傳遞請求參數(shù)
      print("傳遞的itemCode是: ${itemCode}");
      return DetailsPage(itemCode);
   }

 static String detailsPage = "/detailsPage";
 router.define(detailsPage,handler: detailsHandler);

//使用:
onTap: (){
          Application.router.navigateTo(context, "/detailsPage?itemCode=${sectionListItem.productCode}");
       },
     

數(shù)據(jù)獲取:

import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../provide/details_provide.dart';
import './detailsSubWidget/top_swiper_widget.dart';
import './detailsSubWidget/detailsBottom_widget.dart';
import './detailsSubWidget/detailsTitle_widget.dart';
import './detailsSubWidget/detailsDescribe_widget.dart';
import './detailsSubWidget/detailsDelivery_widget.dart';
import './detailsSubWidget/detailsEvaluate_widget.dart';
import './detailsSubWidget/detailsCompany_widget.dart';
import './detailsSubWidget/detailsImgText_widget.dart';

class DetailsPage extends StatelessWidget {
  String itemCode;
  DetailsPage(this.itemCode);
  
  

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      
      appBar: AppBar(
          backgroundColor: Colors.white,
          leading: IconButton(
            icon: Icon(Icons.arrow_back,color: Colors.black,),
            onPressed: (){
                Navigator.pop(context);
            },
          ),
          title: Provide<DetailsPageProvide>(
              builder: (context,child,val){

                 return Text(val.datas.itemName,
                   style: TextStyle(color:Colors.black),
                 );
              },
          )
          
      ),
      body: FutureBuilder(
              future: _getDetailPage(context),
              builder: (context,snapshot){
                if(snapshot.hasData){
                  return Stack(
                       children: <Widget>[
                          Container(
                            color: Colors.black12,
                            child: ListView(
                                children: <Widget>[
                                  TopSwiper(),
                                  DetailsTitle(),
                                  SizedBox(height: 8.0,),
                                  DetailsDescribe(),
                                  SizedBox(height: 8.0,),
                                  DetailsDelivery(),
                                  SizedBox(height: 8.0,),
                                  DetailsEvaluate(),
                                  SizedBox(height: 8.0,),
                                  DetailsCompany(),
                                  SizedBox(height: 8.0,),
                                  DetailsImgText(),
                                  SizedBox(height: 80.0,)
                               ],
                            ),
                          ),
                          Positioned(
                             bottom: 0,
                             left: 0,
                             child: DetailsBottom(),
                          )
  
                       ],
                  );
                   
                }else{
                    return Center(
                      child: Text("暫無數(shù)據(jù)"),
                    ); 
                }
          }
      )
    );
  }

  Future _getDetailPage(BuildContext context) async{
      await Provide.value<DetailsPageProvide>(context).getDetailsPageData(itemCode);
      return "加載完成";
  }

}

從ListView中就是我拆分的詳情頁部分的各個組件迅涮。下面還是將各個組件中的代碼貼出來。

頂部圖片輪播
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import 'package:flutter_swiper/flutter_swiper.dart';



class TopSwiper extends StatelessWidget {
  

  @override
  Widget build(BuildContext context) {
    return Provide<DetailsPageProvide>(
         builder: (context,child,val){
            var coverImages = val.datas.coverImages;
            return Container(
                  color: Colors.white,
                  height: MediaQuery.of(context).size.height*0.6,
                  child: Swiper(
                    itemBuilder: (BuildContext context,int index){
                        return Image.network("${coverImages[index]}");
                    },
                    onTap: (index){
                        print("點(diǎn)擊了輪播組件:${index}");
                    },
                    itemCount: coverImages.length,
                    pagination: buildSwiperPagintion(),
                    autoplay: true,
                    
                  ),
                );
         },
    );
  }

  buildSwiperPagintion(){
     return SwiperPagination(
        builder: FractionPaginationBuilder(
           color: Colors.white,
           activeColor: Colors.orange
        )
     );
  }
}

這個輪播插件還是挺好用的虎眨,就是這個Page指示器和app上的不一樣,由于這個插件只提供了兩種樣式,如果想要和app中的一樣需要自定義這個SwiperPagination, 后面完成后嗽桩,來試試自己自定義這個東東岳守。

頂部標(biāo)題和價格
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';

class DetailsTitle extends StatelessWidget {
    

  @override
  Widget build(BuildContext context) {
    return Provide<DetailsPageProvide>(
          builder: (context,child,val){
             var datas = val.datas;
             return Container(
               
               decoration: BoxDecoration(
                 color: Colors.white,
                  border: Border(
                     top: BorderSide(width: 1,color: Colors.black12),
                     bottom: BorderSide(width: 1,color:Colors.black12)
                  )
               ), 
               child: Padding(
                    padding: EdgeInsets.fromLTRB(10.0, 10.0, 10.0, 10.0),
                    child: Container(
                        child: Column(
                          children: <Widget>[
                            _buildTitle(datas.itemName,datas.introduction),
                            SizedBox(height: 15.0,),
                            _buildPrice(datas),

                          ],
                        ),
                    ), 
                  ),
             );
             
          },
    );
    
  }

  //標(biāo)題
  Widget _buildTitle(String name,String introduction){
     return Container(
         
         child: Row(
            children: <Widget>[
               Expanded(
                 flex: 8,
                 child: Container(
                    child: Text(
                       "${name}--${introduction}",
                       maxLines: 1,
                       overflow: TextOverflow.ellipsis,
                    ),
                 ),
               ),
               Expanded(
                 flex: 2,
                 child: Container(
                    alignment: Alignment.centerRight,
                    child:Icon(Icons.star_border),
                 )
                 
               )
            ],
         ),
     );
  }
  //價格
  Widget _buildPrice(DetailsModelDatas datas){
     return Container(
       child: Row(
         mainAxisAlignment: MainAxisAlignment.spaceBetween,
         children: <Widget>[
            Row(
              children: <Widget>[
                 Text(
                   "¥${datas.price}",
                   style: TextStyle(
                      color:Colors.orangeAccent,
                      fontSize: 24.0
                   ), 
                 ),
                 SizedBox(width: 5.0,),
                 Text(
                   "¥${datas.linePrice}",
                   style: TextStyle(
                     color: Colors.black26,
                     decoration: TextDecoration.lineThrough
                   ),
                 )
              ],
            ),
            Container(
               alignment: Alignment.centerRight,
               child: Text(datas.sale),
            )

         ],
       ), 
     );
  }
}

這個沒什么好說的,說說這個Icon吧碌冶,這里有這個flutter自帶Icon圖標(biāo)圖文對應(yīng)的網(wǎng)址湿痢,里面的圖標(biāo)已經(jīng)算非常全面了,用的時候可以找找看看

Flutter 圖標(biāo)Icon

描述部分
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';

class DetailsDescribe extends StatelessWidget {
  
  @override
  Widget build(BuildContext context) {
    return Provide<DetailsPageProvide>(
        builder: (context,child,val){
           var datas = val.datas;
           return Container(
              color: Colors.white,
              child: Column(
                children: <Widget>[
                    _buildFlowers(datas),
                    _buildMaterial(datas),
                    _buildExpansionpanel(datas)
                    

                ],
              ),
            );
        }, 
    );
    
  }
  
  //花語
  Widget _buildFlowers(DetailsModelDatas datas){
     return Padding(
        padding: EdgeInsets.symmetric(horizontal: 10.0),
        child: Container(
            padding: EdgeInsets.only(top: 10.0),
            child: Row(
               children: <Widget>[
                 Expanded(
                    flex: 1,
                    child: Container(
                       alignment: Alignment.topLeft,
                       child: Text("花語",
                        style:TextStyle(
                          fontWeight:FontWeight.w600
                        )
                       ),
                    ),
                 ),
                 Expanded(
                    flex: 9,
                    child: Container(
                        padding: EdgeInsets.only(bottom: 8.0),
                        decoration: BoxDecoration(
                           border: Border(
                             bottom: BorderSide(width: 1,color:Colors.black12)
                           ) 
                        ),
                        child: Text(
                          datas.huaYu,
                          maxLines: 2,
                          overflow: TextOverflow.ellipsis,
                        ),
                    )
                    
                 )
               ],
            ),  
        ),
     );
  }
  
  //材料
  Widget _buildMaterial(DetailsModelDatas datas){
     return Padding(
        padding: EdgeInsets.symmetric(horizontal: 10.0),
        child: Container(
            padding: EdgeInsets.only(top: 10.0),
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.center,
               children: <Widget>[
                 Expanded(
                    flex: 1,
                    child: Container(
                       padding: EdgeInsets.only(bottom: 8.0),
                       alignment: Alignment.topLeft,
                       child: Text("材料",
                        style:TextStyle(
                          fontWeight:FontWeight.w600
                        )
                       ),
                    ),
                 ),
                 Expanded(
                    flex: 9,
                    child: Container(
                        padding: EdgeInsets.only(bottom: 8.0),
                        decoration: BoxDecoration(
                           border: Border(
                             bottom: BorderSide(width: 1,color:Colors.black12)
                           ) 
                        ),
                        child: Text(
                          datas.stuff,
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                        ),
                    )
                    
                 )
               ],
            ),  
        ),
     );
  }
  //配送
  Widget _buildExpansionpanel(DetailsModelDatas datas){
     return Padding(
        padding: EdgeInsets.symmetric(horizontal: 0.0),
        child: Container(
          
           child: Container(
                  margin: EdgeInsets.all(0.0),
                  padding: EdgeInsets.all(0.0),
                  child: ExpansionTile(
                  title: ListTile(
                    contentPadding: EdgeInsets.all(0),
                    leading: Text("配送",
                          style:TextStyle(
                              fontSize: 14.0,
                              fontWeight:FontWeight.w600
                            )
                    ),
                    title: Text(
                              datas.deliveryArea,
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style:TextStyle(
                                fontSize: 14.0,
                              
                              )
                            ),
                  ),
                  children: <Widget>[
                    Container(
                        padding: EdgeInsets.only(bottom: 10.0),
                        child: Text(datas.deliveryArea),
                    )
                  ],
              ),
           )
           
        )
     );

  }
}

描述部分就注意一下這個ExpansionTile可展開的ListTile組件扑庞,還是比較常用的.

選擇/配送
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';
import 'package:city_pickers/city_pickers.dart';

class DetailsDelivery extends StatelessWidget {
  

  @override
  Widget build(BuildContext context) {
    return Provide<DetailsPageProvide>(
        builder: (context,child,val){
           var datas = val.datas;
           return Container(
              color: Colors.white,
              child: Column(
                children: <Widget>[
                  datas.itemSKUs != null ?  _buildFlowers(context,datas) : SizedBox(height: 0.1,),
                   _buildPeisong(context,"送至", "請選擇配送地區(qū)")
                ],
              ),
            );
        }, 
    );
  }

 Widget _buildFlowers(BuildContext context,DetailsModelDatas datas){
     return Padding(
        padding: EdgeInsets.symmetric(horizontal: 10.0),
        child: Container(
            padding: EdgeInsets.only(top: 10.0),
            child: Row(
               children: <Widget>[
                 Expanded(
                    flex: 1,
                    child: Container(
                       alignment: Alignment.centerLeft,
                       padding: EdgeInsets.only(bottom: 8.0),
                       child: Text("已選",
                        style:TextStyle(
                          fontWeight:FontWeight.w600
                        )
                       ),
                    ),
                 ),
                 Expanded(
                    flex: 8,
                    child: Container(
                        padding: EdgeInsets.only(bottom: 8.0),
                        decoration: BoxDecoration(
                           border: Border(
                             bottom: BorderSide(width: 1,color:Colors.black12)
                           ) 
                        ),
                        child: Text(
                          datas.itemName,
                          maxLines: 2,
                          overflow: TextOverflow.ellipsis,
                        ),
                    )
                    
                 ),
                 Expanded(
                    flex: 1,
                    child: Container(
                       alignment: Alignment.centerRight,
                       child: InkWell(
                          onTap: ()=> _onBottomSheet(context,datas),
                          child: Icon(Icons.more_horiz,
                            size: 30.0,
                          ),
                       ),
                    ),
                 )
               ],
            ),  
        ),
     );
  }
 

  //配送
  Widget _buildPeisong(BuildContext context,String title,String des){
     return Padding(
        padding: EdgeInsets.symmetric(horizontal: 10.0),
        child: Container(
            padding: EdgeInsets.only(top: 10.0),
            child: Row(
               children: <Widget>[
                 Expanded(
                    flex: 1,
                    child: Container(
                       padding: EdgeInsets.only(bottom: 8.0),
                       alignment: Alignment.centerLeft,
                       child: Text(title,
                        style:TextStyle(
                          fontWeight:FontWeight.w600
                        )
                       ),
                    ),
                 ),
                 Expanded(
                    flex: 8,
                    child: Container(
                        padding: EdgeInsets.only(bottom: 8.0),
                        
                        child: Text(
                          des,
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                        ),
                    )
                    
                 ),
                 Expanded(
                    flex: 1,
                    child: Container(
                       alignment: Alignment.centerRight,
                       child: InkWell(
                          onTap: () async {
                            print("選擇配置地址");
                            Result result = await CityPickers.showCityPicker(
                              context: context,
                            );
                            print("選擇地址結(jié)果是: ${result}");
                          },
                          child: Icon(Icons.more_horiz,
                            size: 30.0,
                          ),
                       ),
                    ),
                 )
               ],
            ),  
        ),
     );
  }


  //商品選擇彈出框
  void _onBottomSheet(BuildContext context,DetailsModelDatas datas){
     showModalBottomSheet(
         context: context,
         builder: (context){
            return Stack(
               children: <Widget>[
                   Container(
                      color: Color(0xFF737373),
                      height: MediaQuery.of(context).size.height * 0.55,
                      child: Container(
                        color: Colors.white,
                        child: Column(
                          children: <Widget>[
                              _buildBottomSelectGood(context, datas)
                          ],
                        )
                      ),
                  ),
                   Positioned(
                    bottom: 0,
                    left: 0,
                    child: Container(
                        height: 60.0,
                        child: Row(
                            children: <Widget>[
                                Container(
                                  width: MediaQuery.of(context).size.width/2,
                                  color: Color.fromRGBO(45, 60, 49, 1.0),
                                  alignment: Alignment.center,
                                  child: Text(
                                      "加入購物車",
                                      style:TextStyle(
                                        color:Colors.white,
                                        fontSize: 20.0
                                      )
                                  ),
                                ),
                                Container(
                                  width: MediaQuery.of(context).size.width/2,
                                  color: Colors.orangeAccent,
                                  alignment: Alignment.center,
                                  child: Text(
                                      "立即購買",
                                      style:TextStyle(
                                        color:Colors.white,
                                        fontSize: 20.0
                                      )
                                  ),
                                ) 
                            ],
                            
                        ),
                    )
                  )
               ],
            );
            
         }
     );
  }
  //商品選擇彈出框UI
  Widget _buildBottomSelectGood(BuildContext context,DetailsModelDatas datas){
      return Container(
                  child:Column(
                    children: <Widget>[
                        _buildGoodsShowTop(context, datas),
                        _buildChangeGoods(context, datas),
                        SizedBox(height: 20.0,),
                        _buildGoodsCount(context),


                    ],
                  )
                  
            );
            
          
      
      
  }
  //頭部商品展示
  Widget _buildGoodsShowTop(BuildContext context,DetailsModelDatas datas){
     return Container(
         padding: EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 10.0),
         child:Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                 Container(
                    width: MediaQuery.of(context).size.width / 4,
                    height: MediaQuery.of(context).size.width / 4,
                    decoration: BoxDecoration(
                       border: Border.all(width: 1,color:Colors.black12),
                       borderRadius: BorderRadius.circular(3.0)
                    ),
                    child: Image.network(datas.coverImages[0]),

                 ),
                 
                 Container(
                    padding: EdgeInsets.only(top: 15.0),
                    width: MediaQuery.of(context).size.width / 2,
                    alignment: Alignment.centerLeft,
                    child:Column(
                       mainAxisAlignment: MainAxisAlignment.start,
                       children: <Widget>[
                          Container(
                            alignment: Alignment.centerLeft,
                            child: Text("¥${datas.price}",
                                style: TextStyle(
                                  fontSize: 20.0,
                                  color: Colors.deepOrange
                                ),
                              ),
                          ),
                          
                          SizedBox(height: 3.0,),
                          Container(
                            alignment: Alignment.centerLeft,
                            child: Text("已選  ${datas.itemName}"),
                          )
                          
                       ],
                    ),
                 ),
                 Container(
                    child: InkWell(
                       onTap: (){
                          print("關(guān)閉底部彈窗");
                          Navigator.pop(context);
                       },
                       child: Container(
                           alignment: Alignment.topRight,
                           child: Icon(Icons.close,
                             size: 30.0,
                           ),
                       )
                        
                    ),
                 )

              ],
           ) 
     );
          
  }

  //商品切換選擇
  Widget _buildChangeGoods(BuildContext context,DetailsModelDatas datas){
    return Padding(
        padding: const EdgeInsets.symmetric(horizontal: 15.0),
        child: Container(
           child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              children: <Widget>[
                  Container(
                     alignment: Alignment.centerLeft,
                     child: Text("選擇"),
                  ),
                  SizedBox(height: 10.0,),
                  Wrap(
                    alignment: WrapAlignment.spaceBetween,
                    spacing: 10.0,
                    runSpacing: 10.0,
                    children: _buildChangeList(context, datas.itemSKUs)
                  )
              ],
           ),
        ),
    );

  }
  //選擇列表
  List<Widget> _buildChangeList(BuildContext context,List<DetailsModelDatasItemsku> itemList){
        List<Widget> list = new List();
        for(var i = 0; i < itemList.length; i++){
          list.add(
              Container(
                 
                 width: (MediaQuery.of(context).size.width - 60.0)/4,
                 height: 35.0,
                 color: Colors.black12,
                 alignment: Alignment.center,
                 child: InkWell(
                    onTap: (){},
                    child: Text(itemList[i].optionName),
                 ),
              )
          ); 
          
        }
        return list;

  }



  //商品數(shù)量加減
  Widget _buildGoodsCount(BuildContext context){
     return Padding(
       padding: const EdgeInsets.symmetric(horizontal: 15.0),
       child: Container(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
               Text("數(shù)量"),
               _addOrReduceWidget(context)

            ],
          ),
       ),
     );

  }
  //商品加減小組件
  Widget _addOrReduceWidget(BuildContext context){
      return Container(
         width: MediaQuery.of(context).size.width / 4.2,
         height: 30.0,
         child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
                //減
                Container(
                   width: 24.0,
                   height: 24.0,
                   alignment: Alignment.center,
                   decoration: BoxDecoration(
                      color: Colors.black26,
                      borderRadius: BorderRadius.circular(12.0)
                   ),
                   child: Text("-",
                     style:TextStyle(
                        fontSize: 18.0,
                        color:Colors.white
                     )
                   ),
                ),
                Container(
                   child: Text("1"),
                ),
                Container(
                   width: 24.0,
                   height: 24.0,
                   alignment: Alignment.center,
                   decoration: BoxDecoration(
                      color: Colors.black26,
                      borderRadius: BorderRadius.circular(12.0)
                   ),
                   child: Text("+",
                     style:TextStyle(
                        fontSize: 18.0,
                        color:Colors.white
                     )
                   ),
                ),

            ],
         ),
      );
  }
}

這里面代碼就比較多了譬重,主要是我將這個選擇商品規(guī)格和數(shù)量的底部sheet和這個省市區(qū)選擇放在了一起了。 這里面注意這個底部彈出框是用這個: showModalBottomSheet,非常好用罐氨,不像以前原生要做個底部自定義彈窗(唉)臀规。 還有就是我的省市區(qū)選擇是用的國人寫的插件city_pickers,挺好的,簡單方便栅隐。

訂單評價
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';

class DetailsEvaluate extends StatelessWidget {
  

  @override
  Widget build(BuildContext context) {
    return Provide<DetailsPageProvide>(
        builder: (context,child,val){
           var datas = val.datas;
           return Container(
              color: Colors.white,
              child: 
               //判斷是否有評價
                datas.comments != null ?
                  Column(
                    children: <Widget>[
                        _buildTopTitle(context, datas),
                        _buildEvaluates(context, datas.comments.itemComments),
                        SizedBox(height: 10.0,),
                        Container(
                           alignment: Alignment.center,
                           child: RaisedButton(
                              padding: EdgeInsets.fromLTRB(15.0, 10.0, 15.0, 10.0),
                              onPressed: (){},
                              child: Text("查看更多評價"),
                           ),
                        )
                        

                    ],
                ):Container(
                   child: Center(
                      child: Text("暫無評價"),
                   ),
                )
           );
        },
    );
  }

  //頂部評價
  Widget _buildTopTitle(BuildContext context,DetailsModelDatas datas){
      return Padding(
        padding: EdgeInsets.all(10.0),
        child: Container(
           child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                 Container(
                    child: Text("訂單評價",
                        style:TextStyle(
                           fontSize: 20.0,
                           fontWeight: FontWeight.w600
                        )
                    ),
                 ),
                 Container(
                    child: Text(
                      "最近已有${datas.comments.commentCount}條評價>"
                    ),
                 )
              ],
           ),
        ),
      );
  }

  //評價列表
  Widget _buildEvaluates(BuildContext context,List<DetailsModelDatasCommantsItemcommants> itemComments){
       return Container(
           child: Column(
              children: _buildEvaluateList(context, itemComments),
           ),
       );

  }
  List<Widget> _buildEvaluateList(BuildContext context,List<DetailsModelDatasCommantsItemcommants> itemComments){
        List<Widget> list = new List();
        for(var i = 0; i < itemComments.length; i++){
          list.add(
              _buildEvaluateItem(context, itemComments[i])
          ); 
          
        }
        return list;

  }
  //評價項(xiàng)
  Widget _buildEvaluateItem(BuildContext context,DetailsModelDatasCommantsItemcommants commant){
      return Container(
         padding: EdgeInsets.fromLTRB(10.0, 20.0, 10.0, 10.0),
         decoration: BoxDecoration(
            border: Border(
               top: BorderSide(width: 1,color: Colors.black12)
            )
         ),
         child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
                 Container(
                    child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: <Widget>[
                           Row(
                              children: <Widget>[
                                 Container(
                                    width: 30.0,
                                    height: 30.0,
                                    
                                    child: ClipOval(
                                      child: Image.network(commant.userHeadImg),
                                    ),
                                    
                                 ),
                                 SizedBox(width: 3.0,),
                                 Text(commant.nickName)
                              ],
                           ),
                           Container(
                              child: _buildStars(context,commant.commentGrade),
                           )
                        ],
                    ),
                 ),
                 SizedBox(height: 10.0,),
                 //評價語
                 Container(
                    width: MediaQuery.of(context).size.width * 0.8,
                    
                    alignment: Alignment.centerLeft,
                    child: Text(
                       commant.commentContent
                    ),
                 ),
                 SizedBox(height: 10.0,),
                 //評價圖片
               commant.commentImgs != null ?  Container(
                    alignment: Alignment.centerLeft,
                    width: 150.0,
                    child: Image.network(commant.commentImgs[0],
                      fit: BoxFit.fitWidth,
                    ),
                 ): SizedBox(height: 2.0,),
                 SizedBox(height: 8.0,),
                 //地址
                 Container(
                    child: Row(
                       children: <Widget>[
                          Container(
                             child: Icon(Icons.place,
                               size: 24.0,
                               color: Colors.black45,
                             ),
                          ),
                          Container(
                             child: Text(commant.commentAddress,
                               
                             ),
                          )
                       ],
                    ),
                 )
            ],
         ),
      );
  }

 Widget _buildStars(BuildContext context,int commentGrade){
    List<Widget> lists = List();
    for(var i = 0; i < commentGrade; i++){
       lists.add(
          Container(
             child: Row(
               children: <Widget>[
                  Icon(Icons.star,
                      color: Colors.orangeAccent,
                      size: 20.0,
                      ),
                  SizedBox(width: 2.0,),
               ],
             ),
          )
          
       );
    }
   
    return Container(
        child: Row(
           children: lists
        ),
    );
 }

}

權(quán)當(dāng)練習(xí)布局了

為什么選擇我們
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';

class DetailsCompany extends StatelessWidget {
 

  @override
  Widget build(BuildContext context) {
    return Provide<DetailsPageProvide>(
             builder: (context,child,val){
                var datas = val.datas;
                return  Container(
                    color: Colors.white,
                    child: Column(
                      children: <Widget>[
                          Container(
                            padding: EdgeInsets.only(top: 20.0),
                            child: Center(
                                child: Text(datas.wayChooseUs.subject),
                            ),
                          ),
                          _buildBrands(context, datas.wayChooseUs.titleTextImgs)
                      ],
                    ),
                  );
              },
                
  );
   
}

 //圓形圖片
 Widget _buildBrands(BuildContext context,List<DetailsModelDatasWaychooseusTitletextimg> titleTextImgs){
      return Padding(
         padding: EdgeInsets.all(20.0),
         child: Container(
            child: Wrap(
               spacing: 30.0,
               runSpacing: 30.0,
               children: _buildCompanyList(context, titleTextImgs),
            ),
         ),
      );
  }
  
   List<Widget> _buildCompanyList(BuildContext context,List<DetailsModelDatasWaychooseusTitletextimg> titleTextImgs){
        List<Widget> list = new List();
        for(var i = 0; i < titleTextImgs.length; i++){
          list.add(
             Container(
                width: (MediaQuery.of(context).size.width - 100.0)/3,
                child: Column(
                   mainAxisAlignment: MainAxisAlignment.center,
                   children: <Widget>[
                      Container(
                         child: ClipOval(
                            child: Image.network(titleTextImgs[i].image),
                         ),
                      ),
                      SizedBox(height: 2.0,),
                      Container(
                         alignment: Alignment.center,
                         child: Text(titleTextImgs[i].title),
                      )
                   ],
                ),
             )
          ); 
          
        }
        return list;

  }
}

熟能生巧塔嬉,寫多了,這種布局寫起來就沒什么難度了约啊。

圖文詳情
import 'package:flutter/material.dart';
import 'package:provide/provide.dart';
import '../../provide/details_provide.dart';
import '../../model/details_model.entity.dart';

class DetailsImgText extends StatelessWidget {
  

  @override
  Widget build(BuildContext context) {
    return Provide<DetailsPageProvide>(
         builder: (context,child,val){
            var datas = val.datas;
            return Container(
              color: Colors.white,
              child: Column(
                 children: <Widget>[
                    Container(
                       alignment: Alignment.centerLeft,
                       padding: EdgeInsets.all(15.0),
                       child: Text("圖文詳情"),
                    ),
                    _buildImages(context, datas.itemImages)

                 ],
              )
            );
         },
    );
    
  }

  //循環(huán)圖片
  Widget _buildImages(BuildContext context,List<String> itemImage){
   
     List<Widget> lists = List();
     for(var i = 0; i < itemImage.length; i++){
        lists.add(
           Container(
              width: MediaQuery.of(context).size.width,
              child: Image.network(itemImage[i],
                fit: BoxFit.fitWidth,
              ),
           )
        );
     }
     return Column(
         children: lists,
     );

  }

}

給圖片選擇一個填充方式: fit:BoxFit.fitWidth.

底部購物車欄
import 'package:flutter/material.dart';

class DetailsBottom extends StatelessWidget {
  const DetailsBottom({Key key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var itemW = MediaQuery.of(context).size.width / 6;
    return Container(
      color: Colors.white,
      width: MediaQuery.of(context).size.width,
      height: 60.0,
      child: Row(
          children: <Widget>[
             //客服
             InkWell(
               onTap: (){
                 print("點(diǎn)擊了客服");
               },
               child: Container(
                      width: itemW,
                      decoration: BoxDecoration(
                        border: Border(
                            right: BorderSide(width: 1,color: Colors.black38)
                        )
                      ),
                      child: Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          Icon(Icons.phone_iphone,
                            color: Colors.black45,
                            size: 30.0,
                          ),
                          Text("客服")
                        ],
                      ),
                  ),
             ),
             
             Container(
                width: itemW,
                child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: <Widget>[
                     Icon(Icons.shopping_cart,
                      size: 30.0,
                      color: Colors.black45,
                     ),
                     Text("購物車")
                  ],
                ),
             ),
             Container(
               width: 2*itemW,
               color: Color.fromRGBO(45, 60, 49, 1.0),
               alignment: Alignment.center,
               child: Text(
                  "加入購物車",
                  style:TextStyle(
                    color:Colors.white
                  )
               ),
             ),
             Container(
               width: 2*itemW,
               color: Colors.orangeAccent,
               alignment: Alignment.center,
               child: Text(
                  "立即購買",
                  style:TextStyle(
                    color:Colors.white
                  )
               ),
             )
          ],
      ),
    );
  }
}

這個主要就是在嵌入商品詳情頁的時候邑遏,是要懸浮在詳情頁其它組件之上且在底部:

 Positioned(
                             bottom: 0,
                             left: 0,
                             child: DetailsBottom(),
                          )
商品詳情頁就這么多東西,然后其中的各種數(shù)據(jù)交互的邏輯都還沒做恰矩,這個得和后面的購物車結(jié)合起來做。最后這個項(xiàng)目完成后代碼會上傳到gitHub上憎蛤。 其次其中寫得不好的請指正外傅,共同進(jìn)步。

下一篇購物車界面

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末俩檬,一起剝皮案震驚了整個濱河市萎胰,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌棚辽,老刑警劉巖技竟,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異屈藐,居然都是意外死亡榔组,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進(jìn)店門联逻,熙熙樓的掌柜王于貴愁眉苦臉地迎上來搓扯,“玉大人,你說我怎么就攤上這事包归∠峭疲” “怎么了?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長换可。 經(jīng)常有香客問我椎椰,道長,這世上最難降的妖魔是什么沾鳄? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任慨飘,我火速辦了婚禮,結(jié)果婚禮上洞渔,老公的妹妹穿的比我還像新娘套媚。我一直安慰自己,他們只是感情好磁椒,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布堤瘤。 她就那樣靜靜地躺著,像睡著了一般浆熔。 火紅的嫁衣襯著肌膚如雪本辐。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天医增,我揣著相機(jī)與錄音慎皱,去河邊找鬼。 笑死叶骨,一個胖子當(dāng)著我的面吹牛茫多,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播忽刽,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼天揖,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了跪帝?” 一聲冷哼從身側(cè)響起今膊,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伞剑,沒想到半個月后斑唬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黎泣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年恕刘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片聘裁。...
    茶點(diǎn)故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡雪营,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出衡便,到底是詐尸還是另有隱情献起,我是刑警寧澤洋访,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站谴餐,受9級特大地震影響姻政,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜岂嗓,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一汁展、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧厌殉,春花似錦食绿、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至楼眷,卻和暖如春铲汪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背罐柳。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工掌腰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人张吉。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓齿梁,卻偏偏與公主長得像,于是被迫代替她去往敵國和親肮蛹。 傳聞我的和親對象是個殘疾皇子士飒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,442評論 2 359

推薦閱讀更多精彩內(nèi)容

  • “兵器是磨出來的,士兵是練出來的”——中國拓展訓(xùn)練哲學(xué)理論實(shí)踐撰寫大師何宜宣~(? ̄?? ̄??)~今天我們?nèi)?..
    Hannah宣閱讀 437評論 0 2
  • https://leetcode.com/problems/two-sum/ Given an array of ...
    羊yang678閱讀 148評論 0 1