主要完成沸点页面的话题广场页面. 这个页面涉及到内容包括: 拖拽排序,增加话题动画效果,先分析效果怎么实现,然后就是页面的构建。 最终效果
拖拽
首先想到拖拽,flutter提供了ReorderableListView 拖拽效果如下:
var data = <Color>[
Colors.yellow[50],
Colors.blue[100],
Colors.red[200],
Colors.pink[300],
];
@override
Widget build(BuildContext context) {
return Container(
height: 250,
child: ReorderableListView(
padding: EdgeInsets.all(10),
onReorder: _handleReorder,
scrollDirection: Axis.vertical,
children: data.map((color) => _buildItem(color)).toList(),
),
);
}
void _handleReorder(int oldIndex, int newIndex) {
if (oldIndex < newIndex) {
newIndex -= 1;
}
setState(() {
final element = data.removeAt(oldIndex);
data.insert(newIndex, element);
});
}
Widget _buildItem(Color color) {
return Container(
key: ValueKey(color),
alignment: Alignment.center,
height: 50,
width: 200,
color: color,
);
}
还有利用GridView和LongPressDraggable进行拖拽排序
renderItem(index) {
return Stack(
children: [
Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey, width: 1),
borderRadius: BorderRadius.circular(15),
),
alignment: Alignment.center,
child: Text(widget.dataList[index]['title']),
),
Positioned(
child: Text(widget.dataList[index]['move'] == 'false' ? 'x' : '+'),
right: 10,
top: 2,
),
],
);
}
Widget _buildItemWidget(int index) {
return LongPressDraggable(
data: index,
child: DragTarget<int>(
onAccept: (data) {
widget.onAccept(data, index);
},
builder: (context, data, rejects) {
return renderItem(index);
},
onMove: (data) {
print(data);
},
onLeave: (data) {
print('$data is Leaving item $index');
widget.onAccept(data, index);
},
onWillAccept: (data) {
return true;
},
),
onDragStarted: () {
},
onDraggableCanceled: (Velocity velocity, Offset offset) {
},
onDragCompleted: () {
},
feedback: Material(
child: Container(
width: (Get.width - 20 - 20) / 3.0,
height: (Get.width - 20 - 20) / 3.0 * 4 / 10,
child: renderItem(index),
),
),
childWhenDragging: Container(),
);
}
@override
Widget build(BuildContext context) {
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 2.5,
crossAxisSpacing: 10,
mainAxisSpacing: 10),
itemCount: widget.dataList.length,
itemBuilder: (BuildContext context, int index) {
return _buildItemWidget(index);
});
}
两种效果都能实现需求,没有思路就看看大神们都是怎么写的。看了看源码,有利用GridView加手势识别配合操作实现。 使用dragablegridview_flutter库 然后稍加了修改 传送门。 没有思路可以去搜搜。有实现的大神,读读代码。慢慢的自己也可以造轮子了。
List<ItemBin> itemBins = new List();
var editSwitchController = EditSwitchController();
DragAbleGridView(
mainAxisSpacing: 10.0,
crossAxisSpacing: 0.0,
childAspectRatio: 2.5,
crossAxisCount: 3,
itemBins: itemBins,
editSwitchController: editSwitchController,
isOpenDragAble: alert != '点击进入话题',
animationDuration: 300, //milliseconds
longPressDuration: 800, //milliseconds
child: (int position) {
return Container(
width: (Get.width - 60) / 3.0,
height: (Get.width - 40) / 3.0 * 0.4,
// margin: EdgeInsets.only(top: 6.0, right: 6.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey, width: 1),
borderRadius: BorderRadius.circular(15),
),
alignment: Alignment.center,
child: Text(
itemBins[position].data,
style: TextStyle(fontSize: 16.0, color: Colors.blue),
),
);
},
editChangeListener: () {},
),
),
抖动起来
直接使用补间动画就可以了,点击编辑让可以编辑的动起来
controller = AnimationController(
duration: const Duration(milliseconds: 1000), vsync: this);
animation = TweenSequence<double>([
//使用TweenSequence进行多组补间动画
TweenSequenceItem<double>(tween: Tween(begin: 0, end: 5), weight: 1),
TweenSequenceItem<double>(tween: Tween(begin: 5, end: 0), weight: 2),
TweenSequenceItem<double>(tween: Tween(begin: 0, end: -5), weight: 3),
TweenSequenceItem<double>(tween: Tween(begin: -5, end: 0), weight: 4),
]).animate(controller)
..addListener(() {
setState(() {});
})
..addStatusListener((s) {
if (s == AnimationStatus.completed) {
setState(() {});
// controller.forward();
}
});
Transform(
transform:
Matrix4.rotationZ(animation.value * pi / 180),
alignment: Alignment.center,
child: Container(
width: (Get.width - 60) / 3.0,
height: (Get.width - 40) / 3.0 * 0.4,
margin: EdgeInsets.only(top: 6.0),
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.grey, width: 1),
borderRadius: BorderRadius.circular(15),
),
alignment: Alignment.center,
child: Text(
itemBins[position].data,
style:
TextStyle(fontSize: 16.0, color: Colors.blue),
),
));
添加话题联动
底部添加话题,我的话题中删除话题.产生联动效果,实现起来比较简单,就是最终效果了。
//默认加载5条数据
CommonListWiget(
networkApi: (currentPage) async {
return ['1', '2', '3', '4', '5'];
},
itemBuilder: (BuildContext context, int position) {
//....之前省略代码
// 最后返回:
Wrap(
children: futureList
.map((e) => Stack(
children: [
InkWell(
onTap: () {
futureList.remove(e);
currentList.add(e);
itemBins.add(new ItemBin(e));
// setState(() {});
},
child: Container(
margin: EdgeInsets.only(
bottom: 10, right: 10, left: 10, top: 5),
width: (Get.width - 60) / 3.0,
height: (Get.width - 40) / 3.0 * 0.4,
decoration: BoxDecoration(
color: Colors.white,
border:
Border.all(color: Colors.grey, width: 1),
borderRadius: BorderRadius.circular(15),
),
alignment: Alignment.center,
child: Text(e,
style: TextStyle(
fontSize: 16.0, color: Colors.blue)),
),
),
Positioned(
child: Text(
'+',
style: TextStyle(fontSize: 18),
),
top: 5,
right: 20,
)
],
))
.toList(),
);
}