how can i change the color of text and tint color of image of a components using props in react native? - react-native

I have made a custom button and below is the code.
export class MenuItems extends Component {
constructor(props) {
super(props);
this.state = {
loading: true
};
}
render() {
let { navigation, listingname, imagesource,} = this.props;
return (
<View >
<TouchableOpacity
onPress={this.props.onPress}
style={[styles.menuStyle]}>
<View style={{ flexDirection: 'row', }}>
<Image source={imagesource} style={[styles.menuItemIcon,{tintColor:'black'}]} />
<Text style={[styles.menuTextstyle]}>{listingname} </Text>
</View>
</TouchableOpacity>
</View>
);
}
}
export default MenuItems;
Now I have reused it with different value and images . I want to change the tint color and text color of the custom button to blue . Below is the code.
\<MenuItems listingname="Logout"
onPress={() => {
this.RBSheet.close();
// this.props.navigation.replace('HomeApp', { screen: 'Home' })
// navigation.dispatch(StackActions.popToTop());
// reset Notification counter
this.props.notifyCountrUpdtHndlr(0)
AuthHelpers.logout(this.props.navigation, true);
}}
imagesource ={IMAGE.LOGOUT_ICO}/>
</View>
I want the image color in blue using tint color and text color of the component in blue. kindly provide the solution and correct the code.

Use style
const StyledImage = ({style}) =>
<Image
style={{width: 20, height: 20, ...style}}
...
/>
<StyledImage style={{tintColor: 'blue'}} />
or custom prop
const TintedImage = ({tintColor}) =>
<Image
style={{width: 20, height: 20, tintColor: tintColor}}
...
/>
<TintedImage tintColor='red' />

Related

React Native mapbox | react-native-mapbox-gl |How to change PointAnnotation Image and Callout is not touchable in Android?

