Enable paste and selection within TextInput - React Native - react-native

I am trying to implement copy and paste within my TextInput but cant seem to achieve it. I was expecting a tooltip when I long-pressed on my TextInput, however nothing happens.
I know about Clipboard and would know how to implement it, but I cant seem to get the paste option to pop to the user.
Any ideas how I can achieve this?
<TextInput
maxLength={29}
autoCapitalize={'characters'}
numberOfLines={1}
keyboardType={'default'}
underlineColorAndroid='transparent'
autoCorrect={false}
value={IBAN.printFormat(this.state.ibanInput)}
returnKeyType={'next'}
onChangeText={iban => this.verifyIban(iban)}
style={[{ borderWidth: 1, borderRadius: 2, height: '100%', width: '100%', textAlign: 'center', fontSize: width/24 },
]}
/>

Here is the answer if copy/paste does not work for TextInput - React Native
Step 1) In Contructor take testWidth property and assign value as '99%'.
e.g.
this.state = {testWidth: '99%' };
Step 2) In componentDidMount change testWidth value like '100%', do it inside of setTimeout.
e.g.
setTimeout(() => {
this.setState({ testWidth: '100%' })
}, 100)
Step 3) In style attribute of TextInput add dynamic width which we declare in Contractor, e.g
<TextInput style={{ width: this.state.testWidth }} />
Here is the full code: (Just copy and paste in App.js file).
import React, { Component } from 'react';
import { TextInput, View } from 'react-native';
export class App extends Component {
constructor(props) {
super(props);
this.state = { text: '', testWidth: '99%' };
}
componentDidMount() {
setTimeout(() => {
this.setState({ testWidth: '100%' })
}, 100)
}
render() {
return (
<View style={{ marginTop: 50 }}>
<TextInput
style={{ width: this.state.testWidth }}
placeholder="Type here to translate!"
onChangeText={(text) => this.setState({ text })}
value={this.state.text}
/>
</View>
);
}
}
Good Luck

Have a look at this code!: https://github.com/facebook/react-native/issues/18926#issuecomment-490541013
<ScrollView
contentContainerStyle={Styles.contentContainerStyle}
keyboardShouldPersistTaps="handled"
removeClippedSubviews={false}>
<KeyboardAvoidingView>
<Text style={Styles.labelPageTitle}>
{'bla bla bla'}
</Text>
<Text>
{'bla bla bla'}
</Text>
<TextInput
onChangeText={text => this.setState({ title: text })}
style={Styles.textInput}
value={title}
/>
</KeyboardAvoidingView>

use RN-clipboard
const text = await Clipboard.getString()
setCopiedText(text)

Related

How to create outlined (focused) TextInput in React Native?

Here is my code:
<View style={styles.inputView} >
<TextInput
style={styles.TextInputStyleClass}
placeholder="Email"
placeholderTextColor="#003f5c"
onChangeText={text => this.setState({email:text})}/>
</View>
Here is textinput style
TextInputStyleClass:{
textAlign: 'auto',
height: 50,
borderWidth: 1,
borderColor: '#c2c2c2',
borderRadius: 5 ,
backgroundColor : "#ffffff"
}
I am new to React Native application development and I am trying to textinput outlined focus. But the textinput is not focused with the code which I wrote above. Also I have tried with textinput mode but nothing helped me.
How can I create textInput outlined focus?
try to use component state.
class textInput extends React.Component {
constructor(props) {
super(props);
this.state = { isFocus: false };
}
render() {
return (
<TextInput
onBlur={() => {
this.setState({ isFocus: false });
}}
onFocus={() => {
this.setState({ isFocus: true });
}}
style={this.isFocus ? { borderColor: 'red' } : { borderColor: 'green' }}
/>
);
}
}
you should add the mode='outlined'
<View style={styles.inputView} >
<TextInput
style={styles.TextInputStyleClass}
placeholder="Email"
mode='outlined'
placeholderTextColor="#003f5c"
onChangeText={text => this.setState({email:text})}
/>
</View>

How to change only the active button background color [React-Native]

