Flutter: Animasyonlara genel giriş
Bir uygulama yaparken kullanıcıların dikkat ettiği ilk şey tasarımdır. UI UX odaklı bir uygulama yaparken, ilgili yerlerde kullanılan animasyonlar, tasarımı ve dolayısıyla kullanıcının ilgisini yukarıya çıkarır. Flutter’da bu konuda da oldukça şanslıyız! Bir önceki yazımda da bahsettiğim gibi, saniyede 60 kare hızla çalışan karmaşık animasyonlar oluşturmamıza olanak sağlaması ve sağlam bir animasyon kitaplığının olması Flutter’ı öne çıkartan özelliklerindendir.
Animasyonlara başlarken ele alacağımız 3 ana konu var:
1-Ticker
2-Animation
3-AnimationController
Ticker kelime kökeni, saatteki tikt-tok sesinden geliyor :) Yukarıda da bahsettiğim gibi Flutter’da ekranımız saniyede 60 kare yenileniyor. Yani her bir tik anında Ticker ekranımıza sinyaller yolluyor ve bu sinyallere göre değerlerimizi güncelleyip değiştiriyor veya siliyoruz.
Animation ise belli aralıklarla değişen bir değer. Değişen değer lineer doğru üzerinde sadece düz olarak değişebilir veya farklı değerleri alarak büyüyüp küçülebilir, bu boyut değişimlerini hızlı veya yavaş olarak ayarlayabiliriz.
AnimationController: Bu sınıf sayesinde animasyonumuzu reverse, forward, animateTo gibi metotlarla yönetir. Animasyonun upperBound ve lowerBound değerlerini tanımlar. Varsayılan olarak, bir AnimationController belirli bir süre boyunca doğrusal olarak 0,0 ile 1,0 arasında değişen değerler üretir.
Projemizi oluşturduktan sonra comment satırları hariç projemdeki hiçbir şeyi silmedim. İlk olarak StatefulWidget’ın altına _controller isimli AnimationController’ı oluşturuyoruz ve içindeki vsync(TickerProvider) parametresini doldurabilmemiz için SingleTickerProviderStateMixin sınfını buraya geçiyoruz.
class _MyHomePageState extends State<MyHomePage> with SingleTickerProviderStateMixin{
int _counter = 0;
AnimationController _controller;
Animation _animation;
TickerProvider’ı vsycn içinde verdikten sonra animasyon süremizi Duration içinde, alt ve üst değerlierimizi de lowerBound ve upperBound içinde belirtiyoruz ve her yeni değer geldiğinde setState içinde gösteriyoruz.
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
lowerBound: 0,
upperBound: 100);
}_controller.reverse(from: 30);
_controller.addStatusListener((status) {
if(status== AnimationStatus.completed){
_controller.reverse().orCancel;
}else if(status==AnimationStatus.dismissed){
_controller.forward().orCancel;
}
});
Animasyonlara hala giremedik :) Sadece controller ile kolayca yaptığımız değişiklikler bile bizi her zaman fazlasını yapmaya teşvik ediyor.
Yukarıda belirlediğimiz lowerBound ve upperBound değerleri ile geçişli bir renk oluşturan bir arkaplan yapabiliriz.
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.indigo.withOpacity(_controller.value /100.0),
Artık daha fazla vakit kaybetmeden animasyonlara geçelim diyorum :xX
Animasyonlarda kullanacağımız iki ana sınıf var. İlki tween, aklımıza between kelimesinden gelebilir, başlangıç ve bitiş arasında lineer (doğrusal)değerler üretir. İkincisi ise curve, yine başlangıç ve bitiş arasında ama bu sefer doğrusal olmayan çizgide değerler üretir. Boyutlar, renkler veya int değerleri belli bir aralıkta değiştirmek için tween kullanırız.
Yukarıdakileri tek sayfada şöyle görebilirsiniz.
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>
with SingleTickerProviderStateMixin {
int _counter = 0;
AnimationController _controller;
Animation _animation;
@override
void initState() {
super.initState();
_controller = AnimationController(
vsync: this,
duration: Duration(seconds: 2),
lowerBound: 0,
upperBound: 100);
_controller.addListener(() {
setState(() {
debugPrint(_controller.value.toString());
});
});
_controller.reverse(from: 30);
_controller.addStatusListener((status) {
if (status == AnimationStatus.completed) {
_controller.reverse().orCancel;
} else if (status == AnimationStatus.dismissed) {
_controller.forward().orCancel;
}
debugPrint("status:" + status.toString());
});
}
@override
@override
void dispose() {
// TODO: implement dispose
super.dispose();
_controller.dispose();
}
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.indigo.withOpacity(_controller.value / 100.0),
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: TextStyle(fontSize: _controller.value),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
Animasyonlar oldukça geniş bir konu. Ben sadece genel yapıyı anlamanız için bir giriş yapmak istedim. İlerleyen zamanlarda animasyonları kullanarak kullanıcı odaklı bir çok uygulma oluşturacağız. Bir sonraki yazıma kadar şimdilik hoşçakalın :xX