I currently have three TouchableHighlight buttons and I'd like to keep only one of them highlighted at once and their state stored.
state:
state = {
selected: null,
};
handleClick function
_handleClick(flag) {
if (flag == 1) {
this.setState({selected: true});
}
}
One of the three touchable highlights
<TouchableHighlight
style={styles.container}
onPress={() => this._handleClick('any flag')}
underlayColor="red">
<View>
<Text>
Test
</Text>
</View>
</TouchableHighlight>
So far this only highlights the current button I'm trying to tap for about a second and the underlay colour goes.
Could anyone help me with this?
Thanks
You can try using this:
state:
state = {
selected: null,
SelectedButton: ''
};
handleClick function:
_handleClick(flag, button) {
if (flag == 1) {
this.setState({selected: true});
}
this.setState({SelectedButton: button})
}
Touchable:
<TouchableHighlight
style={styles.container}
onPress={() => this._handleClick('any flag', '1')}
underlayColor="red">
<View style={{backgroundColor: (this.state.SelectedButton === '1' ? 'red' : 'green')}}>
<Text>
Test
</Text>
</View>
</TouchableHighlight>
What it means:
When you press the touchable, the function "handleClick" will not only save the state of the button, but will save the last pressed button too.
And then on the style of the view inside the touchable, here's the magic:
<View`style={{backgroundColor: (this.state.SelectedButton === '1' ? 'red' : 'green')}}>
It means: "If the last selected button it's equals to the atual ID of the button, the color of the view, will be red, otherwise, the color will be green"
You can make this to the others touchables, wich one with your "ID" (1, 2, 3, and so on)
UPDATE:
If each button has a unique value, you can try using:
state:
state = {
selected: null,
value: ''
};
handleClick function:
_handleClick(flag, button) {
if (flag == 1) {
this.setState({selected: true});
}
this.setState({value: 'flag'})
}
Touchable:
<TouchableHighlight
style={[styles.container, { backgroundColor: (this.state.value === 'any flag' ? 'red' : 'green')}]}
onPress={() => this._handleClick('any flag')}
underlayColor="red">
<View>
<Text>
Test
</Text>
</View>
</TouchableHighlight>
Related
I am building an 'Initiative Tracker' for home use. My goal is to have the first item at the top of the list highlighted by default and use a counter that keeps track of the turns to highlight the item to correspong with its turn.
Eg. When the '+' button is pressed, the next item should be highlighted and the previous item should return to normal.
I am currently using the map function to display an array. I feel like there should be a way to use the index and a style to achieve what I want, but I've had no luck so far.
Thanks in advance for any help or suggestions!
related code below:
let Encounter1Array = [
{ name: "goblin1", init: 5 },
{ name: "goblin2", init: 8 },
{ name: "goblin3", init: 15 },
{ name: "goblin4", init: 3 },
{ name: "goblin5", init: 9 },
];
function InitiativeTrackerScreen() {
const [encounter, setEncounter] = useState(Encounter1Array);
encounter.sort(function (x, y) {
return y.init - x.init;
});
return (
<KeyboardAvoidingView style={styles.wrapper}>
<ScrollView>
{encounter.map((item, index) => {
return (
<View key={index}>
<TouchableOpacity style={styles.ItemDisplayContainer}>
<View>
<View>
<Text style={{ fontStyle: "italic", fontSize: 16 }}>
{item.name}
</Text>
</View>
<View>
<Text style={{ fontSize: 12 }}>
Initiative: {item.init}
</Text>
</View>
</View>
</TouchableOpacity>
</View>
);
})}
</ScrollView>
</KeyboardAvoidingView>
);
}
You need extra state to keep track of the index of the element you want to highlight. Then you can use a conditional statement to match to right index and switch its style.
const P = ({ list }) => {
const [current, setCurrent] = useState(0);
return list.map((item, i) =>
<View style={i === current ? highlightStyle : style}>
<Button onPress={() => setCurrent(current + 1)}>
{"+"}
</Button>
{item}
</View>
);
};
I am new to React Native and trying to accomplish something like below, where simple list from server is rendering in a list with a button. Button, upon click, will be disabled and opacity will be changed.
I am able to create the UI but when I click any button that says Join, previous clicked button resets it state to original. In other words, only one button displays clicked state all the time.
so my code is something like
constructor(props){
super(props);
this.state = {selectedIndices: false, groupsData: ''};
}
Flatlist inside render method looks like
<FlatList style={styles.list}
data={this.state.groupsData}
keyExtractor={(groups) => {
return groups.groupId.toString();
}}
renderItem={(item, index) => {
return this.renderGroupItem(item);
}}/>
RenderGroupItem
renderGroupItem = ({item} )=>(
<GroupItem group = {item} style={{height: '10%'}} onPress = {() => this.onJoinButtonPress(item)}
index = {this.state.selectedIndices}/>
)
onJoinButtonPress
onJoinButtonPress = (item) =>{
this.setState({selectedIndices: true});
}
GroupItem
render(){
if(this.props.group.groupId === this.props.index){
return(
<View style = {[styles.container]}>
<Image source={{uri: 'some Image Url'}} style={styles.roundImage}/>
<Text style={styles.groupText}>{this.props.group.name}</Text>
<View >
<TouchableOpacity style = {[styles.button, {opacity: 0.4}]} activeOpacity = { .5 } onPress = {this.props.onPress}
disabled = {true}>
<Text style = {{color: 'white', fontSize: 12}}>Joined</Text>
</TouchableOpacity>
</View>
</View>
);
}else{
return(
<View style = {styles.container}>
<Image source={{uri: 'Some Image Url'}} style={styles.roundImage}/>
<Text style={styles.groupText}>{this.props.group.name}</Text>
<View >
<TouchableOpacity style = {styles.button} activeOpacity = { .5 } onPress = {this.props.onPress}>
<Text style = {{color: 'white', fontSize: 12}}>Join</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
Now I know that I need to pass an array or hasmap which contains mapping of items that have been clicked but I dont know how to do that. Need desperate help here.
I was able to overcome above problem after maintaining a boolean in the groupsData. Upon selection, I update a boolean "groupsJoined" in groupsData and update the state of groupsData which will invoke render. Inside GroupsItem class, I added a check that if data from props has joinedGroups as true then render selected state else non selected state.
Courtesy https://hackernoon.com/how-to-highlight-and-multi-select-items-in-a-flatlist-component-react-native-1ca416dec4bc
I am working on a ReactNative application. I have some input fields, on button click if any of these fields is empty i have to show validation error. My code is:
<View>
<InputField placeholder="Teilnummer"
onChangeText={(nm)=> this.setState({pTeilnummer: nm})}
/>
<View>
{
this.state.ErrorTeilnummer ? <Text style={styles.ValidationErrorMessage}> * Required </Text> : null
}
</View>
<InputField placeholder="Teilbenennung"
onChangeText={(nm)=> this.setState({pTeilbenennung: nm})}
/>
<View>
{
this.state.ErrorTeilbenennung ? <Text style={styles.ValidationErrorMessage}> * Required </Text> : null
}
</View>
<InputField placeholder="Lieferant"
onChangeText={(nm)=> this.setState({pLieferant: nm})}
/>
<View>
{
this.state.ErrorLieferant ? <Text style={styles.ValidationErrorMessage}> * Required </Text> : null
}
</View>
<Button title="Speichern" color="#ee7100" onPress={() => { this._addProject(this.state.pTeilnummer + "_" + this.state.pTeilbenennung + "_" + this.state.pLieferant, this.state.pdate)}}/>
</View>
I have declared these states as:
constructor(props){
this.state = {ErrorTeilbenennung: false, ErrorTeilnummer: false, ErrorLieferant: false pTeilbenennung: null, pTeilnummer: null, pLieferant: null};
My button click code is:
_addProject = (name, date) =>{
teilbenennung = this.state.pTeilbenennung;
teilnummer = this.state.pTeilnummer;
lieferant = this.state.pLieferant;
var selectedCheck = this.state.addCheck
if(teilbenennung == null || teilnummer == null || lieferant == null)
{
if(teilbenennung == null)
this.setState({ErrorTeilbenennung: true})
else
this.setState({ErrorTeilbenennung: false})
if(teilnummer == null)
this.setState({ErrorTeilnummer: true})
else
this.setState({ErrorTeilnummer: false})
if(lieferant == null)
this.setState({ErrorLieferant: true})
else
this.setState({ErrorLieferant: false})
}
else
{ // saving to database
}
}
When i click on the button first time i get the required validation errors. But after i type something in the first InputField and presses the button, i still get the validation error against that field (may be there is some issue with "onChangeText"), but if i click the button again then the validation error against that field is removed (i mean i have to click twice). Let me add one more thing, when i click on the InputField to write something in it the component reloads. How can i remove this issue so that it works fine with single click
I made an example to solve your problem. This is how you solve the problem you want.
Comparing the status values separately is a very inconvenient way. We can solve this problem sufficiently through onChangeText
Example is here ExampleLink
import React, { Component } from 'react';
import { AppRegistry, TextInput,View,Text,Button } from 'react-native';
export default class UselessTextInput extends Component {
constructor(props) {
super(props);
this.state = {
text: '',error1 : "error1" ,
text2: '',error2 : "error2" };
}
checkfunc() {
if(this.state.text !== '' && this.state.text2 !== ''){
alert("sucess");
} else {
alert("faild");
}
}
render() {
return (
<View style={{flex:1,alignItems:"center" , justifyContent:"center"}}>
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
{this.state.text !== '' ? null : (<Text>{this.state.error1}</Text>)}
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text2) => this.setState({text2})}
value={this.state.text2}
/>
{this.state.text2 !== '' ? null : (<Text>{this.state.error2}</Text>)}
<Button title="checkinput" onPress={() => this.checkfunc()}/>
</View>
);
}
}
// skip this line if using Create React Native App
AppRegistry.registerComponent('AwesomeProject', () => UselessTextInput);
Issue was that my view was inside KeyboardAwareScrollView, so the first click closes the keyboard, that's why my button click does not trigger on first click. This can be resolved in two ways:
Use ScrollView instead of KeyboardAwareScrollView
Set keyboardShouldPersistTaps to true like this:
<KeyboardAwareScrollView keyboardShouldPersistTaps={true}>
Let's suppose that i've a FlatList with some items, i press into one of them, then opens me another screen with the details of that item. Alright, so what i need is, after pressing the button called "Got it!" and goes into the back screen(FlatList screen), how can i set the background color to green in the row selected?
So i click in one item of the FlatList, then it shows me another screen with the details of that item
Once im in the Details screen, i press the button "Got it!", and it brings me back to the FlatList screen
This is exactly what i need, set a background color only in the View shown in that item, if i press another item and do the same thing, it will be shown changed the background both of them, and so on...
NOTE: class Details and ProfileActivity are inside App.js as a childs.
class ProfileActivity extends Component
{
GetFlatListItem (Description, Tutorial, Imagen, Title) {
Alert.alert(Description);
this.props.navigation.navigate('Fourth', {Tutorial, Imagen, Title});
}
return(
<View style = { styles.MainContainer }>
<Button title="Logout" onPress={ () => goBack(null) } />
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Email } </Text>
<FlatList
data={ this.state.dataSource }
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem={({item}) => <View style={{flex: 1, flexDirection: 'row'}}> <Text style={styles.points}>+ {item.points}</Text>
<Text style={styles.flatview} onPress={this.GetFlatListItem.bind
(this, item.description, item.tutorial, item.image, item.title)} >{item.title}</Text></View>}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
class Details extends Component{
onPress = () => {
this.setState({
const {goBack} =this.props.navigation;
})
}
return(
<View style = { styles.MainContainer }>
<TouchableHighlight
style={styles.buttonStyle}
onPress={this.onPress}
>
<Text> Got it! </Text>
</TouchableHighlight>
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Title } </Text>
<Image
style={{width: 66, height: 58}}
source={{uri: this.props.navigation.state.params.Imagen}}
/>
<Text style = {styles.TextComponentStyle}> { this.props.navigation.state.params.Tutorial } </Text>
</View>
);
}
export default MainProject = createStackNavigator(
{
First: { screen: App },
Second: { screen: ProfileActivity },
Fourth: { screen: Details }
});
What i think is pass some values to the method onPress() in Details class, but i don't know which one exactly and how. Can somebody help me?
You will have to create this.state.someArrayName and copy from this.props.navigation.state.params and add backgroundColor key to each object and add your color. Apply that color to your items' view background color. *{{backgroundColor : item.backgroundColor}}
Create a function changeColor to change the color of backgroundColor
In your GetFlatListItem function, pass that function to detail view
On Detail View, call that changeColor function. this.props. changeColor() when you tap Got it button.
how to change only clicked button color from the collection of buttons in react-native by onPress.
Button Text Should also change by onPress.
Sample Code
export class App extends Component {
changeColor() {
// code here
}
render() {
return (
<View style={styles.button_view}>
<TouchableOpacity onPress={this.changeColor.bind(this)} style={styles.button}>
<Text style={styles.button_text}>
Button 1
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.changeColor.bind(this)} style={styles.button}>
<Text style={styles.button_text}>
Button 2
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.changeColor.bind(this)} style={styles.button}>
<Text style={styles.button_text}>
Button 3
</Text>
</TouchableOpacity>
</View>
)
}
}
I tried this and it worked ,btw it`s a little long way;
First set a flag for each of them like:
constructor(props){
super(props);
this.state={
button_1 : false,
button_2 : false,
button_3 : false,
button_4 : false,
}
then,for each Button do this:
<Button
title="Button 1"
color={this.state.button_1 ? "green" : "gray"}
onPress={() => {
this.setState({
button_1: !this.state.button_1,
button_2: false,
button_3: false,
button_4: false
});
}}
/>
<Button
title="Button 2"
color={this.state.button_2 ? "green" : "gray"}
onPress={() => {
this.setState({
button_1: false,
button_2: !this.state.button_2,
button_3: false,
button_4: false
});
}}
/>
do this for text too,it will work
From your code, it looks like all the buttons have the same styling, so I would create a custom button component and render it and pass a flag such as active and set it to true from parent component within the changeColor() method.
You can then have styling based on the active prop.
i.e: style={{ color: this.props.active? 'red' : 'white';}}