I am trying to change the default Mapbox pin icon on Android as in iOS I'm getting the expected result.
Issue
Not able to change PointAnnotation Icon(Using PNG format)
Callout image is also not loading(Using PNG format)
Not able to click on callout.
All the above issues I'm facing in Android only, iOS is working fine.
import React from 'react';
import {
View,
Image,
} from 'react-native';
import MapboxGL from '#react-native-mapbox-gl/maps';
const currentLatLng = [
[-74.00597, 40.71427]
];
class BugReportExample extends React.Component {
render() {
return (
View style={{flex: 1}}>
<MapboxGL.MapView
ref={c => (this._map = c)}
logoEnabled={false}
style={{flex: 1}}>
<MapboxGL.Camera
ref={c => (this.camera = c)}
zoomLevel={14}
centerCoordinate={currentLatLng}
/>
{/* User location */}
<MapboxGL.PointAnnotation
key={'9090'}
ref={ref => (this.userAnnotationRef = ref)}
id={'9090'}
coordinate={currentLatLng}
title="">
<View style={{ width: 45,height: 45,alignItems: 'center',justifyContent: 'center',overflow: 'hidden',}}>
<Image
source={{uri:'https://reactnative.dev/img/tiny_logo.png'}}
resizeMode={'contain'}
style={{height: wp('10%'), width: wp('10%')}}
onLoad={() => this.userAnnotationRef.refresh()}
/>
</View>
<MapboxGL.Callout title={'You'} />
</MapboxGL.PointAnnotation>
</MapboxGL.MapView>
</View>
);
}
}
This is working fine on iOS.
iOS Result
Android - Issue
const ImageMarker = ({ children }) =>
Platform.select({
ios: children,
android: (
<Text
style= {{
lineHeight: 60, // there is some weird gap, add 40+ pixels
// backgroundColor: '#dcdcde',
}}>
{ children }
< /Text>
),
});
<ImageMarker>
<Image
source={IMAGE_LINK}
style={{width: 45, height: 55}}
/>
</ImageMarker>
Load image before assigning it to the PointAnnotation.
const [imagesLoaded, setImagesLoaded] = useState(false);
setTimeout(() => {
setImagesLoaded(true);
}, 500);
const Example = () => {
render() {
return (
{imagesLoaded ?
// Your mabox code with PointAnnotation
:
<Image
source={{uri:'https://reactnative.dev/img/tiny_logo.png'}}
resizeMode={'contain'}
style={{height: wp('10%'), width: wp('10%'), opacity:0}}
/>
);
}
}

Change active image react native

I wanna change the active image when it's pressed. So for example I have two zodiacs signs, Capricorn and taurus, and when the user click on Capricorn the image is rendered in color and if the user click on the taurus sign then the Capricorn sign will be in black and white and the taurus sign will be rendered in color. Actually I've only managed to change from black and white to color using states but it will always render the color image, I can't switch it on and off . Here is my code:
class Horoscope extends React.Component {
constructor(props) {
super(props)
this.state = {
belier:false,
balance:false,
cancer:false,
capricorne:false,
gemeaux:false,
lion:false,
poissons:false,
sagittaire:false,
scorpion:false,
taureau:false,
verseau:false,
vierge:false,
}
}
render() {
return (
<View style={styles.main_container}>
<View style = {{height: 150, backgroundColor: '#F5F5F5'}}>
<View style={{flexDirection:'row', justifyContent: 'space-around', marginVertical: 8 }}>
<TouchableOpacity onPress={() => {this.setState({belier: !this.state.belier})}}>
<Image style = {styles.image} source={ this.state.belier === true ? require("../Images/couleurs/icons8-belier-100.png")
: require("../Images/gris/beliergris.png")}/>
</TouchableOpacity>
<TouchableOpacity onPress={()=> {this.setState({taureau: !this.state.taureau})}}>
<Image style = {styles.image} source={this.state.taureau === true ? require("../Images/couleurs/icons8-taureau-96.png")
: require("../Images/gris/taureaugris.png")}/>
</TouchableOpacity>
</View>
</View>
</View>
)}
EDIT: I have also tried with a state clicked but still not know how to change his value to false when the user click on an other image..
You could have an Image mapper,
const Images = {
taureau: {
active: require("../Images/couleurs/icons8-taureau-96.png"),
inactive: require("../Images/gris/taureaugris.png")
},
belier: {
active: require("../Images/couleurs/icons8-belier-100.png"),
inactive: require("../Images/gris/taureaugris.png")
}
};
class Horoscope extends React.Component {
constructor(props) {
super(props)
this.state = {
belier:false,
balance:false,
cancer:false,
capricorne:false,
gemeaux:false,
lion:false,
poissons:false,
sagittaire:false,
scorpion:false,
taureau:false,
verseau:false,
vierge:false,
}
}
onPress = var => {
this.setState(state => ({
[var]: !this.state[var]
}));
}
getImage = var => {
const isActive = this.state[var];
const { active, inactive } = Images[var];
if(isActive) {
return active;
}
return inactive;
}
render() {
<View style={styles.main_container}>
<View style = {{height: 150, backgroundColor: '#F5F5F5'}}>
<View style={{flexDirection:'row', justifyContent: 'space-around', marginVertical: 8 }}>
<TouchableOpacity onPress={() => { this.onPress('belier') }}>
<Image source={() => { this.getImage('belier') }}/>
</TouchableOpacity>
</View>
</View>
</View>
}
}
So I found a way to have what I wanted using map() but I have a problem with the layout now. I have 12 images to render but I can only show 6. And I want to have them 6 on top and 6 just below. Here is the code if someone need it :
And if someone knows why I can't display my 12 images I would appreciate. (will edit if I found it). Thanks
class Horoscope extends React.Component {
constructor(props) {
super(props)
this.state = {
selectedIndex:0,
selectedIndex2:0,
belier:false,
balance:false,
cancer:false,
capricorne:false,
gemeaux:false,
lion:false,
poissons:false,
sagittaire:false,
scorpion:false,
taureau:false,
verseau:false,
vierge:false,
tabList:[
{label:'1', urlActive:require('../Images/couleurs/icons8-belier-100.png'), urlInactive:require('../Images/gris/beliergris.png')},
{label:'2', urlActive:require('../Images/couleurs/icons8-taureau-96.png'), urlInactive:require('../Images/gris/taureaugris.png')},
{label:'3', urlActive:require('../Images/couleurs/icons8-gemeaux-96.png'), urlInactive:require('../Images/gris/gemeauxgris.png')},
{label:'4', urlActive:require('../Images/couleurs/icons8-cancer-96.png'), urlInactive:require('../Images/gris/cancergris.png')},
{label:'5', urlActive:require('../Images/couleurs/icons8-lion-96.png'), urlInactive:require('../Images/gris/liongris.png')},
{label:'6', urlActive:require('../Images/couleurs/icons8-vierge-96.png'), urlInactive:require('../Images/gris/viergegris.png')},
{label:'7', urlActive2:require('../Images/couleurs/icons8-balance-96.png'), urlInactive2:require('../Images/gris/balancegris.png')},
{label:'8', urlActive2:require('../Images/couleurs/icons8-scorpion-96.png'), urlInactive2:require('../Images/gris/scorpiongris.png')},
{label:'9', urlActive2:require('../Images/couleurs/icons8-sagittaire-96.png'), urlInactive2:require('../Images/gris/sagittairegris.png')},
{label:'10', urlActive2:require('../Images/couleurs/icons8-verseau-96.png'), urlInactive2:require('../Images/gris/verseaugris.png')},
{label:'11', urlActive2:require('../Images/couleurs/icons8-capricorne-96.png'), urlInactive2:require('../Images/gris/capricornegris.png')},
{label:'12', urlActive2:require('../Images/couleurs/icons8-poissons-96.png'), urlInactive2:require('../Images/gris/poissonsgris.png')}
]
}
}
render() {
{console.log(this.state.selectedIndex)}
return (
<View style={styles.main_container}>
<View style = {{height: 150, backgroundColor: '#F5F5F5'}}>
<View style={{flexDirection:'row', justifyContent: 'space-between', flexWrap: 'wrap'}}>
{
//loop throught the state
this.state.tabList.map((item,index)=>{
return(
<View>
<TouchableOpacity onPress={()=>{this.setState({selectedIndex:index})}}>
<Image
style = {styles.image}
source={this.state.selectedIndex==index ? item.urlActive:item.urlInactive}/>
</TouchableOpacity>
</View>
)
})
}
</View>
</View>
</View>
)}
}
EDIT: Just using flexWrap: 'wrap'resolve it.

Set a TouchableHighlight near CustomDrawer with React Native

I want to set my simple TouchableHighlight just near my CustomDrawer but i can't find how to do it . Here is the code .
class App extends Component {
render() {
return (
<View style={{ flex: 1, flexDirection: 'row',marginTop: (Platform.OS
=== "ios") ? 20 : 0 }} >
<View style={styles.container}>
<TouchableHighlight onPress={this._onPressButton}>
<Image
style={styles.button}
source={require('./camera.png')}
/>
</TouchableHighlight>
</View>
<CustomDrawer
content={<NavigationMenu />}
ref="drawerSideMenu"
onClose={() => { this.props.dispatch(navigationMenuStatus(false)); }}
onOpen={() => { this.props.dispatch(navigationMenuStatus(true)) }}>
<HeaderBar />
</View>
);
}
}
const styles = StyleSheet.create({
button: {
padding: 6,
height:50,
width:50
},
countContainer: {
},
countText: {
color: '#FF00FF'
}
})
export default Appp
Actually i get this as interface but i want to make the button Camera in the blue area near the icon of menu
Any help please ?
Try inserting the camera icon inside the menu bar.
something like this
<View style={styles.container}>
<View style={styles.menuBar}>
<Icon/>
<Menu/>
</View>
</View>

React Native Navigation Status Bar under Navigation Bar

I'm using react-native-navigation library on my project and i'm having some issues with my status bar. First one is that i'm unable to change my status bar background color on iOS, so i created a component for that as follow:
const S_StatusBar = ({ backgroundColor, ...props }) => (
<View style={[styles.statusBar, { backgroundColor }]}>
<StatusBar translucent backgroundColor={backgroundColor} {...props} />
</View>
);
const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 :
StatusBar.currentHeight;
const styles = StyleSheet.create({
statusBar: {
height: STATUSBAR_HEIGHT,
}
});
I import this component on all my screen as followed:
<View>
<S_StatusBar backgroundColor="#090b4b" barStyle="light-content" />
</View>
Here is how i push my screen using the react-native-navigation library:
pushProductDetailScreen = () => {
this.props.navigator.push({
screen: 'cfl.ProductDetail'
});
};
The screen is pushed correctly but now my problem is that my status bar is under my navigation bar such as followed:
I don't understand the issue and why it's happening!
You are creating a View encapsulating something
<View style={[styles.statusBar, { backgroundColor }]}>
...
</View>
statusBar: {
height: STATUSBAR_HEIGHT,
}
So it does create a View with the specified height and backgroundColor
StatusBar is a component a bit different. It doesn't render anything but change the settings of your StatusBar.
You should be able to configure it from your View itself
<StatusBar
backgroundColor="blue"
barStyle="light-content"
/>
This styling works for me
const STATUSBAR_HEIGHT = Platform.OS === 'ios' ? 20 : 0;
class App extends Component {
render() {
return (
<View style={[styles.container]}>
<View style={[styles.statusbar]}>
<StatusBar barStyle="dark-content"/>
</View>
<WebView
style={[styles.webview]}
source={{ uri: "https://..." }}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
statusbar: {
height: STATUSBAR_HEIGHT,
},
webview: {
flex: 1,
}
});

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>