Custom navigator menu in React Native - react-native

I'm new in React Native and have a project with a kind of menu on the right side (5 buttons) on several screens. What I want to do is to use this menu only once for the whole app with a container, and change the content of the container according to the selected button, like in Android with fragment and fragmentManager.replace...
Screens and menu are developed but I really don't know how to mix everything properly .
I read doc about react-navigation (https://reactnavigation.org/docs/en/custom-navigators.html) but do not understand well everything. However I just need a kind of TabNavigator with custom Tab on the ride side.
Please help me.

Not sure what do you mean, but i think you could try something like this:
const CustomDrawer = createDrawerNavigator({
Screen1: {
screen: Screen1,
},
Screen2: {
screen: Screen2,
},
})
const RootNavigator = createStackNavigator({
MainScreen: {
screen: MainScreen,
},
CustomDrawer: { screen: CustomDrawer }
},
{
initialRouteName: 'Init',
})
Basically, you can create a Drawer on the right/left. And add your 5 screens on it, then you will use the drawer to navigate between those screens. Plus you'll instantiate your drawer on a stackNavigator which will handle the navigation. You can also set your main screen on it and everything else.

I think you want drawer in react native app using react-navigation..
use createDrawerNavigator it providers you to custom design your side bar
createDrawerNavigator({
screen: {..your screen stack here...}
}, {
headerMode: 'none',
gesturesEnabled: false,
contentComponent: DrawerContainer, /// DrawerContainer is custom component container for all tabs
drawerBackgroundColor: 'transparent',
drawerWidth: 240,
useNativeAnimations: true
});
DrawerContainer .js :---
export default class DrawerContainer extends React.Component {
render() {
return (
<View style={{flex:1}}>
<TouchableOpacity
style={{borderBottomColor: '#fff', height: 40}}
onPress={() => this.props.navigation.navigate('screen name')}
>
<Text style={{color: '#FFFFFF',fontSize: 18}}
type='h5White'>your tab name</Text>
</TouchableOpacity>
</View>
);
}
}
for more detail go to https://medium.freecodecamp.org/how-to-build-a-nested-drawer-menu-with-react-native-a1c2fdcab6c9
go for this medium tutorial
https://medium.com/#mehulmistri/drawer-navigation-with-custom-side-menu-react-native-fbd5680060ba
create custom side bar always fixed:---
Don't use drawer. I m making it by using hoc (Higher-Order Components)
Fist make Higher-Order Components as sidebar.js
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
TouchableOpacity
} from 'react-native';
const withSidebar = WrappedComponent => class extends Component {
constructor(props) {
super(props);
this.state = { isConnected: true };
}
render() {
return (
<View style={styles.container}>
<View style={{width:50, top:20, backgroundColor: 'grey',}}>
<TouchableOpacity
style={styles.menu}
onPress={() => console.log('code')}
>
<Text style={styles.menuText} type='h5White'>first</Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.menu}
onPress={() => console.log('code')}
>
<Text style={styles.menuText} type='h5White'>second</Text>
</TouchableOpacity>
</View>
<View style={{flex:1, backgroundColor: 'red', top:20}}>
<WrappedComponent {...this.props} />
</View>
</View>
);
}
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
flexDirection: 'row',
},
welcome: {
flex: 1,
margin: 20,
backgroundColor: 'orange',
margin: 10,
textAlign: 'center',
fontSize: 20,
paddingTop: 70,
},
menu: {
paddingHorizontal: 7,
borderBottomWidth: 1,
borderBottomColor: '#fff',
height: 40,
justifyContent: 'center'
},
menuText: {
justifyContent: 'center',
color: '#FFFFFF',
fontSize: 10,
fontWeight: 'bold'
},
});
export default withSidebar;
Now only connect your screen with this hoc:--
import sidebar.js in your screen as
import withSidebar from 'sidebar'
export default connect(mapStateToProps, mapDispatchToProps)(withSidebar(yourScreenName));
This HOC is available for every screen where you want just use above syntax.
You can also put it in your root level component only once to get it for whole components (its over you how you implement this).

Related

React navigation does not respond click button

