Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(七)
我們假設(shè)一種情況,如果應(yīng)用程序使用條形圖顯示給定年份的產(chǎn)品類別的銷售額,用戶可以選擇另一年,然后該應(yīng)用程序?qū)?dòng)畫到該年的條形圖。如果產(chǎn)品類別在兩年內(nèi)是相同的,或者恰好是相同的,除了在其中一個(gè)圖表中右側(cè)顯示的其他類別,我們可以使用我們現(xiàn)有的代碼。但如果公司在2016年有A,B,C和X類產(chǎn)品,但是在2017年中斷了B并推出了D?

動(dòng)畫效果可以做得非常好看,但仍然會(huì)讓用戶感到困惑。為什么?因?yàn)樗槐A粽Z義。它將表示產(chǎn)品類別B的圖形元素轉(zhuǎn)換為代表類別C的一個(gè)圖形元素,而將C的圖形元素轉(zhuǎn)換到其他地方。正因?yàn)?016 B恰好是在2017 C后來出現(xiàn)的同一位置,并不意味著前者應(yīng)該變成后者。相反,2016年B應(yīng)該消失,2016年C應(yīng)該向左移動(dòng)到2017年,而2017年D應(yīng)該出現(xiàn)在右邊。我們可以使用傳統(tǒng)的合并排序列表實(shí)現(xiàn)這種混合。
我們可以分別給每一個(gè)條形以不同的顏色,然后使用顏色來區(qū)分銷售的產(chǎn)品,一種顏色代表一個(gè)產(chǎn)品,當(dāng)一種顏色消失時(shí),說明該產(chǎn)品已經(jīng)下架,反之,則說明新產(chǎn)品已經(jīng)上架。
通過語義對(duì)應(yīng)的組件進(jìn)行復(fù)合值之間的線性插值(lerp),當(dāng)組件形成排序列表時(shí),合并算法可以將這些組件放在側(cè)面上,使用不可見組件來處理單面合并。我們所需要的是使Bar實(shí)例以線性順序相互比較。然后我們可以將它們合并。
// ...
class BarChart {
// ...
factory BarChart.random(Size size, Random random) {
const barWidthFraction = 0.75;
final ranks = selectRanks(random, ColorPalette.primary.length);
final barCount = ranks.length;
final barDistance = size.width / (1+barCount);
final barWidth = barDistance * barWidthFraction;
final startX = barDistance - barWidth/2;
final bars = new List.generate(
barCount,
(i)=> new Bar(
ranks[i],
startX + i * barDistance,
barWidth,
random.nextDouble() * size.height,
ColorPalette.primary[ranks[i]],
),
);
return new BarChart(bars);
}
static List<int> selectRanks(Random random, int cap) {
final ranks = <int>[];
var rank = 0;
while(true) {
// 模擬產(chǎn)品的上架下架
if(random.nextDouble() < 0.2) rank++;
if(cap <= rank) break;
ranks.add(rank);
rank++;
}
return ranks;
}
static BarChart lerp(BarChart begin, BarChart end, double t) {
final bars = <Bar>[];
final bMax = begin.bars.length;
final eMax = end.bars.length;
var b = 0;
var e = 0;
while (b + e < bMax + eMax) {
/*
這里的條件判斷中包含兩種情況
b < bMax && e == eMax:
當(dāng)新圖表?xiàng)l形數(shù)減少時(shí)
b < bMax && begin.bars[b] < end.bars[e]:
當(dāng)新圖表不包含舊圖表的顏色條形時(shí)
滿足一種情況,處理舊圖表中多余的條形,即向左側(cè)方清除舊條形
*/
if(b < bMax && (e == eMax || begin.bars[b] < end.bars[e])) {
bars.add(Bar.lerp(begin.bars[b], begin.bars[b].collapsed, t));
b++;
/*
這里的條件判斷中包含兩種情況
e < eMax && b == bMax:
當(dāng)新圖表?xiàng)l形數(shù)增加時(shí)
e < eMax && end.bars[e] < begin.bars[b]:
當(dāng)新圖表包含舊圖表沒有的顏色條形時(shí)
滿足一種情況,處理舊圖表中沒有的條形,即向右側(cè)方繪制新條形
*/
} else if(e < eMax && (b == bMax || end.bars[e] < begin.bars[b])) {
bars.add(Bar.lerp(end.bars[e].collapsed, end.bars[e], t));
e++;
// 當(dāng)新圖表與舊圖表有同一個(gè)顏色條形時(shí),原地變形
} else {
bars.add(Bar.lerp(begin.bars[b], end.bars[e], t));
b++;
e++;
}
}
return new BarChart(bars);
}
}
class BarChartTween extends Tween<BarChart> {
BarChartTween(BarChart begin, BarChart end) : super(begin: begin, end: end);
@override
BarChart lerp(double t) => BarChart.lerp(begin, end, t);
}
class Bar {
Bar(this.rank, this.x, this.width, this.height, this.color);
final int rank;
final double x;
final double width;
final double height;
final Color color;
Bar get collapsed => new Bar(rank, x, 0.0, 0.0, color);
/*
bool operator <(
Duration other
)
如果此Duration的值小于other值,則返回true
bool operator <(Duration other) => this._duration < other._duration;
*/
bool operator <(Bar other) => rank < other.rank;
static Bar lerp(Bar begin, Bar end, double t) {
assert(begin.rank == end.rank);
return new Bar(
begin.rank,
lerpDouble(begin.x, end.x, t),
lerpDouble(begin.width, end.width, t),
lerpDouble(begin.height, end.height, t),
Color.lerp(begin.color, end.color, t)
);
}
}
class BarTween extends Tween<Bar> {
BarTween(Bar begin, Bar end) : super(begin: begin, end: end) {
assert(begin.rank == end.rank);
}
@override
Bar lerp(double t) => Bar.lerp(begin, end, t);
}
// ...
具體來說,我們將以整數(shù)rank屬性的形式為每個(gè)條形分配一個(gè)排序鍵。然后可以方便地使用rank來從調(diào)色板中分配每個(gè)條形的顏色,從而使我們能夠跟蹤動(dòng)畫演示中各個(gè)條形圖的移動(dòng)。
隨機(jī)條形圖現(xiàn)在將基于隨機(jī)選擇的行列。

