flutter 通知栏_Flutter启动页:theme、NormalTheme、SplashScreenDrawable、点9、Activity方案...

由于APP启动、Flutter初始化的时延造成第一个画面呈现明显滞后,所以需要一个过渡页面——启动页,直至flutter的第一个页面渲染完成。

官方推荐方案: 

方案一:

初始化应用

    @drawable/launch_background    @drawable/normal_background

在AndroidManifest.xml中设置FlutterActivity

在AndroidManifest.xml中,设置theme的 FlutterActivity,以推出主题。然后,将元数据元素添加到所需的位置,FlutterActivity 以指示Flutter在适当的时间从启动主题切换到正常主题。

    android:name=".MyActivity"    android:theme="@style/LaunchTheme"    // ...    >            android:name="io.flutter.embedding.android.NormalTheme"        android:resource="@style/NormalTheme"        />                        

效果:

隐藏Navigation Bar之后的效果:

从视频可以看出APP启动之后body部分变成了黑色,而通知栏区域显示正常,而body部分正式flutter开始渲染的部分,分析一下flutterActivity:

protected void onCreate(@Nullable Bundle savedInstanceState) {    this.switchLaunchThemeForNormalTheme();    super.onCreate(savedInstanceState);    this.lifecycle.handleLifecycleEvent(Event.ON_CREATE);    this.delegate = new FlutterActivityAndFragmentDelegate(this);    this.delegate.onAttach(this);    this.delegate.onActivityCreated(savedInstanceState);    this.configureWindowForTransparency();    this.setContentView(this.createFlutterView());    this.configureStatusBarForFullscreenFlutterExperience();}

当置空setContentView接口时,启动页正常了,黑色区域变成了目标view,猜测是这个函数里面在设置View的时候做了特殊操作,进一步查看:

View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {    Log.v("FlutterActivityAndFragmentDelegate", "Creating FlutterView.");    this.ensureAlive();    if (this.host.getRenderMode() == RenderMode.surface) {        FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(this.host.getActivity(), this.host.getTransparencyMode() == TransparencyMode.transparent);        this.host.onFlutterSurfaceViewCreated(flutterSurfaceView);        this.flutterView = new FlutterView(this.host.getActivity(), flutterSurfaceView);    } else {        FlutterTextureView flutterTextureView = new FlutterTextureView(this.host.getActivity());        this.host.onFlutterTextureViewCreated(flutterTextureView);        this.flutterView = new FlutterView(this.host.getActivity(), flutterTextureView);    }    this.flutterView.addOnFirstFrameRenderedListener(this.flutterUiDisplayListener);    this.flutterSplashView = new FlutterSplashView(this.host.getContext());    if (VERSION.SDK_INT >= 17) {        this.flutterSplashView.setId(View.generateViewId());    } else {        this.flutterSplashView.setId(486947586);    }    this.flutterSplashView.displayFlutterViewWithSplash(this.flutterView, this.host.provideSplashScreen());    Log.v("FlutterActivityAndFragmentDelegate", "Attaching FlutterEngine to FlutterView.");    this.flutterView.attachToFlutterEngine(this.flutterEngine);    return this.flutterSplashView;}

这个函数里面new了一个FlutterSurfaceView,它被add到了FlutterView,而FlutterView又被添加到了FlutterSplashView,最终反馈的是FlutterSplashView,如果对SurfaceView有一点了解的就能猜到,它渲染的时候默认就是黑色,所以这个是不是启动页被黑色的SurfaceView覆盖导致的异常?

override open fun setContentView(view: View) {    if(view is ViewGroup) {        val v0 = view.getChildAt(0)        if(v0 is ViewGroup) {            val v1 = v0.getChildAt(0)            if(v1 is SurfaceView) {                v1.setZOrderOnTop(true)                v1.getHolder().setFormat(PixelFormat.TRANSLUCENT)            }        }    }    super.setContentView(view)}

运行之后发现黑色区域不见了,启动页正常显示。

WHY

分析FlutterSurfaceView:

private void init() {    if (this.renderTransparently) {        this.getHolder().setFormat(-2);        this.setZOrderOnTop(true);    }    this.getHolder().addCallback(this.surfaceCallback);    this.setAlpha(0.0F);}

在FlutterSurfaceView的构造函数中做了上面操作,只是有条件:this.renderTransparently,它来自: 

FlutterSurfaceView flutterSurfaceView = new FlutterSurfaceView(this.host.getActivity(), this.host.getTransparencyMode() == TransparencyMode.transparent);

FlutterActivity:

@NonNullpublic TransparencyMode getTransparencyMode() {    return this.getBackgroundMode() == BackgroundMode.opaque ? TransparencyMode.opaque : TransparencyMode.transparent;}@NonNullprotected BackgroundMode getBackgroundMode() {    return this.getIntent().hasExtra("background_mode") ? BackgroundMode.valueOf(this.getIntent().getStringExtra("background_mode")) : BackgroundMode.opaque;}

可以通过Intent方式传入,意外的发现,在此Activity里面有两个公开的Builder类:

public static class NewEngineIntentBuilder {    private final Class extends FlutterActivity> activityClass;    private String initialRoute = "/";    private String backgroundMode;    public NewEngineIntentBuilder(@NonNull Class extends FlutterActivity> activityClass) {        this.backgroundMode = FlutterActivityLaunchConfigs.DEFAULT_BACKGROUND_MODE;        this.activityClass = activityClass;    }    @NonNull    public FlutterActivity.NewEngineIntentBuilder initialRoute(@NonNull String initialRoute) {        this.initialRoute = initialRoute;        return this;    }    @NonNull    public FlutterActivity.NewEngineIntentBuilder backgroundMode(@NonNull BackgroundMode backgroundMode) {        this.backgroundMode = backgroundMode.name();        return this;    }    @NonNull    public Intent build(@NonNull Context context) {        return (new Intent(context, this.activityClass)).putExtra("route", this.initialRoute).putExtra("background_mode", this.backgroundMode).putExtra("destroy_engine_with_activity", true);    }}

通过他可以帮助参数传入,这让意味着需要手动启动。

使用点9图片作为启动页:

如果启动页是一张使用点9效果的图片,又出现异常(bug这么多?):

e2bf1d40298c34dfb448ed75396403b0.png

方案二:

设置Flutter启动Drawable:使用SplashScreenDrawable参数

FlutterActivity要显示一个Drawable作为启动画面,以下元数据添加到关联FlutterActivity的AndroidManifest.xml。

    android:name="io.flutter.embedding.android.SplashScreenDrawable"    android:resource="@drawable/my_splash"    />
    android:name="io.flutter.app.FlutterApplication"    android:label="flutter_test_0"    android:icon="@mipmap/ic_launcher">            android:name=".MainActivity"        android:launchMode="singleTop"        android:theme="@style/LaunchTheme"        android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"        android:hardwareAccelerated="true"        android:windowSoftInputMode="adjustResize">                    android:name="io.flutter.embedding.android.SplashScreenDrawable"            android:resource="@drawable/launch_background" />                                            
    @drawable/launch_background
                android:gravity="bottom|center_horizontal"        android:drawable="@mipmap/x_launch"/>

效果如下,完美呈现:

但当为点9图片时,又出现异常,点9区域将被遗弃,flutter将只占用之外的区域,这是flutter的bug:

e2bf1d40298c34dfb448ed75396403b0.png

最终方案:

一、新增一个过渡Activity:

    android:name=".LaunchActivity"    android:launchMode="singleTop"    android:theme="@style/LaunchTheme"    android:screenOrientation="portrait"    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"    android:hardwareAccelerated="true"    android:windowSoftInputMode="adjustResize">                        
class LaunchActivity: Activity() {    override fun onCreate(savedInstanceState: Bundle?) {        super.onCreate(savedInstanceState)        val intent = Intent()        intent.setFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);        intent.setClass(this, MainActivity::class.java)        if(savedInstanceState != null) {            intent.putExtras(savedInstanceState)        }        startActivity(intent)        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {            overridePendingTransition(0, 0)        }    }    override fun onPause() {        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ECLAIR) {            overridePendingTransition(0, 0)        }        super.onPause()        finish()    }}

二、重新设置FutterActivity

    android:name=".MainActivity"    android:launchMode="singleTop"    android:theme="@style/FlutterTheme"    android:screenOrientation="portrait"    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"    android:hardwareAccelerated="true"    android:windowSoftInputMode="adjustResize">            android:name="io.flutter.embedding.android.SplashScreenDrawable"        android:resource="@mipmap/papp_launch_nine" />

三、设置theme

    @null    @null    @null    @null    @null    @null    @null    @null    @null    @null    @null    @null        @style/noAnimation    @drawable/launch_background    @style/noAnimation

四、设置背景Drawable

        

更新:

新版本Flutter V1.22.2已解决:

    android:name=".MainActivity"    android:launchMode="singleTop"    android:theme="@style/LaunchTheme"    android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"    android:hardwareAccelerated="true"    android:windowSoftInputMode="adjustResize">          android:name="io.flutter.embedding.android.NormalTheme"      android:resource="@style/NormalTheme"      />          android:name="io.flutter.embedding.android.SplashScreenDrawable"      android:resource="@drawable/launch_background"      />                        
    @drawable/launch_background    @android:color/white

使用点9图片或者普通图片:

                 layer-list>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值