We are using createBottomTabNavigator. In one of the tab contains search bar at the top. While clicking on that search bar, we are opening the keyboard. But the keyboard pushing up the bottom tab bar also. We need the bottom tab bar remains at the bottom when opening keyboard.
One of the solution I have tried is, in android manifest, I have changed android:windowSoftInputMode="adjustPan" or "adjustNothing". It is working fine as expected. But we are using chat layout in another tab which needs "adjustResize". So I have to keep "adjustResize" for windowSoftInputMode.
As another solution, I tried to change windowSoftInputMode inside component itself. SO I have tried with this - https://www.npmjs.com/package/react-native-android-keyboard-adjust. But no use.
As another one, I tried to create a TabBarComponent like mentioned here https://github.com/react-navigation/react-navigation/issues/618. But not working as expected.
const SignedIn = createBottomTabNavigator(
{
Followers: {
screen: FollowerStack,
...
},
Search: {
screen: SearchStack,
},
Home: {
screen: HomeStack,
},
Bookmarks: {
screen: BookmarkStack,
},
Profile: {
screen: ProfileStack,
}
},
{
initialRouteName: "Home",
tabBarPosition: 'bottom',
swipeEnabled: false,
animationEnabled: false,
tabBarOptions: {
keyboardHidesTabBar: true,
showIcon: true,
showLabel: false,
activeTintColor: "red",
inactiveTintColor: "gray",
adaptive: true,
safeAreaInset: {
bottom: "always"
},
style: {
position: 'relative',
backgroundColor: "#F9F8FB",
height: TAB_NAVIGATOR_DYNAMIC_HEIGHT,
paddingTop: DeviceInfo.hasNotch() ? "5%" : "0%",
minHeight: TAB_NAVIGATOR_DYNAMIC_HEIGHT,
width: '100%',
bottom: 0
}
}
}
);
Is there any other properties existed for making the bottom tab bar sticky at the bottom?
or
Is it possible to change the android manifest windowSoftInputMode from inside component?
Please comment below if you required any other code part for reference. Thanks for any help.
I used React navigation 5, is this what you want?
<SignedIn.Navigator
tabBarOptions={{
keyboardHidesTabBar: true
}}
}>
</SignedIn.Navigator>
The document to read here.
Please use this on
<Tab.Navigator
screenOptions={{
tabBarHideOnKeyboard: true
}}
/>
I am sure it will work perfectly
Just go to AndroidManifest.xml file and change/add inside activity tag:
android:windowSoftInputMode="adjustPan"
Found it, just add your bottom navigation into a view making that view of dimensions of the screen, this way:
import React from 'react'
import { StyleSheet, Text, View, Dimensions } from 'react-native'
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
const { width, height } = Dimensions.get("window")
const Tab = createBottomTabNavigator()
export default function () {
return (
<View style={{
width,
height,
}}>
<Tab.Navigator>
<Tab.Screen
name="Screen1"
component={Component}
/>
<Tab.Screen
name="Screen2"
component={Component}
/>
<Tab.Screen
name="Screen3"
component={Component}
/>
</Tab.Navigator>
</View>
)
}
screenOptions={{
headerShown: false,
tabBarActiveTintColor: '#1a3c43',
tabBarInactiveTintColor: '#1a3c43',
tabBarActiveBackgroundColor: 'white',
tabBarInactiveBackgroundColor: '#1a3c43',
tabBarHideOnKeyboard: true,
tabBarstyle: {
backgroundColor: '#1a3c43',
paddingBottom: 3
}
}}
I was having the exact same issue. Following are the two ways I successfully tackled it.
adding "softwareKeyboardLayoutMode":"pan" to the app.json like below
"android": {
"adaptiveIcon": {
"foregroundImage": "./assets/adaptive-icon.png",
"backgroundColor": "#FFFFFF"
},
"softwareKeyboardLayoutMode":"pan"
}
by doing this, the bottom navigator was staying hidden behind the keyboard. however, the ScrollView containing TextInputs was not working the way I wanted it to. the whole app screen was getting translated by the height of the keyboard, hiding half of my ScrollView and everything above it (Header and stuff).
The second workaround I used is using useKeyboard hook.
step 1: remove "softwareKeyboardLayoutMode" so that it defaults to height
(this causes the CustomBottomTabNav to rise above the keyboard as the whole screen gets squeezed in the remaining height)
step 2: dynamically reset the position of CustomBottomTabNav when the keyboard is active.
In the screen containing TextInputs
<ScrollView style={{ height: keyboard.keyboardShown? 510 - keyboard.keyboardHeight: 510}}>
/* lots of text inputs*/
</ScrollView>
In the CustomBottomTabNav
tabBarOptions={{
...otherStuff,
style={{ bottom: keyboard.keyboardShown? -100: -10, ...otherStuff}}
}}
This second method is working much more reliably. I tried keyboardAvoidingView but was unable to wrap my head around its unpredictable behavior.
<Tab.Navigator screenOptions={{ tabBarHideOnKeyboard: Platform.OS!== 'ios'}}>
</Tab.Navigator>
It will work perfectly for both platforms in react native
I got solution for this problem. Previously, I have done a minor mistake while configuring 'react-native-android-keyboard-adjust'. Now it is working fine. So we can change the 'windowSoftInputMode' for a particular component using this library - https://www.npmjs.com/package/react-native-android-keyboard-adjust
If you are using a TextInput in the search bar you could hide the bottom tab when TextInput is focused (and the keyboard shows) like so:
const [searchBarFocused, setSearchBarFocused] = useState(false)
In the markup:
<TextInput
onFocus = {()=> setSearchBarFocused(true)}
onBlur = {()=> setSearchBarFocused(false)}
/>
//Other code
{!searchBarFocused && <CustomBottomTab/>}
For finegrained control put a ref on the textInput to blur/focus and what not programmatically.
Also, you can check out RN:s KeyboardAvoidingView
I doubt this question is ever going to be closed but in case someone stumbles over this problem and needs an answer, I'd recommend looking through the following thread:
https://github.com/react-navigation/react-navigation/issues/6700
Tl;Dr
When supplying the framework with a custom navbar, you have to take care of the hiding of the said bar on keyboard opening. This is because it is the default android behaviour.
So either change the manifest configuration as the author already described as his first solution that didn't work.
OR modify your component to listen to the react-natives KEYBOARD. keyboardDidShow & keyboardDidHide Events and either move it down with bottomMargin: -XYZ or hide it completely with a flag.
following two responses on github helped me:
https://github.com/react-navigation/react-navigation/issues/6700#issuecomment-625985764
https://github.com/react-navigation/react-navigation/issues/618#issuecomment-303975621
In case someone wnats to use my code as a reference
interface BottomTabStateProps {
// unrelated Props
}
interface BottomTabDispatchProps {
// unrelated service dispatchers
}
interface BottomTabState {
navVisible: boolean;
}
class BottomTabContainerClass extends React.Component<
BottomTabStateProps & BottomTabDispatchProps & NavigationInjectedProps, BottomTabState
> {
constructor(props: BottomTabStateProps & BottomTabDispatchProps & NavigationInjectedProps) {
super(props);
this.state = {
navVisible: true
};
}
componentDidMount() {
Keyboard.addListener('keyboardDidShow', () => this.keyboardDidShow());
Keyboard.addListener('keyboardDidHide', () => this.keyboardDidHide());
}
componentWillUnmount() {
Keyboard.removeAllListeners('keyboardDidShow');
Keyboard.removeAllListeners('keyboardDidHide');
}
keyboardDidShow() {
this.setState({ navVisible: false });
}
keyboardDidHide() {
this.setState({ navVisible: true });
}
render() {
return (
<View>
{
this.state.navVisible &&
<View>
// add custom Navbar here
</View>
}
</View>
);
}
}
Related
Here's a video showcasing all my visible current bottom-tab-items: Home, My Account, Cart and Menu. https://streamable.com/no6anz
I have other bottom-tab-items I want to render on the screen but not be visible in the bottom tab bar itself.(For example: SettingsView)
How do I achieve this using react native navigation v5?
just on the element (Tab.Screen) you don't want to show, render a null tabBarButton.
<Tab.Screen
name="SignIn"
component={SignInScreen}
options={{
tabBarButton: (props) => null, //like this
tabBarStyle: { display: 'none' }, //this is additional if you want to hide the whole bottom tab from the screen version 6.x
}}
/>
I've solved my own question:
<Tab.Navigator
tabBarOptions={{
activeTintColor: '#161718',
inactiveTintColor: '#ffffff',
style: {
backgroundColor: '#161718',
paddingTop: 10,
borderTopColor: '#161718',
},
labelStyle: {
textAlign: 'center',
top: 8,
},
}}
screenOptions={({route}) => ({
tabBarButton: ['Contact', 'Route2ToExclude'].includes(route.name)
? () => {
return null;
}
: undefined,
})}>
As you can see i'm using screenoptions to define which routes to exclude from the bottom tab bar. Note these routes do need to be an actual screen within the <tab.navigator> component.
React Navigation Bottom Tab Navigation github issue link
https://github.com/react-navigation/react-navigation/issues/5230#issuecomment-595846400
I created a component at react-native, but the text of the button is always at uppercase, someone knows why it doesn't take the text that pass, because I want to show 'Login', but it shows 'LOGIN'
import React, { Component } from 'react';
import { View, Button} from 'react-native';
import LabelApp from "../../config/labels.app";
const labelApp = LabelApp.loginView;
export default class Login extends Component {
constructor(props){
super(props);
this.handleClickBtnEnter = this.makeLogin.bind(this);
}
makeLogin() {
}
render() {
return (
<View>
<Button title= {labelApp.textButtonLogin} onPress={this.handleClickBtnEnter}/>
</View>
);
}
}
Label of component
const LabelApp = {
loginView: {
textButtonLogin: 'Ingresar',
},
}
export default LabelApp;
The visualization
For react Native Paper button use uppercase={false} prop:
<Button
mode="outlined"
uppercase={false}
accessibilityLabel="label for screen readers"
style={styles.yourButtonStyle}>Button label</Button>
So, the other two answers are correct that you should use TouchableOpacity, but as someone new to React Native, it took me awhile to understand what was going on here. Hopefully this explanation provides a little more context.
The built-in Button component seems to have some weird compatibility/visibility issues on occasion, one of which is rendering the title prop text all uppercase. When viewing the documentation for the Button component in Chrome, the preview shows all text being capitalized under the "Web" view but not Android or iOS (I was having this issue using Expo and Metro Bundler on an Android device, so not sure what to make of this). I couldn't find anything about capitalization/uppercase in the Button docs, so perhaps this is a bug.
The solution is to use a different component called TouchableOpacity. It also has an onPress event you can use and a built-in touch animation, but it has less out of the box styling than the Button component. Important to note from docs: "Opacity is controlled by wrapping the children in an Animated.View, which is added to the view hierarchy. Be aware that this can affect layout." It doesn't have a title prop, so you just put the button text in a Text component, like so:
<Button
title='text will be capitalized'
onPress={onPress}
/>
becomes
<TouchableOpacity onPress={onPress}>
<Text>text will stay lowercase</Text>
</TouchableOpacity>
I was having the same issue as OP, and this solved it for me.
From the official documentation
A basic button component that should render nicely on any platform. Supports a minimal level of customization.
The recommend use of touchable opacity or touchable native feedback
https://facebook.github.io/react-native/docs/touchableopacity
Below I've added textTransform: 'lowercase', as a style rule for the button to override any inherited text casing.
import React, { Component } from 'react'
import {
StyleSheet,
TouchableOpacity,
Text,
View,
} from 'react-native'
export default class App extends Component {
constructor(props) {
super(props)
this.state = { count: 0 }
}
onPress = () => {
this.setState({
count: this.state.count+1
})
}
render() {
return (
<View style={styles.container}>
<TouchableOpacity
style={styles.button}
onPress={this.onPress}
>
<Text> Touch Here </Text>
</TouchableOpacity>
<View style={[styles.countContainer]}>
<Text style={[styles.countText]}>
{ this.state.count !== 0 ? this.state.count: null}
</Text>
</View>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingHorizontal: 10
},
button: {
alignItems: 'center',
backgroundColor: '#DDDDDD',
padding: 10,
textTransform: 'lowercase', // Notice this updates the default style
},
countContainer: {
alignItems: 'center',
padding: 10
},
countText: {
color: '#FF00FF'
}
})
https://snack.expo.io/Bko_W_gx8
This question is 3 years old and I'm not sure why no one has answered it correctly until now.
Native android buttons are all caps by default starting from android lollipop, which is what react native uses when you use the control Button from react-native in your app. To override the functionality, you just need to add this line in your styles.xml file inside your app theme (not the splash screen style)
<item name="android:textAllCaps">false</item>
You can get more details here: https://stackoverflow.com/a/30464346/11104068
The changes are not going to apply instantly obviously since the change is in the naive xml file and not in a JavaScript file. So you will need to do a npm/yarn run android
I've tried your code and it looks like it's the expected behaviour with Button component from react-native
You can see this at the official documentation
I believe that you need to change Button component, take it from another package to meet your needs.
As an alternative you can create your own button
import React, { Component } from 'react';
import { View, Button, TouchableHighlight, StyleSheet } from 'react-native';
import LabelApp from "../../config/labels.app";
const labelApp = LabelApp.loginView;
export default class Login extends Component {
constructor(props){
super(props);
this.handleClickBtnEnter = this.makeLogin.bind(this);
}
makeLogin() {
}
render() {
return (
<View>
<TouchableHighlight onPress={this.handleClickBtnEnter} underlayColor="white">
<View style={styles.button}>
<Text style={styles.buttonText}>{labelApp.textButtonLogin}</Text>
</View>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3'
},
buttonText: {
textAlign: 'center',
padding: 20,
color: 'white'
}
});
<Button
style={{
borderRadius: 10,
backgroundColor: "#000",
width: 200,
height: 50,
}}
>
<Text
uppercase={false}
>
Login
</Text>
</Button>
I'm developing a simple app in react-native using Expo and native-base. I stumbled upon a problem about which I can't find any infomations in any documentation.
When I blur any text input, textarea etc. the page always scrolls to top rapidly. It only happens on iOS, on Android there is no such problem.
If this was asked before I'd really appreciate some clue what am I doing wrong.
I'm using following packages:
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"react": "16.5.0",
"expo": "32.0.0",
"native-base": "^2.12.0"
Every page in my app is wrapped with following component:
import React from "react";
import { StyleSheet } from "react-native";
import { Container, Content } from "native-base";
const SceneWrapper = ({ Layout, bigTopPadding, ...props }) => {
return (
<Container style={styles.container} >
<Content style={styles.content} keyboardDismissMode="interactive">
<Layout {...props} />
</Content>
</Container>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: "white",
flex: 1,
alignItems: "flex-start",
justifyContent: "flex-start"
},
content: {
padding: 20,
flex: 1,
width: "100%",
height: "100%",
}
});
I'm almost 100% sure that the <Content> component is at fault here, but I don't understand why and what should I change to prevent this. All I know is that keyboardDismissMode is not causing this problem, as it happened before I added this prop.
For anyone having the same problem, I managed to find solution for this.
I solved it by adding enableResetScrollToCoords={false} prop to <Content>.
You can create a function l, which will be called on any input blur. Inside the function just call this method window.scrollTo(0,0)
I'm using react-navigation and stack-navigator to manage my screens.
Platforms I'm using:
Android
React Native: 0.47.1
React Navigation: 1.0.0-beta.11
Emulator and Device
I have a screen, which acts as a modal form but it is really a full screen. Why is it important the part of "acts as a modal form"? That's because it is kind of modal menu with some options and WITH A TRANSPARENT BACKGROUND COLOR.
This is what I expect:
But what I'm getting is this:
As you can see, in the second example the background color is completely replaced or the components previously loaded is unmounted so the effect I want to acchieve is lost.
The idea is to be able to navigate to this screen like any other screen.
If it is not posible to accomplish using react-navigation, what other way can I take to do so?
This component executes actions (redux) since is a cross app component and encapsulates lot of mechanisms and logic inside, that's why I can't use it as a PureComponent relaying on the component which makes use of this one. At least, making this Component as PureComponent would force me to replicate many mechanisms and logic in many other components.
For the sake of the question, and to avoid making the question enormous, both screens have exactly the same style, but the one pushed through StackNavigation replaces the backgroundColor, or unmounts the previus screen.
This is what I've have so far:
//PlaylistSelector.js
render() {
//Just a full size empty screen to check and avoid bugs
//Using red instead of transparent, works
return (
<View style={{ flex: 1, backgroundColor: 'transparent' }}>
</View>
);
}
//Navigator.js
import { StackNavigator } from 'react-navigation';
import Album from './Album'; //This is the screen I expect to keep at the background
import PlaylistSelector from './PlaylistSelector';
const AppNavigator = StackNavigator(
{
...moreScreens,
Album: { screen: Album },
PlaylistSelector: {
screen: PlaylistSelector,
navigationOptions: {
style: { backgroundColor: 'red' } //Does not work, red is just to ilustrate, should be transparent,
cardStyle: { //Does not work,
backgroundColor: 'transparent',
},
bodyStyle: { //Does not work,
backgroundColor: 'transparent',
},
}
}
},
{
initialRouteName: 'Splash',
headerMode: 'none',
cardStyle: { //Does not work
backgroundColor: 'transparent',
},
transitionConfig: (): Object => ({ //Does not work
containerStyle: {
backgroundColor: 'transparent',
},
}),
}
);
export default AppNavigator;
This was really changed in latest React Navigation versions. See
https://reactnavigation.org/docs/themes/
For example
import * as React from 'react';
import { NavigationContainer, DefaultTheme } from '#react-navigation/native';
const MyTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: 'red'
},
};
export default function App() {
return (
<NavigationContainer theme={MyTheme}>{/* content */}</NavigationContainer>
);
}
There's a solution in react-navigation v6.x
Setting cardStyle: {backgroundColor: 'transparent'} on screenOptions prop for the Stack Navigator didn't work for me.
But, with the help of this Github issue page, I found a solution that sets a default background color for our NavigatorContainer:
import {
DefaultTheme,
NavigationContainer,
} from '#react-navigation/native';
...
const navTheme = {
...DefaultTheme,
colors: {
...DefaultTheme.colors,
background: 'transparent',
},
};
...
return (
<NavigationContainer
theme={navTheme}
...
There we can change 'transparent' to anything we want.
With react-navigation v3.x You can use the transparentCard pro:
const MainNavigator = createStackNavigator(
{
BottomTabs: {
screen: BottomTabsStack,
},
Modal: {
screen: ModalScreen,
}
},
{
headerMode: 'none',
mode: 'modal',
transparentCard: true,
cardStyle: { opacity: 1 } //This prop is necessary for eventually issue.
}
);
You can find a complete example below:
https://snack.expo.io/#cristiankmb/stacks-in-tabs-with-header-options-with-modal
Since you want 'Modal', you can use 'Modal' built in react-native.
https://facebook.github.io/react-native/docs/modal.html
Add opacity:
cardStyle: {
backgroundColor: "transparent",
opacity: 1
}
As of react-navigation#2.17.0 there is a config option transparentCard that makes this possible.
const RootNavigator = createStackNavigator(
{
App,
YourModal,
},
{
headerMode: 'none',
mode: 'modal',
transparentCard: true,
},
);
This won't blur the background for you; it will just make it transparent. To properly blur it, you'll need to do something like this. Make sure you start the background way above the top edge of the screen, since the card will animate in from the bottom, and you probably want the screen to gradually blur instead of the opacity having a sharp edge as it animates in.
this way worked for me:
const MyDrawerNavigator = createStackNavigator(
{
screen1: {
screen: screen1,
},
screen2: {
screen: screen2,
},
},
{
navigationOptions: () => ({
cardStyle: {
backgroundColor: "rgba(0,0,0,0.5)",
},
}),
}
);
Just throwing what seem most straight forward to me, e.g. setting a headerBackground on screenOptions:
<Stack.Navigator
headerMode={"float"}
screenOptions={{
headerBackground: () => <View style={{flex: 1, backgroundColor: themeContext.background}} />,
backgroundColor: themeContext.background
}}
>
This doesn't work with transparent headers tho, which might actually be what lead you here in the first place. In that case simply wrap your whole app container into a View like this.
export default function App() {
return (
<View style={{flex: 1, backgroundColor: 'red'}}>
<NavigationContainer linking={linkingConfig}>
<StatusBar />
<ApolloProvider client={client}>
<Provider store={store}>
<Navigator />
</Provider>
</ApolloProvider>
</NavigationContainer>
</View>
)
}
Obviously you want to extract that into it's own (styled) component instead :)
And if you're using Expo, and don't have a seperate dark theme, you can simply set backgroundColor in your app.json.
I'm playing with react native and got a strange behaviour.
When I try to show a ActitvityIndicator for Android setting its animating property to true with a showProgress variable in the state it doesn't work if the variable is started as false.
In the sample below if the ActivityIndicator animating property start as true, then the buttons make the ActivityIndicator hide or appear correctly.
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
TextInput,
TouchableHighlight,
ActivityIndicator
} from 'react-native';
export class Login extends Component {
constructor(props) {
super(props);
this.state = {
showProgress: true
};
}
render() {
return (
<View>
<TouchableHighlight onPress={this.progressOff.bind(this)}>
<Text>progressOff</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this.progressOn.bind(this)}>
<Text>progressOn</Text>
</TouchableHighlight>
<ActivityIndicator animating={this.state.showProgress} size="large"/>
</View>
);
}
progressOff() {
this.setState({showProgress: false});
}
progressOn() {
this.setState({showProgress: true});
}
}
But if i use the code below, with the animating property starting as false, then the button to make the ActivityIndicator appear doesn't work:
import React, { Component } from 'react';
import {
Text,
View,
StyleSheet,
TextInput,
TouchableHighlight,
ActivityIndicator
} from 'react-native';
export class Login extends Component {
constructor(props) {
super(props);
this.state = {
showProgress: false
};
}
render() {
return (
<View>
<TouchableHighlight onPress={this.progressOff.bind(this)}>
<Text>progressOff</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this.progressOn.bind(this)}>
<Text>progressOn</Text>
</TouchableHighlight>
<ActivityIndicator animating={this.state.showProgress} size="large"/>
</View>
);
}
progressOff() {
this.setState({showProgress: false});
}
progressOn() {
this.setState({showProgress: true});
}
}
What am I missing here?
This appears to be a bug in React Native. The code with initial state being showProgress: false works on iOS but not on Android.
I've opened an issue on github if you want to follow the progression:
https://github.com/facebook/react-native/issues/9023
Option 1
A workaround I've used is to use the showProgress variable to render a completely different view with the ActivityIndicator:
render() {
if (this.state.showProgress) {
return this.renderLoadingView();
} else {
return this.renderMainView();
}
}
Option 2
You can also set the opacity of the ActivityIndicator according to the state:
render() {
return (
<View>
<TouchableHighlight onPress={this.progressOff.bind(this)}>
<Text>progressOff</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this.progressOn.bind(this)}>
<Text>progressOn</Text>
</TouchableHighlight>
<ActivityIndicator style={{opacity: this.state.showProgress ? 1.0 : 0.0}} animating={true} size="large"/>
</View>
);
}
However the spinner animation doesn't always start at the same position when using this method.
This is a bug of React-Native for component Activity Indicator.
I am not sure that fb has already solved it but you can try this
constructor(props) {
super(props);
this.state = {
opacity: 0
};
}
to show it use this.setState({opacity:1}) and to hide again this.setState({opacity:0}) in your called functions
and in the render where you are using activity indicator
<ActivityIndicator
animating={true}
color="#ffffff"
style={{height: 80, marginTop: 10, opacity: this.state.opacity }}
size="large"/>
If in your project you can use third party components, I recommend the use of react-native-loading-spinner-overlay
Solved easily our problems, beacause this component use a similar way to show or hide the Activity with the property visible.
Another way I found effective to work around that problem without much code is:
{ this.state.showProgress &&
<ActivityIndicator animating={true} size="large"/>
}
I tried a different approach which I think that it is a more "react way" to solve problems. So, the problems with the opacity solution is that If you just set it to 0, it still will be a animation, so it is not the best solution thinking in your app performance.
I created a separated component that I called <Loading/>, here is the code:
import { ActivityIndicator } from "react-native"
import React from "react"
import PropTypes from "prop-types"
const Loading = (props) =>
props.animating
? <ActivityIndicator style={props.style}
importantForAccessibility='auto' size={props.size}
color={props.size} /> : null
Loading.propTypes = {
animating: PropTypes.bool.isRequired,
style: PropTypes.oneOfType([PropTypes.style, PropTypes.object]),
}
export default Loading
Usage:
<Loading animating={true} importantForAccessibility='auto' size="large" color="#A02BFF" style={styles.loading} />
That way it will avoid to create a animation when it is not a necessity, you will create separated component that can be removed easily at the point that the ActivityIndicator issue becomes solved in the future by replacing it to the original ActivityIndicator native component.
The only problem I had with this, was that in Android it wasn't visible because of the background I had on my screen. I fixed by only changing the color prop to something I knew should stand out in the background:
<ActivityIndicator color={theme.secondary.color} />
i got this problem all by a mistake. i did not put ActivityIndeicator in the center of a view. so it positioned on top of a view, which is covered by a natigation bar. code below is correct. hope this can help u.
<View style={{alignItems: 'center', justifyContent: 'center', flex: 1, backgroundColor: 'white'}}>
<ActivityIndicator
animating={true}
style={
{
alignItems: 'center',
justifyContent: 'center',
opacity: this.state.loading ? 1 : 0
}}
size="large"
/>
</View>
A quick fix Use conditional rendering.. Keep animating : {true} and just Visible and invisible view.
Checkout :
https://kylewbanks.com/blog/how-to-conditionally-render-a-component-in-react-native
In my case, for react native version 0.59.10 , the size property type is different for Android and iOS, so for that I had to make a Platform check as following and it worked.
<ActivityIndicator
size={Platform.OS === "ios" ? 0 : "large"} //This platform check worked.
color={props.color}
animating={props.animating}
style={props.style}
/>
The transition of animating from false to true is too slow on Android. But you can force a re-render using the key prop:
<ActivityIndicator
key={`${props.animating}`}
animating={props.animating}
/>
When props.animating changes from false to true, they key also changes. This forces a re-render, meaning that a new component is rendered with animating = true, which will instantly start your spinner.
If you are testing it on Android one of the reason could be the color property.
Be sure to give the ActivityIndicator a color. For example:
<ActivityIndicator size="large" color="#0000ff" />
This solution work perfectly for me in Android.
Hope this will help you.
import {ActivityIndicator} from 'react-native';
const [opacity, setOpacity] = useState(0)
const onLoadStart = () => {
setOpacity(1);
};
const onLoad = () => {
setOpacity(0);
};
const onBuffer = ({isBuffering}) => {
setOpacity(isBuffering ? 1 : 0);
};
return(
<View>
<Video
video={{uri: props.videoSource}}
autoplay={false}
customStyles={{
seekBarProgress: {
backgroundColor: theme.color.primary,
},
seekBarKnob: {
backgroundColor: theme.color.primary,
},
}}
ref={ref => (player = ref)}
onBuffer={onBuffer}
onLoadStart={onLoadStart}
onLoad={onLoad}
/>
<ActivityIndicator
animating
size="large"
color={color.primarylight}
style={{
opacity: opacity,
position: 'absolute',
top: 70,
left: 70,
right: 70,
// height: 50,
}}
/>
</View>
)