Custom page transition – Flutter

Youtube video

Custom page transition Flutter | Khiêm Lê

Custom page transition

Để custom page transition trong flutter, các bạn sẽ thực hiện animation khi một route mới được thêm vào Stack Navigator. Ví dụ như thông qua push, pushNamed… Để làm được điều này, chúng ta sẽ sử dụng thuộc tính onGenerateRoute của MaterialApp.

Thuộc tính onGenerateRoute của MaterialApp là một function, function này sẽ được thực hiện khi chúng ta push một route vào Stack Navigator.

Thuộc tính onGenerateRoute nhận vào một tham số là RouteSettings, chúng ta sẽ cần thuộc tính name từ tham số này. Chúng ta cần trả về một PageRouteBuilder và sử dụng 3 thuộc tính của nó là pageBuilder, transitionDuration và transitionsBuilder.

Thuộc tính pageBuilder là thuộc tính xác định route nào sẽ được trả về (tức route mà bạn đang push vào stack navigator). Nhận vào một hàm có tham số lần lượt là Context, Animation, Animation, chúng ta chỉ cần quan tâm đến tham số Context, đơn giản bạn chỉ cần trả về route được push dựa vào thuộc tính name của tham số settings được truyền vào thuộc tính onGenerateRoute sử dụng Context.

Vậy để có thể nhận biết được route nào được push vào, các bạn phải sử dụng routes map (tương tự như thuộc tính routes trong MaterialApp). Thêm nữa, để có thể truy cập được routes từ trong các thuộc tính, chúng ta cần phải để biến routes map là biến toàn cục.

Thuộc tính tiếp theo là transitionsBuilder, thuộc tính này cho phép chúng ta custom transition cho page. Thuộc tính này nhận vào một hàm có tham số lần lược là Context, Animation, Animation và child. Ở lần này, chúng ta sẽ sử dụng hai tham số là animation thứ nhất và child.

Tham số animation thứ nhất là để chúng ta thực hiện animation khi navigate route. Do đó, chúng ta sẽ sử dụng các thuộc tính này trong thuộc tính animation value của các widget như SlideTransition, ScaleTransition… và thuộc tính child chính là tham số child truyền vào.

Các Transition Widget đều có thể lồng nhau, do đó, các bạn có lồng nhiều Transition Widget vào nhau để tạo ra các hiện ứng transition đẹp mắt của riêng bạn.

Thuộc tính cuối cùng là transitionDuration, mình có thể custom duration của animation khi navigate route. Thuộc tính này đơn giản nhận vào một Duration, các bạn có thể để thời gian bao lâu tùy thích, milliseconds, seconds…

Ví dụ như mình muốn có hiệu ứng vừa slide, vừa scale từ dưới lên và fade luôn, thì mình sẽ có đoạn code sau:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'screens/screens.dart';

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

class MyApp extends StatelessWidget {
  final _routes = {
    HomeScreen.id: (context) => HomeScreen(),
    SecondScreen.id: (context) => SecondScreen(),
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: HomeScreen.id,
      onGenerateRoute: (settings) {
        return PageRouteBuilder(
          pageBuilder: (context, animation, secondAnimation) {
            return _routes[settings.name](context);
          },
          transitionDuration: Duration(
            milliseconds: 300,
          ),
          transitionsBuilder: (context, animation, secondAnimation, child) {
            return SlideTransition(
              position: animation.drive(
                Tween(
                  begin: Offset(0, 1),
                  end: Offset(0, 0),
                ).chain(CurveTween(curve: Curves.ease)),
              ),
              child: ScaleTransition(
                scale: animation,
                child: FadeTransition(opacity: animation, child: child),
              ),
            );
          },
        );
      },
    );
  }
}

iOS page transition

Nếu các bạn muốn ứng dụng của bạn có hiệu ứng transition như trên iOS, bạn có thể sử dụng Widget CupertinoPageRoute thay cho Widget PageRouteBuilder.

Không giống như Widget PageRouteBuilder, Widget CupertinoPageRoute không đòi hỏi bạn phải custom quá nhiều. Bạn chỉ cần trả về Widget CupertinoPageRoute, bên trong Widget này có thuộc tính builder nhận vào một funciton có tham số là Context, bạn chỉ cần trả về một route dựa trên route name.

Mình sẽ code như sau để có hiệu ứng transition như trên iOS:

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'screens/screens.dart';

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

class MyApp extends StatelessWidget {
  final _routes = {
    HomeScreen.id: (context) => HomeScreen(),
    SecondScreen.id: (context) => SecondScreen(),
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      initialRoute: HomeScreen.id,
      onGenerateRoute: (settings) {
        return CupertinoPageRoute(
          builder: (context) {
            return _routes[settings.name](context);
          },
        );
      },
    );
  }
}

Đối với Widget CupertinoPageRoute, các bạn không thể custom được gì nhiều, chỉ dùng là có transition effect như iOS thôi, tù y hệt như trên iOS luôn.

Tổng kết

Một lưu ý nhỏ là nếu các bạn sử dụng thuộc tính routes trong MaterialApp, hàm trong thuộc tính onGenerateRoute sẽ không được gọi do nó đã tìm được route trong thuộc tính routes rồi. Do đó, các bạn không nên truyền routes vào cho thuộc tính routes của MaterialApp nếu muốn custom transition hoạt động.

Qua bài này, mình đã hướng dẫn các bạn cách custom page transition flutter đơn giản bằng việc sử dụng các Widget Transition có sẵn. Nếu bạn thấy video và bài viết này hay, đừng quên chia sẻ cho bạn bè được biết. Cảm ơn các bạn đã theo dõi bài viết!

Bài viết liên quan
Hướng dẫn cài đặt Flutter SDK trên Linux
Huong dan cai dat flutter sdk tren

Hướng dẫn cài đặt Flutter SDK trên Linux (Ubuntu distro) nhanh và dễ dàng nhất.

Flutter Firebase login với Facebook
Flutter login with Facebook

Hướng dẫn chi tiết cách tích hợp facebook login vào app flutter với firebase

Thêm Firebase vào Flutter và login với Google
FlutterFire Sign in with Google

Hướng dẫn chi tiết cách thêm Firebase vào Flutter và login với Google

Todo App Flutter – Real Code
Flutter Todo App

Todo App Flutter - Code ứng dụng thực tế sử dụng framework Flutter

Để lại một trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *