How can I set the cursor position in a TextInput field with a button and still be able to change the position normally by pressing on a certain point on the text?
You have to keep track of your selection manually (done through selection and onSelectionChange properties):
export default function App() {
const [text, setText] = React.useState("test")
const [selection, setSelection] = React.useState({start:0, end: 0})
return (
<View style={{flex: 1, justifyContent: 'center'}}>
<TextInput
style={{borderWidth: 1}}
value={text}
onChangeText={newText => setText(newText)}
selection={selection}
onSelectionChange={({ nativeEvent: { selection, text } }) => setSelection(selection)}
/>
<Button
title="Press me"
onPress={() => {
setSelection({start: 2, end: 2})
}}
/>
</View>
);
}
Related
I have a TextInput component, and i want to make text visible when keyboard is on, by default, android will have this, but i don't know why the multiline TextInput just scroll down to the bottom of the text exact the same behavior of single line ( also the cursor at the lastest text)
Here is the code of it
<SafeAreaView style={{ margin: spacingWidth[3], flex: 1 }}>
<View row centerV style={HEADER}>. //just set margin
<TouchableOpacity onPress={() => nav.goBack()}>
<BackArrow name="arrowleft" size={onePercentWidth * 6} />
</TouchableOpacity>
<TouchableOpacity
onPress={() => {
editAndSaveFirebase();
nav.goBack();
dispatch(switchReloadOn());
dispatch(fetchNote(userInfo.email)).then(() =>
dispatch(switchReloadOff())
);
// saveAndNavBack();
}}
>
<Text style={SAVE_NOTE_BT}>Save</Text>
</TouchableOpacity>
</View>
<TextInput
onChangeText={(text) => setNoteHeader(text)}
value={noteHeader}
placeholder="Meaningful header"
style={HEADER_INPUT}
/>
<ScrollView
showsVerticalScrollIndicator={false}
style={{
flex: 1,
}}
contentContainerStyle={{
flexGrow: 1,
}}
> ====> the problem here
<TextInput
scrollEnabled={false}
textAlignVertical={Platform.OS === "android" ? "top" : ""}
onChangeText={(text) => setNoteEdit(text)}
placeholder="Type your secret here..."
value={noteEdit}
multiline
style={NOTE_INPUT}. // i just set the fontSize
/>
</ScrollView>
</SafeAreaView>
);
Here is the behavior i talked about
You should set scrollEnabled: false only for iOS. If you still don't reach the expected behaviour, you can pass ref to the scrollView and scrollToEnd on TextInput focus.
const scrollViewRef = useRef<ScrollView>(null)
const handleInputFocus = () => {
if (isAndroid) {
setTimeout(() => scrollViewRef.current?.scrollToEnd({ animated: true }), 200)
}
}
<ScrollView ref={scrollViewRef}>
<TextInput
{...otherInputProps}
onFocus={handleInputFocus}
scrollEnabled={isAndroid}
/>
</ScrollView>
I have added a picture on the bottom of the mobile screen with style as:
bottomView: {
position: 'absolute',
bottom: 0,
},
Above this picture, I have my sign-in form, but because the picture is at the absolute position, it is not letting the keyboard open. I don't want to make this picture relative as it will disturb the picture. Can anyone help me in such a way that I want to keep the picture on the bottom too but want to open the keyboard as well.
Complete code is:
import React from "react";
import { Image, StyleSheet, Text, View ,TextInput,KeyboardAvoidingView} from "react-native";
import Authentication_Button from "./Authentication_Button";
import { SocialIcon } from 'react-native-elements'
const Login = () => {
const [email, setEmail] = React.useState('');
const [password, setPassword] = React.useState('');
return(
<KeyboardAvoidingView behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.container} enabled>
{/* <View style={styles.container}> */}
<Image source={require('./assets/Logo.png')} style={styles.logo}/>
<TextInput
label="Email"
value={email}
onChangeText={email => setEmail(email)}
style={styles.TXT_INPUT}
placeholder="Email"
/>
<TextInput
label="Password"
value={password}
onChangeText={password => setPassword(password)}
style={styles.TXT_INPUT}
placeholder="Password"
/>
<View style={styles.auth}>
<Authentication_Button title={"Login"} backGroundColor={"#2c88d1"} textColor = {"#FFFFFF"} borderColor={"#2c88d1"}/>
<Authentication_Button title={"Signup"} backGroundColor={"#FFFFFF"} textColor = {"#2c88d1"} borderColor={"#2c88d1"}/>
</View>
<Text>- OR -</Text>
<Text>Sign in with </Text>
<SocialIcon
raised={true}
type='google'
style={{backgroundColor:"#2c88d1"}}
/>
<KeyboardAvoidingView style={styles.bottomView}>
<Image source={require('./assets/footLogin.png')} />
</KeyboardAvoidingView>
{/* </View> */}
</KeyboardAvoidingView>
)
};
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor:"#effdfe",
justifyContent:"center",
alignItems:"center",
padding:20
},
logo :{
width:150,
height:150,
resizeMode:'cover'
},
TXT_INPUT:{
marginBottom:10,
marginTop:10,
borderRadius:12,
borderWidth:1.4,
width:"85%",
paddingVertical:14,
backgroundColor:"#ffffff",
color:"#000000",
fontSize:18
},
auth:{
marginTop:10,
marginBottom:10,
width:"85%",
},
bottomView: {
marginTop:'5%',
position: 'absolute', //Here is the trick
bottom: 1, //Here is the trick
},
});
export default Login;
You can use KeyboardAvoidingView as a parent view. It will help you either your internal button or view is an absolute position
<KeyboardAvoidingView
behavior={Platform.OS === "ios" ? "padding" : "height"}
style={styles.container}
>
</KeyboardAvoidingView>
So the issue has been resolved. The issue was that the footer image was basically on top ofthe text input fields so as soon I changed the positions, it started to work!
I am new to React Native. If I asked something so easy sorry 'bout that.
I have Picker Component in my App.js.
I want to go to component depending on a Picker item.
So, for example; I picked the second item of Picker, when I Clicked the 'Next' button it has to go to second.js
Here is some Part of my Code:
My App.js:
...
...
function Third({ navigation }) {
return (
<View style={styles.container}>
<Text style={styles.circle}>2</Text><Text style={styles.titles}>Operating Mode</Text>
<Text />
<Text style={styles.description}>Please select operating mode</Text><Text/>
<Picker/>
<Button title="Next" style={styles.buttons} color="#FF7F11" onPress={() => navigation.navigate("Fourth")}/><Text/>
<Button title="Back" style={styles.buttons} color="#FF7F11" onPress={() => navigation.goBack()} /><Text/>
</View>
);
}
...
...
and my Picker.js:
import React, { Component } from "react";
import { Text, View, StyleSheet } from "react-native";
import { Picker } from "#react-native-picker/picker";
class Picker extends Component {
state = {router: ''}
updaterouter = (router) => {
this.setState({ router: router })
}
render() {
return (
<View>
<Picker selectedValue={this.state.router} style={styles.drop} onValueChange = {this.updaterouter}>
<Picker.Item label="Rt" value="rt" />
<Picker.Item label="Ap" value="ap" />
<Picker.Item label="Rp" value="rp" />
<Picker.Item label="Wp" value="wp" />
</Picker><Text></Text>
</View>
);
}
}
export default Picker
const styles = StyleSheet.create({
drop: {
height: 30,
width: 200,
backgroundColor: "#FFF"
}
})
One option is to pass the value to the parent via a callback function, something like this:
updaterouter = (router) => {
this.setState({ router: router })
props.onRouterUpdated && props.onRouterUpdated(router)
}
<Picker onRouterUpdated={(r)=>{/*do something with r*/}}/>
Another would be to use common store (e.g. Redux)
I have imported CheckBox from NativeBase. On clicking the Checkbox, it calls the toggleCheckBox function to either add or remove the item.ids from the array and also set the flag to true or false based on the contents of the array.
I can see that the toggleCheckBox function works properly and it sets the array with item ids properly and the flag is also fine on click of the CheckBox. But, the checkbox inside the ListItem is not checked when the checkbox is clicked though the toggle function is called properly.
I also noticed that the log "MS CB2: " right above the List is printed after clicking the CheckBox but the log inside the List 'MS insideList :' is not printed. I am assuming that List is not rendered after the toggleCheckBox function is called.
Here is the code:
class MSScreen extends Component {
constructor(props){
super(props);
//this.toggleCheckbox = this.toggleCheckbox.bind(this);
this.state = {
isLoading: true,
checkboxes : [],
plans: {},
};
}
componentDidMount(){
console.log("MS inside componentDidMount");
fetch('http://hostname:port/getData')
.then((response) => {console.log('response'); return response.json();})
.then((responseJson) => {console.log('responseData: '+responseJson); this.setState({isLoading : false, plans : responseJson}); return;})
.catch((err) => {console.log(err)});
}
toggleCheckbox(id) {
let checkboxes = this.state.checkboxes;
if(checkboxes && checkboxes.includes(id)){
const index = checkboxes.indexOf(id);
checkboxes.splice(index, 1);
} else {
checkboxes = checkboxes.concat(id);
}
this.setState({checkboxes});
console.log("MS check a4: "+checkboxes && checkboxes.includes(id))
}
render() {
if (this.state.isLoading) {
return <View><Text>Loading...</Text></View>;
}
const plans = this.state.plans;
const { params } = this.props.navigation.state.params;
const checkboxes = this.state.checkboxes;
console.log("MS CB1: "+checkboxes)
return (
<Container>
<Content>
<View>
{console.log("MS CB2: "+checkboxes)}
<List
dataArray={plans.data}
renderRow={(item, i) => {
console.log('MS insideList : '+checkboxes && checkboxes.includes(item.id))
return(
<ListItem
key={item.id}
>
<Left>
<CheckBox
onPress={() => this.toggleCheckbox(item.id)}
checked={checkboxes && checkboxes.includes(item.id)}
/>
</Left>
<Text>
{item.name}
</Text>
</ListItem>)}}
/>
</View>
</Content>
</Container>
);
}
}
How do I get the CheckBox to get checked inside the List?
For the benefit of the other users, here is the code fix based on the suggestion from Supriya in the comments below:
SOLUTION
<FlatList
extraData={this.state}
data={plans.data}
keyExtractor={(item, index) => item.id}
renderItem={({item}) => {
const itemName = item.name;
return(
<ListItem>
<CheckBox
onPress={() => this.toggleCheckbox(item.id)}
checked={checkboxes && checkboxes.includes(item.id)}
/>
<Body>
<Text style={styles.planText}>
{item.name}
</Text>
</Body>
</ListItem>)}}
/>
Version:
native-base#2.3.5
react-native#0.50.4
Device: Android
CRNA app with Expo
There is a similar issue on github, https://github.com/GeekyAnts/NativeBase/issues/989 with solution
It works with straightforward code without listItem.
The following example handles the checkboxes as radio buttons, but the onPress functions can be changed easily to allow multiple selection.
import React, { Component } from 'react';
import { View } from 'react-native';
import { CheckBox, Text } from 'native-base';
export default class SignupScreen extends Component {
state = {
one: false,
two: false,
three: false
};
render() {
return (
<View style={{ alignItems: 'flex-start' }}>
<View style={{ flexDirection: 'row' }}>
<CheckBox checked={this.state.one}
style={{ marginRight: 20 }}
onPress={this.onePressed.bind(this)}/>
<Text>One</Text>
</View>
<View style={{ flexDirection: 'row' }}>
<CheckBox checked={this.state.two}
style={{ marginRight: 20 }}
onPress={this.twoPressed.bind(this)}/>
<Text>Two</Text>
</View>
<View style={{ flexDirection: 'row' }}>
<CheckBox checked={this.state.three}
style={{ marginRight: 20 }}
onPress={this.threePressed.bind(this)}/>
<Text>Three</Text>
</View>
</View>
);
}
// checkbox functions
// if clicked button was set, only clear it
// otherwise, set it and clear the others
onePressed() {
if (this.state.one)
this.setState({ one: false });
else
this.setState({ one: true, two: false, three: false });
}
twoPressed() {
if (this.state.two)
this.setState({ two: false });
else
this.setState({ one: false, two: true, three: false });
}
threePressed() {
if (this.state.three)
this.setState({ three: false });
else
this.setState({ one: false, two: false, three: true });
}
}
I want to set different click listeners on different words of . Currently what i have is
<Text>Android iOS React Native<Text>
Now i want to know when user click on Android, iOS and React Native, i have to perform some analytics on that so need click listeners for seperate words.
Does any one have idea about it? I have checked this thread but i din't found it useful for my requirement.
Update
String i have given is just an example string, in real time i will be getting dynamic strings.
This is what i will be getting as dynamic string
{
"str":"Hi i am using React-Native, Earlier i was using Android and so on"
"tagWords":["React-Native","Android"]
}
And in output i want, "Hi i am using React-Native, Earlier i was using Android and so on"
with click event on "React-Native" and "Android". Is is possible?
The post you sent is the simplest way you can achieve the desired behavior. Sinse you need to have different listeners you need to implement different Text components.
Example
export default class App extends Component {
onTextPress(event, text) {
console.log(text);
}
render() {
return (
<View style={styles.container}>
<Text>
<Text onPress={(e) => this.onTextPress(e, 'Android')} style={styles.red}>{'Android '}</Text>
<Text onPress={(e) => this.onTextPress(e, 'iOS')} style={styles.purple}>{'iOS '}</Text>
<Text onPress={(e) => this.onTextPress(e, 'React Native')} style={styles.green}>{'React Native'}</Text>
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
},
red: {
fontSize: 20,
color: 'red'
},
purple: {
fontSize: 20,
color: 'purple'
},
green: {
fontSize: 20,
color: 'green'
}
});
Update 1 (Dynamic text)
render() {
const fixedString = 'I\'m a fixed string that slipleted';
const arrayOfStrings = ['These', 'are', 'strings', 'from', 'array'];
return (
<View style={styles.container}>
<Text style={styles.textContainer}>
{
fixedString.split(' ').map((str, index) => {
return (
<Text onPress={(e) => this.onTextPress(e, str)}>
{`${str}${index !== (fixedString.split(' ').lenght -1) && ' '}`}
</Text>
)
})
}
</Text>
<Text style={styles.textContainer}>
{
arrayOfStrings.map((str, index) => {
return (
<Text onPress={(e) => this.onTextPress(e, str)}>
{`${str}${index !== (arrayOfStrings.lenght -1) && ' '}`}
</Text>
)
})
}
</Text>
</View>
);
}
Update 2 (for example dynamic data)
removePunctuation = (text) => {
// this is a hack to remove comma from the text
// you may want to handle this different
return text.replace(/[.,\/#!$%\^&\*;:{}=\_`~()]/g,"");
}
render() {
const arrayOfObjects = [{
str: 'Hi i am using React-Native, Earlier i was using Android and so on',
tagWords: ['React-Native', 'Android']
}];
return (
<View style={styles.container}>
<Text style={styles.textContainer}>
{
arrayOfObjects.map((obj) => {
return obj.str.split(' ').map((s, index) => {
if ( obj.tagWords.indexOf(this.removePunctuation(s)) > -1 ) {
return (
<Text onPress={(e) => this.onTextPress(e, s)} style={styles.red}>
{`${s} ${index !== (obj.str.split(' ').lenght - 1) && ' '}`}
</Text>
)
} else return `${s} `;
})
})
}
</Text>
</View>
);
}
all you need to use is TouchableOpacity(for the tap effect and clicks), View for the alignment of texts. and certain styling. I am providing you the code snippet that will work for you , all other syntax will remain same
import {Text, View, TouchableOpacity} from 'react-native'
<View style={{flexDirection:'row'}}>
<TouchableOpacity onPress={{()=>doSomethingAndroid()}}>
<Text>Android</Text>
</TouchableOpacity>
<TouchableOpacity onPress={{()=>doSomethingiOS()}}><Text> iOS</Text>
</TouchableOpacity>
<TouchableOpacityonPress={{()=>doSomethingReactNative()}}><Text> React Native</Text>
</TouchableOpacity>
</View>
i hope this works, comment back if any issue happens
You can wrap each clickable words into 'TouchableOpacity' component, and tract the onPress event as follows
<View style={{flexDirection: 'row'}}>
<TouchableOpacity onPress={() => {
console.log('Android Clicked');
}}>
<Text>Android</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => {
console.log('iOS Clicked');
}}>
<Text>Ios</Text>
</TouchableOpacity>
</View>
Please do adjust the spacing between words.
Edit:
For dynamic string you can proceed as follows
...
handleWordClick(str, handler) {
var words = str.split(' '), // word separator goes here,
comp = [];
words.forEach((s, ind) =>{
comp.push(
<TouchableOpacity key={ind} onPress={() => handler.call(this, s)}>
<Text>{s}</Text>
</TouchableOpacity>
);
})
return comp;
}
render() {
var comp = this.handleWordClick('Android iOS React-Native', (word) => {
//handle analytics here...
console.log(word);
});
return (
<View>
...
<View style={{flexDirection: 'row'}}>
{comp}
</View>
...
</View>
)
}
I am not sure what will be your word separator as the example you have given has 'React Native' as single word. Please pay attention on this part.
Hope this will help you.