openplanning

Hướng dẫn sử dụng Flutter SplashScreen

Xem thêm các chuyên mục:

1- SplashScreen là gì?

Splash Screen là màn hình người dùng nhìn thấy đầu tiên khi môt ứng dụng được khởi chạy. Nó cũng có thể là màn hình chào mừng của ứng dụng cung cấp trải nghiệm ban đầu đơn giản khi một trò chơi hoặc chương trình di động đang khởi chạy. Đôi khi Splash Screen được sử dụng để cho người dùng xem trạng thái ứng dụng đang được tải lên bộ nhớ trước khi nó sẵn sàng hoạt động.
Sau đây là các đặc điểm cơ bản của Splash Screen:
  • Nó chủ yếu được sử dụng để xây dựng thương hiệu hoặc nhận dạng danh tính của ứng dụng và tạo ấn tượng thương hiệu cho người dùng.
  • Nó cũng được sử dụng để hiển thị tiến trình ứng dụng được tải lên bộ nhớ để trình bầy phần mềm cho người dùng.
  • Khi tải xong Splash Screen, người dùng sẽ nhận được một màn hình chức năng khác sẽ là màn hình chính hoặc trang tổng quan (dashboard), sau đó nó sẽ bị lãng quên. Khi quá trình tải hoàn tất, chúng ta không thể nhấn nút quay lại để quay lại Splash Screen.

2- Thư viện SplashScreen

Trong bài viết này tôi sẽ hướng dẫn bạn sử dụng thư viện splashscreen được cung cấp bởi cộng đồng, nó không sẵn có trong thư viện tiêu chuẩn của Flutter vì vậy để sử dụng bạn phải khai báo nó trong project.
Trên project, mở file pubspec.yaml và khai báo thư viện splashscreen:
pubspec.yaml
.....

dependencies:
  flutter:
    sdk: flutter
  splashscreen: ^1.3.5
Bạn có thể tìm thấy các phiên bản khác hoặc mới nhất của thư viện splashscreen tại liên kết dưới đây:
Lớp SplashScreen cung cấp 3 constructor:
SplashScreen Constructor
@protected
SplashScreen(

    {Color loaderColor,
    Future navigateAfterFuture,
    int seconds,
    double photoSize,
    Route pageRoute,
    dynamic onClick,
    dynamic navigateAfterSeconds,
    Text title: const Text(''),
    Color backgroundColor: Colors.white,
    TextStyle styleTextUnderTheLoader:
         const TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold, color: Colors.black),
    Image image,
    Text loadingText: const Text(""),
    ImageProvider<Object> imageBackground,
    Gradient gradientBackground,
    bool useLoader: true,
    String routeName}
)
SplashScreen.network Constructor
SplashScreen.network(

    {@required Future navigateAfterFuture,
    Color loaderColor,
    Color backgroundColor,
    double photoSize,
    Text loadingText,
    Image image,
    Route pageRoute,
    dynamic onClick,
    dynamic navigateAfterSeconds,
    Text title,
    TextStyle styleTextUnderTheLoader,
    ImageProvider<Object> imageBackground,
    Gradient gradientBackground,
    bool useLoader,
    String routeName}

)
SplashScreen.timer Constructor
SplashScreen.timer(

    {@required int seconds,
    Color loaderColor,
    Color backgroundColor,
    double photoSize,
    Text loadingText,
    Image image,
    Route pageRoute,
    dynamic onClick,
    dynamic navigateAfterSeconds,
    Text title,
    TextStyle styleTextUnderTheLoader,
    ImageProvider<Object> imageBackground,
    Gradient gradientBackground,
    bool useLoader,
    String routeName}
)
Bố cục của SplashScreen:

3- Example: Time based

Trước hết chúng ta sẽ bắt đầu với một ví dụ đơn giản, một Splash Screen hiển thị trong một khoảng thời gian được chỉ định, sau đó nó sẽ được thay thế bởi màn hình chính của ứng dụng. Hãy xem trước kết quả của ví dụ:
Trước hết, bạn cần tạo một dự án Flutter và khai báo thư viện splashscreen vào dự án của bạn như đã được đề cập ở phía trên.
Tiếp theo, mở file main.dart và thay thế nó nội dung của nó bởi code dưới đây:
main.dart (ex1)
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:splashscreen/splashscreen.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: SplashScreenPage(),
      debugShowCheckedModeBanner: false,
    );
  }
}
class SplashScreenPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SplashScreen(
      seconds: 5,
      navigateAfterSeconds: new HomeScreen(),
      backgroundColor: Colors.green,
      title: new Text('o7planning.org',textScaleFactor: 2,),
      image: new Image.network(
          'https://s3.o7planning.com/images/triceratops/image1.png'
      ),
      loadingText: Text("Loading"),
      photoSize: 110.0,
      loaderColor: Colors.red,
    );
  }
}
class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title:Text("Flutter SplashScreen")
      ),
      body: Center(
          child:Text("Welcome to Home Page",
              style: TextStyle( color: Colors.black, fontSize: 30)
          )
      ),
    );
  }
}
Code ở trên cho thấy rằng ban đầu màn hình chính của ứng dụng được tạo ra bởi SplashScreenPage, phương thức build() của lớp này trả về một đối tượng SplashScreen.
Tham số seconds chỉ định số giây Splash Screen sẽ hiển thị, sau khi hết thời gian nó sẽ được thay thế bởi HomeScreen (Được chỉ định bởi tham số navigateAfterSeconds).

