How to create global android device back button handler using React Native? - android

In my scenario, I am trying to create global class for android back button handler and reuse it in multiple screen class files. How to do it? I tried below code but I dont know how to access common class from other classes.
My Code Below (Androidhandler.tsx)
export default class hardware extends Component {
constructor(props) {
super(props);
this.BackButton = this.BackButton.bind(this);
}
componentWillMount() {
BackHandler.addEventListener'BackPress',this.BackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('BackPress',this.BackButton);
}
BackButton() {
if(this.props.navigation){
this.props.navigation.goBack(null);
return true;
}
}
}

the following code allows to show an alert when you want to go back with the android back button, what you need is to use the react native BackHandler component as follows.
import { BackHandler } from "react-native"
export default class hardware extends Component {
constructor(props) {
super(props);
this.BackButton = this.BackButton.bind(this);
}
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.BackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', () => {
if (this.props.navigator && this.props.navigator.getCurrentRoutes().length > 1) {
this.navigator.pop();
return true;
}
return false;
});
}
BackButton() {
Alert.alert(
'Warning',
'Are you sure to leave?',
[
{
text: 'Cancel',
style: 'cancel'
},
{ text: 'OK', onPress: () => BackHandler.exitApp() }
],
);
return true;
}
}

Related

Back button is not disabling for particular screen in android React native

I am trying to disable android back button on home screen only.
My code:
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
navigation.goBack(null);
return true
}
const navigateToNextScreen = () => {
navigation.push('Prmotions');
}
If I remove navigation.goBack(null); back button is disabled for all screen and with above code back button is not disabled at all.
navigation.navigate("ScreenName") isn't working for mu scenario to move to next screen that's why I have used navigation.push
I handled it by putting this on all screens where I wanted to go back on back button press.
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
navigation.goBack(null);
return true
}
and put this where I wanted not to go back.
React.useEffect(() => {
BackHandler.addEventListener('hardwareBackPress', handleBackBtnPressed);
return () => {
BackHandler.removeEventListener('hardwareBackPress', handleBackBtnPressed);
}
}, [])
const handleBackBtnPressed = () => {
return true
}
I know this might not be best solution but it worked for me pretty well.

android default back button to be controlled in Ionic 4

using ionic 4 i have created an application in that i need to control back button. I have used the following code
this.backButtonSubscription =
this.platform.backButton.subscribeWithPriority(1, async () => {
if (this.router.url === '/registration') {
navigator['app'].exitApp();
}
});
This subscription event is working only on root page and not working on other pages.
I want to control the back button on particular page to show alert and other things, but right now when clicking hardware back button in android device it goes to the previous page.
Code below works for me absolutely fine.
In initializeApp() method in app.component.ts
initializeApp() {
this.platform.ready().then(() => {
this.statusBar.styleLightContent();
this.splashScreen.hide();
this.platform.backButton.subscribeWithPriority(9999, () => {
if(this.router.url !== '/login') {
// Back button controls when user is not in Login Page
} else {
navigator['app'].exitApp();
}
});
});
}
if you want the backButton to do Alert or Toast
Create the backButton function:
backButton() {
this.platform.backButton.subscribeWithPriority(0, () => {
this.showAlertBack();
});
}
Create the Alert Function:
async showAlertBack() {
const alert = await this.alertCtrl.create({
message: 'Want to Exit App?',
buttons: [
{
text: 'Ok',
handler: () => {
navigator['app'].exitApp();
}
},
{
text: 'Nop',
handler: () => {
alert.dismiss();
}
}
],
backdropDismiss: false
});
await alert.present();
}
Now Initialize it in ngOnInit() or ionViewWillEnter()
this.backButton();

How to implement bottom tab navigation in RNN V2

