确定是否在React Native中在屏幕上绘制硬件按钮

时间:2017-06-21 12:30:59

标签: android react-native

我在我的React Native应用程序(RN 0.42)中的bottom: 0处绘制了一个按钮。这在iOS和大多数Android设备上运行良好。但是在没有物理硬件按钮的Android设备上,按钮栏会在我按钮上方的屏幕上绘制。

所以:在这种情况下,有没有办法检测硬件按钮是物理的还是软件驱动的,以调整我的布局?或者这只是React Native中的一个错误,因为这只发生在模态对话框中?

Nexus(绿色按钮的样式为:bottom: 45,硬件按钮在屏幕上呈现): enter image description here

Galaxy S5 :(此设备有真正的硬件按钮,因此bottom: 45太多了): enter image description here

2 个答案:

答案 0 :(得分:5)

appears to be easy使用Java来确定Android设备是否有物理按钮,因此要在React Native中访问它,我会使Native Module包装器返回ViewConfiguration.get(context).hasPermanentMenuKey()的结果。

您可以在Android Studio中打开React Native项目的/android目录,然后在/app/src/main/java/<com.companyname.appname>/文件夹中,在您看到MainActivityMainApplication的同一级别文件,创建一个名为detecthardware的新Android资源目录(或任何其他适当的名称)。在其中创建DetectHardwareModule.java并包括:

package com.companyname.appname.detecthardware;

import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.ReactMethod;

import java.util.List;

public class DetectHardwareModule extends ReactContextBaseJavaModule {

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

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

    @ReactMethod
    public void hasHardwareButtons(final Callback callback) {
        callback.invoke(ViewConfiguration.get(getReactApplicationContext()).hasPermanentMenuKey());
    }
}

然后创建DetectHardwarePackage.java并包含:

package com.companyname.appname.detecthardware;

import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.JavaScriptModule;
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 DetectHardwarePackage implements ReactPackage {
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> modules = new ArrayList<>();
        modules.add(new DetectHardwareModule(reactContext));
        return modules;
    }

    @Override
    public List<Class<? extends JavaScriptModule>> createJSModules() {
        return Collections.emptyList();
    }

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

在您的MainApplication.java中,您需要包含getPackages  方法,以便JavaScript代码可以访问它:

@Override
protected List<ReactPackage> getPackages() {
    return Arrays.<ReactPackage>asList(
        new MainReactPackage(),
        new DetectHardwarePackage()
    );
}

现在,在您的React Native组件中,请确保从NativeModules以及react-native导入Platform,以便您只在Android上运行该功能。在componentDidMount

componentDidMount() {
    if (Platform.OS === 'android') {
        NativeModules.DetectHardware.hasHardwareButtons(function(result) {
            this.setState({hasHardwareButtons: result})
        }.bind(this));
    }
}

最后在你的render函数中,如果平台是android并且hasHardwareButtons为真,则计算bottom金额为0,否则为45:

var bottom = (Platform.OS === 'android' && this.state.hasHardwareButtons) ? 0 : 45

答案 1 :(得分:2)

我使用RN Dimensions来做到这一点:

import {Dimensions} from 'react-native';

let deviceHeight = Dimensions.get('screen').height;
let windowHeight = Dimensions.get('window').height;
let bottomNavBarHeight = deviceHeight - windowHeight;
if (bottomNavBarHeight > 0) {
    // onscreen navbar
} else {
    // not onscreen navbar
}