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新手分享,大佬轻喷
以上~ 我是这个学期学的flutter,楼主很棒,加油 不错,感谢分享。 建议代码用代码块包起来,这样看起来比较美观 深渊莫冥 发表于 2020-8-25 14:43
我是这个学期学的flutter,楼主很棒,加油
我是在工作之余学习的,哈哈,加油 jzw12345 发表于 2020-8-25 14:53
不错,感谢分享。
感谢阅读,谢谢你 可以分享下api吗 有零基础的教程么 看不懂{:1_909:}{:1_909:}
不过,支持楼主 值得借鉴的思路,谢谢分享
页:
[1]
2