How do I change the color of bottom tab navigation icon when selected? - react-native-ui-kitten

When I select a tab, the name of the tab changes color. I want to understand how to change the icon color as well.
<BottomNavigationTab
title="Profile"
icon={(focused) => {
return (
<Icon
name="person-outline"
style={{height: 30, width: 30, marginTop: 5}}
fill={focused ? '#B9995A' : '#1f1f1f'}
/>
);
}}
style={tabStyle}
/>

Just listen to the state index and change the color with an if statement
const HomeIcon = (props) => (<Icon name={state.index == 0 ? 'home' : 'home-outline'} fill={state.index == 0 ? '#000' : ''#eee} />)
<BottomNavigation
selectedIndex={state.index}
onSelect={index => {
setTabIndex(index)
navigation.navigate(state.routeNames[index])
}}>
<BottomNavigationTab title="Home" icon={HomeIcon}/>
<BottomNavigationTab title="Search" icon={SearchIcon}/>
</BottomNavigation>

Related

Set a dynamic background colors based on themes in react native

I'm attempting a theme type system, where i can create themes as json files, and then style my app based on it. For the most part all of it works except 2 parts for some reason,
Text Color
Background Colors
So everything else is styled correctly, but the backgroundColor and text colors just wont for some reason. I have checked multiple times over that the theme's values are available, console.log prints them fine too. There's no error message, and other styling from the theme works fine.
Here's where i load in the themes
const themes = {
DEFAULT: require('./../assets/themes/default.json')
};
let theme = {};
function loadDefaultTheme() {
parseTheme(themes.DEFAULT);
}
function parseTheme(json) {
theme.name = json.name;
theme.backgroundColor = json.backgroundColor;
theme.navBackgroundColor = json.navBackgroundColor;
theme.blueColor = json.blueColor;
theme.redColor = json.redColor;
theme.darkBlueColor = json.darkBlueColor;
theme.placeholderColor = json.placeholderColor;
theme.buttonTextColor = json.buttonTextColor;
theme.textColor = json.textColor;
theme.iconColor = json.iconColor;
theme.iconActiveColor = json.iconActiveColor;
theme.navTextColor = json.navTextColor;
theme.navActiveTextColor = json.navActiveTextColor;
}
module.exports = {
themes: themes,
theme: theme,
loadDefaultTheme: loadDefaultTheme,
parseTheme: parseTheme
};
Here's my styling
const welcomeStyles = StyleSheet.create({
background: {
flex: 1,
width: Info.WINDOW_WIDTH,
height: Info.WINDOW_HEIGHT
},
logo: {
width: '50%',
height: '50%',
alignSelf: 'center'
},
text: {
color: ThemeParser.theme.textColor,
alignSelf: 'center',
fontFamily: 'Arial',
},
appNameText: {
fontWeight: 'bold',
fontSize: 30,
marginTop: -60
},
descText: {
fontSize: 22
},
loginView: {
width: Info.WINDOW_WIDTH,
height: Info.WINDOW_HEIGHT * 0.6,
backgroundColor: ThemeParser.theme.backgroundColor,
borderTopColor: '#FE5656', borderTopWidth: 4,
paddingTop: 25
}
});
Finally, my theme:
{
"name": "Default",
"backgroundColor": "#1D1D1D",
"navBackgroundColor": "#343434",
"blueColor": "#05b7ed",
"redColor": "#FF5757",
"darkBlueColor": "#047A9E",
"placeholderColor": "#545454",
"buttonTextColor": "white",
"textColor": "white",
"iconColor": "#047A9E",
"iconActiveColor": "#05B7ED",
"navTextColor": "#C1C1C1",
"navActiveTextColor": "white"
}
I have this bit elsewhere but this works for some reason...
<TouchableOpacity style={[global.globalStyles.halfButton, {backgroundColor: ThemeParser.theme.redColor}]} />
Edit: Components which the styles are not being applied. They work fine when i statically type a color like 'white' or '#1d1d1d'
<View style={styles.loginStyles.loginView}>
<Input
placeholder='Token'
placeholderTextColor={ThemeParser.theme.placeholderColor}
returnKeyType='done'
inputStyle={styles.loginStyles.token}
leftIcon={<Ionicons name='md-key' size={32} color={ThemeParser.theme.blueColor} />}
onChangeText={text => this.setState({token: text})}
/>
<View style={{flex: 1, justifyContent: 'flex-end'}}>
<View style={{flexDirection: 'row'}}>
<TouchableOpacity style={[global.globalStyles.halfButton, {backgroundColor: ThemeParser.theme.blueColor, borderRightColor: 'black', borderRightWidth: 4}]} onPress={() => AniListAuth.getALCode()}>
<Text style={global.globalStyles.buttonText}>Get Code</Text>
</TouchableOpacity>
<TouchableOpacity style={[global.globalStyles.halfButton, {backgroundColor: ThemeParser.theme.redColor}]} onPress={() => AniListAuth.login(this.state.token)}>
<Text style={global.globalStyles.buttonText}>Sign In</Text>
</TouchableOpacity>
</View>
</View>
The background color for the TouchableOpacity seems to work fine, but not for the View background color or Text color
Edit2: Here's a snack of the project thus far if my code above isn't as clear... http://snack.expo.io/Hk1_2AOtr
Check out the working snack.
This is because you are exporting the theme object before you are parsing it.
Your theme object is empty when you are exporting but you are parsing and adding properties to your object after it is exported which means you are calling themeParser.loadDefaultTheme() later in your code, by the time the empty theme object has already been exported.
It would be better if you use your themes object in your ThemeParser.js file:
const themes = {
DEFAULT: require('./../assets/themes/default.json')
};
module.exports = {
themes: themes,
theme: theme,
loadDefaultTheme: loadDefaultTheme,
parseTheme: parseTheme
};
and use it in GlobalStyles like so:
buttonText: {
color: ThemeParser.themes.DEFAULT.textColor,
fontWeight: 'bold',
fontSize: 20
}
And in WelcomeStyles like so:
text: {
color: ThemeParser.themes.DEFAULT.textColor,
alignSelf: 'center',
fontFamily: 'Arial',
},
loginView: {
width: Info.WINDOW_WIDTH,
height: Info.WINDOW_HEIGHT * 0.6,
backgroundColor: ThemeParser.themes.DEFAULT.backgroundColor,
borderTopColor: '#FE5656', borderTopWidth: 4,
paddingTop: 25
},
You can make the checks according to your needs when you want to load the themes object or theme object.

flex box is not working for <Image> in react native android

I just started learning React-Native. I am facing issue while trying to render image on to the screen, it is not appearing. I have tried so many solutions from Google and stack overflow but could not able to solve the issue.
Can someone please help me. Below are the details.
I am using RN 0.53.0 for Android with atom editor. Please let me know if you need more details.
This is where I am extracting data: http://rallycoding.herokuapp.com/api/music_albums
import React from 'react';
import { Text, View, Image, Linking } from 'react-native';
import Card from './Card';
import CardSection from './CardSection';
import Button from './Button';
const AlbumDetail = ({ album }) => {
const {
title,
artist,
thumbnail_image,
image,
url
} = album;
const {
headerContentStyle,
thumbnailStyle,
thumbnailContainerStyle,
imageStyle
} = styles;
return (
<Card>
<CardSection>
<View style={thumbnailContainerStyle}>
<Image style={thumbnailStyle} source={{ uri: thumbnail_image }} />
</View>
<View style={headerContentStyle}>
<Text style={{ fontSize: 18 }}>{title}</Text>
<Text>{artist}</Text>
</View>
</CardSection>
<CardSection>
<View>
<Image style={imageStyle} source={{ uri: image }} />
</View>
</CardSection>
<CardSection>
<Button onPress={() => Linking.openURL(url)}>
Purchase
</Button>
</CardSection>
</Card>
);
};
const styles = {
headerContentStyle: {
flexDirection: 'column',
justifyContent: 'space-around'
},
thumbnailStyle: {
height: 50,
width: 50
},
thumbnailContainerStyle: {
justifyContent: 'center',
alignItems: 'center',
marginLeft: 10,
marginRight: 10
},
imageStyle: {
height: 350,
width: null,
flex: 1,
justifyContent: 'center'
}
};
export default AlbumDetail;
Here is your code :
Please remove View tag from the image
<CardSection>
<Image style={imageStyle} source={{ uri: image }} />
</CardSection>
stylesheet : for imageStyle
imageStyle: {
height: 300,
width: null,
flex: 1,
}
Please check it and let me know if it working or not.
Here:
imageStyle: {
height: 350,
width: null,
flex: 1,
justifyContent: 'center'
}
You have set the image width to null. Try setting it to a reasonable value.
You need add the style to Image with height and width.
in your code you are not adding the style, try this:
<Image style={styles.imageStyle} source={{ uri: image }} />
Add too a valid size for height and width when you are using a image from internet.

react-native webview loading indicator

I am trying to show loading indicator in webweb as follow. Loading indicator is showing but there is white background show after page is loaded. If I change to startInLoadingState to false, web content is showing but loading indicator does not show. It is happing in "react-native": "0.46.3" on ios
renderLoadingView() {
return (
<ActivityIndicator
animating = {this.state.visible}
color = '#bc2b78'
size = "large"
style = {styles.activityIndicator}
hidesWhenStopped={true}
/>
);
}
<WebView
source={source}
renderLoading={this.renderLoadingView} startInLoadingState={true} />
I like this approach which shows the activity indicator overlayed on the loading Webview so you don't have to wait until the entire page is loaded to start seeing content.
constructor(props) {
super(props);
this.state = { visible: true };
}
hideSpinner() {
this.setState({ visible: false });
}
render() {
return (
<View style={{ flex: 1 }}>
<WebView
onLoad={() => this.hideSpinner()}
style={{ flex: 1 }}
source={{ uri: this.props.navigation.state.params.url }}
/>
{this.state.visible && (
<ActivityIndicator
style={{ position: "absolute", top: height / 2, left: width / 2 }}
size="large"
/>
)}
</View>
);
}
A nice approach is setting the property startInLoadingState to true and set the renderLoading to return the desired View.
See the example below.
displaySpinner() {
return (
<View>
{/* Your spinner code goes here.
This one commes from react-native-material-kit library */}
<SingleColorSpinner />
</View>
);
}
render() {
return (
<WebView
startInLoadingState={true}
source={{ uri: this.state.myUri }}
renderLoading={() => {
return this.displaySpinner();
}}
/>
);
}
I have steped on that problem and after some research i found a pretty good solution.
It requires the "react-native-loading-spinner-overlay"
npm install --save react-native-loading-spinner-overlay
index.android.js
import Spinner from 'react-native-loading-spinner-overlay';
const main = 'http://www.myURI.pt';
class MyApp extends Component {
constructor(props) {
super(props);
this.state = { uri: main, visible: true };
}
showSpinner() {
console.log('Show Spinner');
this.setState({ visible: true });
}
hideSpinner() {
console.log('Hide Spinner');
this.setState({ visible: false });
}
render() {
return (
<View>
<Spinner
visible={this.state.visible}
textContent={'Loading...'}
textStyle={{ color: '#FFF' }}
/>
<WebView
scalesPageToFit
source={{ uri: this.state.uri }}
onLoadStart={() => (this.showSpinner())}
onLoad={() => (this.hideSpinner())}
/>
</View>
);
}
}
I think i didn't miss any line.
Alter your renderLoadingView function to the following, and the loading indicator should work as desired:
renderLoadingView() {
return (
<ActivityIndicator
color='#bc2b78'
size='large'
styles={styles.activityIndicator}
/>
);
}
So essentially, just remove the animating (as it is not required for the given usage) and hidesWhenStopped props from your ActivityIndicator. Hope this helps.
Copy & Pasteable: Minimal Webview Component with Loading Indicator
import React, { Component } from "react";
import { ActivityIndicator} from "react-native";
import { WebView } from "react-native-webview";
// Pass a "uri" prop as the webpage to be rendered
class WebViewScreen extends Component {
constructor(props) {
super(props);
this.state = { visible: true };
}
hideSpinner() {
this.setState({ visible: false });
}
render() {
return (
<React.Fragment>
<WebView
onLoadStart={() => this.setState({ visible: true })}
onLoadEnd={() => this.setState({ visible: false })}
// Pass uri in while navigating with react-navigation. To reach this screen use:
// this.props.navigation.navigate("WebViewScreen", {uri: "google.ca"});
source={{ uri: this.props.navigation.state.params.uri }}
/>
{this.state.visible ? (
<ActivityIndicator
style={{
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
jusityContent: "space-around",
flexWrap: "wrap",
alignContent: "center",
}}
size="large"
/>
) : null}
</React.Fragment>
);
}
}
export default WebViewScreen;
react-native webview is now deprecated.
You can import react-native-webview and do the following:
<WebView
source={{ uri: 'https://reactnative.dev' }}
startInLoadingState={true}
renderLoading={() => <Loading />}
/>
If you want to show a Spinner and then replace that spinner with the WebView already loaded, this is your answer:
import React from 'react';
import { StyleSheet, ActivityIndicator, View } from 'react-native';
import { WebView } from "react-native-webview";
function MyApp() {
const Spinner = () => (
<View style={styles.activityContainer}>
<ActivityIndicator size="large" color={white} />
</View>
);
return (
<WebView
bounces={false}
startInLoadingState={true}
renderLoading={Spinner}
style={styles.container}
source={{ uri: yourURL }}
showsHorizontalScrollIndicator={false}
scalesPageToFit
/>
)
}
export default StyleSheet.create({
container: {
flex: 1
},
activityContainer: {
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
top: 0,
left: 0,
backgroundColor: black,
height: '100%',
width: '100%'
}
});
I've used #AdamG's solution but there have a problem with absolute path. The below solution is set ActivityIndicator to the center but with a different way.
<View style={{ flex: 1 }}>
<WebView
onLoad={() => this.hideSpinner()}
style={{ flex: 1 }}
source={{ uri: 'yourhtml.html' }}
/>
<View style={{backgroundColor:'white', height:1}}></View>
{this.state.visible && (
<View style={{flex:1, alignItems:'center'}}>
<ActivityIndicator
size="large"
/>
</View>
)}
</View>
There is 2 another {flex:1} View and ActivityIndicator is in top of the bottom View. I've centered that.
<View style={{backgroundColor:'white', height:1}}></View>
And this line is set the opacity when you have loading state, there have two different View. In top view there is WebView and there is a black bottom border View belong to the WebView.For closing I've patched it with a white helper view.
Hey bro this is my solution, you have to use the event onLoadEnd instead onLoad, the event onLoad is not working for me.
import React, { Component } from 'react';
import { StyleSheet, ActivityIndicator, View } from 'react-native';
import { WebView } from "react-native-webview";
export default class MainActivity extends Component {
constructor(props) {
super(props);
this.state = { visible: true };
}
showSpinner() {
console.log('Show Spinner');
this.setState({ visible: true });
}
hideSpinner() {
console.log('Hide Spinner');
this.setState({ visible: false });
}
render() {
return (
<View
style={this.state.visible === true ? styles.stylOld : styles.styleNew}>
{this.state.visible ? (
<ActivityIndicator
color="#009688"
size="large"
style={styles.ActivityIndicatorStyle}
/>
) : null}
<WebView
style={styles.WebViewStyle}
//Loading URL
source={{ uri: 'https://aboutreact.com' }}
//Enable Javascript support
javaScriptEnabled={true}
//For the Cache
domStorageEnabled={true}
//View to show while loading the webpage
//Want to show the view or not
//startInLoadingState={true}
onLoadStart={() => this.showSpinner()}
onLoad={() => this.hideSpinner()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
stylOld: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
styleNew: {
flex: 1,
},
WebViewStyle: {
justifyContent: 'center',
alignItems: 'center',
flex: 1,
marginTop: 40,
},
ActivityIndicatorStyle: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
position: 'absolute',
},
});
My response will not directly answer your question but it will get you to think about using Skeleton loaders in place of traditional loading indicators (ie. spinner). I've replaced all my project's indicators with Skeletons and have received great user feedback since the change.
Here's a detailed explanation:
https://mechanicalrock.github.io/2022/07/11/replace-circular-loaders-with-skeletons-a.html
Hope this plants the seed as a pattern going forward.
<WebView
style={{
flex: 1
}}
startInLoadingState={true}
source={{ uri: "https://google.com" }}
renderLoading={() => (
)}
/>

react-native nested text with differnt fontsizes (initial, first letter)

I currently write a news reader app in react-native and want to style the first letter of an article as an initial, like below:
For my first attempt I use the nested text aproach. The code is attached below. And this is my current result:
The code in the render function:
<View style={styles.container}>
<Text style={styles.text}>
<Text style={styles.initial}>W</Text>
<Text>
elcome to React Native! To get started, edit index.android.js To get started, edit index.android.js To get started, edit index.android.js
</Text>
</Text>
</View>
My stylesheet:
const fontSize = 14;
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#F5FCFF',
},
initial: {
fontSize: fontSize * 2,
},
text: {
fontSize: fontSize,
color: '#333333',
},
});
My Question:
How can I style my first char to get a pretty initial?
Environment
react: 16.0.0-alpha.6
react-native: 0.44.2
Android 6.0 on an emulated Nexus 5
you can try in this way too, add the regular style for parent Text element and required style for the "W" text child element.
export default class DemoProject extends Component {
render() {
return (
<View style={styles.container}>
*<Text>
<Text style={[styles.textCommon, styles.firstLetter]}>W</Text>
elcome</Text>*
</View>
);
}
}
text: {
fontSize: fontSize,
color: '#333333',
}
This is one way of doing it:
export default class DemoProject extends Component {
render() {
return (
<View style={styles.container}>
<Text style={[styles.textCommon, styles.firstLetter]}>W</Text>
<Text>elcome</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
flexDirection: 'row'
},
textCommon: {
color: '#333333',
},
firstLetter: {
fontSize: 23,
}
});
I think this is the best solution for your question
How can I make the first letter push itself into the paragraph like a newspaper style?
just convert css to react-style