I am trying to implement navigation with bottom tabs in my shiny new React Native application. I chose to start with React Native Navigation, version two.
Here is the code so far:
import React from 'react'
import { Navigation } from 'react-native-navigation'
import { Text, View } from 'react-native'
import Icon from 'react-native-vector-icons/Ionicons'
const prepareIcons = async () => {
const [ home, trend, wifi, list, help ] = await Promise.all([
Icon.getImageSource('ios-home', 30),
Icon.getImageSource('ios-trending-up', 30),
Icon.getImageSource('ios-wifi', 30),
Icon.getImageSource('ios-list', 30),
Icon.getImageSource('ios-help-buoy', 30)
])
return { home, trend, wifi, list, help }
}
const Monitor = class extends React.Component {
render() {
return <View><Text>Monitor</Text></View>
}
}
const Usage = class extends React.Component {
render() {
return <View><Text>Usage profile</Text></View>
}
}
const Connection = class extends React.Component {
render() {
return <View><Text>WiFi connection</Text></View>
}
}
const Reports = class extends React.Component {
render() {
return <View><Text>Reports log</Text></View>
}
}
const Support = class extends React.Component {
render() {
return <View><Text>Support</Text></View>
}
}
const main = async () => {
const icons = await prepareIcons()
Navigation.events().onAppLaunched(() => {
Navigation.setRoot({
bottomTabs: {
children: [{
component: {
name: 'Monitor',
options: {
bottomTab: {
icon: icons.home,
title: 'Monitor',
visible: true
}
}
}
}, {
component: {
name: 'Usage',
options: {
bottomTab: {
icon: icons.trend,
title: 'Usage'
}
}
}
}, {
component: {
name: 'Connection',
options: {
bottomTab: {
icon: icons.wifi,
title: 'WiFi'
}
}
}
}, {
component: {
name: 'Reports',
options: {
bottomTab: {
icon: icons.list,
title: 'Reports'
}
}
}
}, {
component: {
name: 'Support',
options: {
bottomTab: {
icon: icons.help,
title: 'Support'
}
}
}
}]
}
})
})
}
Navigation.registerComponent('Monitor', () => Monitor)
Navigation.registerComponent('Usage', () => Usage)
Navigation.registerComponent('Connection', () => Connection)
Navigation.registerComponent('Reports', () => Reports)
Navigation.registerComponent('Support', () => Support)
main()
It produces this (Android emulator):
The application opens. No errors. The tabs do change when clicked, but as you can see in the screenshot, the contents of the current component, Connection, is not visible. What am I doing wrong? I feel there is something I'm missing, but this could be a bug.
React Native Navigation version: 2.0.2125
React Native version: 0.53.0
Platform: Android
Device: Nexus 5X, Android 8.1.0, Debug
The problem was on the selectTabAtIndex method of the com.reactnativenavigation.viewcontrollers.BottomTabsController class. Applying the diff below fixes it.
diff --git a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsContr
index 87812bc5..69d45877 100644
--- a/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java
+++ b/lib/android/app/src/main/java/com/reactnativenavigation/viewcontrollers/BottomTabsController.java
## -145,7 +145,7 ## public class BottomTabsController extends ParentController implements AHBottomNa
void selectTabAtIndex(final int newIndex) {
getView().removeView(getCurrentView());
bottomTabs.setCurrentItem(newIndex, false);
- getView().addView(getCurrentView());
+ getView().addView(getCurrentView(), MATCH_PARENT, MATCH_PARENT);
}
#NonNull

React Native BackHandler not removing event Listener

I am using React Navigation and I need some custom functionality when back button is pressed. Here is my code:
class AddEditIngredient extends Component {
constructor(props) {
super(props);
this.state = {
editStarted: false
};
this.goBack = () => {
if (this.state.editStarted === true) {
Alert.alert(
"Ingredient Not Saved",
"Do you want to navigate away without saving ingredient?",
[
{ text: "Cancel", onPress: () => null, style: "cancel" },
{ text: "Yes", onPress: () => this.props.navigation.goBack() }
],
{ cancelable: true }
);
} else {
this.props.navigation.goBack();
}
};
}
componentWillMount() {
BackHandler.addEventListener("hardwareBackPress", this.goBack);
}
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.goBack);
}
My goBack function works fine for back button on screen, however when I try to press the physical back button it pops out all the screens and minimizes the application. From what I have gathered by reading previous posts on the issue, removeEventListener is not referring to the same function as addEventListener. So I tried this:
constructor(props) {
super(props);
this.state = {
editStarted: false
};
this.goBack = this.goBack.bind(this);
}
goBack = () => {
if (this.state.editStarted === true) {
Alert.alert(
"Ingredient Not Saved",
"Do you want to navigate away without saving ingredient?",
[
{ text: "Cancel", onPress: () => null, style: "cancel" },
{ text: "Yes", onPress: () => this.props.navigation.goBack() }
],
{ cancelable: true }
);
} else {
this.props.navigation.goBack();
}
};
But it didn't work. Can anyone point out my mistake?
Thanks
you need to attach return true on your custom back listener or return false to follow your parent handler
Finally found the answer in this post. I needed to return true at the end of my goBack function to indicate that back behaviour has been handled.

Preventing hardware back button android for React Native

