debug_cat 发表于 2020-8-25 14:23

Flutter 领券联盟特惠推荐列表

## 效果图
![图片描述](https://imgs.sunofbeaches.com/group1/M00/00/2B/rBsADV82lm2ACq1FAAxzhPz6VkI268.png)

### 分析组成控件
1:列表控件,类似Android listview,recyclerview。等列表控件
2:ios的uiTableview
以上是整体。

#### 分析item:
![图片描述](https://imgs.sunofbeaches.com/group1/M00/00/2B/rBsADV82l1GAEU0MAAXV73O-yhI331.png)

我们在写ui之前,先规划好怎么布局它,分析之后,可以确定,
整体:垂直Android:LinearLayout => Column
图片:ImageView => Image
文字:TextView => Text
水平布局:Android:LinearLayout => Row

以上是Android类比flutter控件。
我们需要学习这些控件,如何使用。比如文字大小,颜色,边距等

····
··
·        这里就自学完成了。😀
··
····

点击事件:GestureDetector

最里面的构造就是这样了。
![图片描述](https://imgs.sunofbeaches.com/group1/M00/00/2B/rBsADV82muuAezfCAAQBFYuhkdw623.png)





#### 网络获取数据
还记得上一篇文章吗,使用原生网络工具,请求数据。
```language
var baseUrl = 'https://api.sunofbeach.net/shop/onSell/1';

```
我们请求上面的数据。
用浏览打开,然后得到json。
把这个json转成dart bean : UnionOnSellEntity
上一篇中我们有具体教程转的,使用as插件。这里就不说了。

![图片描述](https://imgs.sunofbeaches.com/group1/M00/00/2B/rBsADV82nN6AGW-vAAXd_H-xOYQ233.png)


#### 全部代码
```language
UnionOnSellEntity
class UnionOnSellEntity with JsonConvert<UnionOnSellEntity> {
        bool success;
        int code;
        String message;
        UnionOnSellData data;
}

class UnionOnSellData with JsonConvert<UnionOnSellData> {
        @JSONField(name: "tbk_dg_optimus_material_response")
        UnionOnSellDataTbkDgOptimusMaterialResponse tbkDgOptimusMaterialResponse;
}

class UnionOnSellDataTbkDgOptimusMaterialResponse with JsonConvert<UnionOnSellDataTbkDgOptimusMaterialResponse> {
        @JSONField(name: "is_default")
        String isDefault;
        @JSONField(name: "result_list")
        UnionOnSellDataTbkDgOptimusMaterialResponseResultList resultList;
        @JSONField(name: "request_id")
        String requestId;
}

class UnionOnSellDataTbkDgOptimusMaterialResponseResultList with JsonConvert<UnionOnSellDataTbkDgOptimusMaterialResponseResultList> {
        @JSONField(name: "map_data")
        List<UnionOnSellDataTbkDgOptimusMaterialResponseResultListMapData> mapData;
}

class UnionOnSellDataTbkDgOptimusMaterialResponseResultListMapData with JsonConvert<UnionOnSellDataTbkDgOptimusMaterialResponseResultListMapData> {
        @JSONField(name: "category_id")
        int categoryId;
        @JSONField(name: "category_name")
        String categoryName;
        @JSONField(name: "click_url")
        String clickUrl;
        @JSONField(name: "commission_rate")
        String commissionRate;
        @JSONField(name: "coupon_amount")
        int couponAmount;
        @JSONField(name: "coupon_click_url")
        String couponClickUrl;
        @JSONField(name: "coupon_end_time")
        String couponEndTime;
        @JSONField(name: "coupon_info")
        String couponInfo;
        @JSONField(name: "coupon_remain_count")
        int couponRemainCount;
        @JSONField(name: "coupon_share_url")
        String couponShareUrl;
        @JSONField(name: "coupon_start_fee")
        String couponStartFee;
        @JSONField(name: "coupon_start_time")
        String couponStartTime;
        @JSONField(name: "coupon_total_count")
        int couponTotalCount;
        @JSONField(name: "item_description")
        String itemDescription;
        @JSONField(name: "item_id")
        int itemId;
        @JSONField(name: "level_one_category_id")
        int levelOneCategoryId;
        @JSONField(name: "level_one_category_name")
        String levelOneCategoryName;
        String nick;
        @JSONField(name: "pict_url")
        String pictUrl;
        @JSONField(name: "seller_id")
        int sellerId;
        @JSONField(name: "shop_title")
        String shopTitle;
        @JSONField(name: "small_images")
        UnionOnSellDataTbkDgOptimusMaterialResponseResultListMapDataSmallImages smallImages;
        String title;
        @JSONField(name: "user_type")
        int userType;
        int volume;
        @JSONField(name: "zk_final_price")
        String zkFinalPrice;
}

class UnionOnSellDataTbkDgOptimusMaterialResponseResultListMapDataSmallImages with JsonConvert<UnionOnSellDataTbkDgOptimusMaterialResponseResultListMapDataSmallImages> {
        List<String> string;
}

```
#### 页面代码
```language
class Recommend extends StatelessWidget {
@override
Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
      title: Text('特惠推荐'),
      ),
      body: RecommendPage(),
    );
}
}

class RecommendPage extends StatefulWidget {
RecommendPage({Key key}) : super(key: key);

@override
_RecommendPageState createState() => new _RecommendPageState();
}

class _RecommendPageState extends State<RecommendPage>
    with AutomaticKeepAliveClientMixin {
@override
bool get wantKeepAlive => true;

@override
void initState() {
    super.initState();
    _getUnionRecommend();
}

var baseUrl = 'https://api.sunofbeach.net/shop/onSell/1';

List<UnionOnSellDataTbkDgOptimusMaterialResponseResultListMapData> mList =
      List();

_getUnionRecommend() async {
    var url = baseUrl;
    var httpClient = new HttpClient();
    List<UnionOnSellDataTbkDgOptimusMaterialResponseResultListMapData> tempList;
    try {
      var request = await httpClient.getUrl(Uri.parse(url));
      var response = await request.close();
      if (response.statusCode == HttpStatus.OK) {
      var json = await response.transform(utf8.decoder).join();
      Map<String, dynamic> map = jsonDecode(json);
      //json 转 data bean
      var entity = UnionOnSellEntity().fromJson(map);

      tempList = entity.data.tbkDgOptimusMaterialResponse.resultList.mapData;
      } else {
      print("request error");
      }
    } catch (exception) {
      print("request error");
    }
    if (!mounted) return;
    setState(() {
      //请求成功之后,赋值列表中,就可以刷新grid view了.
      mList = tempList;
    });
}

@override
Widget build(BuildContext context) {
    return new Scaffold(
      body: GridView.builder(
          itemCount: mList?.length ?? 0,
          gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
            //2列
            crossAxisCount: 2,
            //间距0
            mainAxisSpacing: 0,
            //间距0
            crossAxisSpacing: 0,
            //子 view的比例宽高比
            childAspectRatio: 0.65,
          ),
          itemBuilder: (context, index) {
            if (mList == null) {
            return Text("");
            }
            var item = mList;
            var imageUrl = item == null ? "" : "https:" + item.pictUrl;
            var itemTitle = item == null ? "" : item.title;
            //点击事件需要用手势包裹
            return GestureDetector(
            //整个card效果
            child: Card(
                child: Container(
                  margin: EdgeInsets.all(5),
                  //整个item的垂直布局
                  child: Column(
                  children: <Widget>[
                      //图片
                      Image.network(imageUrl),
                      //标题
                      Container(
                        margin: EdgeInsets.fromLTRB(2, 10, 15, 2),
                        child: Text(
                        itemTitle,
                        style: TextStyle(
                              fontSize: 16,
                              color: ColorsUtil.hexColor(0x000814)),
                        ),
                      ),
                      //水平布局包含左边的黄色价格,右边的原价
                      Row(
                        children: <Widget>[
                        Container(
                            margin: EdgeInsets.fromLTRB(2, 5, 0, 10),
                            //黄色价格
                            child: Text(
                              "¥" +
                                  (double.parse(item.zkFinalPrice) -
                                          item.couponAmount)
                                    .toStringAsFixed(2)
                                    .toString(),
                              style: TextStyle(
                                  color: ColorsUtil.hexColor(0xFF8500),
                                  fontSize: 15),
                            ),
                        ),
                        Container(
                            margin: EdgeInsets.fromLTRB(5, 5, 0, 10),
                            child: Text(
                              "原价价:" +
                                  (double.parse(item.zkFinalPrice))
                                    .toStringAsFixed(2)
                                    .toString(),
                              style: TextStyle(
                                  color: ColorsUtil.hexColor(0x666666),
                                  fontSize: 13,
                                  //中横线
                                  decoration: TextDecoration.lineThrough,
                                  decorationColor:
                                    ColorsUtil.hexColor(0x454646)),
                            ),
                        )
                        ],
                      )
                  ],
                  ),
                ),
            ),
            onTap: () {
                setState(() {
                  //点击事件
                  itemClick(index);
                });
            },
            );
          }),
    );
}

void itemClick(int index) {
    var item = mList;
    //进入领券详情页面.你可以先把这里的代码注释,因为你没有接下来的页面.
    Navigator.push(
      context,
      MaterialPageRoute(
      builder: (context) => TicketDetail(),
      settings: RouteSettings(
          arguments: TicketArgs(
            item.title,
            item.couponClickUrl == null ? item.clickUrl : item.couponClickUrl,
            "https:" + item.pictUrl,
          ),
      ),
      ),
    );
}
}

```

![图片描述](https://imgs.sunofbeaches.com/group1/M00/00/2B/rBsADV82nW-AQ_WQAADXAVA1Vf4057.png)
在你的app入口,替换成

```language
Recommend
```

运行app,就能看的效果了。
```language
配置文件记得增加这个权限
<uses-permission android:name="android.permission.INTERNET" />
```

flutter新手分享,大佬轻喷
以上~

深渊莫冥 发表于 2020-8-25 14:43

我是这个学期学的flutter,楼主很棒,加油

jzw12345 发表于 2020-8-25 14:53

不错,感谢分享。

正己 发表于 2020-8-25 15:14

建议代码用代码块包起来,这样看起来比较美观

debug_cat 发表于 2020-8-25 16:25

深渊莫冥 发表于 2020-8-25 14:43
我是这个学期学的flutter,楼主很棒,加油

我是在工作之余学习的,哈哈,加油

debug_cat 发表于 2020-8-25 16:27

jzw12345 发表于 2020-8-25 14:53
不错,感谢分享。

感谢阅读,谢谢你

986244073 发表于 2020-8-25 16:45

可以分享下api吗

爱你分享 发表于 2020-8-25 16:55

有零基础的教程么

YI封夕 发表于 2020-8-25 17:41

看不懂{:1_909:}{:1_909:}
不过,支持楼主

yangcg8 发表于 2020-8-27 16:18

值得借鉴的思路,谢谢分享
页: [1] 2
查看完整版本: Flutter 领券联盟特惠推荐列表