先看一下效果图吧。
其实没有实现难点,直接通过网络请求获取到动态数据,图片链接就在获取到的数据中,直接使用ListView,然后定义一下item布局和数据,图片展示直接用的三目表达式,单个图片使用Image,多个图片使用GridView。
先来第一步,获取网络数据。想要网络数据首先要进行网络访问,我使用的是dio库,链接如下:
dio: 2.1.13#网络
网络请求就不写了,很简单,大家直接百度一大堆。
然后第二步,创建ListView,为了代码清晰,我把ListView放在了另一个dart文件中,其中也实现了下拉刷新和上拉加载功能,下面是ListView的详细代码。
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_learning/bean/dynamicbean_entity.dart';
import 'package:flutter_learning/utils/http.dart';
import 'package:flutter_learning/utils/toast.dart';
import 'package:flutter_learning/utils/viewpicture.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
class projectitemextends StatefulWidget {
Listdynamicbean;
projectitem(List dynamicbean) {
this.dynamicbean = dynamicbean;
}
@override
StatecreateState() {
// TODO: implement createState
return itemBuild();
}
}
class itemBuildextends State {
//初始化滚动监听器,加载更多使用
intpages =1;
ScrollController_controller =new ScrollController();
StringloadMoreText ="没有更多数据";
TextStyleloadMoreTextStyle =
new TextStyle(color:const Color(0xFF999999), fontSize:14.0);
@override
Widgetbuild(BuildContext context) {
// TODO: implement build
return Container(
child:RefreshIndicator(
child:ListView.builder(
//physics: NeverScrollableScrollPhysics(),
shrinkWrap:true,
itemCount:widget.dynamicbean.length,
itemBuilder: (BuildContext context, int position) {
return getItem(widget.dynamicbean[position]);
},
controller:_controller,
),
onRefresh: _refresh),
);
}
Future_refresh()async {
_controller.addListener(() {
/*var maxScroll = _controller.position.maxScrollExtent;
var pixel = _controller.position.pixels;*/
load(++pages,"");
setState(() {
loadMoreText ="正在加载中...";
loadMoreTextStyle =
new TextStyle(color:const Color(0xFF4483f6), fontSize:14.0);
});
});
load(1, "");
return;
}
//获取当前登录人的数据库信息
void load(int page, String keyword)async {
if(page==1){
widget.dynamicbean.clear();
}
Dio dio = http.getDio();
var _result ="";
try {
await dio
.get(
"dynamic/getDynamics?data={'page': '${page}','keyword': '${keyword}'}")
.then((responses) {
if (responses.statusCode ==200) {
_result = responses.data.toString();
print(_result);
/*先将字符串转成json*/
Map json = jsonDecode(_result);
/**/
//UserBean newsBean = UserBean.fromJson(json);
DynamicbeanEntity dynamicbeanEntity =
DynamicbeanEntity.fromJson(json);
if (dynamicbeanEntity.success) {
widget.dynamicbean.addAll(dynamicbeanEntity.rows);
setState(() {});
}
}else {
_result ='error code : ${responses.statusCode}';
}
});
}catch (exception) {
print('exc:$exception');
_result ='网络异常';
}
}
WidgetgetItem(DynamicbeanRow mData) {
return Card(
margin:EdgeInsets.all(10),
child:InkWell(
onTap: () {
toast.showToasts(mData.name);
/*Navigator.push(
context,
new MaterialPageRoute(builder: (context) => new map(mData)),
);*/
},
child:Container(
alignment: Alignment.topLeft,
width: MediaQuery.of(context).size.width,
padding:EdgeInsets.all(ScreenUtil().setHeight(20)),
child:Column(
//mainAxisAlignment: MainAxisAlignment.start, 行里用这个
crossAxisAlignment: CrossAxisAlignment.start, //列里用这个
children: [
Container(
//显示用户名
margin:EdgeInsets.all(1),
child:Text(
mData.name,
style:TextStyle(color: Colors.blue, fontSize:16),
),
),
Container(
//显示时间
margin:EdgeInsets.all(1),
child:Text(
mData.date,
style:TextStyle(color: Colors.black54, fontSize:14),
),
),
Container(
//画一条线
margin:EdgeInsets.all(1),
child:Divider(
height:0.2,
indent:0,
color: Colors.black45,
),
),
Container(
//显示内容
margin:EdgeInsets.all(3),
child:Text(
mData.content,
style:TextStyle(color: Colors.black87, fontSize:14),
),
),
mData.urlList.length >0
? mData.urlList.length ==1
?Image.network(
mData.urlList[0],
width:ScreenUtil().setWidth(1000),
height:ScreenUtil().setHeight(1000),
)
:GridView.builder(
physics:NeverScrollableScrollPhysics(),
shrinkWrap:true,
itemCount: mData.urlList.length,
gridDelegate:
SliverGridDelegateWithFixedCrossAxisCount(
//横轴元素个数
crossAxisCount:3,
/*//纵轴间距mainAxisSpacing: 1.0,
//横轴间距crossAxisSpacing: 1.0,
//子组件宽高长度比例childAspectRatio: 1.4*/
),
itemBuilder: (BuildContext context, int index) {
return InkWell(
onTap: () {
toast.showToasts("哈哈哈");
Navigator.of(context).push( //点击显示类似朋友圈查看图片功能
NinePicture(mData.urlList, index), // 图片集合,要显示的下标
);
},
child:Container(
margin:EdgeInsets.all(1),
child:Image.network(mData.urlList[index]),
),
);
},
)
:Container(),
],
),
),
),
);
}
}
对了,里面还实现了类似朋友圈点击图片查看图片的功能,该工具类如下,这位兄台写的工具类。
import 'package:flutter/material.dart';
class NinePictureextends PopupRoute {
final StringbarrierLabel;
final ListpicList; //图片集合
final intindex; //显示的图片下标
intstartX;
intendX;
NinePicture(this.picList, this.index, {this.barrierLabel});
@override
Durationget transitionDuration =>Duration(milliseconds:2000);
@override
@override
Colorget barrierColor => Colors.black54;
@override
boolget barrierDismissible =>true;
AnimationController_animationController;
@override
AnimationControllercreateAnimationController() {
assert(_animationController ==null);
_animationController =
BottomSheet.createAnimationController(navigator.overlay);
return _animationController;
}
@override
WidgetbuildPage(BuildContext context, Animation animation,
Animation secondaryAnimation) {
return MediaQuery.removePadding(
removeTop:true,
context: context,
child:GestureDetector(
child:AnimatedBuilder(
animation: animation,
builder: (BuildContext context, Widget child) =>GestureDetector(
onTap: () {
Navigator.pop(context);
},
child:_PictureWidget(picList, index),
),
),
),
);
}
}
class _PictureWidgetextends StatefulWidget {
final ListpicList;
final intindex;
_PictureWidget(this.picList, this.index);
@override
StatecreateState() {
return _PictureWidgetState();
}
}
class _PictureWidgetStateextends State<_PictureWidget> {
intstartX =0;
intendX =0;
intindex =0;
@override
void initState() {
// TODO: implement initState
super.initState();
index =widget.index;
print("全屏显示:${widget.picList}${widget.index}");
}
@override
Widgetbuild(BuildContext context) {
return new Material(
color: Colors.transparent,
child:new Container(
width: double.infinity,
child:Stack(
children: [
GestureDetector(
child:Center(
child:
Image.network(widget.picList[index])
/*CachedNetworkImage(
imageUrl: widget.picList[index],
fit: BoxFit.cover,
)*/,
),
onHorizontalDragDown: (detail) {
startX = detail.globalPosition.dx.toInt();
},
onHorizontalDragUpdate: (detail) {
endX = detail.globalPosition.dx.toInt();
},
onHorizontalDragEnd: (detail) {
_getIndex(endX -startX);
setState(() {});
},
onHorizontalDragCancel: () {},
),
Align(
alignment: Alignment.bottomCenter,
child:Padding(
padding:const EdgeInsets.all(8.0),
child:Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children:List.generate(
widget.picList.length,
(i) =>GestureDetector(
child:CircleAvatar(
foregroundColor: Theme.of(context).primaryColor,
radius:4.0,
backgroundColor:index == i
? Theme.of(context).primaryColor
: Colors.white,
),
onTap: () {
setState(() {
startX =endX =0;
index = i;
});
},
),
).toList(),
),
),
)
],
),
alignment: Alignment.center,
),
);
}
void _getIndex(int delta) {
if (delta >50) {
setState(() {
index--;
index =index.clamp(0, widget.picList.length -1);
});
}else if (delta <50) {
setState(() {
index++;
index =index.clamp(0, widget.picList.length -1);
});
}
}
}
好了。先这样吧,周末再写点数据库(sqllite)和编写界面的心得。