I'm creating an app with react native and using lib react navigation. When trying to make a button call a new screen, navigation doesn't respond to the click, does anyone know what it might be?
App.js
import Initial from "./app/screens/Initial";
import Login from "./app/screens/Login";
const AppNavigator = createStackNavigator(
{
Initial:{
screen: Initial
},
Login:{
screen: Login
}
},
{
initialRouteName: 'Initial',
headerMode: 'none',
}
);
export default createAppContainer(AppNavigator);
Initial.js (My Screen)
This is the screen where I render the button and call the click event to react with react navigation
import React, { Component } from "react";
import { View, StyleSheet, Text, ImageBackground } from "react-native";
import Button from "../components/Form/Button";
import imageLogo from "../assets/images/background2.jpg";
import colors from "../config/color";
class Initial extends Component {
render(){
const { navigate } = this.props.navigation;
return (
<View style={styles.wrapper}>
<ImageBackground source={imageLogo} style={styles.image}>
<Text style={styles.appName}>Hello</Text>
<View style={styles.areaMarketing}>
<Text style={styles.textAds}>text text text </Text>
<Text style={styles.textAds}>good good good.</Text>
</View>
<View style={styles.form}>
<Button onPress={() => this.props.navigation.navigate('Login')}
buttonBackColor={colors.emerald}
buttonBorderColor={colors.emerald}
color={colors.white} labelButton="Entrar"/>
<Button labelButton="Criar conta"/>
</View>
</ImageBackground>
</View>
);
}
}
const styles = StyleSheet.create({
wrapper: {
flex: 1,
justifyContent: "space-between"
},
form: {
flex: 1,
justifyContent: "flex-end"
},
appName: {
margin: 20,
fontSize: 25,
fontFamily: "Nunito-Bold",
color: colors.white
},
areaMarketing: {
marginLeft: 20
},
textAds: {
color: colors.white,
fontSize: 23,
fontFamily: "Nunito-Regular"
},
image: {
width: "100%",
height: "100%"
}
});
export default Initial;
package.json
"dependencies": {
"react": "16.8.6",
"react-native": "0.60.4",
"react-native-gesture-handler": "^1.3.0",
"react-navigation": "^3.11.1",
"react-navigation-stack": "^1.9.4"
Please look at react navigation 3 simple live example with single one file App.js with 2 screens:
https://snack.expo.io/r1eXFk7tB
P.S.
You didn't provide the full code of your issue like click hanlders and render of buttons but i guess you can see the example to find the problem in your project.

React Native View not displaying anything

I followed the tutorial Here to set up a drawer navigator for my app and I'm doing pretty much everything the same as this guide mentions but my output is something like this
According to the guide though, and according to my code there should be text in the middle of the white empty screen. This makes me think that the View tag of my home file is not working or it's not rendering for some reason but the render function does get called though, i see the logs and the console.log inside the function does show up there, so I just can't figure out what the issue is here.
Here's my code:
Home.js
class Home extends Component{
render() {
console.log("I AM HERE")
return (
<View style={styles.container}>
<Text style={styles.text}>Home Page</Text>
</View>
)
}
}
styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 20,
alignItems: 'center',
marginTop: 50,
justifyContent: 'center',
},
text: {
fontSize: 50,
color: 'red'
}
})
HomeRoute.js
const ROUTES = createStackNavigator({
[ROUTE_NAMES.HOME]: {
screen: Home,
navigationOptions: ({ navigation }) => ({
title: 'Home',
headerLeft: <SideDrawer navigationProps={navigation} />,
headerStyle: {
backgroundColor: '#FF9800',
},
headerTintColor: '#fff',
}),
},
});
const HOME_ROUTES = createAppContainer(ROUTES);
export default HOME_ROUTES;
SideDrawer.js
export default class NavigationDrawerStructure extends Component {
toggleDrawer = () => {
this.props.navigationProps.toggleDrawer();
};
render() {
return (
<View style={{ flexDirection: 'row' }}>
<TouchableOpacity onPress={this.toggleDrawer.bind(this)}>
{/*Donute Button Image */}
<Image
source={drawerImage}
style={{ width: 25, height: 25, marginLeft: 5 }}
/>
</TouchableOpacity>
</View>
);
}
}
There is quite a difference between CSS flexbox and the one implemented by Facebook. Lots of things in common but defaults are very different. Specifically:
Everything is displayed: flex by default. All the behaviors of block and inline-block can be expressed in term of flex but not the opposite.
flex: attribute is only used when at the same level there are few components with different flex values (flex: 1, flex: 3) means that the second element should be 3 times bigger than the first one. flex attribute is the only one supported (no grow/shrink support).
More info: yoga
Do you have an App.js file ? I don't see it in your post. If not, you should add the code below:
import React from 'react';
import { View } from 'react-native';
import HomeRoute from './your_path/HomeRoute.js';
export default class App extends React.Component {
render() {
return (
<View style={{ flex: 1 }}>
<HomeRoute/>
<FlashMessage position="top" />
</View>
);
}
}
Otherwise I will be curious to glance your App.js.

