I have a React Native textInput and a button and I would like to remove the focus from the textInput if I were to click on the button. Would that be possible?
My TextInput looks like this:
<TextInput
onChangeText={onChange}
value={searchQuery}
placeholder="Start typing to search or add your own"
maxLength={80}
onFocus={() => {
setIsInputFocused(true);
}}
onBlur={() => {
setIsInputFocused(false);
setSearchQuery('');
}}
blurOnSubmit={true}
/>
And then I have a pressable element:
<View onPress={() => { //remove focus from Text Input }></View>
The useImperativeHandle hook is the one you need here, And forwardRef, useRef hooks. I have created a new TextInput called ControlledTextInput to pass a react ref to it and expose the blur method outside (App component level). Note that there are two refs one is coming as a prop(to which we bind the functions) and the one inside ControlledTextInput(which is the ref to the actual text input)
import React, { useImperativeHandle, forwardRef, useRef } from "react";
import { StyleSheet, Text, View, TextInput, Button } from "react-native";
const ControlledTextInput = forwardRef((props, ref) => {
const internalInputRef = useRef();
useImperativeHandle(ref, () => ({
blur: () => {
internalInputRef.current.blur();
}
}));
return (
<TextInput
placeholder={"Type something"}
style={styles.textInputStyle}
ref={internalInputRef}
/>
);
});
const App = () => {
const inputRef = useRef(null);
return (
<View style={styles.app}>
<View style={styles.header}>
<Text style={styles.title}>Focus lose when button click</Text>
</View>
<ControlledTextInput ref={inputRef} />
<Button title="Click ME" onPress={() => inputRef.current.blur()} />
</View>
);
};
const styles = StyleSheet.create({
app: {
marginHorizontal: "auto",
maxWidth: 500
},
header: {
padding: 20
},
title: {
fontWeight: "bold",
fontSize: "1.5rem",
marginVertical: "1em",
textAlign: "center"
},
textInputStyle: {
border: "2px solid black",
maxWidth: 500,
height: 50,
textAlign: "center",
fontSize: 20
}
});
export default App;
React Native Codesandox:
Related
I am a bit new to react native and I have an issue I need help with
how do I build a text input in react native that has a placeholder that changes to a text view on top when clicked?
Similar to the screenshot below
empty text input field looks like this in its default state
text field with data entered
see the empty input text has a placeholder appearing in the middle of the input text field
see the second diagram, the place holder text is moved to the top of the input field once the user starts typing text into the input field
The easiest way is to use react-native-paper package with their text input:
import * as React from 'react';
import { TextInput } from 'react-native-paper';
const MyComponent = () => {
const [text, setText] = React.useState('');
return (
<TextInput
label="Email"
value={text}
onChangeText={text => setText(text)}
/>
);
};
export default MyComponent;
Result:
Here is what I use without any library, working example and if you want to add animation to the fields working example with animation
import React, { Component } from 'react';
import {
View,
StatusBar,
TextInput,
Text,
} from 'react-native';
class FloatingLabelInput extends Component {
state = {
isFocused: false,
};
handleFocus = () => this.setState({ isFocused: true });
handleBlur = () => this.setState({ isFocused: false });
render() {
const { label, ...props } = this.props;
const { isFocused } = this.state;
const labelStyle = {
position: 'absolute',
left: 0,
top: !isFocused ? 18 : 0,
fontSize: !isFocused ? 20 : 14,
color: !isFocused ? '#aaa' : '#000',
};
return (
<View style={{ paddingTop: 18 }}>
<Text style={labelStyle}>
{label}
</Text>
<TextInput
{...props}
style={{ height: 26, fontSize: 20, color: '#000', borderBottomWidth: 1, borderBottomColor: '#555' }}
onFocus={this.handleFocus}
onBlur={this.handleBlur}
blurOnSubmit
/>
</View>
);
}
}
export default class App extends Component {
state = {
value: '',
};
handleTextChange = (newText) => this.setState({ value: newText });
render() {
return (
<View style={{ flex: 1, padding: 30, backgroundColor: '#f5fcff' }}>
<StatusBar hidden />
<FloatingLabelInput
label="Email"
value={this.state.value}
onChangeText={this.handleTextChange}
/>
</View>
);
}
}
I have a ScrollView component, and within it I have a form (<AppForm >) that works using Formik and Yup. This form has some input fields (<AppTextInput >). In the form I assign the keyboardType prop for each input field.
The problem is that the fields with keyboardType set to default scroll down the whole ScrollView component when you focus on it, like adding margin to the top of it. This only happens when the keyboardType is set to default.
If I focus on an input field with the keyboardType prop set to numeric, everything works fine.
Any idea of what am I doing wrong?
Here is a gif of what's exactly the problem:
https://giphy.com/gifs/djoHUBAKu9XGyu37OO
And here is my code:
AppFormField (Main screen)
function ActivityFormScreen({ navigation }) {
return (
<View style={styles.container}>
<ActivityIndicator
visible={
postActivityApi.loading ||
editActivityApi.loading ||
getTrabajosApi.loading ||
getCosechasApi.loading ||
getMaquinariasApi.loading
}
/>
<ScrollView style={{ paddingBottom: 500 }}>
<ActivityTitle
text="Información"
name="information-variant"
size={35}
/>
<AppForm
onSubmit={(form) => handleSubmit(form)}
validationSchema={validationShema}
initialValues={{
fecha: getFormValue("fecha"),
finca_id: getFormValue("finca_id"),
lote: getFormValue("lote"),
cosecha: getFormValue("cosecha"),
cultivos: getFormValue("cultivos"),
maquinaria: getFormValue("maquinaria"),
tiempo_actividad: getFormValue("tiempo_actividad"),
productos: getFormValue("productos"),
cantidad: getFormValue("cantidad"),
unidad: getFormValue("unidad"),
hectarea_trabajada: getFormValue("hectarea_trabajada"),
trabajos: getFormValue("trabajos"),
observaciones: getFormValue("observaciones"),
}}
>
<AppFormField
name="fecha"
holder="Fecha"
keyboardType="default"
placeholder="AAAA-MM-DD"
defaultValue={getFormValue("fecha")}
/>
<AppPickerField
name="finca_id"
holder="Granja"
data={context.allFarms} //Seleccionar el array de granjas
pickerPlaceholder="Seleccione una granja"
value={getFormValue("finca_id")}
/>
<AppFormField
name="lote"
holder="Lote"
keyboardType="numeric"
defaultValue={getFormValue("lote")}
/>
.
.
.
<SubmitButton title="Guardar" />
</AppForm>
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: "white",
flex: 1,
justifyContent: "center",
marginHorizontal: 10,
// paddingTop: 50,
},
});
AppFormField
import React from "react";
import { useFormikContext } from "formik";
import { StyleSheet, View } from "react-native";
import AppTextInput from "../AppTextInput";
import ErrorMessage from "./ErrorMessage";
function AppFormField({ placeholder, name, width, holder, ...otherProps }) {
const { setFieldTouched, handleChange, errors, touched } = useFormikContext();
return (
<View style={styles.container}>
<AppTextInput
onBlur={() => setFieldTouched(name)}
onChangeText={handleChange(name)}
width={width}
holder={holder}
placeholder={placeholder}
{...otherProps}
/>
<ErrorMessage error={errors[name]} visible={touched[name]} />
</View>
);
}
const styles = StyleSheet.create({
container: {
marginBottom: 20,
marginHorizontal: 20,
},
});
export default AppFormField;
AppTextInput
import React from "react";
import { StyleSheet, View, TextInput, Text, Keyboard } from "react-native";
function AppTextInput({ placeholder = " ", holder, ...otherProps }) {
return (
<View style={styles.container}>
<Text style={styles.holder}>{holder}</Text>
<TextInput
style={styles.input}
placeholder={placeholder}
returnKeyLabel="Listo"
returnKeyType="done"
onSubmitEditing={Keyboard.dismiss}
{...otherProps}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
backgroundColor: "transparent",
},
holder: {
fontSize: 20,
textAlign: "left",
color: "#000",
opacity: 0.6,
width: "100%",
height: 30,
},
input: {
fontSize: 20,
borderBottomWidth: 1,
borderColor: "#D9D5DC",
width: "100%",
},
});
export default AppTextInput;
SOLVED:
For some reason my ScrollView component had the property paddingBottom set to 500, and just by removing it, I solved the issue.
I'm making a search bar that displays results live. I've managed to do it properly utilizing SearchBar from 'react-native-elements'. Firstly I had it written as a class component, but decided to rewrite it as a functional component. After rewriting it I'm encountering a bug where the keyboard closes after one letter as seen in the video here
Here is the code of the component
import React, { Component, useEffect, useState } from "react";
import { View, Text, FlatList, TextInput, ListItem } from "react-native";
import { SearchBar } from "react-native-elements";
import { Button } from 'react-native-paper'
import Header from "../navigation/Header";
export default function AktSelect() {
const [data, setData] = useState([])
const [value, setValue] = useState('')
const [akt, setAkt] = useState([])
useEffect(() => {
fetch("http://192.168.5.12:5000/aktprikaz", {
method: "get"
})
.then(res => res.json())
.then(res => setAkt(res));
}, []);
function renderSeparator() {
return (
<View
style={{
height: 1,
width: "100%",
backgroundColor: "#CED0CE"
}}
/>
);
}
function searchItems(text) {
const newData = akt.filter(item => {
const itemData = `${item.title.toUpperCase()}`;
const textData = text.toUpperCase();
return itemData.indexOf(textData) > -1;
});
setData(newData)
setValue(text)
}
function renderHeader() {
return (
<SearchBar
placeholder=" Type Here...Key word"
onChangeText={text => searchItems(text)}
value={value}
lightTheme={true}
/>
);
}
return (
<View
style={{
flex: 1,
width: "98%",
alignSelf: "center",
justifyContent: "center"
}}
>
<Header title='Pretraživanje aktivnosti' />
<FlatList
data={data}
renderItem={({ item }) => (
<View style={{flex: 1}}>
<Text style={{ padding: 10 }}>{item.title} </Text>
<View style={{flexDirection:'row'}}>
<Text style={{ padding: 10 }}>{item.start_time} </Text>
<Button style={{justifyContent: 'flex-end', alignContent: 'flex-end', width:'30%'}} mode='contained' onPress={() => console.log('hi')}>hi</Button>
</View>
</View>
)}
keyExtractor={item => item.id.toString()}
ItemSeparatorComponent={renderSeparator}
ListHeaderComponent={renderHeader}
/>
</View>
);
}
The old class component can be found here
This question already has answers here:
how to design react native OTP enter screen?
(9 answers)
Closed 3 years ago.
I have tried several articles to build OTP component which is customizable but hard luck getting it
Some of them are running on IOS platform but not on android
Finally, I completed that after a lot of struggle as a newbie to react-native
This is done using React functional component and React hooks
yarn add react-native-confirmation-code-input
yarn add react-native-countdown-component
yarn add react-redux
import React, { useState, useRef } from "react";
import {
View,
StyleSheet,
Text,
TextInput,
TouchableOpacity,
Alert
} from "react-native";
import CountDown from 'react-native-countdown-component';
import CodeInput from 'react-native-confirmation-code-input';
import Icon from "react-native-vector-icons/FontAwesome5";
import { Input, Button } from "react-native-elements";
import { useSelector, useDispatch } from "react-redux";
import * as AuthActions from "../store/actions/auth";
export const OtpVerifyScreen = props => {
const auth = useSelector(state => state.auth);
const dispatch = useDispatch();
const inputRef = useRef('codeInputRef2');
const [counter, SetCounter] = useState(150); // Set here your own timer configurable
const [random, SetRandom] = useState(Math.random());
const [disabled, setDisabled] = useState(true)
const handleResend = () => {
SetRandom(Math.random())
// Handle Resend otp action here
}
const handleVerify = (otp) => {
// Handle the verification logic here
// dispatch verify action
};
return (
<View style={styles.container}>
<Text style={{ padding: 10 }}>Enter OTP</Text>
<View style={styles.otp}>
<View style={{ height: 100, width: 200, marginLeft: 10 }}>
<CodeInput
ref={inputRef}
// secureTextEntry
className={'border-b'}
activeColor='rgba(0, 0, 0, 1)'
inactiveColor='rgba(0, 0, 0, 1)'
space={10}
keyboardType="numeric"
autoFocus={true}
codeLength={6}
size={20}
inputPosition='left'
onFulfill={(code) => handleVerify(code)}
/>
</View>
<View style={{ display: 'flex', flexDirection: 'row', justifyContent: 'center' }}>
<CountDown
key={random}
until={counter}
size={15}
onFinish={() => setDisabled(() => false)}
separatorStyle={{ color: 'black' }}
digitStyle={{ backgroundColor: '#FFF' }}
digitTxtStyle={{ color: 'black' }}
timeToShow={['M', 'S']}
showSeparator
timeLabels={{ m: '', s: '' }}
/>
<Button disabled={disabled} style={{ marginLeft: 10 }} title="RESEND" onPress={handleResend}></Button>
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
alignItems: "flex-start",
marginTop: 20,
},
otp: {
flex: 1,
justifyContent: "flex-start",
alignItems: "flex-start"
}
});
export default OtpVerifyScreen;
Hope this helps
Happy Coding !!
I'm using react native to create a test App, There is no effect on a button when I do styling. can anyone tell me what I am doing wrong.
For example, I am trying to put red color to a button but it is not working.
What can I do to make it right?
import React, { Component } from 'react'
import {
AppRegistry,
StyleSheet,
Text,
Button,
ScrollView,
Dimensions,
PanResponder,
Animated,
View
} from 'react-native'
import { StackNavigator } from 'react-navigation'
class Home extends Component{
static navigationOptions = {
title:'Home'
};
componentWillMount(){
this.animatedValue = new Animated.ValueXY();
this._value = {x:0 , y:0}
this.animatedValue.addListener((value) => this._value = value);
this.panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, gestureState) => true,
onMoveShouldSetPanResponder: (evt, gestureState) => true,
onPanResponderGrant: (e, gestureState) => {
this.animatedValue.setOffset({
x:this._value.x,
y:this._value.y,
})
this.animatedValue.setValue({x:0 , y:0})
},
onPanResponderMove:Animated.event([
null,{dx: this.animatedValue.x , dy:this.animatedValue.y}
]),
onPanResponderRelease: (e, gestureState) => {
},
})
}
render(){
var animatedStyle = {
transform:this.animatedValue.getTranslateTransform()
}
return(
<View style={styles.container}>
<Button
style={styles.button}
title="Login"
onPress={() => this.props.navigation.navigate("Login")} />
</View>
)
}
}
class Login extends Component{
static navigationOptions = {
title:'Login'
};
render(){
return(
<View>
<Text>home</Text>
</View>
)
}
}
const App = StackNavigator({
Home:{ screen: Home},
Login:{ screen:Login}
});
var styles = StyleSheet.create({
container: {
},
button:{
color:'red'
}
});
export default App
You cannot apply color to a button using stylesheet.
Checkout the link here
It has to be given inline. It is a property of button, its not like style attribute unlike tags like View and Text, where stylesheet applies.
If you give some style to your view container it will work, but not with button as its it not supported that way.
Solution :
<View style={styles.container}>
<Button
title="Login"
color="red"
onPress={() => this.props.navigation.navigate("Login")} />
</View>
Hope that helps!
If your button doesn't look right for your app, you can build your own button using TouchableOpacity or TouchableNativeFeedback. For inspiration, look at the source code for this button component. Or, take a look at the wide variety of button components built by the community.
Look this:
<TouchableOpacity
style={[styles.buttonLargeContainer, styles.primaryButton]}
onPress={() => {}}>
<Text style={styles.buttonText}>SEND TO AUCTION?</Text>
</TouchableOpacity>
const styles = StyleSheet.create({
buttonLargeContainer: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
marginRight: 10
},
primaryButton: {
backgroundColor: '#FF0017',
},
buttonText: {
color: 'white',
fontSize: 14,
fontWeight: 'bold'
}
})