主要完成沸點頁面的話題廣場頁面. 這個頁面涉及到內容包括: 拖拽排序,增加話題動畫效果,先分析效果怎麼實現,然後就是頁面的構建。 最終效果
拖拽
首先想到拖拽,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(),
);
}
複製程式碼