Flex box dynamic width and height

I am trying to create a messages view using react-native e.g.:
As you can see:
The bubbles have a dynamic width and height based on the content
There is a maximum width for the bubbles and they grow downwards
I am trying to recreate this using react native, however I am only able to acheive (2) and not sure how to go about acheiving both.. this is what i have thus far:
<View style={{flex:1,backgroundColor:'blue',flexDirection:'row'}}>
<View style={{backgroundColor:'orange'}}>
<View style={{width:90,flex:1}}>
<Text>123</Text>
</View>
</View>
<View style={{flex:0.25,backgroundColor:'red'}}>
<Text>123</Text>
</View>
</View>
If I increase the orange view to represent a big bubble then it just goes off the screen... e.g.:
I was having same issue. I tried many things including putting wrappers here-and-there (like mentioned in previous answers). None of them worked.
#André Junges's answer is not correct because #kingkong and I have different requirements.
Then, I saw that flex can also take value -1. And setting it solved the problem.
Here is the code:
const messages = [
'hello',
'this is supposed to be a bit of a long line.',
'bye'
];
return (
<View style={{
position: 'absolute',
top: 0,
left: 0,
width: 150,
alignItems: 'flex-end',
justifyContent: 'flex-start',
backgroundColor: '#fff',
}}>
{messages.map( (message, index) => (
<View key={index} style={{
flexDirection: 'row',
marginTop: 10
}}>
<View style={{
flex: -1,
marginLeft: 5,
marginRight: 5,
backgroundColor: '#CCC',
borderRadius: 10,
padding: 5,
}}>
<Text style={{
fontSize: 12,
}}>
{message}
</Text>
</View>
<Image source={require('some_path')} style={{width:30,height:30}} />
</View>
))}
</View>
)
And here is the result:
I've come up with a somewhat contrived way of doing this. Let's look at the problem first.
We can use flexbox to put the "badge" on the left and the text on the right, then have "message rows" going down horizontally. That's easy, but what we want is for the message row to change width depending on its content, and flexbox won't let you do that as it greedily expands to fill all of the space.
What we need is a way of checking the width of the message text then resizing the view accordingly, forcing it to a specified width. We can't use measure to get the text width since that actually only gives us the width of the underlying node, not the actual text itself.
To do this I stole an idea from here and created a bridge to Obj-C which creates a UILabel with the text and gets its width that way.
// TextMeasurer.h
#import "RCTBridgeModule.h"
#import <UIKit/UIKit.h>
#interface TextMeasurer : NSObject<RCTBridgeModule>
#end
// TextMeasurer.m
#import "TextMeasurer.h"
#implementation TextMeasurer
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(get:(NSString *)text cb:(RCTResponseSenderBlock)callback)
{
UILabel *label = [[UILabel alloc]init];
label.font = [UIFont fontWithName:#"Helvetica" size:14.0];
label.text = text;
callback(#[[NSNumber numberWithDouble: label.intrinsicContentSize.width]]);
}
#end
I then wrapped the usage of this into a component:
var AutosizingText = React.createClass({
getInitialState: function() {
return {
width: null
}
},
componentDidMount() {
setTimeout(() => {
this.refs.view.measure((x, y, width, height) => {
TextMeasurer.get(this.props.children, len => {
if(len < width) {
this.setState({
width: len
});
}
})
});
});
},
render() {
return <View ref="view" style={{backgroundColor: 'red', width: this.state.width}}><Text ref="text">{this.props.children}</Text></View>
}
});
All this will do is resize the containing view if the width of the text is less than the original width of the view - which will have been set by flexbox. The rest of the app looks like this:
var messages = React.createClass({
render: function() {
var rows = [
'Message Text',
'Message Text with lots of content ',
'Message Text with lots of content put in here ok yeah? Keep on talking bla bla bla whatever is needed to stretch this message body out.',
'Keep on talking bla bla bla whatever is needed to stretch this message body out.'
].map((text, idx) => {
return <View style={styles.messageRow}>
<View style={styles.badge}><Text>Me</Text></View>
<View style={styles.messageOuter}><AutosizingText>{text}</AutosizingText></View>
</View>
});
return (
<View style={styles.container}>
{rows}
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'flex-start',
alignItems: 'stretch',
flexDirection: 'column',
backgroundColor: '#F5FCFF',
},
messageRow: {
flexDirection: 'row',
margin: 10
},
badge: {
backgroundColor: '#eee',
width: 80, height: 50
},
messageOuter: {
flex: 1,
marginLeft: 10
},
messageText: {
backgroundColor: '#E0F6FF'
}
});
AppRegistry.registerComponent('messages', () => messages);
And it gives you this:
I would keep an eye on the Github issue as this solution is definitely a bit clunky and at the very least I'd expect to see a better way of measuring text in RN at some point.
I know this question is from a year ago, but I had a similar issue and I think it can be useful for other devs.
So what I was trying to achieve was to create boxes like the image below where I would have a text in the left, and an arrow in the right.
Note that the boxes should have a auto height - since the text can be multiple lines..
JSX
<View style={styles.container}>
<View style={styles.textContainer}>
<Text style={styles.text}>{props.message.text}</Text>
</View>
<View style={styles.iconContainer}>
<Icon name="chevron-right" size={30} color="#999" />
</View>
</View>
Styles
container: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
backgroundColor: '#FFF',
marginBottom: Metrics.baseMargin,
borderRadius: 3,
},
textContainer: {
flex: 1,
flexDirection: 'column',
paddingVertical: 30,
paddingHorizontal: Metrics.doubleBaseMargin,
},
text: {
color: '#333',
},
iconContainer: {
width: 35,
borderLeftWidth: 1,
borderLeftColor: '#ddd',
justifyContent: 'center',
alignItems: 'center',
alignSelf: 'stretch',
},
And of course, it didn't work. For some reason if I had an parent with flexDirection: 'row' the child wouldn't grow. The text was being wrapped in multiple lines, but the parent's height (.textContainer) wasn't growing - and the text was being displayed even outside the container in some cases. You can see it in the image below ( third message ).
The fix was to wrap this whole component with one more View, like the code below:
<View style={styles.wrapper}>
<View style={styles.container}>
<View style={styles.textContainer}>
<Text style={styles.text}>{props.message.text}</Text>
</View>
<View style={styles.iconContainer}>
<Icon name="chevron-right" size={30} color="#999" />
</View>
</View>
</View>
The .wrapper class has only styles details on it (moved from .container)
wrapper: {
backgroundColor: '#FFF',
marginBottom: Metrics.baseMargin,
borderRadius: 3,
},
So I think the strategy here is that you want to contain the message bubble inside a full width block, then have two inner views. One inner view attempts to be as thin as possible, that's the one you put text in. The other tries to be as wide as possible, thus condensing the other block just wide enough to contain the text.
<View style={{flex:1,backgroundColor:'blue',flexDirection:'row'}}>
<View style={{flex:0,backgroundColor:'red'}}>
<Text>123</Text>
</View>
<View style={{backgroundColor:'orange', flex: 1}}/>
</View>

Resources