I have a simple <Text> element in my react-native application and I can't figure out what's going on with this behavior.
When I provide a longer string and the <Text> element wraps the text, it seems to be adding a bunch of padding to the right side of the view.
Note: I've made the <Text> element have a red background just so it's easier to see what's going on in this image.
The left button has the wrapped text, the right button does not. Only when the text wraps do I see the strange padding.
Note that I'm using flexShrink: 1 so that my icon doesn't get stomped out by the text element.
<View style={styles.buttonContainer}>
<View style={styles.buttonContent}>
<Grid fill={'#fff'} style={[styles.buttonIcon, {marginRight: 6}]} />
<Text style={styles.buttonText}>
Something Longer Here
</Text>
</View>
</View>
const styles = StyleSheet.create({
buttonContainer: {
justifyContent: 'center',
paddingVertical: 14,
paddingHorizontal: 12,
borderRadius: 16,
backgroundColor: '#27292d',
opacity: 0.90,
shadowColor: '#000',
shadowOffset: { width: 0, height: 1},
shadowOpacity: 0.8,
shadowRadius: 1,
elevation: 5
},
buttonContent: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center'
},
buttonIcon: {
width: 16,
height: 16,
flexShrink: 1
},
buttonText: {
color: 'white',
fontSize: 14,
lineHeight: 16,
backgroundColor: '#ff0000',
fontFamily: 'GeezaPro',
flexShrink: 1
}
});
Update
I've put together this small example to demonstrate the problem.
https://snack.expo.dev/72_24tf4O
When run on the web it looks like this:
But when run on android, it looks like this:
Related
I am using the react-native-mapbox-gl library and I am showing some points on a map. Each has its own callout to display additional information when the respective point is pressed.
I have found the docs/Callout.md and Callout.js source and and example using it in example/src/examples/ShowPointAnnotation.js. This was a great help, thank you so much for the example... I might though doing something really wrong and I have spent days already on this...
My issue is that when I press one annotation, the styling of the annotations appears to be lost (they go all black). Similarity, the styling for the callouts don't seem to be applied. They all black, too. I have shared code and screenshots bellow.
<MapboxGL.PointAnnotation
key={id}
id={id}
coordinate={coordinate}
title={title}
onSelected={feature => {
debugger
this.onAnnotationSelected(i, feature)
}}
onDeselected={this.onAnnotationDeselected}
>
<View
style={[
styles.annotationContainer,
{
backgroundColor: bgColour,
borderRadius: ANNOTATION_SIZE / 2,
borderWidth: StyleSheet.hairlineWidth,
borderColor: borderColor
}
]}
>
<Text style={[styles.annotationFill, { color: borderColor }]}>
{studio.id}
</Text>
</View>
<MapboxGL.Callout
style={[
styles.calloutContainer,
{ backgroundColor: bgColour, borderColor: borderColor }
]}
title={title}
>
<View
style={[
styles.calloutContent,
{
backgroundColor: bgColour,
borderColor: borderColor
}
]}
>
<Text style={[styles.annotationFill, { color: borderColor }]}>
{title}
</Text>
</View>
<View
style={[
styles.tip,
styles.calloutContent,
{
backgroundColor: bgColour,
borderColor: borderColor
}
]}
/>
</MapboxGL.Callout>
</MapboxGL.PointAnnotation>
And stylings
const ANNOTATION_SIZE = 32
const styles = StyleSheet.create({
annotationContainer: {
width: ANNOTATION_SIZE,
height: ANNOTATION_SIZE,
alignItems: 'center',
justifyContent: 'center'
},
annotationFill: {
color: 'black'
},
container: {
flex: 1
},
calloutContainer: {
alignItems: 'center',
justifyContent: 'center',
width: 180,
zIndex: 9999999
},
calloutContent: {
flex: 1,
position: 'relative',
padding: 8,
borderRadius: 3,
borderWidth: 1
},
calloutTitle: {
width: ANNOTATION_SIZE,
height: ANNOTATION_SIZE,
color: 'black',
textAlign: 'center'
},
calloutTip: {
zIndex: 1000,
marginTop: -2,
elevation: 0,
backgroundColor: 'transparent',
borderTopWidth: 16,
borderRightWidth: 8,
borderBottomWidth: 0,
borderLeftWidth: 8,
borderTopColor: 'white',
borderRightColor: 'transparent',
borderBottomColor: 'transparent',
borderLeftColor: 'transparent'
}
})
I am concerned though as well that I should not be using PointAnnotation, as it is marked to be deprecated. Is there an alternative way to achieve the same? Could someone point me into right direction? I am happy to contribute too if needed.
In react native sign in button I am trying to put icon as horizontally left and vertically at the center and the text at the center both horizontally and vertically. With the below code as soon as I do alignSelf as 'center' on the Icon it looses its vertical position. As per the documentation alignSelf should only ovverride the property in cross-axis and not main axis. Here the icon is SVG icon.
const GoogleSignInBtn = ({style, onPress, children}) => {
const {buttonStyles, textStyle, iconStyle} = styles;
return (
<TouchableOpacity onPress={onPress} style={buttonStyles}>
<GoogleIcon style={iconStyle} />
<Text style={textStyle}>{children}</Text>
</TouchableOpacity>
);
};
const styles = {
textStyle: {
color: '#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10,
},
buttonStyles: {
justifyContent: 'center',
alignItems: 'center',
marginTop: 5,
flex: 1,
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5,
},
iconStyle: {
height: 20,
width: 20,
alignSelf: 'flex-start',
},
[Screen Shot of output][1]};
Try
const styles = StyleSheet.create({
textStyle: {
color: '#007aff',
fontSize: 16,
fontWeight: '600',
paddingTop: 10,
paddingBottom: 10,
marginHorizontal: 'auto',
},
buttonStyles: {
justifyContent: 'flex-start',
alignItems: 'center',
marginTop: 5,
flex: 1,
flexDirection: 'row',
borderRadius: 5,
borderWidth: 1,
borderColor: '#007aff',
marginLeft: 5,
marginRight: 5,
},
iconStyle: {
height: 20,
width: 20,
alignSelf: 'center',
},
});
You are indeed overriding alignItems, however it seems for whatever reason your flexDirection is implicitly set to 'column', so the icon is being set to the top of the flexbox.
Changing flexDirection to 'row' allows the items to be oriented horizontally, and thus alignSelf works as desired.
Additionally, I used marginHoritonal: auto to center the text.
See In CSS Flexbox, why are there no “justify-items” and “justify-self” properties? for more information on this.
I'm having an issue where my container is collapsing on my child components which consists of a list of 4 images and one icon at the end of the container in a row. If I set the height explicitly then I can make it large enough to fit the content for one device. However, I have the images resizing themselves right now based off of width of the phone and a percent and then scaling to conserve aspect ratio. Is there a way to make my container grow just large enough to ensure it fits its child components when its child components scale based off of device width?
I thought that React Native flex default was to do this but for whatever reason my container is not fitting the images inside it but instead shrinking and all inside content is shrinking down except the images which lay over the top of my now shrunk containers.
export default function BadgeQuickView() {
return (
<View style={styles.badgeViewContainer}>
<View style={styles.badgeContainerTop}>
<View style={styles.badgeContainerLeftBorder}></View>
<Text style={styles.badgeContainerTitle}>FEATURED BADGES</Text>
<View style={styles.badgeContainerRightBorder}></View>
</View>
<View style={styles.quickBadgeList}>
{TEST_BADGE_ARRAY.map(option => (
<View style={styles.badgeInfoContainer} key={option.id}>
<Image style={styles.badgeImage} source={{uri: option.url}} fadeDuration={0} />
<Text style={styles.badgeDescText}>{option.name}</Text>
</View>
))}
<View style={styles.moreBadgesButtonContainer}>
<TouchableOpacity style={styles.moreBadgesButton}>
<Text style={styles.moreBadgesText}>All {`\n`} Badges</Text>
<Entypo name={'dots-three-horizontal'} size={moderateScale(20)} color={profileColors.editProfileText}/>
</TouchableOpacity>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
badgeViewContainer: {
width: '100%',
height: moderateScale(130),
borderStyle: 'solid',
borderColor: userInterface.borderColor,
borderBottomWidth: 2,
backgroundColor: 'white',
paddingBottom: 5
},
moreBadgesText: {
color: 'black',
fontFamily: 'montserrat',
fontSize: moderateScale(8),
textAlign: 'center',
color: profileColors.editProfileText,
textAlign: 'center',
},
badgeDescText: {
color: 'black',
fontFamily: 'montserrat',
fontSize: moderateScale(8),
textAlign: 'center',
color: profileColors.editProfileText,
textAlign: 'center',
},
quickBadgeList: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
paddingLeft: 15,
},
badgeImage: {
aspectRatio: 1,
width: '100%',
height: undefined,
resizeMode: 'contain',
marginBottom: 10,
},
moreBadgesButton: {
height: '100%',
width: '100%',
alignItems: 'center',
justifyContent: 'center',
textAlign: 'center'
},
moreBadgesButtonContainer: {
height: '100%',
width: '15%',
},
badgeInfoContainer: {
height: '100%',
width: '20%',
flexDirection: 'column',
padding: 5,
},
badgeContainerTop: {
flexDirection: 'row',
alignItems: 'center',
},
badgeContainerLeftBorder: {
borderStyle: 'solid',
borderColor: userInterface.borderColor,
borderTopWidth: 2,
width: '5%',
bottom: moderateScale(13) / 2,
},
badgeContainerTitle: {
fontFamily: 'montserrat-bold',
color: profileColors.editProfileText,
marginHorizontal: 10,
fontSize: moderateScale(13),
bottom: moderateScale(13) /2,
},
badgeContainerRightBorder: {
borderStyle: 'solid',
borderColor: userInterface.borderColor,
borderTopWidth: 2,
width: '100%',
bottom: moderateScale(13) / 2,
},
});
** Edit: Added current working code for reference. moderateScale(...) is just taking the screenHeight and scaling the height and working for most devices that I have tested thus far. I would like to not have to set this explicitly though if possible and instead have it expand based on its content.
Below is the desired and undesired looks. When I comment out the height: from the view container and set it to flex it won't expand to fit its content. When real images are added in the images show over the top of the bottom border and the text is not visible at all that will show under the red box typically. Added the red just as an indicator of where the image and text renders.
I use React Native 0.55, and I want to display a kind of icon on top of a , like this : http://b3.ms/qpknagGre9BR
For now, I use this :
<View style={styles.cardContainer}>
<Image source={iconPlayers} style={styles.iconTop} />
<View style={styles.cardBox}>
<View style={styles.container}>
<Text style={styles.txtTitle}>
My title
</Text>
</View>
</View>
</View>
And my styles :
cardBox: {
borderRadius: 20,
backgroundColor: "#FFF",
padding: 5,
marginBottom: 10,
borderColor: "#DDD",
elevation: 4,
paddingTop: 40,
},
cardContainer: {
marginTop: 40,
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
txtTitle: {
color: "#000",
textAlign: "center",
fontWeight: "bold",
},
iconTop: {
width: 60,
height: 60,
zIndex: 999,
position: "absolute",
top: -30,
elevation: 4,
alignSelf: "center",
},
It's crazy because now it works, but I have a problem, I can't put elevation: 4 on styles for an <Image /> element, I have a Warning.
If I remove the elevation: 4, of my styles, the image is shown behind the cardBox.
How can I achieve what I want without any warning ... ? Thanks.
** EDIT **
I wrapper the <Image /> in a <View />, and I put elevation property to the wrapper, and it works.
I thought elevation was for boxShadow for android, but it impacts the zIndex.
I am trying your code in snack expo, which uses the latest react-native version (55.4). There is no warning in applying elevation to Image property, it just works fine and the image is also above the card. If your react-native version gives warning just wrap it in a View and apply elevation to that View. Also, remember zIndex gets affected by your Views elevation (only Android). Since you have applied elevation: 4 to card box, you must give elevation >= 4 for your Image component else it will draw beneath the card box.
snack example: https://snack.expo.io/B14UPA9Bm
You can also avoid Zindex by changing the order of components,
// Render the image component after your card box this way you can avoid setting the zIndex
<View style={styles.cardContainer}>
<View style={styles.cardBox}>
<View style={styles.container}>
<Text style={styles.txtTitle}>
My title
</Text>
</View>
</View>
<Image source={iconPlayers} style={styles.iconTop} />
</View>
cardBox: {
borderRadius: 20,
backgroundColor: "#FFF",
padding: 5,
marginBottom: 10,
borderColor: "#DDD",
elevation: 4,
paddingTop: 40,
},
cardContainer: {
marginTop: 40,
},
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
txtTitle: {
color: "#000",
textAlign: "center",
fontWeight: "bold",
},
iconTop: {
width: 60,
height: 60,
//zIndex: 999, not required now
position: "absolute",
top: -30,
elevation: 4,
alignSelf: "center",
},
Check and tell if it works in Android and iOS. thanks
As you guys can see the text is cut at the end, how can I change that small white box size or make my text show 'Enter a postcode, street or ...' since, if, the text was smaller it would cut it and put the three dots.
TouchablePlatform is a component used to join both TouchableOpacity and TouchableComponent.
<View style={styles.subContainer1}>
<TouchablePlatform onPress={this._onBackIconPress}>
<Image
source={icon}
style={isListing ? styles.imageIconBack : styles.image}
/>
</TouchablePlatform>
<TextInput
ref={textInput => (this.textInput = textInput)}
placeholderTextColor={'#9CAFB3'}
underlineColorAndroid={'#FFFFFF00'}
placeholder={'Enter a postcode, street or area…'}
style={styles.textInput}
onFocus={this._onTextInputFocus}
value={this.state.text}
/>
</View>
These are the styles being used
const styles = StyleSheet.create({
...
subContainer1: {
flexDirection: 'row',
justifyContent: 'flex-start',
alignItems: 'center',
marginLeft: 15,
marginTop: 10,
height: 40,
borderRadius: 5,
elevation: 4,
shadowOpacity: 0.4,
shadowRadius: 4,
shadowColor: '#073741',
shadowOffset: { height: 2, width: 0 },
},
image: {
resizeMode: 'contain',
height: 25,
width: 25,
marginLeft: 15,
},
imageIconBack: {
resizeMode: 'contain',
height: 18,
width: 18,
marginLeft: 22,
},
...
textInput: {
width: '65%',
fontSize: 14,
marginLeft: 15,
fontFamily: 'azo-sans-light',
color: '#043742',
},
});
How can I change the size of the white area? To make sure the text isn't cut, or, at least, make it cut the text, and show three dots (...) on the trimmed area.
The starting point of the TextInput is controlled by the textInput.marginLeft style, and the end point is set by textInput.width, which is set to 65% of the parent container. You can tweak these values to resize the input box.
The React Native TextInput does not support automatic ellipsization of overflowing placeholder text. If you want to do this, you could hack it by absolutely positioning a Text element on top of it with the following properties, and hiding it when the text input is focused.
<Text numberOfLines={1} ellipsizeMode="tail" pointerEvents="none" />