4- Example: Time based + route Map

Nếu ứng dụng của bạn sử dụng route Map để điều hướng các trang bạn có thể đặt SplashScreen ở phía trước giống như hình minh hoạ dưới đây:
Trong tình huống này tham số navigateAfterSeconds là kiểu String, nó là tên của một trang mà bạn muốn chuyển hướng đến.
main.dart (ex2)
import 'package:flutter/material.dart';
import 'package:splashscreen/splashscreen.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'o7planning.org',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: SplashScreenPage(),
      routes: <String, WidgetBuilder>{
        '/home': (BuildContext context) => HomePage(),
        '/details': (BuildContext context) => DetailsPage(),
        '/about': (BuildContext context) => AboutPage(),
      },
    );
  }
}

class SplashScreenPage extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return SplashScreen(
      title: new Text('Welcome In SplashScreen' ),
      image: new Image.network(
          'https://s3.o7planning.com/images/triceratops/image1.png'
      ),
      backgroundColor: Colors.white,
      photoSize: 100.0,
      loaderColor: Colors.red,
      seconds: 15,
      navigateAfterSeconds: "/home"
    );
  }

}

class HomePage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Title of Home Page"),
      ),
      body: Center(

          child: Row (
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              ElevatedButton(
                child: Text('Go to Details Page'),
                onPressed: () {
                  Navigator.of(context).pushNamed('/details');
                },
              ),
              ElevatedButton(
                child: Text('Go to About Page'),
                onPressed: () {
                  Navigator.of(context).pushNamed('/about');
                },
              ),
            ],
          )
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Title of Details Page"),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('Close'),
          onPressed: () {
            // Close page and pass a value back to previous page
            Navigator.of(context).pop();
          },
        ),
      ),
      backgroundColor: Colors.lightGreen[100],
    );
  }
}

class AboutPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Title of About Page"),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('Close'),
          onPressed: () {
            // Close page
            Navigator.of(context).pop();
          },
        ),
      ),
      backgroundColor: Colors.cyan[100],
    );
  }
}

5- Example: Time based + pageRoute

Trong Flutter sử dụng Navigator & Route bạn có thể nhẩy từ một trang này sang một trang khác, và đây chính là một ý tưởng để bạn chuyển từ Splash Screen tới màn hình chính của ứng dụng. Điều quan trọng là lớp SplashScreen cũng hỗ trợ Route, chúng ta hãy xem một ví dụ:
main.dart (ex3)
import 'package:flutter/material.dart';
import 'package:splashscreen/splashscreen.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'o7planning.org',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: SplashScreenPage()
    );
  }
}

class SplashScreenPage extends StatefulWidget {
  @override
  _SplashScreenPageState createState() => _SplashScreenPageState();
}

class _SplashScreenPageState extends State<SplashScreenPage> {

  @override
  Widget build(BuildContext context) {
    return SplashScreen(
        title: new Text('Welcome In SplashScreen'),
        image: new Image.network(
            'https://s3.o7planning.com/images/triceratops/image1.png'
        ),
        backgroundColor: Colors.white,
        photoSize: 100.0,
        loaderColor: Colors.red,
        seconds: 10,
        navigateAfterSeconds: Text("Any Widget"), // Any not null widget.
        pageRoute: _createRoute()
    );
  }

  Route _createRoute() {
    return PageRouteBuilder(
      pageBuilder: (BuildContext context, Animation<double> animation,//
          Animation<double> secondaryAnimation) {
        return HomeScreen();
      },
      transitionsBuilder: (BuildContext context, Animation<double> animation, //
          Animation<double> secondaryAnimation, Widget child) {
        return child;
      },
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title:Text("Flutter SplashScreen")
      ),
      body: Center(
          child:Text("Welcome to Home Page",
              style: TextStyle( color: Colors.black, fontSize: 30)
          )
      ),
      backgroundColor: Colors.green[100],
    );
  }
}
Chú ý: Trong ví dụ này bạn cần sét đặt giá trị cho các tham số seconds, navigateAfterSecondspageRoute.
  • Tham số pageRoute sẽ được sử dụng nếu nó không null.
  • Tham số navigateAfterSeconds là một Widget bất kỳ và không null, mặc dù nó không được sử dụng nhưng bạn cần phải sét đặt giá trị cho nó.