I want to prevent the user from going back to the previous screen. So I added code, but this does not work. Are there any solutions for this? The alert pop up is seen but "return false" does not work.
componentDidMount() {
BackAndroid.addEventListener('hardwareBackPress', () => {
Alert.alert("alert","alert")
this.props.navigator.pop();
return false;
});
You need to return true, if you want to disable the default back button behavior.
Here is a sample component which will block the user from going back to previous screen.
import React, {Component,} from 'react';
import {
View,
Text,
BackHandler,
ToastAndroid,
} from 'react-native';
class BackButtonDemo extends Component {
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton() {
ToastAndroid.show('Back button is pressed', ToastAndroid.SHORT);
return true;
}
render() {
return (
<View>
<Text>Back button example</Text>
</View>
);
}
}
module.exports = BackButtonDemo;
Note:
Also remove this.props.navigator.pop(); from your solution.
Navigator pop function will take the user to the previous screen rendered by Navigator.
Shiny new implementation using react hooks:
import React, {Component, useEffect} from 'react';
import {
View,
Text,
BackHandler,
} from 'react-native';
const LogInView = () => {
useEffect(() => {
const backHandler = BackHandler.addEventListener('hardwareBackPress', () => true)
return () => backHandler.remove()
}, [])
return (
<View>
<Text>Back button example</Text>
</View>
);
}
export default LoginView
I disable my back button (android) for whole application by add this code in App.js
componentDidMount() {
BackAndroid.addEventListener('hardwareBackPress', this.handleBackButton);
}
componentWillUnmount() {
BackAndroid.removeEventListener('hardwareBackPress', this.handleBackButton);
}
handleBackButton() {
return true;
}
don't forget to import BackAndroid
import {BackAndroid} from 'react-native'
Try this Disable back button by just returning true
import {BackAndroid} from 'react-native';
componentWillMount() {
BackAndroid.addEventListener('hardwareBackPress', () => {return true});
}
So While Everyone is working with the Backhandler of react-native I tried to do it with react-navigation to prevent going back handler.
This worked for me.
If you just want to prevent going back without showing or alerting anything to the user.
React.useEffect(() => {
navigation.addListener('beforeRemove', (e) => {
e.preventDefault();
});
}, [navigation]);
You can put this code in your function component.
Use Case:
In User Registration when the user signup and go to the confirmation
screen for the code so we dont want him back you can use this code at
the moment.
Just to give you a complete answer when using react-navigation:
If you're using react-navigation, place the following in your RootNavigation class not the App.js in order to disable the back-button for the whole application.
import { BackHandler } from 'react-native';
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.onBackButtonPressed);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.onBackButtonPressed);
}
onBackButtonPressed() {
return true;
}
using the BackHandler from react native worked for me. Just include this line in your ComponentWillMount:
BackHandler.addEventListener('hardwareBackPress', function() {return true})
it will disable back button on android device.
If you are using react-natigation then you need to use BackHandler instead of BackAndroid
import { BackHandler } from 'react-native';
// code
componentDidMount() {
BackHandler.addEventListener('backPress');
}
// some more code
componentWillUnmount() {
BackHandler.removeEventListener('backPress');
}
Disable back button for module react-navigation, use hook useFocusEffect
const hardwareBackPressCustom = useCallback(() => {
return true;
}, []);
useFocusEffect(() => {
BackHandler.addEventListener('hardwareBackPress', hardwareBackPressCustom)
return () => {
BackHandler.removeEventListener('hardwareBackPress', hardwareBackPressCustom)
};
}, []);
For me, this was the solution:
import React, { useEffect } from 'react'
import { View } from 'react-native'
function Home({ navigation }) {
useEffect(() =>
navigation.addListener('beforeRemove', (e) => {
e.preventDefault();
return
}),
[navigation]
);
return (
<View>
...
</View>
)
}
export default Home
You can see an example in docs
The only correct solution can be found here: https://reactnavigation.org/docs/custom-android-back-button-handling/
function ScreenWithCustomBackBehavior() {
// ...
useFocusEffect(
React.useCallback(() => {
const onBackPress = () => {
return true;
};
BackHandler.addEventListener('hardwareBackPress', onBackPress);
return () =>
BackHandler.removeEventListener('hardwareBackPress', onBackPress);
}, [isSelectionModeEnabled, disableSelectionMode])
);
// ...
}
All the others are for class components or apply to all screens, rather than only the screen where the hook is applied.
Just an update for Version 6.x as seen in RN docs
function ScreenWithCustomBackBehavior() {
// ...
useFocusEffect(
React.useCallback(() => {
const onBackPress = () => {
if (isSelectionModeEnabled()) {
disableSelectionMode();
return true;
} else {
return false;
}
};
BackHandler.addEventListener('hardwareBackPress', onBackPress);
return () =>
BackHandler.removeEventListener('hardwareBackPress', onBackPress);
}, [isSelectionModeEnabled, disableSelectionMode])
);
// ...
}
Alternatively as a hook
import {useNavigation} from '#react-navigation/native';
import {useEffect, useState, useCallback} from 'react';
export const usePreventGoBack = () => {
const navigation = useNavigation();
const [allow, setAllow] = useState(false);
const beforeRemoveListener = useCallback(
e => {
if (allow) {
return;
}
e.preventDefault();
},
[allow],
);
useEffect(() => {
const unsub = navigation.addListener('beforeRemove', beforeRemoveListener);
return () => {
unsub();
};
}, [navigation, beforeRemoveListener, allow]);
return (cb: () => void) => {
setAllow(true);
setTimeout(() => {
cb();
});
};
};
To bypass
const continuePressed = () => {
allowBackButton(() => {
navigation.popToTop();
});
};
import React, {useEffect} from 'react';
import {BackHandler} from 'react-native';
useEffect(() => {
const backHandler = BackHandler.addEventListener(
'hardwareBackPress',
() => {
return true;
},
);
return () => backHandler.remove();
})
For IOS use this code... In the Stack Navigation. react-navigation > 5
<LoginStackNav.Screen name="Home" component={Home} options={{gestureEnabled: false }}/>
Onclick of hardware back button OnBackPressed callback gets called
you can just remove super declaration in onBackPressed call back.
#Override
public void onBackPressed() {
}

Categories

Resources