React-Native:按下Android硬件后退按钮

时间:2016-09-12 08:22:48

标签: android reactjs webview react-native

我试图在按下Android后退按钮时添加回webview,我仍然无法使其工作。

这是我的代码:

<WebView
    ref={WEBVIEW_REF}
    source={source}
    domStorageEnabled={true}
    onNavigationStateChange={this.onNavigationStateChange}
/>

componentDidMount() {
    BackAndroid.addEventListener('hardwareBackPress', function() {
        if(this.state.backButtonEnabled) {
            this.refs[WEBVIEW_REF].goBack();
            return true;
        }
    });
};

onNavigationStateChange = (navState) => {
    this.setState({
        backButtonEnabled: navState.canGoBack,
    });
};

使用上面的代码我得到错误undefined不是一个对象this.state.backButtonEnabled(在状态中设置)。

我只是想看看goBack是否有效,所以我删除了if语句而不是我得到错误undefined不是对象this.refs [WEBVIEW_REF]。

最佳解决方案是什么?

7 个答案:

答案 0 :(得分:15)

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_home"
            android:icon="@drawable/ic_dashboard"
            android:title="Home" />
    </group>

    <item android:title="Information">
        <group android:checkableBehavior="single">
            <item
                android:id="@+id/nav_the_wetlands"
                android:icon="@drawable/ic_event"
                android:title="The Wetlands" />
            <item
                android:id="@+id/nav_the_mistbelt_forests"
                android:icon="@drawable/ic_event"
                android:title="The Mistbelt Forests" />
            <item
                android:id="@+id/nav_the_grasslands"
                android:icon="@drawable/ic_event"
                android:title="The Grasslands" />
        </group>
    </item>

    <item android:title="Quick Go To">
        <group android:checkableBehavior="single">
            <item
                android:id="@+id/nav_accommodation"
                android:icon="@drawable/ic_event"
                android:title="Accommodation" />
            <item
                android:id="@+id/nav_cuisine"
                android:icon="@drawable/ic_forum"
                android:title="Cuisine" />
            <item
                android:id="@+id/nav_leisure_activites"
                android:icon="@drawable/ic_forum"
                android:title="Leisure &amp; Activites" />
            <item
                android:id="@+id/nav_agri_tourism"
                android:icon="@drawable/ic_forum"
                android:title="Agri-tourism" />
            <item
                android:id="@+id/nav_education"
                android:icon="@drawable/ic_forum"
                android:title="Education" />
            <item
                android:id="@+id/nav_arts_crafts_decor"
                android:icon="@drawable/ic_forum"
                android:title="Arts, Crafts &amp; DeCor" />
            <item
                android:id="@+id/nav_selective_shopping"
                android:icon="@drawable/ic_forum"
                android:title="Selective Shopping" />
            <item
                android:id="@+id/nav_for_children"
                android:icon="@drawable/ic_forum"
                android:title="For Children" />
        </group>
    </item>

    <item android:title="Midlands Animals">
        <group android:checkableBehavior="single">
            <item
                android:id="@+id/nav_midlands_birding_checklist"
                android:icon="@drawable/ic_dashboard"
                android:title="Midlands Birding Checklist" />
            <item
                android:id="@+id/nav_midlands_mammals_checklist"
                android:icon="@drawable/ic_dashboard"
                android:title="Midlands Mammals Checklist" />
        </group>
    </item>

</menu>

1)绑定你的处理程序2)不要忘记在unmount上删除removeListener。

答案 1 :(得分:13)

想要添加一个完整的示例以防万一:

import React, { Component } from 'react';
import {
  BackHandler,
  Platform,
  WebView,
} from 'react-native';

class ExampleWebView extends Component {
  webView = {
    canGoBack: false,
    ref: null,
  }

  onAndroidBackPress = () => {
    if (this.webView.canGoBack && this.webView.ref) {
      this.webView.ref.goBack();
      return true;
    }
    return false;
  }

  componentWillMount() {
    if (Platform.OS === 'android') {
      BackHandler.addEventListener('hardwareBackPress', this.onAndroidBackPress);
    }
  }

  componentWillUnmount() {
    if (Platform.OS === 'android') {
      BackHandler.removeEventListener('hardwareBackPress');
    }
  }

  render() {
    return (
      <WebView
        source={{ uri: "https://www.google.com" }}
        ref={(webView) => { this.webView.ref = webView; }}
        onNavigationStateChange={(navState) => { this.webView.canGoBack = navState.canGoBack; }}
      />
    );
  }
}

答案 2 :(得分:1)

这是使用Typescript以及useRefuseEffect钩子的解决方案。

