Flutter添加購物車效果實(shí)現(xiàn)

trimVideo_2019-12-16_19_51_24.gif

1. 要實(shí)現(xiàn)先要了解的知識 :

(0)flutter 常用組件的使用

(1)flutter 動畫

(2) flutter 控件位置及大小如何獲取

動畫:

這里只隨口一說里邊用到的, 詳細(xì)的flutter動畫介紹后面會再整理。

(1)AnimationController: 動畫的控制: 控制動畫的開始,介紹,時長等。

(2)Animation: 動畫, 可設(shè)置監(jiān)聽動畫的狀態(tài)變化監(jiān)聽。 通過 animation.value 來獲取動畫的值。

控件位置及大小的獲取:

一句話--> 通過 BuildContext , 能拿到BuildContext就可以拿到控件相關(guān)的位置、大小等信息。

至于一個小組件的context 如果??? 一般我了解的有2種,

a. 一個是提取一個小組件為自定義widget,build里邊的context即是我們所需要的。

b. 另外一個相對簡單的就是直接通過 GlobalKey 的 .currentContext 來拿到。

key.currentContext的方式:

RenderBox renderBox = spKey.currentContext.findRenderObject();

// 這個就是控件的大小 size.width, size.height

Size size = renderBox.size;

// offset 就是坐標(biāo)相關(guān)的 offset.dx, offset.dy

Offset offset = renderBox.localToGlobal(Offset(renderBox.size.width * 0.5, renderBox.size.height * 0.5)); // 轉(zhuǎn)化為全局左邊, 這樣更容易我們后邊的處理。

通過提取Widget的方式:

相對于上邊的3行代碼, 就第一行不一樣,RenderBox renderBox = context.findRenderObject(); // context 就是widget 中的BuildContext。

2. 思路

效果是 從點(diǎn)擊的位置 在一小段時間內(nèi) 將一個圖片or紅點(diǎn)or XXX 以一個曲線的方式移動到購物車中,來給人更真實(shí)的 “雞蛋放到框里”的感覺。

我們知道這個移動的紅點(diǎn)(這里就用紅點(diǎn)了,你可以移動任何東西)移動的過程中是要跨越很多其他widget的,比如從列表第一個移動跨越整個列表到列表右下角懸浮的一個“購物車” , 或者更復(fù)雜點(diǎn)的,要移動到下邊主菜單(Tabbar)中的購物車。所以, 我們完成移動的畫布就需要是 “屏幕級”的了。 那我們就用 Stack ,用Stack在原有的頁面上疊加一個用戶看不到的“頁面”, 我們的效果動畫就在這個疊加的Widget上去完成。

動畫的實(shí)現(xiàn): (1)獲取點(diǎn)擊的按鈕的位置a, (2)獲取“購物車”的位置b 這樣我們要做的工作就變成了, 將一個紅點(diǎn)按動畫的方式 從位置a移動到位置b, 這樣問題就簡單了 。 a --> b

3. 實(shí)現(xiàn)(主要代碼)

(1)商品列表加入購物車主要代碼的實(shí)現(xiàn)

Stack(

children: <Widget>[

Container(

child: ListView(

children: goodsList.map((item) {

return GoodsItem(

item: item,

addToShoppingCart: (o) {

count++;

setState(() {

goodsOffset = o;

});

},

);

}).toList()),

),

// 這個就是我們要做動畫移動的“浮層”頁面

AddAnimationContainer(

startOffset: goodsOffset, // 點(diǎn)擊的商品位置

endOffset: spOffset, // 購物車位置

topHeight: topHeight, // 這個看實(shí)際情況,這里是頂部appBar的高度,我們做動畫的時候計算用的 (全局坐標(biāo)- 這個)

),

],

),

(2)移動動畫實(shí)現(xiàn)

double top = 0; // 要移動的紅點(diǎn)距離頂部的距離

double left = 0; // 要移動的紅點(diǎn)距離左邊的距離

AnimationController _controller;

Animation _animation;

@override

void initState() {

super.initState();

_controller =

AnimationController(duration: Duration(milliseconds: 800), vsync: this);

_animation = Tween(begin: 0, end: 1.0).animate(_controller)

..addListener(() {

setState(() {});

})

..addStatusListener((AnimationStatus status) { // 動畫狀態(tài)的監(jiān)聽

if (status == AnimationStatus.completed) { // 動畫完成以后 通知上層回調(diào)

if (widget.onEnd != null) {

widget.onEnd(this.widget);

}

}

});

WidgetsBinding.instance.addPostFrameCallback((_) { // 這個回調(diào)是在組件繪制完成后第一個調(diào)用的,且只調(diào)用一次, 這里做開啟動畫的動作

_controller.forward();

});

}

@override

void dispose() {

// 一定不要忘記做 銷毀 釋放

_controller.dispose();

_animation = null;

_controller = null;

super.dispose();

}

@override

Widget build(BuildContext context) {

// 1\. 開始的坐標(biāo)信息

var startX = widget.startOffset.dx;

var startY = widget.startOffset.dy;

// 2\. 結(jié)束點(diǎn)的坐標(biāo)信息

var endX = widget.endOffset.dx;

var endY = widget.endOffset.dy;

// 3\. 動畫值變化過程中計算 紅點(diǎn)的 實(shí)時位置

var x = startX + (endX - startX) * _animation.value;

var y = startY + (endY - startY) * _animation.value;

// 4\. 根據(jù)實(shí)時位置來確定組件的實(shí)際位置

top = y;

left = x;

return Container(

child: Positioned(

top: top - widget.topHeight,

left: left,

child: Icon( // 這 就是 所說的要移動的 “紅點(diǎn)” 組件,,,可以任意定義

Icons.arrow_drop_down_circle,

color: Colors.red,

size: 18,

),

),

);

}

4. 全部代碼

下載地址一:
https://download.csdn.net/download/chwei_cson/12032825
下載地址二:
https://github.com/chweiGitHub/flutter_demo.git

5. 這只是學(xué)習(xí)筆記,有錯誤歡迎指出。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容