中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Flutter怎么實現動畫效果

發布時間:2021-05-27 17:19:05 來源:億速云 閱讀:284 作者:Leah 欄目:移動開發

本篇文章為大家展示了使用Flutter怎么實現動畫效果,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。

首先,我們需要創建一個新項目myapp,然后把main.dart的內容替換成下面的代碼

import 'package:flutter/material.dart';
import 'dart:math';

void main() {
 runApp(new MyApp());
}

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return new MaterialApp(
 title: 'Flutter Demo',
 home: new MyHomePage(),
 );
 }
}

class MyHomePage extends StatefulWidget {
 @override
 _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 // Random([int seed ]):創建一個隨機數生成器
 final random = new Random();
 int dataSet;

 void changeData() {
 setState(() {
 dataSet = random.nextInt(100);
 });
 }

 @override
 Widget build(BuildContext context) {
 return new Scaffold(
 body: new Center(
 child: new Text('數據集:$dataSet'),
 ),
 floatingActionButton: new FloatingActionButton(
 onPressed: changeData,
 child: new Icon(Icons.refresh),
 ),
 );
 }
}

啟動項目后,應用程序會顯示一個居中的文本標簽,顯示“數據集:null”和浮動按鈕來刷新數據。

我們的應用程序生成的樹結構如下圖所示,您可以看到,雖然控件概念相當廣泛,但每個具體的控件類型通常具有非常重要的責任。

使用Flutter怎么實現動畫效果

通過定義用戶界面的不可變的控件樹,修改用戶界面的唯一方法是重建樹,當下一幀到期時告訴Flutter一個子樹所依賴的一些狀態已經改變了。這種狀態依賴的子樹的根必須是StatefulWidget,一個StatefulWidget不是可變的,但是它的子樹是由State對象構建的。Flutter在構建期間通過樹重建保留State對象并將其附加到新樹中的各自的控件,然后,它們確定該控件的子樹是如何構建的。在我們的應用程序中,MyHomePage是以_MyHomePageState為其狀態的StatefulWidget,每當用戶按下按鈕時,我們執行一些代碼來更改_MyHomePageState。我們已經用setState劃分了這個變化,以便Flutter可以進行內部管理,并調度控件樹進行重建。當發生這種情況時,_MyHomePageState將構建一個稍微不同的子樹,這個子樹以新的MyHomePage實例為根。

不可變的控件和狀態依賴的子樹是Flutter提供的主要工具,用于處理響應異步事件(比如按鈕、定時器刻度或輸入數據)的復雜用戶界面中的狀態管理的復雜性。

我們的應用程序將保持簡單的控件結構,但我們會做一些動畫定制圖形,第一步是用一個非常簡單的圖表替換每個數據集的文本顯示。由于數據集當前僅有一個在0~100之間數字,所以圖表將是一個帶有單個條形的條形圖,其高度由該數字確定,我們將使用初始值50來避免高度為null。

import 'package:flutter/material.dart';
import 'dart:math';

void main() {
 runApp(new MyApp());
}

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return new MaterialApp(
 title: 'Flutter Demo',
 home: new MyHomePage(),
 );
 }
}

class MyHomePage extends StatefulWidget {
 @override
 _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
 // Random([int seed ]):創建一個隨機數生成器
 final random = new Random();
 int dataSet = 50;

 void changeData() {
 setState(() {
 dataSet = random.nextInt(100);
 });
 }

 @override
 Widget build(BuildContext context) {
 return new Scaffold(
 body: new Center(
 child: new CustomPaint(
 size: new Size(200.0, 100.0),
 painter: new BarChartPainter(dataSet.toDouble())
 )
 ),
 floatingActionButton: new FloatingActionButton(
 onPressed: changeData,
 child: new Icon(Icons.refresh),
 ),
 );
 }
}

// CustomPaint:是將繪畫委托給CustomPainter策略的控件
class BarChartPainter extends CustomPainter {
 static const barWidth = 10.0;

 BarChartPainter(this.barHeight);
 final double barHeight;

 /*
 void paint(
 Canvas canvas,
 Size size
 )
 當對象需要繪制時調用,它給出Canvas的坐標空間,使得原點位于框的左上角,
 框的面積是size參數的大小
 */
 @override
 void paint(Canvas canvas, Size size) {
 final paint = new Paint()
 ..color = Colors.blue[400]
 ..style = PaintingStyle.fill;
 // drawRect:使用給定的Paint繪制一個矩形,是否填充或描邊(或兩者)是由Paint.style控制
 canvas.drawRect(
 // Rect.fromLTWH(double left, double top, double width, double height):
 // 從左上角和上邊緣構造一個矩形,并設置其寬度和高度
 new Rect.fromLTWH(
 size.width-barWidth/2.0,
 size.height-barHeight,
 barWidth,
 barHeight
 ),
 paint
 );
 }

 /*
 bool shouldRepaint(
 CustomPainter,
 oldDelegate
 )
 當定制繪畫委托類的新實例被提供給RenderCustomPaint對象時,
 或任何時候使用自定義繪畫委托類的新實例創建新的CustomPaint對象
 (這相當于同一件事,因為后者是以前者實施)
 */
 @override
 bool shouldRepaint(BarChartPainter old) => barHeight != old.barHeight;
}

