Flutter 使用SafeArea终结沉浸式状态栏、刘海屏与虚拟键之乱(竖屏篇)

本文的目的为使用Flutter技术时,实现如下效果:
1、安卓或苹果手机为刘海屏手机、虚拟键手机时,在竖屏状态下正常显示刘海屏和虚拟键,沉浸式状态栏
2、之外的手机全屏显示,没有状态栏,虚拟键正常显示

详细步骤:

1、安卓端设置
包括识别O版部分机型的刘海屏,P版的所有刘海屏并进行设置。状态栏背景颜色设置为透明


    private void useSafeArea(Context context) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            getHighNotchParams();
        } else {
            getLowNotchParams(context);
        }
    }

    public void getLowNotchParams(Context context) {
        if (hasNotchInHuawei(context)) {
            _topHeight = getNotchSize(context);
        } else if (hasNotchInOppo(context)) {
            _topHeight = getStatusBarHeight(context);
        } else if (hasNotchInVivo(context)) {
            _topHeight = getStatusBarHeight(context);
        } else if (getInt("ro.miui.notch", context) == 1) {
            int resourceId = context.getResources().getIdentifier("notch_height", "dimen", "android");
            if (resourceId > 0) {
                _topHeight = context.getResources().getDimensionPixelSize(resourceId);
            }
        }

        lastSet(_topHeight > 0);
    }

    // 是否是小米手机
    public static boolean isXiaomi() {
        return "Xiaomi".equals(Build.MANUFACTURER);
    }

    /**
     * 小米刘海屏判断.
     *
     * @return 0 if it is not notch ; return 1 means notch
     * @throws IllegalArgumentException if the key exceeds 32 characters
     */
    public static int getInt(String key, Context context) {
        int result = 0;
        if (isXiaomi()) {
            try {
                ClassLoader classLoader = context.getClassLoader();
                @SuppressWarnings("rawtypes")
                Class SystemProperties = classLoader.loadClass("android.os.SystemProperties");
                //参数类型
                @SuppressWarnings("rawtypes")
                Class[] paramTypes = new Class[2];
                paramTypes[0] = String.class;
                paramTypes[1] = int.class;
                Method getInt = SystemProperties.getMethod("getInt", paramTypes);
                //参数
                Object[] params = new Object[2];
                params[0] = new String(key);
                params[1] = new Integer(0);
                result = (Integer) getInt.invoke(SystemProperties, params);

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    //判断该华为手机是否刘海屏
    public static boolean hasNotchInHuawei(Context context) {
        boolean hasNotch = false;
        try {
            ClassLoader cl = context.getClassLoader();
            Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method hasNotchInScreen = HwNotchSizeUtil.getMethod("hasNotchInScreen");
            if (hasNotchInScreen != null) {
                hasNotch = (boolean) hasNotchInScreen.invoke(HwNotchSizeUtil);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return hasNotch;
    }

    //获取刘海的高度
    public static int getNotchSize(Context context) {
        int[] ret = new int[]{0, 0};
        try {
            ClassLoader cl = context.getClassLoader();
            Class HwNotchSizeUtil = cl.loadClass("com.huawei.android.util.HwNotchSizeUtil");
            Method get = HwNotchSizeUtil.getMethod("getNotchSize");
            ret = (int[]) get.invoke(HwNotchSizeUtil);
        } catch (ClassNotFoundException e) {
            Log.e("test", "getNotchSize ClassNotFoundException");
        } catch (NoSuchMethodException e) {
            Log.e("test", "getNotchSize NoSuchMethodException");
        } catch (Exception e) {
            Log.e("test", "getNotchSize Exception");
        } finally {
            return ret[1];
        }
    }

    public static boolean hasNotchInOppo(Context context) {
        return context.getPackageManager().hasSystemFeature("com.oppo.feature.screen.heteromorphism");
    }

    public static int getStatusBarHeight(Context context) {
        int statusBarHeight = 0;
        int resourceId = context.getResources().getIdentifier("status_bar_height", "dimen", "android");
        if (resourceId > 0) {
            statusBarHeight = context.getResources().getDimensionPixelSize(resourceId);
        }
        return statusBarHeight;
    }

    public static boolean hasNotchInVivo(Context context) {
        boolean hasNotch = false;
        try {
            ClassLoader cl = context.getClassLoader();
            Class ftFeature = cl.loadClass("android.util.FtFeature");
            Method[] methods = ftFeature.getDeclaredMethods();
            if (methods != null) {
                for (int i = 0; i < methods.length; i++) {
                    Method method = methods[i];
                    if (method != null) {
                        if (method.getName().equalsIgnoreCase("isFeatureSupport")) {
                            hasNotch = (boolean) method.invoke(ftFeature, 0x00000020);
                            break;
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            hasNotch = false;
        }
        return hasNotch;
    }

    private int _topHeight = 0;

    @TargetApi(28)
    public void getHighNotchParams() {
        final View decorView = getWindow().getDecorView();

        decorView.post(new Runnable() {
            @Override
            public void run() {
                DisplayCutout displayCutout = decorView.getRootWindowInsets().getDisplayCutout();
                if (displayCutout != null) {
                    //是刘海屏。顶部状态栏默认存在,高度传入flutter里
                    _topHeight = displayCutout.getSafeInsetTop();
                }
                lastSet(_topHeight > 0);
            }
        });
    }

    public void lastSet(boolean isNotch) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            //P+版本下的调整
            if (isNotch) {
               //有刘海
            } else {
                //没有刘海,设置全屏
                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                        WindowManager.LayoutParams.FLAG_FULLSCREEN);
            }
        } else {
            //P-版本
            if (isNotch) {
                //有刘海,不做任何操作,默认
            } else {
                //不是刘海屏,全屏
                getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                        WindowManager.LayoutParams.FLAG_FULLSCREEN);
            }
        }
        //修改状态栏背景颜色为透明
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().setStatusBarColor(0x00000000);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            WindowManager.LayoutParams localLayoutParams = getWindow().getAttributes();
            localLayoutParams.flags = (WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS | localLayoutParams.flags);
        }
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        GeneratedPluginRegistrant.registerWith(MainActivity.this);
    }

在AndroidManifest中加入全局代码用于识别华为刘海屏

<meta-data android:name="android.notch_support" android:value="true"/>

2、苹果端无需设置
判断是否为苹果刘海屏的方法非常简单,在Flutter中判断即可,无需对IOS代码进行操作

if (Platform.isIOS) {
      //手机的状态栏默认为打开的
      //判断是否为苹果手机。如果是,并且padding top不为0即为x系列
      //其他系列关闭状态栏
      if (MediaQuery.of(context).padding.top == null ||
          MediaQuery.of(context).padding.top == 0) {
        SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.top]);
      }
    } 

3、Flutter设置
在需要适配的页面使用SafeArea
例:

Scaffold(
	//沉浸式状态栏在这里设置背景颜色
	backgroundColor: Colors.blue,
	body: SafeArea(top:true,child:???));//把ui全部包在SafeArea里

MediaQueryData的padding属性会在非全屏模式下得到顶部bar与底部bar的高度,分别体现在top与bottom属性上,如果不为0则表示存在状态栏或虚拟键
SafeArea的高度通过MediaQueryData确认,具体为size.height-padding.top-padding.bottom。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter中,可以通过使用SystemChrome类和SystemUiOverlay枚举来隐藏状态栏。首先,我们可以使用`SystemChrome.setEnabledSystemUIOverlays([])`来隐藏状态栏和底部按钮栏。例如,以下代码可以实现隐藏状态栏和底部按钮栏: ```dart import 'package:flutter/services.dart'; SystemChrome.setEnabledSystemUIOverlays([]); ``` 如果你只想隐藏状态栏而保留底部按钮栏,可以使用`SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom])`。例如,以下代码隐藏状态栏但保留底部按钮栏: ```dart import 'package:flutter/services.dart'; SystemChrome.setEnabledSystemUIOverlays([SystemUiOverlay.bottom]); ``` 如果你想显示状态栏和底部按钮栏,可以使用`SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values)`。例如,以下代码显示状态栏和底部按钮栏: ```dart import 'package:flutter/services.dart'; SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values); ``` 在隐藏状态栏的同时,你还可以使用`SystemChrome.setSystemUIOverlayStyle`来设置状态栏的样。例如,你可以设置状态栏为透明: ```dart import 'package:flutter/services.dart'; import 'package:flutter/material.dart'; SystemChrome.setSystemUIOverlayStyle( SystemUiOverlayStyle( statusBarColor: Colors.transparent, ), ); ``` 请注意,上述代码只适用于Flutter应用程序中隐藏和显示状态栏的方法。如果你想在Android上隐藏状态栏,你可以使用`SystemChrome.setSystemUIOverlayStyle`来设置`statusBarColor`为透明。例如,以下代码可以在Android上隐藏状态栏: ```dart import 'dart:io'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; if (Platform.isAndroid) { SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle( statusBarColor: Colors.transparent, statusBarIconBrightness: Brightness.dark, ); SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle); } ``` 希望这些代码对你有帮助!<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [flutter 隐藏状态栏和底部按钮](https://blog.csdn.net/NotesChapter/article/details/110406540)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [flutter-status-alert:显示类似Apple系统的自动隐藏状态警报。 非常适合在不中断用户流程的情况下通知用户](https://download.csdn.net/download/weixin_42162216/15048923)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值