Flutter启动页(闪屏页)的具体实现及原理详析

发布时间:2019-08-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Flutter启动页(闪屏页)的具体实现及原理详析脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

Flutter启动页(闪屏页)的具体实现及原理详析

为什么要有启动页?

在以下文章中,启动页就是闪屏页。

现在大部分App都有启动页,那么为什么要有启动页?这是个值得思考的问题,如果没有启动页会怎样,大部分的App会白屏(也有可能是黑屏,主题设置有关系)非常短的时间,然后才能展示App的内容。

那么问题来了,一定要有启动页吗?答案:不是,而且是尽可能不要有启动页,因为启动页会让用户体验不够连贯,甚至IOS在开发手册上就不推荐使用启动页。

我们深入思考一下,既然不推荐为什么这样流行,答案非常简单,启动页的成本非常低,如果你想把的App启动优化到一个非常短的时间,还是有一定成本的。

AndROId启动流程

为什么要谈Android的启动流程呢?因为Flutter启动的时候,依赖的是Android的运行环境,其本质是ActivITy上添加了一个FlutterView,FlutterView继承SurfaceView,那么就容易理解了,Flutter的全部页面都是渲染到了FlutterView上,如果不熟悉Flutter的启动流程可以参考Flutter启动流程 这篇文章,下面是对Flutter启动的一个简单描述。

Flutter启动页(闪屏页)的具体实现及原理详析

在Flutter中,启动页的作用是在FlutterView显示第一帧之前,不要出现白屏,在FlutterView显示第一帧之前,我们分成两个阶段,Android启动阶段和Flutter启动阶段,Android启过程添加启动页非常容易,在主题XMl中添加android:windowBackground属性,Flutter怎么添加启动页呢?其实框架已经帮助咱们实现好了,我下面就给大家说一下原理。

Flutter启动页具体实现和原理

创建一个SplashActivity,这Activity继承FlutterActivity,重写onCreate()方法,在onCreate()方法中调用GeneratedPluginRegistrant.registerWith() ,下面是启动页的代码。

 public class SplashActivity extends FlutterActivity {   @override  PRotected void onCreate(Bundle savedInstancestate) {  suPEr.onCreate(savedInstanceState);  GeneratedPluginRegistrant.registerWith(this);  } }

在Manifest中添加SplashActivity作为App的启动Activity,设置SplashActivity的主题是LaunchTheme。下面是Manifest的配置文件。

  <activity  android:name=".SplashActivity"  android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"  android:hardwareAccelerated="true"  android:launchMode="singleTop"  android:theme="@style/LaunchTheme"  android:windowSoftInputMode="adjustResize">  <;meta-data  android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"  android:value="true" />  <intent-filter>  <action android:name="android.intent.action.MaiN" />  <category android:name="android.intent.category.launcher" />  </intent-filter>  </activity>

meta-data的name = "io.flutter.app.android.SplashScreenUntilFirstFrame"的value一定要设置成true,一定要设置成true,一定要设置成true重要的事情说三遍,如果这个属性设置成false,效果是这样的。

Flutter启动页(闪屏页)的具体实现及原理详析