但這不是最有效的解決方案,我們正在BarChart.lerp中重復(fù)執(zhí)行合并算法,對(duì)于t的每個(gè)值都執(zhí)行一次。為了解決這個(gè)問題,我們將實(shí)現(xiàn)前面一篇文章中提到的想法,以便在BarChartTween中存儲(chǔ)可重用的信息。
// ...
class BarChartTween extends Tween<BarChart> {
final _tweens = <BarTween>[];
BarChartTween(BarChart begin, BarChart end) : super(begin: begin, end: end) {
final bMax = begin.bars.length;
final eMax = end.bars.length;
var b = 0;
var e = 0;
while (b + e < bMax + eMax) {
if(b < bMax && (e == eMax || begin.bars[b] < end.bars[e])) {
_tweens.add(new BarTween(begin.bars[b], begin.bars[b].collapsed));
b++;
} else if(e < eMax && (b == bMax || end.bars[e] < begin.bars[b])) {
_tweens.add(new BarTween(end.bars[e].collapsed, end.bars[e]));
e++;
} else {
_tweens.add(new BarTween(begin.bars[b], end.bars[e]));
b++;
e++;
}
}
}
@override
BarChart lerp(double t) => new BarChart(
new List.generate(
_tweens.length,
(i) => _tweens[i].lerp(t))
);
}
// ...
然后我們就可以刪除靜態(tài)的BarChart.lerp方法了。
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(一)
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(二)
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(十)
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(三)
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(五)
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(九)
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(四)
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(八)
- Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(六)
- Flutter實(shí)戰(zhàn)教程之酷炫的開關(guān)動(dòng)畫效果
相關(guān)文章
Android使用OkHttp進(jìn)行重定向攔截處理的方法
這篇文章主要介紹了Android使用OkHttp進(jìn)行重定向攔截處理的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-08-08
Kotlin注解實(shí)現(xiàn)Parcelable序列化流程詳解
有時(shí)我們會(huì)在界面跳轉(zhuǎn)的過程中,做對(duì)象傳值,這時(shí)就需要對(duì)該對(duì)象做序列化處理了。Android中對(duì)對(duì)象的序列化處理有兩種方式,這篇文章主要介紹了Kotlin注解實(shí)現(xiàn)Parcelable序列化2022-12-12
Android CountDownTimer案例總結(jié)
這篇文章主要介紹了Android CountDownTimer案例總結(jié),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08
Android ImageView實(shí)現(xiàn)圖片裁剪和顯示功能
這篇文章主要介紹了Android ImageView實(shí)現(xiàn)圖片裁剪和顯示功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-02-02
a2sd+狀態(tài)下應(yīng)用程序丟失的解決方法詳細(xì)解析
用了a2sd+和SD分區(qū)方案的朋友可能會(huì)遇到突然某次開機(jī)之后,a2sd+失效,同時(shí)發(fā)生丟失若干應(yīng)用程序的現(xiàn)象或者安裝軟件提示空間不足2013-09-09
Android 自定義縮短Toast顯示時(shí)間的實(shí)例代碼
這篇文章主要介紹了Android 自定義縮短Toast顯示時(shí)間,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
Android Material加載進(jìn)度條制作代碼
這篇文章主要為大家詳細(xì)介紹了AndroidMaterial加載進(jìn)度條的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
android 指紋識(shí)別調(diào)用實(shí)現(xiàn)方法及示例代碼
這里主要介紹Android 指紋識(shí)別的簡單實(shí)現(xiàn)代碼,希望能幫助開發(fā)這部分應(yīng)用的朋友,有需要的小伙伴可以參考下2016-09-09