SplashScreen(
    ...
    seconds: 10,
    navigateAfterSeconds: Text("Any Widget"), // Any not null widget.
    pageRoute: _createRoute()
);

6- Example: Time based + routeName

  • TODO

7- Example: Future based

Trong một số tình huống Splash Screen được sử dụng để biểu thị trạng thái ứng dụng đang được tải vào bộ nhớ trước khi ứng dụng sẵn sàng sử dụng đối với người dùng. Khoảng thời gian mà Splash Screen hiển thị phụ thuộc vào sức mạnh của thiết bị. Sau khi Splash Screen hoàn thành các nhiệm vụ, nó sẽ được thay thế bởi màn hình chính của ứng dụng.
Về mặt kỹ thuật màn hình chính sẽ được gói trong một đối tượng Future (Tương lai) để sẵn sàng thay thế Splash Screen khi cần thiết.
Hãy xem trước ví dụ này:
Trong ví dụ này bạn cần sét đặt giá trị cho tham số navigateAfterFuture và không sét đặt giá trị cho tham số seconds.
main.dart (ex7)
import 'package:flutter/material.dart';
import 'package:splashscreen/splashscreen.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'o7planning.org',
        debugShowCheckedModeBanner: false,
        theme: ThemeData(
          primarySwatch: Colors.blue,
          visualDensity: VisualDensity.adaptivePlatformDensity,
        ),
        home: SplashScreenPage()
    );
  }
}

class SplashScreenPage extends StatefulWidget {
  @override
  _SplashScreenPageState createState() => _SplashScreenPageState();
}

class _SplashScreenPageState extends State<SplashScreenPage> {
  int loadingPercent = 0;

  Future<Widget> loadFromFuture() async {
    // <fetch data from server. ex. login>
    while(this.loadingPercent < 100)  {
      this.setState(() {
        this.loadingPercent++;
        print("Percent: " + this.loadingPercent.toString());
      });
      // Delay 100 millisecond.
      await Future.delayed(const Duration(milliseconds : 100));
    }
    // Show Main Screen (After Splash Screen)
    return Future.value(HomeScreen());
  }

  @override
  Widget build(BuildContext context) {
    return SplashScreen(
        navigateAfterFuture: loadFromFuture(),
        title: Text(
          'Welcome In SplashScreen',
          style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 20.0
          ),),
        image: Image.network(
            'https://s3.o7planning.com/images/triceratops/image1.png'
        ),
        backgroundColor: Colors.white,
        styleTextUnderTheLoader: TextStyle(),
        photoSize: 100.0,
        onClick: () => print("Flutter o7planning.org"),
        loadingText: Text("Loading " + this.loadingPercent.toString() +" %"),
        loaderColor: Colors.red
    );
  }
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          title: Text("Flutter SplashScreen Package"),
          automaticallyImplyLeading: false
      ),
      body: Center(
        child: Text(
          "Welcome To Home Page!",
          style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 30.0
          ),
        ),
      ),
    );
  }
}

8- Example: Future based + route Map

Tiếp theo chúng ta sẽ đến với một ví dụ phức tạp hơn, ứng dụng của bạn sử dụng route Map để điều hướng các trang, và SplashScreen được sử dụng để biểu thị trạng thái ứng dụng đang được tải vào bộ nhớ trước khi ứng dụng sẵn sàng sử dụng đối với người dùng.
 
Xem trước ví dụ:
main.dart (ex8)
import 'package:flutter/material.dart';
import 'package:splashscreen/splashscreen.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'o7planning.org',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: SplashScreenPage(),
      routes: <String, WidgetBuilder>{
        '/home': (BuildContext context) => HomePage(),
        '/details': (BuildContext context) => DetailsPage(),
        '/about': (BuildContext context) => AboutPage(),
      },
    );
  }
}

class SplashScreenPage extends StatefulWidget {
  @override
  _SplashScreenPageState createState() => _SplashScreenPageState();
}

class _SplashScreenPageState extends State<SplashScreenPage> {
  int loadingPercent = 0;

  Future<String> loadFromFuture() async {
    // <fetch data from server. ex. login>
    while(this.loadingPercent < 100)  {
      this.setState(() {
        this.loadingPercent++;
        print("Percent: " + this.loadingPercent.toString());
      });
      // Delay 100 millisecond.
      await Future.delayed(const Duration(milliseconds : 100));
    }
    // Show Main Screen (After Splash Screen)
    return Future.value('/home');
  }