从现象观察,启动页中间有一段时间黑屏,这个为什么呢?前面我们说过,Flutter的启动流程分成两部分,一部分是Android启动阶段,一个是Flutter的启动阶段,这个黑屏就是Flutter的启动阶段没有启动页所造成的。我们从码入手,详细分析一下,下面是FlutterActivityDelegate的部分源码。

 public final class FlutterActivityDelegate  implements FlutterActivityEvents,   FlutterView.Provider,   PluginRegistry {  private static final String SPLASH_SCREEN_META_DATA_KEY = "io.flutter.app.android.SplashScreenUntilFirstFrame";   private View launchView;   @Override  public void onCreate(Bundle savedInstanceState) {  String[] args = getArgsFromIntent(activity.getIntent());  FlutterMain.ensureinitializationcomplete(activity.getApplicationContext(), args);  flutterView = viewFactory.createFlutterView(activity);  if (flutterView == null) {  FlutterNativeView nativeView = viewFactory.createFlutterNativeView();  flutterView = new FlutterView(activity, null, nativeView);  flutterView.setLayoutParams(matchParent);  activity.setContentView(flutterView);  launchView = createLaunchView();//1  if (launchView != null) {  addLaunchView();//2  }  }  }   private View createLaunchView() {  if (!showSplashScreenUntilFirstFrame()) {//3  return null;  }  final Drawable launchScreenDrawable = getLaunchScreenDrawableFromActivityTheme();  final View view = new View(activity);  view.setBackground(launchScreenDrawable);  return view;  }   private Drawable getLaunchScreenDrawableFromActivityTheme() {  //省略了部分代码  try {  return activity.getResources().getDrawable(typedValue.resourceId);  } catch (NotFoundException e) {  return null;  }  }   private Boolean showSplashScreenUntilFirstFrame() {  try {  ActivityInfo activityInfo = activity.getPackageManager().getActivityInfo(  activity.getcomponentName(),  PackageManager.GET_META_DATA|PackageManager.GET_ACTIVITIES);  Bundle metadata = activityInfo.metaData;  return metadata != null && metadata.getBoolean(SPLASH_SCREEN_META_DATA_KEY);  } catch (NameNotFoundException e) {  return false;  }  }   private void addLaunchView() {  activity.addContentView(launchView, matchParent);//4  flutterView.adDFirstFrameListener(new FlutterView.FirstFrameListener() {//5  @Override  public void onFirstFrame() {  FlutterActivityDelegate.this.launchView.aniMATE()   .alpha(0f)   .setListener(new AnimatorListenerAdapter() {   @Override   public void onAnimationEnd(Animator animation) {   ((ViewGroup) FlutterActivityDelegate.this.launchView.getParent())   .removeView(FlutterActivityDelegate.this.launchView);//5   }   });  }  });  activity.setTheme(android.R.style.Theme_Black_NoTitleBar);  } }

注释1

这个段代码很容易理解,创建一个LaunchView,主要逻辑在createLaunchView()中,原理也很简单,根据主题中的R.attr.windowBackground属性,生成一个Drawable,然后创建了一个View,并且把这个View的背景设置成Drawable。

注释3

showSplashScreenUntilFirstFrame()是得到Manifet中io.flutter.app.android.SplashScreenUntilFirstFrame的属性的值,如果是false,那么久返回一个空的的LaunchView,也就不会执行注释2的代码。这就是我们上面说的如果设置成false就显示黑屏的原因

注释2

调用addLaunchView(),这方法也很简单,首先看注释4,把LaunchView添加到当前的Activity中,然后添加了一个监听,在注释5处,这个监听是当FlutterView第一帧加载完成后回调,回调做了什么事情呢?很简单,把LaunchView删除了,显示FlutterView的第一帧。

总结一下,就是把Android的启动页生成一个Drawable,创建了一个LaunchView,把Drawable设置成LaunchView的背景,当前的Activity添加这LaunchView,如果FlutterView的第一帧显示了,把LaunchView删除。

设置主题,下面是LaunchTheme的代码。

 <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>  </style> </resources>

下面是launch_background的代码。

 <&#63;xML version="1.0" encoding="utf-8"?> <layer-list xmlns:android="http://schemas.android.COM/apk/res/android"  android:opacity="opaque">  <item>  <bitmap android:src="@mipmap/ic_launch_bg" />  </item>  <item  android:width="90dp"  android:height="90dp"  android:gravity="center">  <bitmap android:src="@mipmap/ic_launch_LOGo" />  </item> </layer-list>

最终效果如下,没有黑屏,非常顺滑。

Flutter启动页(闪屏页)的具体实现及原理详析

总结

@H_69_126@
android教程
脚本网站
android studio

脚本宝典总结

以上是脚本宝典为你收集整理的Flutter启动页(闪屏页)的具体实现及原理详析全部内容,希望文章能够帮你解决Flutter启动页(闪屏页)的具体实现及原理详析所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。