Flutter’da Fizik Bazlı Animasyonlar (Physics-based animation)

Bir önceki yazıda Tween ile bir değeri değiştirerek bunu widget içinde kullanıp bir animasyon oluşturmaya çalışmıştık. Şimdi diğer bir animasyon türü olan fizik bazlı animasyonları tanıyalım.

Gerçek dünya hareketlerini taklit etmeye yaran animasyon sınıfları bu gruba dahil ediliyor. Yer çekimi  ya da bir yayın salınımı algısını vermeye çalıştığınızda bunların uğraştırıcı matematik hesaplarını kodumuza ekleyip karıştırmadan sade bir simülasyon elde edebiliriz.

Şurada bütün simülasyon sınıflarını görebilirsiniz. Bunlardan GravitySimulation ve SpringSimulation sınıfları ile birer örnek yapalım.

import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';
import 'package:flutter/physics.dart';

void main() => runApp(PhysicsAnimation());

class PhysicsAnimation extends StatefulWidget {
  _PhysicsAnimation createState() => _PhysicsAnimation();
}

class _PhysicsAnimation extends State<PhysicsAnimation>
    with SingleTickerProviderStateMixin{
  
  AnimationController controller;
  GravitySimulation simulation;
  
  @override
  void initState() {
    super.initState();

    simulation = GravitySimulation(
      100.0, // ivme
      0.0, // başlangıç
      500.0, // bitiş
      0.0, // başlangıç hızı
    );

    controller =
        AnimationController(vsync: this, upperBound: 500)
          ..addListener(() {
            setState(() {});
          });

    controller.animateWith(simulation);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Stack(
        children: [
          Positioned(
            left: 50,
            top: controller.value,
            height: 10, //animation.value,
            width: 10, //animation.value,
            child: Container(
              color: Colors.redAccent,
            ),
          ),
        ]
      ),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

Bazı açıklamaları Tween animasyon yazısında zaten yapmıştım. Bu bölüme özel kısımlardan bahsedeyim.

GravitySimulation: Yer çekimi simülasyon için oluşturulmuş bir sınıf. İvme başlangıç ve bitiş pozisyonları ve başlangıç hızı için değerler verebiliyoruz. Bu örnekte 500 piksellik hedefe 100 piksellik ivme ile gitmesini istedik.

upperBound: Belki bir bug olabilir fakat simülasyon kullanıldığında verdiğimiz 500 değeri bir işe yaramayacak çünkü AnimationController sınıfında bir üst değer limiti var. Ve bu limit ön tanımlı olarak 1. Yani simülasyon kullandığınızda değeriniz bire gelip takılıyorsa bu değeri tanımlamanız gerekli. Bir de lowerBound var ön tanımlı olarak sıfır ama bu örnekte önemli değil. Başlangıç pozisyonunu negatif vererek ekran dışından gelmesini isteseydik elemanımızın o zaman lowerBound için bir değer vermemiz gerekecekti.

controller.animateWith: Burada animasyon kontrolcüsü değerimize tanımladığımız simülasyonu aktararak bununla ilerle diyoruz. Farkettiyseniz tween örneklerinde olduğu gibi bir zaman değişkeni yok çünkü zaman simulation içinde tanımladığımız değerlerden hesaplanarak oluşacak.

Animasyonu hazırladıktan sonra Stack widget’ı içinde bir Positioned oluşturarak top değerine controller.value veriyoruz. Aşağıdaki animasyonu elde ediyoruz.

Şimdi yay simülasyonu sınıfından bir örnek yapalım.

import 'package:flutter/material.dart';
import 'package:flutter/animation.dart';
import 'package:flutter/physics.dart';

void main() => runApp(PhysicsAnimation());

class PhysicsAnimation extends StatefulWidget {
  _PhysicsAnimation createState() => _PhysicsAnimation();
}

class _PhysicsAnimation extends State<PhysicsAnimation>
    with SingleTickerProviderStateMixin{
  AnimationController controller;

  SpringSimulation simulation;
  Animation<double> animation;


  @override
  void initState() {
    super.initState();

    simulation = SpringSimulation(
      SpringDescription(
        mass: 1, // kütle
        stiffness: 100, // yay sertliği
        damping: 1, // zayıflama
      ),
      0.0, // başlangıç
      300.0, // bitiş
      10, // hız
    );


    controller =
        AnimationController(vsync: this, upperBound: 500, )
          ..addListener(() {
            print(controller.value);
            setState(() {});
          });

    controller.animateWith(simulation);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Stack(
        children: [
          Positioned(
            left: 50,
            top: controller.value,
            height: 10,
            width: 10,
            child: Container(
              color: Colors.redAccent,
            ),
          ),
        ]
      ),
    );
  }

  @override
  void dispose() {
    controller.dispose();
    super.dispose();
  }
}

Önceki örnek ile aynı. Sadece simulation için başka bir sınıf tanımladık ve değerlerini girdik. upperBound için yayın hareket alanı bitiş noktasının ötesinde olacağı için daha yüksek bir değer girmekte fayda var.

SpringSimulation için girilen parametrelerin yanlarına yazdım açıklamaları. Bunları anlamlandırmanın en uygun yolu örnek üzerinde olur.

mass: 1 ve stiffness: 100 vererek damping değerini değiştirdiğimizde neler olduğunu aşağıdaki görselden görebilirsiniz. Damping arttıkça salınım sayısı azalıyor.

Bu sefer stiffness değerini değiştirelim. (mass:1 ve damping:1) Stiffness değeri de salınımın gücünü arttırıyor gibi. Ama tüm salınımlar aynı zamanda sona yaklaşıyorlar.

Malum gif masraflı bir şey bu yüzden kısa tuttum ve salınımların tamamen bitmesini beklemedim.

Medium hesabımdaki şu yazımın çevirisidir.


Yayımlandı

kategorisi

yazarı:

Etiketler:

Yorumlar

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir