Flutter 启动图

882 阅读2分钟

以下内容参考自flutter_splash_screen插件

Flutter app启动流程

Flutter应用相对于原生app启动,需要额外加载一个Flutter引擎启动过程,大概是如下流程:

原生框架启动 --> Flutter引擎启动 --> Flutter视图

所以,在Flutter app中,启动图的持续时间应该是从原生引擎启动到Flutter视图正式出现的时间。启动图的显示应该是在原生端进行显示,关闭则是Flutter进行。

Flutter端:

  • 关闭启动图类封装

import 'package:flutter/services.dart';
class FlutterSplashScreen {  
    static const MethodChannel _channel =  const MethodChannel('flutter_splash_screen');  
    
    static Future<Null> hide() async {    
        await _channel.invokeMethod('hide');  
    }
}


  • 在即将显示Flutter视图端地方,关闭启动图:

Future.delayed(const Duration(milliseconds: 500),() {  
        FlutterSplashScreen.hide();
    }
);

Android

1. 在Android端实现一个类,封装显示与隐藏启动页方法

大概的思路便是在Activity启动前弹出一个带有启动图的对话框:

```

import android.app.Activity;
import android.app.Dialog;
import android.os.Build;
import java.lang.ref.WeakReference;

public class SplashScreen {    
    private static Dialog mSplashDialog;    
    private static WeakReference<Activity> mActivity;
    
    /**
     * 打开启动屏
     */    
    public static void show(final Activity activity, final int themeResId) {        
        if (activity == null) return;        
        mActivity = new WeakReference<>(activity);        
        activity.runOnUiThread(new Runnable() {    
            @Override            
            public void run() {                
                if (!activity.isFinishing()) {
                    mSplashDialog = new Dialog(activity, themeResId);
                    mSplashDialog.setContentView(R.layout.launch_screen);
                    mSplashDialog.setCancelable(false);
                    if (!mSplashDialog.isShowing()) {
                        mSplashDialog.show();
                    }
                }
            }
        });
    }

    /**
     * 打开启动屏
     */
    public static void show(final Activity activity, final boolean fullScreen) {
        int resourceId = fullScreen ? R.style.SplashScreen_Fullscreen : 
            R.style.SplashScreen_SplashTheme;
        show(activity, resourceId);
    }    

    /**
     * 打开启动屏
     */
    public static void show(final Activity activity) {
        show(activity, false);
    }

    /**
     * 关闭启动屏
     */
    public static void hide(Activity activity) {
        if (activity == null) {
            if (mActivity == null) {
                return;
            }
            activity = mActivity.get();
        }
        if (activity == null) return;
        final Activity _activity = activity;
        _activity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                if (mSplashDialog != null && mSplashDialog.isShowing()) {
                    boolean isDestroyed = false;
                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
                        isDestroyed = _activity.isDestroyed();
                    }
                    if (!_activity.isFinishing() && !isDestroyed) {
                        mSplashDialog.dismiss();
                    }
                    mSplashDialog = null;
                }
            }
        });
    }}

```


所需的资源文件:

  • 启动layout,这里设置启动图资源

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/splash"
        android:scaleType="centerCrop" />
</RelativeLayout>

  • style,这里需要添加windowIsTranslucent属性为true,关闭app启动时的背景

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="LaunchTheme" parent="@android:style/Theme.Black.NoTitleBar">
        <!-- Show a splash screen on the activity. Automatically removed when             Flutter draws its first frame -->
        <item name="android:windowBackground">@drawable/launch_background</item>
        <item name="android:windowIsTranslucent">true</item>
    </style>
    <style name="SplashScreen_SplashAnimation">
        <item name="android:windowExitAnimation">@android:anim/fade_out</item>
    </style>
    <style name="SplashScreen_SplashTheme" parent="@android:style/Theme.Black.NoTitleBar">
        <item name="android:windowAnimationStyle">@style/SplashScreen_SplashAnimation</item>
    </style>
    <style name="SplashScreen_Fullscreen" parent="SplashScreen_SplashTheme">
        <item name="android:windowFullscreen">true</item>
    </style>
</resources>

2.  Android原生层实现启动闪屏页:

在MainActivity onCreate中调用show:

@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
  SplashScreen.show(this,true);
  super.onCreate(savedInstanceState, persistentState);
}

3. Flutter调用插件实现

  • Flutter插件接口封装:

import android.app.Activity;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;

public class FlutterSplashScreenPlugin implements MethodCallHandler {
    private final Activity activity;
    private FlutterSplashScreenPlugin(Activity activity) {
        this.activity = activity;
    }

    public static void registerWith(Registrar registrar) {
        final MethodChannel channel = new MethodChannel(registrar.messenger(),"flutter_splash_screen");
        channel.setMethodCallHandler(new FlutterSplashScreenPlugin(registrar.activity()));
    }

    @Override
    public void onMethodCall(MethodCall methodCall, Result result) {
        switch (methodCall.method) {
            case "show":
                show();
                break;
            case "hide":
                hide();
                break;
            default:
                result.notImplemented();
        }
    }

    /**
     * 打开启动屏
     */
    private void show() {
        SplashScreen.show(activity);
    }    

    /**
     * 关闭启动屏
     */
    private void hide() {
        SplashScreen.hide(activity);
    }
}

  • 在Android MainActivity中注册该插件:

@Overridepublic void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
  GeneratedPluginRegistrant.registerWith(flutterEngine);
  new MethodChannel(flutterEngine.getDartExecutor(),"flutter_splash_screen")
    .setMethodCallHandler(
          new FlutterSplashScreenPlugin(this)
    )
  ;
}

iOS端

研究中...