React Native Switch not animating when using React Navigation - react-native

I am trying to add a Switch to my App, and its animation is not working. I tried to create a Snack and noticed that it works without navigation (see this snack) but doesn't work when it is inside a Screen (see this snack).
It seems to be a problem just in Android.
The Switch code is just it:
const MySwitch = () => {
const [value, setValue] = React.useState(false);
return <Switch value={value} onValueChange={setValue} />;
};
Am I doing something wrong? Is it a problem with Expo, React Navigation or Switch?
In the worst case, how can I animate the component on my own?
Current behavior / Expected behavior:
React Navigation versions:
"#react-navigation/native": "^5.7.2",
"#react-navigation/bottom-tabs": "^5.7.2",

came upon this bug as well, exactly as described.
I implement a settings page where if you toggle one option, another toggle option is displayed. The second Toggle does not suffer from this bug, and this is 100% consistent. So my guess is that he bug is triggered only for Switch components that are rendered on the initial render pass somehow.
as a workaround for this bug, introducing a small delay of 10ms for rendering Switch completely resolves the issue without visible side effects.
function useDelay(ms: number) {
const [gate, setGate] = useState(false);
useEffect(() => {
setTimeout(() => {
setGate(true);
}, ms);
});
return gate;
}
const delayRender = useDelay(10);
return (
<>
{delayRender && (
<Switch />
)}
</>
);

Related

Lottie ref in Expo (react native)

I am trying to move my existing React Native (typescript) project to Expo. Everything is working fine in Expo except modal with Lottie animation ( without expo it is working properly).
My code:
export const SuccessModal = ({isVisible = false, onAnimationFinish}: Props) => {
let animation: any = React.createRef();
useEffect(() => {
if (isVisible) {
animation.current.play();
}
}, []);
return (
<Modal
visible={isVisible}
backdropStyle={{backgroundColor: 'rgba(230, 228, 253, 0.5)'}}>
<LottieView
ref={animation}
source={require('../assets/success-lottie.json')}
style={{width: 300, height: 300}}
autoPlay={true}
loop={false}
onAnimationFinish={onAnimationFinish}
/>
</Modal>
);
};
I guess the problem is with ref={animation} , because modal is being displayed, but animation is not moving - seems like animation.current.play() is not invoked in the effect. I tried useRef(null) and useRef<LottieView | null>(null) as suggested in other posts. Also tried to reinstall lottie with command: expo install lottie-react-native.
Any ideas what might be wrong here? What is so specific for Expo?
I think calling animation.current.reset(); before animation.current.play(); would do the trick.
I am using const animation = useRef(null) hook and got it working with Expo too.
However, initial play() was not working by default and I had did this trick to make it work as soon as component loads.
...
const animation = useRef(null);
...
useEffect(() => {
animation.current?.reset();
animation.current?.play();
}, []);

React navigation 5 bottom tab bar android keyboard ISSUE

There is huge problem with bottom tab navigation on android that I'm struggling with and can't find any solution!!
on Android when keyboard shows the bottom tab bar goes upon the keyboard, which is obviously not a desired behaviour!
This happens when softInputMode in Android Manifest is set to adjustResize (which is the default mode for react native), I've tried with adjustPan and resolves the problem, but now when keyboard appears android avoids not only the view but either the header of the app! This behaviour too is not acceptable!
I've also tried with workarounds like listening to keyboard events (didShow, and didHide are only available) and disabling the bottom bar on keyboard appearingt but this leads to many glitches in the app.
The keyboardHidesTabBar prop is also very ugly cause it is an animation that hides the bar that starts after keyboard opening...
Have you tried this solution keyboardHidesTabBar: true in TabBarOptions props.
<Tab.Navigator
tabBarOptions={{
keyboardHidesTabBar: true,
}}
>
<Tab.Screen />
<Tab.Screen />
</Tab.Navigator>
Answer for React Navigation V5 with or without a Custom tabBar
if you use a custom tabBar the keyboardHidesTabBar: true prop is not working but when i change the custom tabBar to default tab bar that prop works but i don't like the behavior of that prop on android, so i used keyboard from react-native to check if the keyboard is active or not and setting the css display prop to 'none'
import { Keyboard, View } from "react-native";
const [keyboardStatus, setKeyboardStatus] = useState<boolean>();
useEffect(() => {
const showSubscription = Keyboard.addListener('keyboardDidShow', () => {
setKeyboardStatus(true);
});
const hideSubscription = Keyboard.addListener('keyboardDidHide', () => {
setKeyboardStatus(false);
});
return () => {
showSubscription.remove();
hideSubscription.remove();
};
}, []);
so on the custom tab bar component now we can do like this.
<View style={
[
styles.mainContainer,
keyboardStatus ? styles.hideTabNavigation : null,
]
}
>
// your code here
</View>
Hope this will help someone until they fix this issue!

