react native 安卓(特别是小米手机)全面屏是否开虚拟按键的适配

Posted 春春小姐姐做前端

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了react native 安卓(特别是小米手机)全面屏是否开虚拟按键的适配相关的知识,希望对你有一定的参考价值。

react native 安卓(特别是小米手机)全面屏是否开虚拟按键的适配

做rn蛮久了,遇到的坑无数,谢谢大家带我爬过的坑,这次我也来分享一下,希望帮助到有需要的人!

大家先看先后效果对比:

没开虚拟按键的时候完美:
在这里插入图片描述
开了虚拟按键之后,显示不全了:
在这里插入图片描述
处理之后的效果:
在这里插入图片描述
产生的原因:
andorid全面屏幕中 Dimensions.get(‘window’).height 计算屏幕高度时会自动减少StatusBar 的高度

解决方案:

const { width,height } = Dimensions.get('window');
let deviceHeight = height/width > 1.8 ? height+ NativeModules.StatusBarManager.HEIGHT: height;
然后将deviceHeight设成我们的内容高度就行了!

到这里我以为完美解决了哈哈,其实还有另一个大坑等着呢!
测试了几乎所有主流机型,基本都没问题很完美,唯独小米手机,真的是坑啊!
这时候小米全面屏手机开启虚拟按键的状态是对的,可是没开按键的时候下面没有铺满,缺了一大截,其原因就是它不管开不开按键它的height/width 都大于 1.8 ,因为它的Dimensions.get(‘window’).height不随开不开按键而变化,始终是那个那么高,所以根本无法用这个比例来判断了!

查阅很多资料,rn不好解决了,只能用调用原生方法试试了,结果终于完美解决,步骤我也给大家贴出来:

1.在com.xx.xx创建包名milletAdaptation;
编写 Module,在milletAdaptation包下创建MilletAdaptation.java,代码如下:

package com.项目工程名.milletAdaptation;

import android.app.Activity;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.WindowManager;
import com.facebook.react.ReactApplication;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.swordsmanapp.MainActivity;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import java.lang.reflect.Method;

public class MilletAdaptation extends ReactContextBaseJavaModule{

    DisplayMetrics metrics = new DisplayMetrics();

    public MilletAdaptation(ReactApplicationContext reactContext) {
        super(reactContext);
    }

    @NonNull
    @Override
    public String getName() {
        return "MilletAdaptation";
    }

    @ReactMethod
    public  void getHeight(final Promise promise) {
        int height = metrics.heightPixels;
        Activity activty = MainActivity.getActivity();
        if (isXiaoMi(getReactApplicationContext())) {
            height += getNavigationBarHeight(activty);
        }else {
            height=0 ;
        }
        promise.resolve(height);
    }


    /**
     * 获取底部虚拟按键高度
     * @param context
     * @return
     */
    public static int getNavigationBarHeight(Context context) {
        WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        DisplayMetrics dm = new DisplayMetrics();
        try {
            @SuppressWarnings("rawtypes")
            Class c = Class.forName("android.view.Display");
            @SuppressWarnings("unchecked")
            Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
            method.invoke(display, dm);
            return dm.heightPixels - display.getHeight();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return 0;
    }



    /**
     * 判断是否是小米手机 并且是否开启全面屏
     *
     * @return
     */
    public static boolean isXiaoMi(Context context) {
        if (Build.MANUFACTURER.equals("Xiaomi")) {
            return Settings.Global.getInt(context.getContentResolver(), "force_fsg_nav_bar", 0) != 0;
        }
        return false;
    }

    @Override
    public void initialize() {
        MainActivity.getActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
    }

    @Override
    public boolean canOverrideExistingModule() {
        return false;
    }

    @Override
    public void onCatalystInstanceDestroy() {

    }
}

2.编写 Package,在milletAdaptation包下创建MilletAdaptationPackage.java,代码如下:

package com.项目工程名.milletAdaptation;

import com.swordsmanapp.milletAdaptation.MilletAdaptation;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class MilletAdaptationPackage implements ReactPackage {

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }

    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new MilletAdaptation(reactContext));
        return modules;
    }
}

3.最后在 Android 这边要做的最后一件事就是注册这个模块,在MainApplication中注册模块:

 List<ReactPackage> packages = new PackageList(this).getPackages();
          // Packages that cannot be autolinked yet can be added manually here, for example:
            packages.add(new AlipayReactPackage());
            packages.add(new MilletAdaptationPackage()); // <-- 注册模块
          return packages;

原生这部分就完成了,在rn端调用:

import {PixelRatio,NativeModules} from 'react-native';

  componentDidMount() {
        NativeModules.MilletAdaptation.getHeight()
            .then((height) => {
                // console.log('height:',height);
                if(height){
                    this.setState({
                        deviceHeight:height/PixelRatio.get() //当是小米手机并且是全面屏没开按键的情况使用这个高度
                    })
                }
            })
            .catch((err) => {
                console.log('err:', err);
            });
    }

这下是真的完美解决咯,大家如果也遇到这样的困扰,希望可以帮到你们哦~
步骤写得很清楚,如果有不懂的可以留言,如果觉得有帮助记得给小姐姐点赞哈💗

以上是关于react native 安卓(特别是小米手机)全面屏是否开虚拟按键的适配的主要内容,如果未能解决你的问题,请参考以下文章

react native 安卓(特别是小米手机)全面屏是否开虚拟按键的适配

react native 安卓(特别是小米手机)全面屏是否开虚拟按键的适配

react native 适配安卓全面屏手机

react-native-video解决安卓无法全屏

国产安卓手机全系通用刷机解锁BL锁-胎教级教程

在小米手机上调试react-native白屏问题