How do i navigate between screens in my shopping app?

'm new to react-native and mobile application. I'm trying to build a basic shopping app.i have the sports options such as cricket,football,tennis and whenever the cricket button is pressed, the cricket products must be displayed and i can follow it up for the other two products
i tried using stack navigator to navigate between screens but i seem to get a error . i tried using createstacknavigator but it doesnt come out right
1.App.js
import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { StackNavigator } from 'react-navigation'
import FirstScreen from './src/FirstScreen'
import SecondScreen from './src/cricket'
const Navigation = StackNavigator({
First: {screen: FirstScreen},
Second: {screen: SecondScreen}
});
export default Navigation
AppRegistry.registerComponent('AwesomeProject', () => Navigation);
2.FirstScreen.js
import React, { Component } from 'react';
import { Alert, AppRegistry, Image, Platform, StyleSheet, Text,
TouchableHighlight, TouchableOpacity, TouchableNativeFeedback,
TouchableWithoutFeedback, View } from 'react-native';
import { StackNavigator } from 'react-navigation'
export default class FirstScreen extends Component {
//_onPressButton() {
// Alert.alert('You tapped the button!')
//}
//_onLongPressButton() {
//Alert.alert('You long-pressed the button!')
//}
static navigationOptions = {
title: 'First Screen',
};
render() {
return (
<View style={styles.container}>
<TouchableOpacity onPress={this._onPressButton}>
<View style={styles.button}>
<Text style={styles.buttonText}>Cricket</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this._onPressButton}>
<View style={styles.button}>
<Text style={styles.buttonText}>Football</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={this._onPressButton}>
<View style={styles.button}>
<Text style={styles.buttonText}>Tennis</Text>
</View>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 60,
alignItems: 'center'
},
button: {
marginBottom: 30,
width: 260,
alignItems: 'center',
backgroundColor: '#2196F3'
},
buttonText: {
padding: 20,
color: 'white'
}
});
// skip this line if using Create React Native App
//AppRegistry.registerComponent('AwesomeProject', () => Touchables);
3.Cricket.js
import React, { Component } from 'react';
import {Alert, Button, ScrollView, StyleSheet, AppRegistry, Text, View
} from 'react-native';
const styles = StyleSheet.create({
rowContainer: {
flex: 1,
height: 75,
width: '100%',
flexDirection: 'row', // children will be on the same line
justifyContent: 'space-between',
alignItems: 'center',
margin: 10,
},
buttonContainer: {
flex: 1,
},
text: {
flex: 2, // Text takes twice more space as button container
color: 'red',
fontWeight: 'bold',
fontSize: 20,
},
});
class Greeting extends Component {
static navigationOptions = {
title: 'Second Screen',
};
_onPressButton() {
Alert.alert('Sorry you have no credit!')
}
render() {
return (
<View style={styles.rowContainer}>
<Text style={styles.text}>{this.props.name}</Text>
<View style={styles.buttonContainer}>
<Button
onPress={this._onPressButton}
title="BUY"
/>
</View>
</View>
);
}
}
export default class SecondScreen extends Component {
render() {
return (
<ScrollView>
<View style={{alignItems: 'flex-start', top: 0, flex: 2,
backgroundColor: 'black'}}>
<Greeting name='Shoe- 800' />
<Greeting name='Jersey - 350' />
<Greeting name='Stockings - 100' />
<Greeting name='Cones - 50' />
<Greeting name='Whistle - 80' />
<Greeting name='Helmet - 750' />
<Greeting name='Tennis Ball-6 pack - 800' />
<Greeting name='Nets - 1500' />
<Greeting name='Leg Pads - 1000' />
<Greeting name='Stumps - 800' />
<Greeting name='Gloves - 600' />
</View>
</ScrollView>
);
}
}
When the cricket button is pressed, the screen should navigate to the list of cricketproducts which is the (cricket.js)
As you are using react-navigation, you just need to use the navigation prop. You have commented the part where you handle the press. Just change that function to actually navigate to the screen you want:
_onPressButton=()=>{
this.props.navigation.navigate("Second")
}
If you are not using arrow functions, you need to bind the function to have access to the this of that screen. To do that you need to add inside your constructor:
constructor(props){
super(props)
this._onPressButton.bind(this)
}
after that you can call it by doing:
_onPressButton() {
this.props.navigation.navigate("Second")
}
As you are using a stackNavigator, you have different ways to navigate to the other screen of the same stack. You have different ways to navigate. For example:
this.props.navigation.push("Second")
This method pushes a new screen to the stack, no matter what screen it is
this.props.navigation.navigate("Second")
Navigates to a new screen in the stack, will push it in the stack only if the screen hasn't been focussed before
this.props.navigation.replace("Second")
This will navigate to a new screen without pushing it to the stack, "replacing" the screen you was watching with the new one.
EDIT.
For the error you stated in the comment, it's because there's not an app container. To do so, just do:
import { createStackNavigator, createAppContainer } from 'react-navigation'
Then do
const Navigation = createAppContainer(createStackNavigator({
First: {screen: FirstScreen},
Second: {screen: SecondScreen}
}));
Use the Move Screen command.
this.props.navigation.navigate("Second")