import React, { Component } from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
class App extends Component {
constructor(props){
super(props)
this.state={
selected:null
}
}
handle=()=>{
this.setState({selected:1})
}
render() {
return (
<View>
<TouchableOpacity style={[styles.Btn, {backgroundColor:this.state.selected===1?"green":"white"}]} onPress={this.handle}>
<Text style={styles.BtnText}>Button 1</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.Btn} onPress={this.handle}>
<Text style={styles.BtnText}>Button 2</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.Btn} onPress={this.handle}>
<Text style={styles.BtnText}>Button 3</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
Btn: {
borderWidth: 1,
width: 100,
height: 20,
borderRadius: 8,
margin: 5,
padding: 10,
justifyContent: 'center',
flexDirection: 'row',
alignItems: 'center',
},
BtnText: {
fontSize: 15,
},
});
export default App;
Snack Link : https://snack.expo.dev/U_fX-6Tao-
I want to make it so when I click a button, the active button backgroundColor should change to "green" and text to "white" and the rest of the buttons backgroundColor and textColor should stay "red". But when I click another button then that button should become active and the previous active button should get back to its normal state.
It would be wonderful if you could also explain the logic behind it as I'm a newbie in React Native.
Thank you.
You are always setting the active button to the first one. Also, I would use an array to render the buttons. I would do something like this:
class App extends Component {
constructor(props){
super(props)
this.state = {
selected: null
}
}
handlePress = (item) => {
this.setState({ selected: item })
}
render() {
return (
<View>
{[...Array(3).keys()].map((item) => {
return (
<TouchableOpacity key={item} style={[styles.Btn, {backgroundColor: this.state.selected === item ? "green" : "white" }]} onPress={() => this.handlePress(item)}>
<Text style={styles.BtnText}>Button {item + 1}</Text>
</TouchableOpacity>
)
})}
</View>
);
}
}
I created an Themed component(OK I did not create it. It is there when I create the app with Expo).
import { useState } from 'react';
import { TouchableOpacity as DefaultTouchableOpacity } from 'react-native';
export type TouchableProps = DefaultTouchableOpacity['props'] & { activeBgColor?: string };
export function TouchableOpacity(props: TouchableProps) {
const [active, setActive] = useState(false);
const { style, activeBgColor, ...otherProps } = props;
if (activeBgColor) {
return (
<DefaultTouchableOpacity
style={[style, active ? { backgroundColor: activeBgColor } : {}]}
activeOpacity={0.8}
onPressIn={() => setActive(true)}
onPressOut={() => setActive(false)}
{...otherProps}
/>
);
}
return <DefaultTouchableOpacity style={style} activeOpacity={0.8} {...otherProps} />;
}
Then I use this TouchableOpacity everywhere.
<TouchableOpacity
style={tw`rounded-sm h-10 px-2 justify-center items-center w-1/5 bg-sky-400`}
activeBgColor={tw.color('bg-sky-600')}
>
<Text style={tw`text-white font-bold`}>a Button</Text>
</TouchableOpacity>
Oh I am writing TailwindCSS with twrnc by the way. You will love it.
See the screenshot below.

Hide the bottom image view when showing keyboard react-native

How I can hide this picture...
Thank you for any help!
You can use Keyboard in ReactNative to listen for changes of keyboard and hide your image when the keyboard is visible.
check below sample code
import * as React from "react";
import { View, Keyboard, TextInput, Image } from "react-native";
export default class App extends React.Component {
state = {
isKeyboadVisible: false,
text: ""
};
componentDidMount() {
this.keyboardDidShowListener = Keyboard.addListener(
"keyboardDidShow",
this._keyboardDidShow
);
this.keyboardDidHideListener = Keyboard.addListener(
"keyboardDidHide",
this._keyboardDidHide
);
}
componentWillUnmount() {
this.keyboardDidShowListener.remove();
this.keyboardDidHideListener.remove();
}
_keyboardDidShow = () => {
this.setState({
isKeyboadVisible: true
});
};
_keyboardDidHide = () => {
this.setState({
isKeyboadVisible: false
});
};
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<TextInput
style={{
height: 40,
width: "80%",
borderColor: "red",
borderWidth: 1,
marginBottom: 10
}}
onChangeText={text => this.setState({ text })}
value={this.state.text}
/>
{!this.state.isKeyboadVisible && (
<Image
style={{ width: 100, height: 100 }}
source={{ uri: "https://reactnative.dev/img/tiny_logo.png" }}
/>
)}
</View>
);
}
}
Change the above code according to your requirements.
Hope this helps you. Feel free for doubts.
You need to using ScrollView to wrapper your view. Therefore, when you click to input component, keyboard will overlap your picture.
https://reactnative.dev/docs/using-a-scrollview#__docusaurus
Another solution is try to using KeyboardAvoidingView
https://reactnative.dev/docs/keyboardavoidingview

React Native: Text strings must be rendered within a <Text> component

