React native Flexbox center ignoring previous item - flexbox

I'm creating a custom "Navigation bar" for my app and I need the following layout:
| ================================== |
| ICON TWO LINES TEXT |
| TWO LINES TEXT |
| ================================== |
The two <Text> fields should be at the center of the status bar and the icon on the right
That's how it looks like now:
Current layout
and in the inspector its how it looks
View inspector
as you can see the text is at the center of his space, but I want to be at the center of the entire component.
That's the code right now:
const styles = {
container: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#64619b',
height: 64,
paddingTop: 10,
},
title: {
color: 'white',
fontSize: 17,
},
belowTitle: {
color: 'white',
fontSize: 20,
fontWeight: 'bold',
},
backButton: {
width: 32,
height: 32,
alignSelf: 'center',
marginLeft: 16,
},
textContainer: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
},
};
class NavigatorHeader extends React.Component {
render() {
return <View style={[styles.container, this.props.style]}>
<TouchableOpacity onPress={this.onBackPress.bind(this)}>
<Icon name="ion|ios-arrow-back" size={32} color="white" style={styles.backButton} />
</TouchableOpacity>
<View style={styles.textContainer}>
<Text style={styles.title}>{this.props.title}</Text>
{this.props.belowTitle && <Text style={styles.belowTitle}>{this.props.belowTitle}</Text>}
</View>
</View>;
}
}

You could handle this by making it three views across. Put you button in the left, text in the center and then leave the right one empty. Then do "flex: 0.25" for the left and right then put "flex: 0.5" for the center. You can of course increase or decrease the two sides just make sure the center is whatever is left to get to 1.0

Related

TouchableOpacity doesn't respond

I'm very new to React native and lately just been messing around with it. I've been having problems every time I use one of the touchable components. For some reason it doesn't respond when I click the touchable component. I tried looking at other solutions but got no where. (I'm also using Expo if you need to know that)
import {
ImageBackground,
StyleSheet,
View,
SafeAreaView,
Platform,
StatusBar,
Text,
TouchableOpacity,
} from "react-native";
const StartScreen = () => {
return (
<ImageBackground
source={require("../assets/Background.png")}
style={{ flex: 1 }}
>
<SafeAreaView style={styles.ContentArea}>
<TouchableOpacity onPress={console.log("Button pressed!")}>
<View style={styles.nextButton}>
<Text style={{ fontWeight: "bold", fontSize: 15 }}>Test</Text>
</View>
</TouchableOpacity>
</SafeAreaView>
</ImageBackground>
);
};
const styles = StyleSheet.create({
ContentArea: {
flex: 1,
paddingTop: Platform.OS === "android" ? StatusBar.currentHeight : 0,
justifyContent: "flex-end",
alignItems: "center",
},
nextButton: {
width: 150,
height: 40,
backgroundColor: "tomato",
marginBottom: 45,
alignItems: "center",
justifyContent: "center",
borderRadius: 50,
},
});
export default StartScreen;
You are passing a function invocation inside the onPress method. This makes the console.log run on the render. console.log() returns undefined, so your onPress prop is ultimately undefined itself. What you want to do, is pass a reference to a function, or an anonymous function instead. Here's an example:
...
<TouchableOpacity onPress={() => console.log("Button pressed!")}>
<View style={styles.nextButton}>
<Text style={{ fontWeight: "bold", fontSize: 15 }}>Test</Text>
</View>
</TouchableOpacity>
...

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

react-native-linear-gradient Only red border is visible on iOS

On react-native iOS, "react-native-linear-gradient": "^2.0.0".
After installing correctly this package with npm then using 'react-native link', i see a red border around my text but not any gradient with the example provided.
import LinearGradient from 'react-native-linear-gradient';
// Within your render function
<LinearGradient colors={['#4c669f', '#3b5998', '#192f6a']} style={styles.linearGradient}>
<Text style={styles.buttonText}>
Sign in with Facebook
</Text>
</LinearGradient>
// Later on in your styles..
var styles = StyleSheet.create({
linearGradient: {
flex: 1,
paddingLeft: 15,
paddingRight: 15,
borderRadius: 5
},
buttonText: {
fontSize: 18,
fontFamily: 'Gill Sans',
textAlign: 'center',
margin: 10,
color: '#ffffff',
backgroundColor: 'transparent',
},
});
Please check this out
https://alligator.io/react/gradient-border-react-native/
I have solved this problem from this blog.
Code Example :
<LinearGradient
colors={["#FFA500", "#C5121B"]}
start={{ x: 0, y: 0 }}
end={{ x: 1, y: 0 }}
style={{ borderRadius: 5 }}
>
<View style={styles.registerButtonStyle}>
<Text>Register</Text>
</View>
</LinearGradient>
registerButtonStyle: {
paddingLeft: 16,
paddingRight: 16,
paddingBottom: 7,
paddingTop: 7,
margin: 1,
backgroundColor: "white",
borderRadius: 5
},
Solved in my case with RN 0.41.2: run this command in the terminal 'react-native run-ios' for recompiling with xCode (necessary in general after a 'react-native link' command)

React Native - Sticky footer at the bottom of container

I'm trying to make a <View> called footer stick at the bottom of the right container.
Here is a live example:
https://rnplay.org/apps/G3rHqQ
If I make the left container higher than the right one then it won't work. If the right container is higher than the left one then it works....
The red and orange elements are dynamic, have different height depending on their content. The blue one, instead, should always stick to the bottom of the right container.
I have also tried with position: 'absolute'; bottom:0; left: 0; right: 0; and it does stick to the bottom but only IF the right container is higher than the left one.
It looks like you need to set a flex:1 on the outermost container to get the flex properties working the way you want. I've set up a working project here and pasted the code below as well.
https://rnplay.org/apps/WoceXg
'use strict';
import React, { AppRegistry, StyleSheet, View, Text } from 'react-native';
const SampleApp = React.createClass({
render: function() {
return (
<View style={{ flex:1 }}>
<View style={styles.wrapper}>
<View style={styles.left}>
<Text>Left</Text>
<Text>Left</Text>
<Text>Left</Text>
<Text>Left</Text>
<Text>Left</Text>
<Text>Left</Text>
<Text>Left</Text>
<Text>Left</Text>
<Text>Left</Text>
</View>
<View style={styles.right}>
<View style={styles.rightInner}>
<View style={styles.content}>
<Text>content</Text>
<Text>content</Text>
</View>
<View style={styles.footer}>
<Text>Sticky</Text>
</View>
</View>
</View>
</View>
<View style={{ flex:1 }}></View>
</View>
);
},
});
const styles = StyleSheet.create({
wrapper: {
flexDirection: 'row',
paddingTop: 50,
flex:1
},
left: {
backgroundColor: 'lightblue',
flex: 1,
},
right: {
backgroundColor: 'lightgreen',
flex: 4,
},
rightInner: {
flex: 1,
backgroundColor: 'orange',
},
content: {
flex: 1,
},
footer: {
backgroundColor: 'green',
}
});
AppRegistry.registerComponent('SampleApp', () => SampleApp);
I'm trying to do something similar. I need a View to stick to the bottom. I used poistion: 'absolute', bottom:0 and it does stick to the bottom but the width of the view does not stretch anymore.

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