我没有使用canGoBack,但是无论如何它似乎都可以工作。

import React, { useEffect, useRef } from 'react';
import { BackHandler } from 'react-native';
import WebView from 'react-native-webview';

const WebViewWrapper = (): JSX.Element => {
  const webview = useRef<WebView>(null);
  const onAndroidBackPress = (): boolean => {
    if (webview.current) {
      webview.current.goBack();
      return true; // prevent default behavior (exit app)
    }
    return false;
  };
  useEffect((): (() => void) => {
    BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress);
    return (): void => {
      BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
    };
  }, []); // Never re-run this effect
  return (
    <WebView
      source={{ uri: 'https://stackoverflow.com' }}
      ref={webview}
    />
  )
}

答案 3 :(得分:1)

如果您正在寻找functional component解决方案。

注意:执行返回操作不需要canGoBack状态,它只是保存当前状态,您可以根据需要安全地删除它

import React, { useState, useEffect, useRef } from "react"
import { BackHandler, Platform } from "react-native"
import { SafeAreaView } from "react-navigation"
import { WebView } from "react-native-webview"

const Webview = () => {
  const webView = useRef(null);
  const [canGoBack, setCanGoBack] = useState(false);

  useEffect(() => {
    if (Platform.OS === 'android') {
      BackHandler.addEventListener('hardwareBackPress', HandleBackPressed);

      return () => {
        BackHandler.removeEventListener('hardwareBackPress', HandleBackPressed);
      }
    }
  }, []); // INITIALIZE ONLY ONCE

  const HandleBackPressed = () => {
    if (webView.current) {
      webView.current.goBack();
      return true; // PREVENT DEFAULT BEHAVIOUR (EXITING THE APP)
    }
    return false;
  }

  return (
    <SafeAreaView>
      <WebView
        ref={webView}
        source={{
          uri: "<YOUR_URL>"
        }}
        onNavigationStateChange={navState => setCanGoBack(navState.canGoBack)}
      />
    </SafeAreaView>
  )
}

export default Webview;

答案 4 :(得分:0)

这可能会帮助某人,因为上述解决方案无法解决我的问题。...

import React, { Component } from 'react';
import {
  BackHandler,
  WebView,
} from 'react-native';

export default class App extends Component {

constructor(props) {
    super(props);
    this.WEBVIEW_REF = React.createRef();
}

componentDidMount() {
    BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}

componentWillUnmount() {
  BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}

handleBackButton = ()=>{
   this.WEBVIEW_REF.current.goBack();
   return true;
}

onNavigationStateChange(navState) {
  this.setState({
    canGoBack: navState.canGoBack
  });
}

render(){
   return (
    <WebView
        source={{ uri: "https://www.cbt.ng" }}
        ref={this.WEBVIEW_REF}
        onNavigationStateChange={this.onNavigationStateChange.bind(this)}
     />
    )

 }
}

答案 5 :(得分:0)

如果在React Native中使用Webview,则默认情况下按下移动设备的后退按钮时应用退出。如果要在按返回按钮时转到上一页,则需要实现react-native webview的“ goback”功能。

您可以看到本文的 Step 5 : Handle Mobile Back Button 部分。

答案 6 :(得分:0)

添加到@Nisharg Shah 答案。对于 onNavigationStateChange 道具,添加以下行

onNavigationStateChange={navState => {webView.current.canGoBack = navState.canGoBack}}

并在 HandleBackPressed 方法中检查是否 webView.current.canGoBack 然后 webView.current.goBack(); else return false

import React, { useState, useEffect, useRef } from "react"
import { BackHandler, Platform } from "react-native"
import { SafeAreaView } from "react-navigation"
import { WebView } from "react-native-webview"

const Webview = () => {
const webView = useRef(null);
const [canGoBack, setCanGoBack] = useState(false);

useEffect(() => {
  if (Platform.OS === 'android') {
    BackHandler.addEventListener('hardwareBackPress', HandleBackPressed);

    return () => {
       BackHandler.removeEventListener('hardwareBackPress', HandleBackPressed);
    }
  }
}, []); // INITIALIZE ONLY ONCE

const HandleBackPressed = () => {
    if (webView.current.canGoBack) {
        webView.current.goBack();
        return true; // PREVENT DEFAULT BEHAVIOUR (EXITING THE APP)
    }
    return false;
}

return (
  <SafeAreaView>
    <WebView
      ref={webView}
      source={{
        uri: "<YOUR_URL>"
      }}
      onNavigationStateChange={navState => {webView.current.canGoBack = navState.canGoBack}} ->> This line is important
  />
 </SafeAreaView>
 )
}

export default Webview;