I am trying to create a Profile page where the user can upload an image as the react-native-elements Avatar and update his profile information on a native-base form element.
I am also using the React Native default ImageEditor for image cropping and ImagePicker from Expo to select images.
But when I open the app on Expo, i get this error
Invariant Violation: Invariant Violation: Text strings must be rendered within a component
Below is the code that I am using.
Please help.
import React from "react";
import {
View,
Text,
FlatList,
ActivityIndicator,
TouchableOpacity,
StyleSheet,
ImageEditor
} from "react-native";
import { Avatar } from "react-native-elements";
import { Container, Content, Form, Input, Label, Item } from 'native-base';
import * as Expo from 'expo';
export default class ProfileScreen extends React.Component {
static navigationOptions = {
}
constructor(props) {
super(props);
this.state = {
loading: false,
image: null,
error: null,
refreshing: false
};
}
async _pickImage() {
let result = await Expo.ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3],
});
if (result.cancelled) {
console.log('got here');
return;
}
let resizedUri = await new Promise((resolve, reject) => {
ImageEditor.cropImage(result.uri,
{
offset: { x: 0, y: 0 },
size: { width: result.width, height: result.height },
displaySize: { width: 100, height: 100 },
resizeMode: 'contain',
},
(uri) => resolve(uri),
() => reject(),
);
});
// this gives you a rct-image-store URI or a base64 image tag that
// you can use from ImageStore
this.setState({ image: resizedUri });
}
render () {
let { image } = this.state;
return (
<Container>
<Content>
<View style={{flex:1, flexDirection: 'column', alignContent: 'flex-start', marginLeft: 20}}>
<View style={{flex:1, flexDirection: 'row', alignContent: 'flex-end'}}>
<TouchableOpacity onPress={() => alert('Save')}>
<Text style={{color: '#1f618d', fontWeight: 'bold'}}>Save</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => alert('Cancel')}>
<Text style={{color: '#1f618d', fontWeight: 'bold'}}>Cancel</Text>
</TouchableOpacity>
</View>
<View style={{height: 30}}></View> //Empty view
<View style={{alignContent: 'center'}}>
<Avatar rounded size="xlarge" title="Profile Photo" source={{ uri: this.state.image }} onPress={this._pickImage}/>
</View>
<View style={{height: 30}}></View> //Empty view
<Form>
<Item floatingLabel>
<Label style={styles.labelText}>First Name</Label>
<Input/>
</Item>
<Item floatingLabel>
<Label style={styles.labelText}>Last Name</Label>
<Input/>
</Item>
<Item floatingLabel>
<Label style={styles.labelText}>Email</Label>
<Input/>
</Item>
</Form>
</View>
</Content>
</Container>
)
}
}
const styles = StyleSheet.create({
labelText: {
fontSize: 12,
color: '#1f618d',
fontWeight: '100'
}
});
the problem is the way that use comment in render //Empty View use something like that {/* Empty view */}
Comments inside JSX must have the following syntax.
{/* Empty view */}
Remove comment using like //Empty view
if you wish to add comment in render return method you have to use {/*Empty View*/} something like this.
Instead of
<View style={{height: 30}}></View> //Empty view
write
<View style={{height: 30}}>{/*Empty View*/}</View>
you can not add comment directly like //comments in return function, only allow to in render or business logic parts.
Thanks
remove the // comment
make use of jsx commenting style
{/* comment */}
This can happen if you pass and empty string into a component, which is then "rendered" within a <Text> element.

How would I grow <TextInput> height upon text wrapping?

