效果图
分析组成控件
1:列表控件,类似Android listview,recyclerview。等列表控件 2:ios的uiTableview 以上是整体。
分析item:
我们在写ui之前,先规划好怎么布局它,分析之后,可以确定, 整体:垂直Android:LinearLayout => Column 图片:ImageView => Image 文字:TextView => Text 水平布局:Android:LinearLayout => Row
以上是Android类比flutter控件。 我们需要学习这些控件,如何使用。比如文字大小,颜色,边距等
···· ·· · 这里就自学完成了。? ·· ····
点击事件:GestureDetector
最里面的构造就是这样了。
网络获取数据
还记得上一篇文章吗,使用原生网络工具,请求数据。
var baseUrl = 'https://api.sunofbeach.net/shop/onSell/1';
我们请求上面的数据。 用浏览打开,然后得到json。 把这个json转成dart bean : UnionOnSellEntity 上一篇中我们有具体教程转的,使用as插件。这里就不说了。
全部代码
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;
}
页面代码
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[index];
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[index];
//进入领券详情页面.你可以先把这里的代码注释,因为你没有接下来的页面.
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => TicketDetail(),
settings: RouteSettings(
arguments: TicketArgs(
item.title,
item.couponClickUrl == null ? item.clickUrl : item.couponClickUrl,
"https:" + item.pictUrl,
),
),
),
);
}
}
在你的app入口,替换成
Recommend
运行app,就能看的效果了。
配置文件记得增加这个权限
<uses-permission android:name="android.permission.INTERNET" />
flutter新手分享,大佬轻喷 以上~