  @override
  Widget build(BuildContext context) {
    return SplashScreen(
        navigateAfterFuture: loadFromFuture(),
        title: Text(
          'Welcome In SplashScreen',
          style: TextStyle(
              fontWeight: FontWeight.bold,
              fontSize: 20.0
          ),),
        image: Image.network(
            'https://s3.o7planning.com/images/triceratops/image1.png'
        ),
        backgroundColor: Colors.white,
        styleTextUnderTheLoader: TextStyle(),
        photoSize: 100.0,
        onClick: () => print("Flutter o7planning.org"),
        loadingText: Text("Loading " + this.loadingPercent.toString() +" %"),
        loaderColor: Colors.red
    );
  }
}

class HomePage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Title of Home Page"),
      ),
      body: Center(

          child: Row (
            mainAxisAlignment: MainAxisAlignment.spaceAround,
            children: [
              ElevatedButton(
                child: Text('Go to Details Page'),
                onPressed: () {
                  Navigator.of(context).pushNamed('/details');
                },
              ),
              ElevatedButton(
                child: Text('Go to About Page'),
                onPressed: () {
                  Navigator.of(context).pushNamed('/about');
                },
              ),
            ],
          )
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Title of Details Page"),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('Close'),
          onPressed: () {
            // Close page and pass a value back to previous page
            Navigator.of(context).pop();
          },
        ),
      ),
      backgroundColor: Colors.lightGreen[100],
    );
  }
}

class AboutPage extends StatelessWidget {
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Title of About Page"),
      ),
      body: Center(
        child: ElevatedButton(
          child: Text('Close'),
          onPressed: () {
            // Close page
            Navigator.of(context).pop();
          },
        ),
      ),
      backgroundColor: Colors.cyan[100],
    );
  }
}

9- loaderColor

Property loaderColor được sử dụng để sét đặt mầu sắc của loader (CircularProgressIndicator) đang biểu thị tiến trình tải của ứng dụng.
Color loaderColor

10- navigateAfterFuture

Future navigateAfterFuture
Xem giải thích về property này trong ví dụ ở trên.

11- seconds

Property seconds được sử dụng để sét đặt số giây Splash Screen sẽ xuất hiện trước khi nó được thay thế bởi màn hình chính của ứng dụng.
int seconds
Nếu bạn sét đặt giá trị cho tham số seconds có nghĩa là bạn chọn cách điều hướng dựa trên thời gian, sau khi thời gian hết hạn Splash Screen sẽ được thay thế bởi màn hình chính của ứng dụng.

12- pageRoute

Route pageRoute
Xem giải thích về property này trong ví dụ ở trên.

13- onClick

dynamic onClick

14- navigateAfterSeconds

dynamic navigateAfterSeconds
Xem giải thích về property này trong ví dụ ở trên.

15- title

title là một widget nằm phía dưới image, trong hầu hết các trường hợp sử dụng nó là một đối tượng Text.
Text title: const Text('')

16- backgroundColor

Property backgroundColor được sử dụng để sét đặt mầu nền cho Splash Screen, giá trị mặc định của nó là Colors.white.
Color backgroundColor: Colors.white

17- styleTextUnderTheLoader

Property styleTextUnderTheLoader không còn được sử dụng.
TextStyle styleTextUnderTheLoader:
         const TextStyle(fontSize: 18.0, fontWeight: FontWeight.bold, color: Colors.black)

18- image

Property image được sử dụng để chỉ định một ảnh xuất hiện trong Splash Screen, nó được đặt trong một CircleAvatar với bán kính là photoSize.
Image image
  • TODO Link!

19- photoSize

Về mặt cấu trúc image của SplashScreen được đặt trong một CircleAvatarphotoSize là giá trị của bán kính.
double photoSize

20- loadingText

loadingText là một widget nằm ở phía dưới của loader (CircularProgressIndicator) thường được sử dụng để hiển thị thông tin liên quan tới tiến trình tải của ứng dụng.
Text loadingText: const Text("")

21- useLoader

Property useLoader được sử dụng để hiển thị (hoặc không hiển thị) loader (CircularProgressIndicator) trên SplashScreen. Mặc định nó có giá trị true, nghĩa là loader sẽ được hiển thị.
bool useLoader: true

22- imageBackground

imageBackground được sử dụng để sét đặt hình nền cho SplashScreen.
ImageProvider<Object> imageBackground
  • TODO Link!

23- gradientBackground

Gradient gradientBackground
  • TODO Link!

24- routeName

String routeName
Xem giải thích về property này trong ví dụ ở trên.

Xem thêm các chuyên mục: