How to focus one textinput per time in react-native? - react-native

I have 3 different textinput, textinput1, textinput2 and textinput 3.
I want that when i click on textinput1 that his bordercolor be blue, i did that and works.
What i want now is, when i click on textinput2 to textinput1 be back to his orignal color and the textinput2 be blue now.
Example on the photo.
Example
This is my code:
state = { isFocused: true };
onFocusChange = () => {
this.setState({ isFocused: false });
}
render() {
return (
<View style={styles.container}>
<Text style={styles.headline}>Website ou App</Text>
//TEXTINPUT1
<TextInput
onFocus={this.onFocusChange}
style={(this.state.isFocused) ? {marginTop: 5, height: 40, borderWidth: 2, borderRadius: 5, borderColor: 'gray'} : {marginTop: 5, height: 40, borderWidth: 2, borderRadius: 5, borderColor: '#00b7eb'}}
onChangeText={(text) => this.setState({ site: text })}
value={this.state.site}
//TEXTINPUT2
<Text style={styles.headline}>Utilizador/Email</Text>
<TextInput
style={{ marginTop: 5, height: 40, borderColor: 'gray', borderWidth: 1 }}
onChangeText={(text) => this.setState({ local: text })}
value={this.state.local}
/>
Some idea how i can do that? Thank you.

Sharing my same answer from here.
Set up your text inputs and their styles in a component. Then use state in the component to control your styles.
const [focus, setFocus] = useState(false);
<TextInput
style={focus ? styles.inputOnFocus : styles.inputOnBlur}
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
/>
Styles:
const styles = StyleSheet.create({
inputOnFocus: { borderColor: '#C0C0C0' },
inputOnBlur: { borderColor: '#4b6cd5' }
});

One option is to track the name of the focused TextInput. You'll need to make sure to use the updater version of setState in the blur event to avoid race conditions between the onBlur and onFocus methods of the two inputs:
state = { focusedInput: null };
onFocusChange = (inputName) => {
this.setState({focusedInput: inputName});
}
onBlurChange = (inputName) => {
this.setState(state => {
if (state.focusedInput === inputName) {
return {focusedInput: null};
}
// no change if some other input already has focus
return null;
}
}
render() {
return (
<View style={styles.container}>
<Text style={styles.headline}>Website ou App</Text>
//TEXTINPUT1
<TextInput
onFocus={() => this.onFocusChange("input1")}
onBlur={() => this.onBlurChange("input1")}
style={(this.state.focusedInput === "input1") ? {marginTop: 5, height: 40, borderWidth: 2, borderRadius: 5, borderColor: 'gray'} : {marginTop: 5, height: 40, borderWidth: 2, borderRadius: 5, borderColor: '#00b7eb'}}
onChangeText={(text) => this.setState({ site: text })}
value={this.state.site} />
Repeat for other inputs with a name different than "input1".

I think the easiest way to do it is just to create your own custom component to handle the border line. I have created a expo snack for you to see a workaround (other than the mentioned before). https://snack.expo.io/#ianvasco/e8efb0.
Anyway here is the code.
//somefile.js
import React, {useState} from 'react';
import { Text, View, StyleSheet, TextInput } from 'react-native';
import Constants from 'expo-constants';
export default App = () => {
const [isInputFocused, setInputFocused] = useState({input1: false, input2: false})
return (
<View style={styles.container}>
<TextInput
onFocus={() => setInputFocused((prev) => ({...prev, input1: true}))}
onBlur={() => setInputFocused((prev) => ({...prev, input1: false}))}
style={isInputFocused.input1 ? styles.input : styles.inputFocused }
onChangeText={() => {}}/>
<TextInput
style={isInputFocused.input2 ? styles.input : styles.inputFocused }
onChangeText={() => {}}
onFocus={() => setInputFocused((prev) => ({...prev, input2: true}))}
onBlur={() => setInputFocused((prev) => ({...prev, input2: false}))}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
inputFocused: {
marginTop: 5,
height: 40,
borderWidth: 2,
borderRadius: 5,
borderColor: 'grey'
},
input: {
marginTop: 5,
height: 40,
borderWidth: 2,
borderRadius: 5,
borderColor: '#00b7eb'
}
});
Also, I just added React Hooks. I encourage you to use them, since the code get simplified a lot. Here is more about Hooks

Create Custom TextInput component which will set "borderColor" to "black" or "blue" in component with help of "onFocus" and "onBlur" events. In this way you can use multiple TextInputs without any conditions in parent
Sample Code
import React from "react";
import { SafeAreaView, TextInput, Text } from "react-native";
class CustomTextInput extends React.Component {
state = { hasFocus: false };
_onFocus = () => {
this.setState({ hasFocus: true });
};
_onBlur = () => {
this.setState({ hasFocus: false });
};
render() {
const borderColor = this.state.hasFocus ? "blue" : "black";
return (
<TextInput
style={{ padding: 16, borderColor: borderColor, borderWidth: 1 }}
onFocus={this._onFocus}
onBlur={this._onBlur}
/>
);
}
}
export default class App extends React.Component {
render() {
return (
<SafeAreaView style={{ flex: 1 }}>
<Text style={{ marginTop: 16, textAlign: "center" }}>Website App</Text>
<CustomTextInput />
<Text style={{ marginTop: 16, textAlign: "center" }}>Email</Text>
<CustomTextInput />
<Text style={{ marginTop: 16, textAlign: "center" }}>Password</Text>
<CustomTextInput />
</SafeAreaView>
);
}
}
App Preview

**We can control the multiple text input by using Switch case and method **
_onFocusTo=(data)=>{
const {
overdueAmount,
bounceCharges,
penalInterest,
overdueCharges,
collectionPickupCharge,
ebcCharges,
foreClosureAmount,
amount,
} = this.state;
console.log("focus");
switch(data) {
case 1:{
if(amount === "0"){
this.setState({amount:""})
}
}break;
case 2:{
if(bounceCharges === "0"){
this.setState({bounceCharges:""})
}
}break;
case 3:{
if(penalInterest === "0"){
this.setState({penalInterest:""})
}
}break;
case 4:{
if(foreClosureAmount === "0"){
this.setState({foreClosureAmount:""})
}
}break;
case 5:{
if(ebcCharges === "0"){
this.setState({ebcCharges:""})
}
}break;
case 6:{
if(collectionPickupCharge === "0"){
this.setState({collectionPickupCharge:""})
}
}break;
}
}
/In Textinput make function and pass it to onFocus
<TextInput
underlineColorAndroid="transparent"
style={styles.textInput1}
placeholder={""}
placeholderTextColor={Colors.labelTextColor1}
keyboardType={"numeric"}
onFocus={() => this._onFocusTo(1)}
onBlur={this.addTotal}
onChangeText={(amount) => this.setAmountDes(amount)}
value={this.state.amount}
/>
<TextInput
underlineColorAndroid="transparent"
style={styles.textInput1}
placeholder={""}
placeholderTextColor={Colors.labelTextColor1}
onFocus={() => this._onFocusTo(2)}
onBlur={this.addTotal}
keyboardType={"numeric"}
onChangeText={(bounce) => this.setBounce(bounce)}
value={this.state.bounceCharges}
/>
<TextInput
underlineColorAndroid="transparent"
style={styles.textInput1}
placeholder={this.state.penalInterest}
placeholderTextColor={Colors.labelTextColor1}
onFocus={() => this._onFocusTo(3)}
onBlur={this.addTotal}
keyboardType={"numeric"}
onChangeText={(penal) => this.setPenal(penal)}
value={this.state.penalInterest}
/>
....continues

Related

I am unable to delete items in my React Native app

I am unable to delete items.
This is App.js file main file:
import { useState } from "react";
import {
StyleSheet,
Text,
View,
Button,
TextInput,
FlatList,
} from "react-native";
import Goalresults from "./Componets/Goalresult";
export default function App() {
const [comingdata, SetData] = useState("");
const [listdata, setlistdata] = useState([]);
function fetchText(enteredText) {
SetData(enteredText);
}
function buttonPress() {
setlistdata((newdata) => [
...newdata,
{ text: comingdata, id: Math.random.toString() },
]);
}
I am passing id as parameter here and used filter method so that it filter all the id and delete id from the array list.
function deleteitem(id) {
setlistdata((newdata) => {
return newdata.filter((goal) => goal.id !== id);
});
}
return (
<View style={styles.container}>
<View>
<Text style={styles.goalsc}>Your Goals</Text>
</View>
<View style={styles.container1}>
<TextInput
style={styles.textInput}
placeholder="Add Your Goals here..."
onChangeText={fetchText}
/>
<Button title="Add Goal" onPress={buttonPress} />
</View>
<View style={styles.hello}>
<FlatList
data={listdata}
renderItem={(itemdata) => {
return (
<Goalresults
id={itemdata.item.id}
onDeleteItem={deleteitem}
text={itemdata.item.text}
/>
);
}}
keyExtractor={(item, index) => {
return item.id;
}}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: 50,
paddingHorizontal: 16,
},
container1: {
flex: 1,
height: 120,
// paddingTop: 10,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center",
marginBottom: 20,
borderBottomWidth: 1,
borderBottomColor: "#808080",
},
textInput: {
width: "70%",
borderWidth: 1,
borderRadius: 10,
marginRight: 10,
padding: 8,
},
hello: {
flex: 3,
},
goalsc: {
fontSize: 20,
fontWeight: "bold",
paddingLeft: 140,
},
});
Second separated file:
import { View, Text, StyleSheet,Pressable} from "react-native";
function Goalresults(props) {
I used bind there to bind id:
return (
<Pressable onPress={props.onDeleteItem.bind(this,props.id)}>
<View style={styles.goalInput}>
<Text style={styles.textcolor}>{props.text}</Text>
</View>
</Pressable>
);
}
export default Goalresults;
const styles = StyleSheet.create({
goalInput: {
flex: 5,
borderRadius: 5,
paddingTop: 10,
backgroundColor: "#A020F0",
padding: 10,
margin: 10,
},
textcolor: {
color: "white",
},
});
There are a few issues with your code. I will list them as follows.
Inside Goalresults function change the bind on Pressable as
follows: <Pressable onPress={props.onDeleteItem.bind(props, props.id)}>
Inside buttonPress function correct this line { text: comingdata, id: Math.random().toString() }, you missed '()' paranthesis on random
Also on Goalresults add a key={itemdata.item.id}. It will help resolve the warning "duplicate keys".
Following is the complete code
App.js
export default function App() {
const [comingdata, SetData] = useState("");
const [listdata, setlistdata] = useState([]);
function fetchText(enteredText) {
SetData(enteredText);
}
function buttonPress() {
setlistdata((newdata) => [
...newdata,
{ text: comingdata, id: Math.random().toString() },
]);
}
function deleteitem(id) {
console.log('id: ', id)
setlistdata((newdata) => {
return newdata.filter((goal) => goal.id !== id);
});
}
return (
<View style={styles.container}>
<View>
<Text style={styles.goalsc}>Your Goals</Text>
</View>
<View style={styles.container1}>
<TextInput
style={styles.textInput}
placeholder="Add Your Goals here..."
onChangeText={fetchText}
/>
<Button title="Add Goal" onPress={buttonPress} />
</View>
<View style={styles.hello}>
<FlatList
data={listdata}
renderItem={(itemdata) => {
return (
<Goalresults
key={itemdata.item.id}
id={itemdata.item.id}
onDeleteItem={deleteitem}
text={itemdata.item.text}
/>
);
}}
keyExtractor={(item, index) => {
return item.id;
}}
/>
</View>
</View>
);
}
GoalResults.js
function Goalresults(props) {
return (
<Pressable onPress={props.onDeleteItem.bind(props, props.id)}>
<View style={styles.goalInput}>
<Text style={styles.textcolor}>{props.text}</Text>
</View>
</Pressable>
);
}

React Native Conditional style onFocus onBlur using Reusable Function Component

I have a reusable text input component using Native Base that I used on many screen, the goal is when text input on focus, the border changes color to #6852E1. When on blur, it changes to #8B8B8B.
The code below doesn't work like I want, or maybe there is something wrong with my code. How can I achieve that? Thanks
Here's the code
import React, { useState } from "react";
import { Dimensions } from "react-native";
import { Item, Input, Label, Icon } from "native-base";
import * as Font from "expo-font";
let borderColor;
// prettier-ignore
Font.loadAsync({
Calibre_Regular: require("../assets/fonts/Calibre-Regular.ttf"),
"Calibre_Regular": require("../assets/fonts/Calibre-Regular.ttf"),
});
const CustomTextInput = ({
value,
onChangeText,
label,
onSubmitEditing,
getRef,
onPress,
onPress2,
returnKeyType,
keyboardType,
editable,
secureTextEntry,
iconName,
iconName2,
whichStyle,
defaultValue,
}) => {
const { itemStyle1, itemStyle2, textInput, floatingLabel } = InputFieldStyles;
return (
<Item
floatingLabel
style={whichStyle ? itemStyle2 : itemStyle1}
onPress={onPress2}
>
<Icon style={{ marginLeft: 10, color: "#8B8B8B" }} name={iconName2} />
<Label style={floatingLabel}>{label}</Label>
<Input
onBlur={() => (borderColor = "#8B8B8B")}
onFocus={() => (borderColor = "#6852E1")}
style={textInput}
blurOnSubmit={false}
getRef={getRef}
value={value}
defaultValue={defaultValue}
editable={editable}
onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing}
returnKeyType={returnKeyType}
keyboardType={keyboardType}
secureTextEntry={secureTextEntry}
/>
<Icon name={iconName} onPress={onPress} />
</Item>
);
};
const InputFieldStyles = {
textInput: {
padding: 10,
marginVertical: 10,
fontSize: 16,
color: "rgba(0, 0, 0, 0.87)",
fontFamily: "Calibre_Regular",
},
floatingLabel: {
marginLeft: 10,
marginTop: 8,
fontFamily: "Calibre_Regular",
},
itemStyle1: {
marginLeft: 0,
backgroundColor: "#FFF",
borderColor: borderColor,
// borderColor: "#6852E1",
// borderColor: "#8B8B8B",
borderBottomWidth: 3,
},
itemStyle2: {
marginLeft: 0,
backgroundColor: "#F6F7FC",
borderColor: borderColor,
borderBottomWidth: 3,
},
itemStyle3: {
marginLeft: 0,
backgroundColor: "#FFF",
borderColor: "#6852E1",
borderBottomWidth: 3,
},
};
export { CustomTextInput };
this is my code with the right answer for those who needs
import React, { useState } from "react";
import { Dimensions } from "react-native";
import { Item, Input, Label, Icon } from "native-base";
import * as Font from "expo-font";
// prettier-ignore
Font.loadAsync({
Calibre_Regular: require("../assets/fonts/Calibre-Regular.ttf"),
"Calibre_Regular": require("../assets/fonts/Calibre-Regular.ttf"),
});
const CustomTextInput = ({
value,
onChangeText,
label,
onSubmitEditing,
getRef,
onPress,
onPress2,
returnKeyType,
keyboardType,
editable,
secureTextEntry,
iconName,
iconName2,
whichStyle,
defaultValue,
}) => {
const { itemStyle1, itemStyle2, textInput, floatingLabel } = InputFieldStyles;
const [isFocused, setIsFocused] = useState(false);
return (
<Item
floatingLabel
style={whichStyle ? itemStyle2 : itemStyle1({ isFocused })}
onPress={onPress2}
>
<Icon style={{ marginLeft: 10, color: "#8B8B8B" }} name={iconName2} />
<Label style={floatingLabel}>{label}</Label>
<Input
onBlur={() => setIsFocused(false)}
onFocus={() => setIsFocused(true)}
style={textInput}
blurOnSubmit={false}
getRef={getRef}
value={value}
defaultValue={defaultValue}
editable={editable}
onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing}
returnKeyType={returnKeyType}
keyboardType={keyboardType}
secureTextEntry={secureTextEntry}
/>
<Icon name={iconName} onPress={onPress} />
</Item>
);
};
const InputFieldStyles = {
textInput: {
padding: 10,
marginVertical: 10,
fontSize: 16,
color: "rgba(0, 0, 0, 0.87)",
fontFamily: "Calibre_Regular",
},
floatingLabel: {
marginLeft: 10,
marginTop: 8,
fontFamily: "Calibre_Regular",
},
itemStyle1: ({ isFocused }) => ({
marginLeft: 0,
backgroundColor: "#FFF",
borderColor: isFocused ? "#6852E1" : "#8B8B8B",
borderBottomWidth: 3,
}),
itemStyle2: {
marginLeft: 0,
backgroundColor: "#F6F7FC",
borderBottomWidth: 3,
},
itemStyle3: {
marginLeft: 0,
backgroundColor: "#FFF",
borderColor: "#6852E1",
borderBottomWidth: 3,
},
};
export { CustomTextInput };
Try this:
const CustomTextInput = () => {
const [isFocused, setIsFocused] = setState(false);
return (
/** ... */
<Item style={itemStyle({ isFocused })}>
>
<Input
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
/>
</Item>
/** ... */
);
};
itemStyle: ({ isFocused }) => ({
borderColor: isFocused ? 'focused-color' : 'unfocused-color'
}),

Showing search icon inside react-native-autocomplete-input component

I am using the react-native-autocomplete-input package for auto-complete searching.
https://www.npmjs.com/package/react-native-autocomplete-input
Here is a template code which works:
//Example of React Native AutoComplete Input
//https://aboutreact.com/example-of-react-native-autocomplete-input/
//import React in our code
import React, {useState, useEffect} from 'react';
//import all the components we are going to use
import {
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
//import Autocomplete component
import Autocomplete from 'react-native-autocomplete-input';
const App = () => {
const [films, setFilms] = useState([]); // For the main data
const [filteredFilms, setFilteredFilms] = useState([]); // Filtered data
const [selectedValue, setSelectedValue] = useState({}); // selected data
useEffect(() => {
fetch('https://aboutreact.herokuapp.com/getpost.php?offset=1')
.then((res) => res.json())
.then((json) => {
const {results: films} = json;
setFilms(films);
//setting the data in the films state
})
.catch((e) => {
alert(e);
});
}, []);
const findFilm = (query) => {
//method called everytime when we change the value of the input
if (query) {
//making a case insensitive regular expression
const regex = new RegExp(`${query.trim()}`, 'i');
//setting the filtered film array according the query
setFilteredFilms(
films.filter((film) => film.title.search(regex) >= 0)
);
} else {
//if the query is null then return blank
setFilteredFilms([]);
}
};
return (
<SafeAreaView style={{flex: 1}}>
<View style={styles.container}>
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
//data to show in suggestion
data={filteredFilms}
//default value if you want to set something in input
defaultValue={
JSON.stringify(selectedValue) === '{}' ?
'' :
selectedValue.title
}
// onchange of the text changing the state of the query
// which will trigger the findFilm method
// to show the suggestions
onChangeText={(text) => findFilm(text)}
placeholder="Enter the film title"
renderItem={({item}) => (
//you can change the view you want to show in suggestions
<TouchableOpacity
onPress={() => {
setSelectedValue(item);
setFilteredFilms([]);
}}>
<Text style={styles.itemText}>
{item.title}
</Text>
</TouchableOpacity>
)}
/>
<View style={styles.descriptionContainer}>
{films.length > 0 ? (
<>
<Text style={styles.infoText}>
Selected Data
</Text>
<Text style={styles.infoText}>
{JSON.stringify(selectedValue)}
</Text>
</>
) : (
<Text style={styles.infoText}>
Enter The Film Title
</Text>
)}
</View>
</View>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',
flex: 1,
padding: 16,
marginTop: 40,
},
autocompleteContainer: {
backgroundColor: '#ffffff',
borderWidth: 0,
},
descriptionContainer: {
flex: 1,
justifyContent: 'center',
},
itemText: {
fontSize: 15,
paddingTop: 5,
paddingBottom: 5,
margin: 2,
},
infoText: {
textAlign: 'center',
fontSize: 16,
},
});
export default App;
The input box looks like below.
I want a search icon at the right/left inside of the search input box.
Is there any way I can do this?
Here is the working code with
//Example of React Native AutoComplete Input
//https://aboutreact.com/example-of-react-native-autocomplete-input/
//import React in our code
import React, {useState, useEffect} from 'react';
import AntDesign from 'react-native-vector-icons/AntDesign';
//import all the components we are going to use
import {
SafeAreaView,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
//import Autocomplete component
import Autocomplete from 'react-native-autocomplete-input';
const App = () => {
const [films, setFilms] = useState([]); // For the main data
const [filteredFilms, setFilteredFilms] = useState([]); // Filtered data
const [selectedValue, setSelectedValue] = useState({}); // selected data
useEffect(() => {
fetch('https://aboutreact.herokuapp.com/getpost.php?offset=1')
.then((res) => res.json())
.then((json) => {
const {results: films} = json;
setFilms(films);
//setting the data in the films state
})
.catch((e) => {
alert(e);
});
}, []);
const findFilm = (query) => {
//method called everytime when we change the value of the input
if (query) {
//making a case insensitive regular expression
const regex = new RegExp(`${query.trim()}`, 'i');
//setting the filtered film array according the query
setFilteredFilms(
films.filter((film) => film.title.search(regex) >= 0)
);
} else {
//if the query is null then return blank
setFilteredFilms([]);
}
};
return (
<View style={{flex: 1}}><View><Text>Hello Friend</Text></View>
<View style={styles.container}>
<View style={styles.searchSection}>
<AntDesign
name="search1"
size={18}
color="gray"
style={styles.searchIcon}
/>
<Autocomplete
autoCapitalize="none"
autoCorrect={false}
containerStyle={styles.autocompleteContainer}
inputContainerStyle={styles.inputContainer}
//data to show in suggestion
data={filteredFilms}
//default value if you want to set something in input
defaultValue={
JSON.stringify(selectedValue) === '{}'
? ''
: selectedValue.title + selectedValue.id
}
// onchange of the text changing the state of the query
// which will trigger the findFilm method
// to show the suggestions
onChangeText={(text) => findFilm(text)}
placeholder="Search doctors, specialities, symptoms"
renderItem={({item}) => (
//you can change the view you want to show in suggestions
<View>
<TouchableOpacity
onPress={() => {
setSelectedValue(item);
setFilteredFilms([]);
}}>
<Text style={styles.itemText}>{item.title + item.id}</Text>
</TouchableOpacity>
</View>
)}
/>
<AntDesign
name="close"
size={18}
color="gray"
style={styles.clearIcon}
/>
</View>
<View style={styles.descriptionContainer}>
{films.length > 0 ? (
<>
<Text style={styles.infoText}>
Selected Data
</Text>
<Text style={styles.infoText}>
{JSON.stringify(selectedValue)}
</Text>
</>
) : (
<Text style={styles.infoText}>
Enter The Film Title
</Text>
)}
</View>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
backgroundColor: '#F5FCFF',
flex: 1,
padding: 16,
marginTop: 40,
},
autocompleteContainer: {
backgroundColor: '#ffffff',
borderWidth: 0,
marginLeft: 10,
marginRight: 10,
//paddingLeft: 15,
},
inputContainer: {
//minWidth: 300,
//width: "90%",
//height: 55,
backgroundColor: 'transparent',
//color: '#6C6363',
//fontSize: 18,
//fontFamily: 'Roboto',
borderBottomWidth: 1,
//borderBottomColor: 'rgba(108, 99, 99, .7)',
borderColor: 'transparent',
},
descriptionContainer: {
flex: 1,
justifyContent: 'center',
},
itemText: {
fontSize: 15,
paddingTop: 5,
paddingBottom: 5,
margin: 2,
},
infoText: {
textAlign: 'center',
fontSize: 16,
},
// testing below
searchSection: {
flex: 1,
height: 50,
borderRadius: 10,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
marginLeft: '5%',
marginRight: '5%',
backgroundColor: '#fff',
},
searchIcon: {
//padding: 10,
paddingLeft: 10,
backgroundColor: 'transparent',
},
clearIcon: {
paddingRight: 10,
backgroundColor: 'transparent',
},
});
export default App;
npm install react-native-vector-icons for the AntDesign icons.
I am using "react-native-vector-icons": "^7.1.0".
Your output will be like:
Have a great day!!

React Native TouchableOpacity onPress using index/key of the item in FlatList

We created a FlatList component and a Contact screen in our app. We want to add 'heart' icon to the near of the images in Contact screen. We added heart icon near to all of items. But, if we pressed one of these icons, it changes all of theirs colors to red, not only one of them. We want to change the color of clicked item.
Screenshot of our program:
This is our FlatList component:
import React, { Component } from 'react';
import { View, Text, SafeAreaView, StyleSheet, FlatList, Image, TouchableOpacity,
TouchableWithoutFeedback, TextInput } from 'react-native';
import { Right, Icon } from 'native-base';
import data from '../../data';
export default class FlatListComponent extends Component {
state = {
text: '',
contacts: data,
like: false,
color: 'white',
}
toggleLike=()=>{
this.setState({
like: !this.state.like
})
if(this.state.like){
this.setState({
color: 'red',
})
}else{
this.setState({
color: 'white',
})
}
}
renderContactsItem = ({item, index}) => {
return (
<View style={[styles.itemContainer]}>
<Image
style={styles.avatar}
source={{ uri: item.image }} />
<View style={styles.textContainer}>
<Text style={[styles.name], {color: '#fafafa'}}>{item.first_name}</Text>
<Text style={{ color: '#fafafa' }}>{item.last_name}</Text>
</View>
<Right style={{justifyContent: 'center'}}>
<TouchableWithoutFeedback onPress={this.toggleLike}>
{/*{this.like ? (
<Icon name="heart" type='FontAwesome' style={{paddingRight: 10, fontSize: 30, color: 'red'}} />
) :
( <Icon name="heart" type='FontAwesome' style={{paddingRight: 10, fontSize: 30, color: 'white'}} /> )
}*/}
<Icon name='heart' type='FontAwesome' size={32} style={{color: this.state.color === "white" ? 'white' :'red', paddingRight: 10 }}/>
{/*<Icon name="heart" type='FontAwesome' style={{paddingRight: 10, fontSize: 30, color: this.state.color}} />*/}
</TouchableWithoutFeedback>
</Right>
</View>
);
}
searchFilter = text => {
const newData = data.filter(item => {
const listItems = `${item.first_name.toLowerCase()}`
return listItems.indexOf(text.toLowerCase()) > -1;
});
this.setState({
contacts: newData,
});
};
renderHeader = () => {
const {text} = this.state;
return (
<View style={styles.searchContainer}>
<TextInput
onChangeText = {text => {
this.setState ({
text,
});
this.searchFilter(text);
}}
value={text}
placeholder="Search..."
style={styles.searchInput} />
</View>
)
}
render() {
return (
<FlatList
ListHeaderComponent={this.renderHeader()}
renderItem={this.renderContactsItem}
keyExtractor={item => item.id}
data={this.state.contacts}
/>
);
}
}
const styles = StyleSheet.create({
itemContainer: {
flex: 1,
flexDirection: 'row',
paddingVertical: 10,
borderBottomWidth: 1,
borderBottomColor: '#eee'
},
avatar: {
width: 50,
height: 50,
borderRadius: 25,
marginHorizontal: 10,
},
textContainer: {
justifyContent: 'space-around',
},
name: {
fontSize: 16,
},
searchContainer: {
padding: 10
},
searchInput: {
fontSize: 16,
backgroundColor: '#f9f9f9',
padding: 10,
}
});
Our Contact screen is just:
import React from 'react';
import 'SafeAreaView' from 'react-native';
import FlatList from './FlatList';
export default function Contact() {
<SafeAreaView style={{ flex: 1 }}>
<FlatList />
</SafeAreaView>
}
How can we implement this?
I've run into this recently :) One option is to make the renderContactsItem its own component. For example:
const RenderContactsItem = ({item, index}) => {
const [like, setLike] = useState(false);
const [color, setColor] = useState("white");
const toggleLike = () => {
setLike(!like)
if(like) {
setColor("red");
} else {
setColor("white");
}
}
return (
<View style={[styles.itemContainer]}>
<Image
style={styles.avatar}
source={{ uri: item.image }} />
<View style={styles.textContainer}>
<Text style={[styles.name], {color: '#fafafa'}}>{item.first_name}</Text>
<Text style={{ color: '#fafafa' }}>{item.last_name}</Text>
</View>
<Right style={{justifyContent: 'center'}}>
<TouchableWithoutFeedback onPress={toggleLike}>
<Icon name='heart' type='FontAwesome' size={32} style={{color, paddingRight: 10 }}/>
</TouchableWithoutFeedback>
</Right>
</View>
);
}
In this case, each item manages its own state, so setting like doesn't set it for every item.
Another option would be to build an object with "like" states and set the values as the hearts are pressed. For example:
state = {
text: '',
contacts: data,
like: {},
color: 'white', // You don't need this
}
Then, when a heart is pressed, you can send toggleLike the index, and set the state like so:
toggleLike = (index) => {
let newLike = {...this.state.like};
newLike[index] = !Boolean(newLike[index]);
this.setState({
like: newLike,
});
}
And render the color conditionally depending on the index value of the like state, like so:
<Icon name='heart' type='FontAwesome' size={32} style={{color: this.state.like[index] ? 'red' :'white', paddingRight: 10 }}/>

React Native : Arranging elements

I am building a very simple app with a picker and two inputs/labels.
It currently looks like this in my iphone.
This is my code
import React from 'react';
import { StyleSheet, Text, View, Button, Modal, TextInput, Picker } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
}
state = {
b1text: 'Kg',
b2text: 'Cm',
weight: '',
height: '',
standard: 'Metric'
}
render() {
return (
<View style={styles.container}>
<Picker
selectedValue={this.state.standard}
onValueChange={(itemValue, itemIndex) => {
this.setState({standard: itemValue});
if(itemValue === "Metric") {
this.setState({b1text: "Kg"});
this.setState({b2text: "Cm"});
}
if(itemValue === "Imperial") {
this.setState({b1text: "Lbs"});
this.setState({b2text: "Inches"});
}
} }
style={{height: 100, width: 100 }}
>
<Picker.Item label="Metric" value="Metric" />
<Picker.Item label="Imperial" value="Imperial" />
</Picker>
<TextInput
style={{height: 40, width: 60, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text: weight})}
value={this.state.weight}
/>
<Text>{this.state.b1text}</Text>
<TextInput
style={{height: 40, width: 60, borderColor: 'gray', borderWidth: 1}}
onChangeText={(text) => this.setState({text: height})}
value={this.state.height}
/>
<Text>{this.state.b2text}</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
},
});
But I want it to look something like this as shown below.
I have tried margin, padding etc. Still no luck.
Can someone tell me what css/flex property I can use to change the UI like how I want ?
I've created an Expo Snack that has a closer example of the UI you want to achieve. But I'll leave it to you to work out the details.
import React from 'react';
import { StyleSheet, Text, View, TextInput, Picker } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
}
state = {
b1text: 'Kg',
b2text: 'Cm',
weight: '',
height: '',
standard: 'Metric',
};
render() {
return (
<View style={styles.container}>
<View style={styles.top}>
<Picker
selectedValue={this.state.standard}
onValueChange={itemValue => {
this.setState({ standard: itemValue });
if (itemValue === 'Metric') {
this.setState({ b1text: 'Kg' });
this.setState({ b2text: 'Cm' });
}
if (itemValue === 'Imperial') {
this.setState({ b1text: 'Lbs' });
this.setState({ b2text: 'Inches' });
}
}}>
<Picker.Item label="Metric" value="Metric" />
<Picker.Item label="Imperial" value="Imperial" />
</Picker>
</View>
<View style={styles.bottom}>
<TextInput
style={{
height: 40,
width: 60,
borderColor: 'gray',
borderWidth: 1,
}}
onChangeText={() => this.setState({ text: weight })}
value={this.state.weight}
/>
<Text>{this.state.b1text}</Text>
<TextInput
style={{
height: 40,
width: 60,
borderColor: 'gray',
borderWidth: 1,
}}
onChangeText={() => this.setState({ text: height })}
value={this.state.height}
/>
<Text>{this.state.b2text}</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
top: {
width: '100%',
flex: 1,
},
bottom: {
flex: 1,
alignItems: 'center',
},
});
One of the crucial things you need to is learn how to write styles with react-native. Here is a resource that has a guide of all of the style properties you can use with const {StyleSheet} from 'react-native'.
https://github.com/vhpoet/react-native-styling-cheat-sheet
Good luck :)