下一步是添加動畫,每當數據集發生變化時,我們希望該欄可以平滑而不是突然地改變高度。Flutter有一個AnimationController的概念,用于編排動畫,通過注冊一個監聽器,我們被告知當動畫值(0.0~1.0)改變時。每當發生這種情況,我們可以像以前一樣調用setState并更新_MyHomePageState。

import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';
import 'dart:math';
import 'dart:ui' show lerpDouble;

void main() {
 runApp(new MyApp());
}

class MyApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return new MaterialApp(
 title: 'Flutter Demo',
 home: new MyHomePage(),
 );
 }
}

class MyHomePage extends StatefulWidget {
 @override
 _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
 // Random([int seed ]):創建一個隨機數生成器
 final random = new Random();
 int dataSet = 50;
 AnimationController animation;
 double startHeight;
 double currentHeight;
 double endHeight;

 /*
 @protected
 @mustCallSuper
 void initState()
 將此對象插入樹中時調用
 該框架將為其創建的每個State對象精確地調用此方法一次
 */
 @override
 void initState() {
 super.initState();
 /*
 AnimationController({
 double value,
 Duration duration,
 String debugLabel,
 double lowerBound: 0.0,
 double upperBound: 1.0,
 TickerProvider vsync
 })
 創建動畫控制器
 */
 animation = new AnimationController(
 // 這個動畫應該持續的時間長短
 duration: const Duration(milliseconds: 300),
 vsync: this
 )
 /*
 void addListener(
 VoidCallback listener
 )
 每次動畫值更改時調用監聽器
 可以使用removeListener刪除監聽器
 */
 ..addListener((){
 setState((){
 /*
 double lerpDouble(
 num a,
 num b,
 double t
 )
 在兩個數字之間進行線性內插
 return a + (b - a) * t;
 */
 currentHeight = lerpDouble(
 startHeight,
 endHeight,
 animation.value
 );
 });
 });
 startHeight = 0.0;
 currentHeight = 0.0;
 endHeight = dataSet.toDouble();
 // 開始向前運行這個動畫(朝向最后)
 animation.forward();
 }

 /*
 @override
 void dispose()
 當該對象永久從樹中刪除時調用
 當該State對象永遠不會再次構建時,該框架調用此方法
 框架調用dispose后,該State對象被視為已卸載,并且mounted屬性為false,此時調用setState是一個錯誤
 生命周期的這個階段是終點:沒有辦法重新安裝dispose的State對象
 */
 @override
 void dispose() {
 animation.dispose();
 super.dispose();
 }

 void changeData() {
 setState(() {
 startHeight = currentHeight;
 dataSet = random.nextInt(100);
 endHeight = dataSet.toDouble();
 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(currentHeight)
 )
 ),
 floatingActionButton: new FloatingActionButton(
 onPressed: changeData,
 child: new Icon(Icons.refresh),
 ),
 );
 }
}

// CustomPaint:是將繪畫委托給CustomPainter策略的控件
class BarChartPainter extends CustomPainter {
 static const barWidth = 10.0;

 BarChartPainter(this.barHeight);
 final double barHeight;

 /*
 void paint(
 Canvas canvas,
 Size size
 )
 當對象需要繪制時調用,它給出Canvas的坐標空間,使得原點位于框的左上角,
 框的面積是size參數的大小
 */
 @override
 void paint(Canvas canvas, Size size) {
 final paint = new Paint()
 ..color = Colors.blue[400]
 ..style = PaintingStyle.fill;
 // drawRect:使用給定的Paint繪制一個矩形,是否填充或描邊(或兩者)是由Paint.style控制
 canvas.drawRect(
 // Rect.fromLTWH(double left, double top, double width, double height):
 // 從左上角和上邊緣構造一個矩形,并設置其寬度和高度
 new Rect.fromLTWH(
 size.width-barWidth/2.0,
 size.height-barHeight,
 barWidth,
 barHeight
 ),
 paint
 );
 }

 /*
 bool shouldRepaint(
 CustomPainter,
 oldDelegate
 )
 當定制繪畫委托類的新實例被提供給RenderCustomPaint對象時,
 或任何時候使用自定義繪畫委托類的新實例創建新的CustomPaint對象
 (這相當于同一件事,因為后者是以前者實施)
 */
 @override
 bool shouldRepaint(BarChartPainter old) => barHeight != old.barHeight;
}

上面代碼中的lerpDouble函數比較難理解,代入參數之后計算結果如下圖。

使用Flutter怎么實現動畫效果

數據從一開始的0.0到達50.0時,花費了10個時間點。再到達52時,則花費了16個時間點。因此大約得出的結論時,在我們的應用程序中,數據變化越小,花費的時間點越多。

使用Flutter怎么實現動畫效果

上述內容就是使用Flutter怎么實現動畫效果,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

靖西县| 建德市| 孙吴县| 民权县| 璧山县| 潜山县| 石屏县| 花垣县| 张家港市| 镇雄县| 红原县| 枣阳市| 兴宁市| 横山县| 高碑店市| 黑水县| 石泉县| 宣武区| 奉化市| 永安市| 乐山市| 云阳县| 体育| 芮城县| 红桥区| 和林格尔县| 宣城市| 仙游县| 阿拉善右旗| 松溪县| 巍山| 嵩明县| 扶绥县| 莎车县| 扎赉特旗| 达孜县| 鄂州市| 任丘市| 田东县| 和林格尔县| 延庆县|