How to open keyboard automatically in React Native when component mounts?

My page has only a single TextInput, and I have passed in the autoFocus prop: autoFocus: true.
<TextInput
style={styles.textInput}
placeholder="Quiz Deck Title"
autoFocus={true}
value={this.state.title}
onChangeText={(title) => this.controlledTextInput(title)}
/>
What I am trying to avoid is requiring the user to "click" in the TextInput box before the keyboard pops up.
But I would also like to have the soft keyboard also open automatically (if the device does not have a hardware keyboard).
Is there way to make this happen in react native? I am developing for both ios and android.
If it matters, my page is navigated to via TabNavigator.
I mention this because a comment to another similar SO question (see below) suggests they had a similar issue when they arrived at their page using StackNavigator.
Note on Similar SO questions:
How to open keyboard automatically in React Native?
: does not provide a solution, and comments by others suggest the same results as myself: input is focused, but keyboard does not automatically open.
Close/hide the Android Soft Keyboard
and Android: show soft keyboard automatically when focus is on an EditText
: are using native android code (java), not react native code (javascript).
Note: I am developing using the android emulator Nexus 6P with android 23 (as recommended), and ios simulator with iPhone 6s, as I do not have physical devices.
Edit: Adding Requested Code
NewDeck.js (the view I want the keyboard to auto pop up on):
import React from 'react';
import { connect } from 'react-redux';
import { View, Text, TouchableOpacity,
TextInput, KeyboardAvoidingView,
StyleSheet, Platform,
} from 'react-native';
import StyledButton from '../components/StyledButton';
import { saveDeck } from '../store/decks/actionCreators';
import { getDeckList } from '../store/decks/selectors';
import { fetchDecks } from '../utils/api';
import { saveDeckTitle } from '../utils/api';
} from '../utils/colors';
import { titleCase, stripInvalidChars, makeStringUnique }
from '../utils/helpers';
import { white, gray, primaryColor, primaryColorDark, primaryColorLight,
class NewDeck extends React.Component {
state = {
title: '',
canSubmit: false,
}
componentDidMount () {
this.textInputRef.focus()
}
controlledTextInput(title){
title = titleCase(stripInvalidChars(title));
const canSubmit = this.isValidInput(title);
this.setState({ title, canSubmit });
}
isValidInput(text){
return text.trim() !== '';
}
onBlur(){
title = this.state.title.trim();
const unique = makeStringUnique(title, this.props.existingTitles);
this.setState({ title: unique });
}
onSubmit(){
let title = this.state.title.trim();
title = makeStringUnique(title, this.props.existingTitles)
saveDeckTitle(title)
this.props.navigation.navigate('Home');
}
render() {
return (
<View style={styles.container}>
<View style={[styles.cardContainer, {flex: 1}]}>
<Text style={styles.instructionsText}
>
Title for your New Quiz Deck
</Text>
<KeyboardAvoidingView {...keyboardAvoidingViewProps}>
<TextInput
style={styles.textInput}
placeholder="Quiz Deck Title"
value={this.state.title}
onChangeText={(title) => this.controlledTextInput(title)}
/* autoFocus={true} */
ref={ref => this.textInputRef = ref}
/>
</KeyboardAvoidingView>
</View>
<KeyboardAvoidingView
{...keyboardAvoidingViewProps}
style={[styles.buttonsContainer, styles.buttonContainer]}
>
<StyledButton
style={[styles.item, style={flex: 2}]}
onPress={() => this.onSubmit()}
disabled={!this.state.canSubmit}
>
<Text>
Submit
</Text>
</StyledButton>
</KeyboardAvoidingView>
</View>
);
}
}
const keyboardAvoidingViewProps = {
behavior: 'padding',
};
// ...styles definition here, - I posted it in a later code block, to minimize
// clutter, in the event that it is irrelevant to this issue
function mapStoreToProps(store){
const decks = getDeckList(store) || null;
// ensure titles are unique (better UX than if just make id unique)
const existingTitles = decks && decks.map(deck => {
return deck.title
}) || [];
return {
existingTitles,
}
}
export default connect(mapStoreToProps)(NewDeck);
TabNavigator and StackNavigator code (in App.js):
// ... the TabNavigator I'm using:
import { TabNavigator, StackNavigator } from 'react-navigation';
//... the class's render method, uses StackNavigator (as MainNavigation)
render(){
return (
<Provider store={createStore(rootReducer)}>
<View style={{flex:1}}>
<AppStatusBar
backgroundColor={primaryColor}
barStyle="light-content"
/>
<MainNavigation />
</View>
</Provider>
);
}
}
// ...
const Tabs = TabNavigator(
{
DeckList: {
screen: DeckList,
navigationOptions: {
tabBarLabel: 'Quiz Decks',
tabBarIcon: ({ tintColor }) => // icons only show in ios
<Ionicons name='ios-bookmarks' size={30} color={tintColor} />
},
},
NewDeck: {
screen: NewDeck,
navigationOptions: {
tabBarLabel: 'Create New Deck',
tabBarIcon: ({ tintColor }) => // icons only show in ios
<FontAwesome name='plus-square' size={30} color={tintColor} />
},
},
},
{
navigationOptions: {
// do-not-display page headers for Tab Navigation
header: null
},
tabBarOptions: {
// ios icon and text color; android text color
activeTintColor: Platform.OS === 'ios' ? primaryColor : white,
pressColor: white,
indicatorStyle: {
backgroundColor: primaryColorDark,
height: 3,
},
style: {
height: 56,
backgroundColor: Platform.OS === 'ios' ? white : primaryColor,
shadowColor: 'rgba(0, 0, 0, 0.24)',
shadowOffset: {
width: 0,
height: 3
},
shadowRadius: 6,
shadowOpacity: 1
}
}
}
);
//... StackNavigator uses TabNavigator (as Tabs)
const stackScreenNavigationOptions = {
headerTintColor: white,
headerStyle: {
backgroundColor: primaryColor,
}
};
const MainNavigation = StackNavigator(
// RouteConfigs: This is analogous to defining Routes in a web app
{
Home: {
screen: Tabs, // Which also loads the first Tab (DeckList)
},
Deck: {
screen: Deck,
navigationOptions: stackScreenNavigationOptions,
},
Quiz: {
screen: Quiz,
navigationOptions: stackScreenNavigationOptions,
},
NewDeck: {
screen: NewDeck,
navigationOptions: stackScreenNavigationOptions,
},
NewCard: {
screen: NewCard,
navigationOptions: stackScreenNavigationOptions,
},
},
);
This is the styles definition for NewDeck.js
const styles = StyleSheet.create({
// CONTAINER styles
wrapper: {
// this was the previous container style
flex: 1,
backgroundColor: white,
alignItems: 'center',
justifyContent: 'center',
},
container: {
flex: 1,
backgroundColor: white,
alignItems: 'center',
justifyContent: 'space-between',
padding: 10,
paddingTop: 30,
paddingBottom: 5,
},
cardContainer: {
flex: 1,
justifyContent: 'flex-start',
alignSelf: 'stretch',
backgroundColor: '#fefefe',
padding: 20,
marginLeft: 30,
marginRight: 30,
marginTop: 10,
borderRadius: Platform.OS === 'ios' ? 20 : 10,
shadowRadius: 3,
shadowOpacity: 0.8,
shadowColor: 'rgba(0, 0, 0, 0.24)',
shadowOffset: {
width: 0,
height: 3,
},
marginBottom:20,
},
buttonsContainer: {
flex: 3,
alignSelf: 'stretch',
justifyContent: 'flex-start',
},
buttonContainer: {
justifyContent: 'center',
margin: 10,
},
// TEXT Styles
instructionsText: {
flex: 1,
fontSize: 20,
color: gray,
alignSelf: 'center',
textAlign: 'center',
},
// INPUTTEXT styles
textInput: {
fontSize: 27,
color: primaryColor,
alignSelf: 'stretch',
flexWrap: 'wrap',
textAlign: 'center',
marginTop: 10,
},
});
StyledButton.js (Basically, TouchableOpacity with platform-specific styling, for universal use across the app):
import React from 'react';
import { Text, TouchableOpacity, StyleSheet, Platform } from 'react-native';
import { white, gray, primaryColor, primaryColorLight, primaryColorDark} from '../utils/colors';
export default function TextButton({ children, onPress, customColor, disabled=false }) {
const disabledColor = disabled ? gray : null;
const backgroundColor = Platform.OS==='ios' ? white : disabledColor || customColor || primaryColorLight;
const borderColor = Platform.OS==='ios' ? disabledColor || customColor || primaryColorDark
const textColor = Platform.OS==='ios' ? disabledColor || customColor || primaryColor : white;
const btnStyle = Platform.OS==='ios' ? styles.iosBtn : styles.androidBtn;
const txtStyle = styles.txtDefault;
const btnColor = { backgroundColor, borderColor };
const txtColor = { color: textColor };
return (
<TouchableOpacity
onPress={onPress}
disabled={disabled}
style={[btnStyle, btnColor]}
>
<Text
style={[styles.txtDefault, txtColor]}
>
{children}
</Text>
</TouchableOpacity>
);
}
const styles = StyleSheet.create({
txtDefault: {
textAlign: 'center',
// because of bleeding of white text to colored background on android,
// enlarge text (or increase fontWeight) for better readability
fontSize: Platform.OS==='ios' ? 15 : 18,
padding: 10,
},
iosBtn: {
height: 45,
borderRadius: 7,
alignSelf: 'center',
justifyContent: 'center',
alignItems: 'center',
// ios only settings
borderColor: primaryColorDark,
borderWidth: 1,
borderRadius: 3,
paddingLeft: 25,
paddingRight: 25,
},
androidBtn: {
height: 45,
borderRadius: 5,
alignSelf: 'center',
justifyContent: 'center',
alignItems: 'center',
// android- only settings
// (padding accepts clicks, vs. margin === no-click zone)
padding: 20,
paddingLeft: 15,
paddingRight: 15,
},
});
// ios has white buttons with colored outlines and colored text
// android has colored buttons with white text
// Pass in a button color, or it defaults to the App's primary colors
just wrap the ref inside timeout
setTimeout(()=>{this.textInputRef.focus()},100)
Old Issue, but if anyone is searching through here for an answer..
It looks like the keyboard doesn't come up if you're stuck in an animation (e.g. if coming from another screen).
You can use a ref to focus on your input, but must wrap in within InteractionManager.runAfterInteractions for it to work correctly.
This is how I solved it:
export const CustomInput: FunctionComponent<Props & TextInputProps> = ({
error,
...props
}) => {
const inputRef = useRef<TextInput>(null);
useEffect(() => {
// Must run after animations for keyboard to automatically open
InteractionManager.runAfterInteractions(() => {
if (inputRef?.current) {
inputRef.current.focus();
}
});
}, [inputRef]);
return (
<View>
<TextInput
ref={inputRef}
{...props}
/>
{error && <ErrorText>{error}</ErrorText>}
</View>
);
};```
You can always use .focus on any of your TextInput when the component loads, to show the keyboard if you want to avoid the autoFocus.
componentDidMount () {
this.textInputRef.focus()
}
<TextInput
style={styles.textInput}
ref={ref => this.textInputRef = ref}
placeholder="Quiz Deck Title"
autoFocus={true}
value={this.state.title}
onChangeText={(title) => this.controlledTextInput(title)}
/>
As mentioned in the docs
Two methods exposed via the native element are .focus() and .blur() that will focus or blur the TextInput programmatically.
I only needed the 'autoFocus' prop to get this going as at today.
https://reactnative.dev/docs/textinput#autofocus

Callback after the end of animation in react-navigation

Using react-navigation with react-native.
How can jeg run a function at the end of animation?
So I want callback like
navigate('RoadObject', () => { at the end of animationto do something... });
My tab navigator:
const MainNavigator = TabNavigator({
Map: {
screen: MapScreen
},
RoadObject: {
screen: RoadObjectScreen
}
},
{
animationEnabled: true
});
Have you tried Transitioner | React Navigation?
Seems like this might be relevant for your case...
Transitioner is a React component that helps manage transitions for complex animated components. It manages the timing of animations and keeps track of various screens as they enter and leave, but it doesn't know what anything looks like, because rendering is entirely deferred to the developer.
Under the covers, Transitioner is used to implement CardStack, and hence the StackNavigator.
The most useful thing Transitioner does is to take in a prop of the current navigation state. When routes are removed from that navigation state, Transitioner will coordinate the transition away from those routes, keeping them on screen even though they are gone from the navigation state.
Example
class MyNavView extends Component {
...
render() {
return (
<Transitioner
configureTransition={this._configureTransition}
navigation={this.props.navigation}
render={this._render}
onTransitionStart={this.onTransitionStart}
onTransitionEnd={this.onTransitionEnd}
/>
);
}
I had some problem with transictions too. I was entering on a Screen with Camera and it got too slow. So I decided to keep the Camera off before finishing the transition animation and after that I turned it on.
Example:
import React, {Component, createRef, RefObject} from 'react';
import {SafeAreaView, StyleSheet, Text, TouchableOpacity, View} from 'react-native';
import {Camera} from 'expo-camera';
import {CameraType} from 'expo-camera/build/Camera.types';
import {FontAwesome} from '#expo/vector-icons';
import {StackNavigationProp} from "#react-navigation/stack/lib/typescript/src/types";
export interface State {
type: CameraType,
hasPermission: boolean | null,
takenPictures: Array<string>,
isNavigating: boolean,
}
export interface Props {
navigation: StackNavigationProp<any>,
}
export class CameraMan extends Component<Props, State> {
private readonly camera: RefObject<Camera>;
constructor(props: Props) {
super(props);
this.camera = createRef();
this.state = {
type: Camera.Constants.Type.back,
hasPermission: null,
takenPictures: [],
isNavigating: true
}
}
async componentDidMount() {
this.props.navigation.addListener('transitionEnd', e => {
this.setState({
isNavigating: false
});
});
let permissionResponse = await Camera.requestPermissionsAsync();
this.setState({
hasPermission: permissionResponse.granted
});
}
render() {
if (this.state.hasPermission == null) {
return <SafeAreaView style={styles.container}>
</SafeAreaView>;
}
if (!this.state.hasPermission) {
return <SafeAreaView style={styles.container}>
<Text>Acesso negado!</Text>
</SafeAreaView>;
}
return (
<SafeAreaView style={styles.container}>
{
(this.state.isNavigating) ?
<View style={{flex: 1, backgroundColor: '#000'}} />
:
<Camera style={{flex: 1}}
type={this.state.type}
ref={this.camera}>
<View style={{flex: 1, backgroundColor: 'transparent', flexDirection: 'row'}}>
<TouchableOpacity style={{
position: 'absolute',
bottom: 20,
left: 20,
}}
onPress={() => this.switchCameraType()}>
<Text style={{fontSize: 20, marginBottom: 13, color: '#FFF'}}>Trocar</Text>
</TouchableOpacity>
</View>
</Camera>
}
<TouchableOpacity style={{
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#121212',
margin: 20,
borderRadius: 10,
height: 50,
}} onPress={() => this.takePicture()}>
<FontAwesome name="camera" size={23} color="#FFF" />
</TouchableOpacity>
</SafeAreaView>
);
}
private async takePicture() {
const capturedPicture = await this.camera.current?.takePictureAsync();
console.log(capturedPicture?.uri);
}
private switchCameraType() {
const selectedCameraType = this.state.type == Camera.Constants.Type.back ? Camera.Constants.Type.front : Camera.Constants.Type.back;
this.setState({type: selectedCameraType});
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
}
});
Based on this: https://reactnavigation.org/docs/navigation-events/