How to use refreshControl on a ScrollView but prevent dragging direction?

I have content that I want to "refresh" with a RefreshControl but I do not want the content to scroll upwards. I was originally under the impression that setting bounces=false and scrollEnabled=true would achieve this.
How about you set a key to the Component, then update it when you want to refresh it.
When a key changes, React see it as a new component. As a result, it will literally refresh the component.
export default () => {
const [refreshKey, setRefreshKey] = React.useState('randomstring');
// call me when refresh required
const refresh = () => {
setRefreshKey(refreshKey + 'randomstring');
};
return (
<ScrollView key={refreshKey}>
{/* Some Awesome Contents */}
</ScrollView>
);
};

react native webview navigation issue

I am making a test with react navigaton and webview , I have 2 screens , Home and Details , at details screen I am calling / opening a webpage inside webview , let's say that I am calling stackoverflow.com (Page A) , my problem is that when user click a link of the stackoverflow page and navigate and after wants to go back to the previous page (Page A) , it doesn't go , its going or navigating to the Home screen !!!
how can I let The user go back to the previous page. ?
that 's how I am calling the page
<WebView
javaScriptEnabled
source={{uri: 'https://stackoverflow.com/'}}
style={{marginTop: 20}}
/>
As we know built in back button is not provided in iOs but it is provided in android .
So for considering both platform there is two possibility.
Android.
-> For android you have to define BackHandler so here are the step.
import it like this.
import {BackHandler } from 'react-native'.
initialize backhandler inside the life cycle methods.
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.handleBackPress);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.handleBackPress);
}
handleBackPress = () => {
if (this.state.canGoBack) {
this.refWeb.goBack();
}
else{
this.props.navigation.goBack(null)
}
return true;
}
define a userdefine variable canGoBack inside the status.
constructor(props) {
super(props)
this.state = {
canGoBack: false
}
}
create a method which detect the change in navigation of the webview and bind it with the web view.
onNavigationStateChange(navState) {
this.setState({
canGoBack: navState.canGoBack
});
}
Bind it like this.
<WebView
ref={(myWeb) => this.refWeb = myWeb}
onNavigationStateChange={this.onNavigationStateChange.bind(this)}
source={{ uri: 'https://stackoverflow.com/questions/51712310/react-
native-webview-navigation-issue' }} />
And thsts it you are ready to go..
iOs
For iOs you didn't have to bother too much.
Create a button for back press above the webview or according to your design logic
Follow the above webview and navigation logic . forgot about the backhandler and set this code inside the onPress() method of your created button of backpress
if (this.state.canGoBack) {
this.refWeb.goBack();
}else{
this.props.navigation.goBack(null)
}
Note : Here I use stackNavigator for screen navigation so i used this.props.navigation.goBack(null) this code. if you didn't use it then dont consider this code and replace with your feasible navigator code in else condition
Thankyou..

Is it possible to render two headers on one screen using React Navigation?

I'm writing an iPad / Android Tablet app with React Native and I'm using React Navigation for the navigation.
The mock up I received has a screen which is split in half (in landscape mode) with two different headers. Is is possible to achieve this with react navigation?
What I've tried is setting header: null in the navigation options for the screen, and then rendering two components on that split screen, each of the components has React Navigation's Header component as the first child. This somehow does not work (the header does not get rendered).
Like you can see in the source of Header it does not render if the header option is null:
_renderHeader(props) {
const { options } = props.scene.descriptor;
if (options.header === null) {
return null;
}
...
}
So using the Header component manually will not work.
You could just create your own Header components with a title and a "back" touchable. If a designer gave you a mock up I assume the Header must be styled very differently from original Header component anyway :)
Your component could look like this:
export default class MyCustomHeader extends Component {
handlePress = () => {
const { navigation } = this.props;
navigation.goBack(); // or .navigate() to whatever you want
};
render() {
return (
<View>
<TouchableHighlight onPress={this.handlePress}>
<some-icon>
</TouchableHighlight>
<Text>My title</Text>
</View>
);
}
}
With proper styling of course :)