I'm trying to create a <TextInput> that can grow in height when the text wraps to the next line, similar to how Slack's message input grows with the text up to a point.
I have the multiline prop set, so it is wrapping but the docs don't seem to mention any event regarding wrapping, and the only thing I can think of is a really hacky strategy to character count to figure out when to increase height of the input. How would I accomplish this?
https://facebook.github.io/react-native/docs/textinput.html
Thanks to react-native doc: https://facebook.github.io/react-native/docs/textinput.html
You can do something like that:
class AutoExpandingTextInput extends React.Component {
state: any;
constructor(props) {
super(props);
this.state = {text: '', height: 0};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChange={(event) => {
this.setState({
text: event.nativeEvent.text,
height: event.nativeEvent.contentSize.height,
});
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
);
}
}
0.46.1 or higher: (as explained by Nicolas de Chevigné)
class AutoExpandingTextInput extends React.Component {
constructor(props) {
super(props);
this.state = {text: '', height: 0};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChangeText={(text) => {
this.setState({ text })
}}
onContentSizeChange={(event) => {
this.setState({ height: event.nativeEvent.contentSize.height })
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
);
}
}
Since React Native 0.46.1 :
contentSize property was removed from TextInput.onChange event
If you use this version, you can deal with onContentSizeChange prop
From the Jérémy answer, we have
class AutoExpandingTextInput extends React.Component {
constructor(props) {
super(props);
this.state = {
text: '',
height: 0
};
}
render() {
return (
<TextInput
{...this.props}
multiline={true}
onChangeText={(text) => {
this.setState({ text })
}}
onContentSizeChange={(event) => {
this.setState({ height: event.nativeEvent.contentSize.height })
}}
style={[styles.default, {height: Math.max(35, this.state.height)}]}
value={this.state.text}
/>
);
}
}
You should just set a maxHeight property in the style:
<TextInput multiline style={{maxHeight: 80}} />
Demo here: https://snack.expo.io/#yairopro/multiline-input-with-max-height
My answer is to use onContentSizeChange and numberOfLines props in TextInput, of course turn on multiline, this is my solution:
let numOfLinesCompany = 0;
<TextInput
...
multiline={true}
numberOfLines={numOfLinesCompany}
onContentSizeChange={(e) => {
numOfLinesCompany = e.nativeEvent.contentSize.height / 18;
}}
/>
18 is the height of text, propably depends on fontSize
Shoutout to Jérémy Magrin for his answer. This is his code but refactored to use functional components and hooks.
Note, you might need to use minHight instead of height in some RN versions.
const AutoExpandingTextInput = ({...props})=> {
const [text, setText] = useState('');
const [height, setHeight] = useState();
return (
<TextInput
{...props}
multiline={true}
onChangeText={text => {
setText(text);
}}
onContentSizeChange={event => {
setHeight(event.nativeEvent.contentSize.height);
}}
style={[styles.default, {height: height}]}
value={text}
/>
);
}
<TextInput multiline style={{maxHeight: ...}} />
In the hooks.
const [inputHeight, setInputHeight] = React.useState(40);
<TextInput
multiline
style={{ inputHeight }}
onContentSizeChange={(event) => {
setInputHeight(event.nativeEvent.contentSize.height);
}}
/>
What I have done is set View for the Input max height, for example:
messageBox: {
maxHeight: 110,
width: '80%',
borderRadius: 10,
padding: 10,
backgroundColor: Color.White},
and set the Input to multiline:
<View style={[styles.messageBox, styles.managerMsg]}>
<Input
allowFontScaling={false}
name="notes"
blurOnSubmit={false}
onChangeText={notes => console.log(notes)}
returnKeyType="go"
onSubmitEditing={() => Keyboard.dismiss()}
multiline
/>
</View>
This "Input" is just a simple custom component that receives all Props.
You might as well try something like this.
<TextInput style={[styles.inputs,{height: Math.max(35, this.state.height)}]}
placeholder="Write a message..."
multiline={true}
onChangeText={(msg) => this.setState({ text: msg })}
onSubmitEditing={Keyboard.dismiss}
onContentSizeChange = {() => this.scrollView.scrollToEnd({animated:true})}
/>
style.inputs
inputs: {
minHeight:40,
marginLeft: 16,
paddingTop: 10,
overflow:'hidden',
padding: 15,
paddingRight: 25,
borderBottomColor: '#000000',
flex: 1,
position: 'absolute',
width: '100%',
},
When the text grows beyond one line, a scroll view is created within the text input field and scrolls automatically to the bottom. This actually doesn't increase the text input height when the content grows, instead, a scroll view is created within the input field. Serves the purpose.
I'm posting my solution as others didn't work for me(the text input size grew behind the keyboard, and there were text-overflow issues).
Hence, for anyone who faced a similar problem as I did, this would hopefully work for you.
<View style={{flex:1}}>
<TextInput
multiline={true} />
</View>
You can also use onChangeText to set the TextInput height like so.
const textHeight = 19 //fontsize of the text
<TextInput
style={[styles.input,
{height:Math.max(40,inputHeight)}]}
onChangeText= {text => {
const height = text.split("\n").length
setInputHeight(height * textHeight)
}}
multiline
/>
Just use multiline={true} no need to set height. check the following
<SafeAreaView style={{flex:1, backgroundColor:"#F8F8F9"}}>
<ScrollView style={{flex:1}}>
{
this.state.data && <CommentListView data={this.state.data} onReplyClick={this.onReplyClick}/>
}
</ScrollView>
<View style={{bottom:Platform.OS=="ios" ? this.state.keyboardHeight : 0, flexDirection:"row", alignItems:"flex-end", padding:10}}>
<TextInput
multiline={true}
style={{flex:3, backgroundColor:"#EFEFEF", borderRadius:5, padding:10}}
value={this.state.comment}
onChangeText={(text)=> this.setState({comment:text})}
/>
<TouchableOpacity style={{flex:1}} onPress={()=> this.submit()}>
<Text style={{padding:13, color:"#fff", textAlign:"center", fontWeight:"bold", backgroundColor:"#00394D", borderWidth:1, borderColor:"#00FFEE", borderRadius:5, overflow: "hidden"}}>Post</Text>
</TouchableOpacity>
</View>
</SafeAreaView>