Flutter進(jìn)階之實(shí)現(xiàn)動(dòng)畫效果(四)
在上一篇文章:Flutter進(jìn)階—實(shí)現(xiàn)動(dòng)畫效果(三)中,實(shí)現(xiàn)了一個(gè)隨機(jī)高度、顏色的條形。這一篇文章我們會(huì)實(shí)現(xiàn)多個(gè)條形,同樣是隨機(jī)高度、顏色。
首先在bar.dart中創(chuàng)建BarChart類,并使用固定長度的Bar實(shí)例列表。我們將使用5個(gè)條形,表示一周的5個(gè)工作日。然后,我們需要將創(chuàng)建空白和隨機(jī)實(shí)例的責(zé)任從Bar轉(zhuǎn)移到BarChart。
import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';
import 'dart:ui' show lerpDouble;
import 'dart:math';
import 'color_palette.dart';
class BarChart {
static const int barCount = 5;
final List<Bar> bars;
BarChart(this.bars) {
assert(bars.length == barCount);
}
factory BarChart.empty() {
return new BarChart(
/*
List.filled(
int length,
E fill, {
bool growable: false
}
)
創(chuàng)建給定長度的固定長度列表,并用fill在每個(gè)位置初始化值
length必須是非負(fù)整數(shù)
*/
new List.filled(
barCount,
new Bar(0.0, Colors.transparent)
)
);
}
factory BarChart.random(Random random) {
final Color color = ColorPalette.primary.random(random);
return new BarChart(
/*
List.generate(
int length,
E generator(
int index
), {
bool growable: true
}
)
創(chuàng)建給定長度的固定長度列表,并用generator創(chuàng)建的值在每個(gè)位置初始化值
創(chuàng)建的列表是固定長度,除非growable為true
*/
new List.generate(
barCount,
(i) => new Bar(
random.nextDouble()*100.0,
color
)
)
);
}
static BarChart lerp(BarChart begin, BarChart end, double t) {
return new BarChart(
new List.generate(
barCount,
(i) => Bar.lerp(begin.bars[i], end.bars[i], t)
)
);
}
}
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.height, this.color);
final double height;
final Color color;
static Bar lerp(Bar begin, Bar end, double t) {
return new Bar(
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);
@override
Bar lerp(double t) => Bar.lerp(begin, end, t);
}
class BarChartPainter extends CustomPainter {
static const barWidthFraction = 0.75;
BarChartPainter(Animation<BarChart> animation)
: animation = animation,
super(repaint: animation);
final Animation<BarChart> animation;
@override
void paint(Canvas canvas, Size size) {
void drawBar(Bar bar, double x, double width, Paint paint) {
paint.color = bar.color;
canvas.drawRect(
new Rect.fromLTWH(
x,
size.height-bar.height,
width,
bar.height
),
paint
);
}
/*
Paint:Canvas繪制時(shí)使用的樣式說明
style:是否繪制內(nèi)部的形狀、形狀的邊緣或兩者都有,默認(rèn)為PaintingStyle.fill
*/
final paint = new Paint()..style = PaintingStyle.fill;
final chart = animation.value;
// 每個(gè)條形占用的空間寬度
final barDistance = size.width/(1+chart.bars.length);
// 每個(gè)條形占用空間75%的寬度
final barWidth = barDistance*barWidthFraction;
// 用于計(jì)算每個(gè)條形的x坐標(biāo)點(diǎn)
var x = barDistance-barWidth/2;
for (final bar in chart.bars) {
drawBar(bar, x, barWidth, paint);
x += barDistance;
}
}
@override
bool shouldRepaint(BarChartPainter old) => false;
}
BarChartPainter在條形之間均勻分配可用寬度,并使每個(gè)條形占用可用寬度的75%。接下來我們要更新main.dart,用BarChart、BarChartTween替換Bar、BarTween。
// ...
class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
final random = new Random();
AnimationController animation;
BarChartTween tween;
@override
void initState() {
super.initState();
animation = new AnimationController(
duration: const Duration(milliseconds: 300),
vsync: this
);
tween = new BarChartTween(new BarChart.empty(), new BarChart.random(random));
animation.forward();
}
@override
void dispose() {
animation.dispose();
super.dispose();
}
void changeData() {
setState(() {
tween = new BarChartTween(
tween.evaluate(animation),
new BarChart.random(random),
);
animation.forward(from: 0.0);
});
}
@override
Widget build(BuildContext context) {
return new Scaffold(
body: new Center(
child: new CustomPaint(
size: new Size(200.0, 100.0),
painter: new BarChartPainter(tween.animate(animation))
)
),
floatingActionButton: new FloatingActionButton(
onPressed: changeData,
child: new Icon(Icons.refresh),
),
);
}
}
現(xiàn)在應(yīng)用程序的效果如下圖:

以上就是本文的全部內(nèi)容,希望對大家的學(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 Handler實(shí)現(xiàn)閃屏頁倒計(jì)時(shí)代碼
這篇文章主要介紹了Android Handler實(shí)現(xiàn)閃屏頁倒計(jì)時(shí)代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
Android使用PowerImageView實(shí)現(xiàn)播放強(qiáng)大的ImageView動(dòng)畫效果
今天我們就來編寫一個(gè)PowerImageView控件,讓它既能支持ImageView控件原生的所有功能,同時(shí)還可以播放GIF圖片2018-05-05
Android IPC機(jī)制利用Messenger實(shí)現(xiàn)跨進(jìn)程通信
這篇文章主要介紹了Android IPC機(jī)制中 Messager 實(shí)現(xiàn)跨進(jìn)程通信的知識(shí),對Android學(xué)習(xí)通信知識(shí)非常重要,需要的同學(xué)可以參考下2016-07-07
android實(shí)現(xiàn)倒計(jì)時(shí)動(dòng)態(tài)圈
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)倒計(jì)時(shí)動(dòng)態(tài)圈,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01
Android studio有關(guān)側(cè)滑的實(shí)現(xiàn)代碼
這篇文章主要介紹了Android studio有關(guān)側(cè)滑的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-06-06
Android自定義View實(shí)現(xiàn)隨機(jī)數(shù)驗(yàn)證碼
這篇文章主要為大家詳細(xì)介紹了Android如何利用自定義View實(shí)現(xiàn)隨機(jī)數(shù)驗(yàn)證碼效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-06-06
Android入門之ActivityGroup+GridView實(shí)現(xiàn)Tab分頁標(biāo)簽的方法
這篇文章主要介紹了Android入門之ActivityGroup+GridView實(shí)現(xiàn)Tab分頁標(biāo)簽的方法,非常實(shí)用的功能,需要的朋友可以參考下2014-08-08
android 實(shí)現(xiàn)側(cè)邊彈窗特效代碼
側(cè)邊彈窗是在左邊,需要定位好位置,實(shí)現(xiàn)原理其實(shí)就是進(jìn)出動(dòng)效,用位移加透明度效果來控制,下面通過代碼給大家介紹android 實(shí)現(xiàn)側(cè)邊彈窗,需要的朋友參考下吧2021-06-06

