How to styles view to a ratio like 16:9 in React Native? - ios

I want to let the red view keep ratio 16:9. I try but failed. I know React Native use Flexbox (Reimplement in Javascript), but I don't know how to do this. Thanks.
Here is my Javascript:
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
View,
} = React;
var AwesomeProject = React.createClass({
render: function() {
return (
<View style={styles.container}>
<View style={styles.banner}>
</View>
<View style={styles.items}>
</View>
</View>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
},
banner: {
backgroundColor: 'red',
flex: 1,
},
items: {
backgroundColor: 'blue',
flex: 3,
},
});
AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
Here is document about Flexbox in React Native:
http://facebook.github.io/react-native/docs/flexbox.html#content
Here is valid style props:
Valid style props: [
"width",
"height",
"top",
"left",
"right",
"bottom",
"margin",
"marginVertical",
"marginHorizontal",
"marginTop",
"marginBottom",
"marginLeft",
"marginRight",
"borderWidth",
"borderTopWidth",
"borderRightWidth",
"borderBottomWidth",
"borderLeftWidth",
"position",
"flexDirection",
"flexWrap",
"justifyContent",
"alignItems",
"alignSelf",
"flex",
"resizeMode",
"backgroundColor",
"borderColor",
"borderRadius",
"tintColor",
"opacity",
"fontFamily",
"fontSize",
"fontWeight",
"fontStyle",
"lineHeight",
"color",
"containerBackgroundColor",
"textAlign",
"writingDirection",
"padding",
"paddingVertical",
"paddingHorizontal",
"paddingTop",
"paddingBottom",
"paddingLeft",
"paddingRight",
"borderTopColor",
"borderRightColor",
"borderBottomColor",
"borderLeftColor",
"overflow",
"shadowColor",
"shadowOffset",
"shadowOpacity",
"shadowRadius",
"transformMatrix",
"rotation",
"scaleX",
"scaleY",
"translateX",
"translateY"
]"

React Native (since 0.40) supports the aspectRatio prop.
You can do:
style={{ aspectRatio: 16/9 }}
See Maintain aspect ratio of image with full width in React Native

You can use on layout function.
class AwesomeProject = extends React.Component<{}> {
constructor(props) {
super(props)
this.state = {width: 0,height:0}
}
onPageLayout = (event) => {
const {width, height} = event.nativeEvent.layout;
this.setState({
width,
height
})
};
render(){
return (
<View style={styles.container}>
<View style={[
styles.banner,
{
height:this.state.width*9/16
}
]}>
</View>
<View style={styles.items}>
</View>
</View>
);
}
});

Related

React Native- Touchable not working and no errors?

I am trying to detect touch on a view in React Native. I followed this link and incorporated the Touchable around my styled view like so:
<TouchableWithoutFeedback onPress={cardPressed}>
<View style={styles.card}>
<Text style={styles.card_Head}>What is Something?</Text>
<Text style={styles.card_Body}>Something</Text>
</View>
</TouchableWithoutFeedback>
I am using a functional component, so after export default function App() { I have:
function cardPressed()
{
console.log('pressed');
}
No errors, but I get nothing. What is wrong w this implementation?
Check your import. You should import TouchableWithoutFeedback from react-native and not from react-native-gesture-handler
Check out this code.
import React, { useState } from "react";
import { StyleSheet, TouchableWithoutFeedback, Text, View } from "react-native";
const App = () => {
const [count, setCount] = useState(0);
const cardPressed = () => {
console.log('pressed');
setCount(count + 1);
};
return (
<View style={styles.container}>
<View style={styles.countContainer}>
<Text style={styles.countText}>Count: {count}</Text>
</View>
<TouchableWithoutFeedback onPress={cardPressed}>
<View style={styles.button}>
<Text style={styles.card_Head}>What is Something?</Text>
<Text style={styles.card_Body}>Something</Text>
</View>
</TouchableWithoutFeedback>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: "center",
paddingHorizontal: 10
},
button: {
alignItems: "center",
backgroundColor: "#DDDDDD",
padding: 10
},
countContainer: {
alignItems: "center",
padding: 10
},
countText: {
color: "#FF00FF"
},
card_Head: {
fontWeight: 'bold',
fontSize: 24
},
card_Body: {
fontStyle: 'italic'
}
});
export default App;

React Native's React-Navigation: Adding a badge in TabNavigator's Tab

In React-Native with React-Navigation I have a Tabnavigator like so:
const testScreenNavigator = TabNavigator({
Tab1: { screen: Tab1Screen },
Tab2: { screen: Tab2Screen },
Tab3: { screen: Tab3Screen },
});
testScreenNavigator.navigationOptions = {
title: 'MY TITLE',
header: {
titleStyle:{
},
style:{
// how to set the options?
},
}
}
Now I want to add a badge next to Tab1: e.g.
Tab1 (2) | Tab2 | Tab3
In Android this can be done via:
static navigationOptions = {
tabBar: {
label: () => {
...
return (
<Text style={{ backgroundColor: '...', borderRadius: 10}}>
{badgeNumber}
</Text>
...
In iOS it displays the TabMenu at the bottom, which is ok, since it is the native behavior of iOS. But in iOS the circle of the badge does not show, but a rectangular background instead.
Why is that and/or how would a Badge be done in iOS?
Regards
There is actually a badge-package in RN:
https://github.com/react-native-component/react-native-smart-badge .
import React, {Component } from 'react';
import {Animated ,Text,View,AppRegistry,Button, StyleSheet,Image } from 'react-native';
// Badge
export default class App extends Component {
state = {
badgeScale : new Animated.Value(0),
textValue :0,
}
animatedBadge(){
this.state.badgeScale.setValue(0);
const newTextValue = ++this.state.textValue
this.setState({textValue: newTextValue})
Animated.timing(this.state.badgeScale , {
toValue : 1,
duration : 500
}).start()
}
render(){
const msize = 40;
return(
<View style={styles.container}>
<View style={{ width :100, height :100, borderRadius :50, margin:10,}}>
<View
style={{ width :100, height :100, backgroundColor:'green', borderRadius :50,}}
/>
{/* <Image
source={require('./circle.png')} // style={imageStyle}
style={{ width :100, height :100, borderRadius :50,}}
/> */}
<Animated.View style={{
position: 'absolute', width:msize, height:msize,
borderRadius:msize/2, backgroundColor:'black',
justifyContent:'center', alignContent:'center',
borderColor:'green',borderWidth:1,
// left:0, top:0,
left:70, top:0,
// using this change bedge position
transform:[
{
scale:this.state.badgeScale
}
]
}}>
<Text style={{backgroundColor :'transparent' ,
textAlign:'center',
color:'red'}}>
{this.state.textValue}
</Text>
</Animated.View>
<Button style={{ flex:1 , marginTop:50,justifyContent:'center',
alignContent:'center', }}
title='Add'
onPress={ () =>this.animatedBadge() }>
</Button>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex:1,
justifyContent:'center',
alignItems :'center',
// backgroundColor:'#F5FCFF'
},
imageStyle :{
width:200,
height:200,
},
viewTextStyle:{
position : 'absolute',
justifyContent:'center',
alignItems:'center',
},
textStyle:{
fontSize:23,
fontWeight:'bold',
color:'white'
}
})

How to range ScollView and Button in a row in react native?

I wanna to place a ScrollView and Button in a row, but It doesn't work, neither paddingLeft or width.
Without the Button the NaviScrollView will fill the hole view even I had set the width; with the Button and the Button will fill the hole view. Why?
export class Home extends Component {
render() {
return (
<View style={ styles.container }>
<NaviScrollView data= { fakeData }/>
<Button title="添加" color='gray' style={{right:0, width:20}}/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'red',
top: 20,
height: 44
},
})
class NaviScrollView extends Component {
render(){
return (
<ScrollView horizontal={true}>
{
this.props.data.map((item, index) =>
<Button key={ index } title={ item.title } onPress={ () => this._buttonPressed(item.title + item.url)}
color = 'black'/>)
}
</ScrollView>
);
}
}
Using style property : flexDirection : 'row' for View tag to organize childrens in a row or flexDirection : 'column' to organize childrens in a column.
I make a simple example base on your project. I didn't know its similar with your project or not but just take a look.
export default class Home extends Component {
render(){
return(
<View style={ styles.container }>
<ScrollView>
<Text>ABC</Text>
<Text>DEF</Text>
<Text>GHI</Text>
<Text>JKL</Text>
<Text>NMO</Text>
</ScrollView>
<TouchableOpacity style={styles.press}>
<Text>Press Me</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
button : {
width : 50,
height : 50
},
container: {
flexDirection : 'row',
backgroundColor: 'red',
top: 20,
height: 44
},
press: {
width: 150,
padding: 10,
backgroundColor : 'yellow'
}
})

Content hidden behind TabBarIOS with React Native

I'm building an iOS app with React Native and am implementing a TabBarIOS. The content on the tabs seems to flow behind and be obscured by the bar. In xcode I would have just unchecked the "extend edges" boxes but am not sure how to do this with React Native.
Here's an abbreviated version of what I'm trying to do. The <View> from CreateUser flows behind the tab bar. Is there an easy way to make sure content doesn't get obscured by the tab bar?
import React from 'react'
import {
StyleSheet,
Text,
TextInput,
View,
TouchableHighlight,
} from 'react-native'
export default class TabBar extends React.Component {
state = {
selectedTab: 'list'
}
render() {
return (
<TabBarIOS selectedTab={this.state.selectedTab}
unselectedTintColor="#ffffff"
tintColor="#ffe429"
barTintColor="#294163">
<TabBarIOS.Item
title="My List"
systemIcon="bookmarks"
selected={this.state.selectedTab==='list'}
onPress={() => {
this.setState({
selectedTab: 'list',
});
}}
>
<CreateUser />
</TabBarIOS.Item>
</TabBarIOS>
);
}
}
var styles = StyleSheet.create({
tabContent: {
flex: 1,
alignItems: 'center',
},
tabText: {
color: 'darkslategrey',
margin: 50,
},
});
export default class CreateUser extends React.Component{
render(){
return (
<View style={styles.container}>
<TouchableHighlight style={styles.button}>
<Text style={styles.buttonText}>LOG IN</Text>
</TouchableHighlight>
</View>
)
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
justifyContent: "flex-end",
alignItems: 'center',
},
button: {
backgroundColor: "#ffe429",
borderRadius: 3,
height: 60,
width: 200,
margin: 7,
//flex: 1,
alignItems: "center",
justifyContent: "center",
},
buttonText: {
color: "#294163",
}
})
This was a problem for me when using a NavigatorIOS component that then rendered it's initialRoute component which contained a TabBarIOS component.
If this is the case for your scenario, you can fix it by using a ScrollView:
Add the flex layout style to your NavigatorIOS:
<NavigatorIOS
initialRoute={{
component: MyView,
title: 'My View',
}}
style={{flex: 1}}
/>
Use a ScrollView:
<TabBarIOS>
<TabBarIOS.Item
systemIcon="history"
title="A Tab">
<ScrollView>
<Text>
Hello World
</Text>
</ScrollView>
</TabBarIOS.Item>
</TabBarIOS>
In my case I needed to add flex: 1 to the style props for the top-level View of the screen.
RN Navigation docs
//MyScreen.tsx
export default () => (
<View style={{ flex: 1 }}>
...
</View>
)

React native listview add item not working

I am new to react native and I was implemented a simple idea in my head. Basically, I am doing a 'todo list' like component which theres a add button below and items can be added. The problem arises after clicking on the add button and the list gets updated and the following xcode warning message appears. And I have realised, after implementing the ListView, that the app in the simulator slows down so much i couldn't even inspect. The alert popup would freeze the UI after some text are entered too, and the entire app needs to be built again since I couldn't do anything. Thanks for all the help!
Main component: SurveyQn
'use strict'
import React, {
Component,
StyleSheet,
Text,
TouchableHighlight,
TextInput,
View,
ListView,
AlertIOS
} from 'react-native';
var LongButton = require('./LongButton.js');
class SurveyQn extends Component {
constructor(props) {
super(props);
this.state = {
options: [{option: 'Pizza'}],
};
}
componentWillMount() {
this.dataSource = new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
})
}
_renderItem(item) {
return (
<LongButton
text={item.option}
onPress={() => {}}
//btnViewStyle={styles.buttonView}
//btnTextStyle={styles.buttonText}
/>
);
}
_addItem() {
AlertIOS.alert(
'Add new option',
null,
[
{
text: 'Add',
onPress: (text) => {
var options = this.state.options;
options.push({option: text})
this.setState({ options: options})
}
},
],
'plain-text'
);
}
render(){
var dataSource = this.dataSource.cloneWithRows(this.state.options);
return (
<View style={styles.container}>
<TextInput
style={styles.question}
placeholder="Question title"
placeholderTextColor="#4B667B"
selectionColor="#4B667B"
onChangeText={(text) => this.setState({text})}/>
<View style={styles.listView}>
<ListView
dataSource={dataSource}
renderRow={this._renderItem.bind(this)}/>
</View>
<TouchableHighlight
onPress={this._addItem.bind(this)}
style={styles.buttonView}
underlayColor='rgba(0,0,0,0)'>
<Text style={styles.buttonText}>
Add option
</Text>
</TouchableHighlight>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
width: 300,
flex :1,
},
listView: {
flex: 1,
},
question: {
height: 30,
fontSize: 20,
fontWeight: "100",
color: '#4B667B',
marginTop: 10,
marginBottom: 10,
},
buttonView: {
width: 300,
paddingVertical: 9,
borderWidth: 1,
borderColor: '#F868AF',
marginBottom: 13,
},
buttonText: {
textAlign: 'center',
fontSize: 25,
color: '#F868AF',
fontWeight: '500'
},
});
ListView item: LongButton
'use strict'
import React, {
Component,
StyleSheet,
Text,
TouchableHighlight,
View,
} from 'react-native';
class LongButton extends Component {
render(){
return (
<TouchableHighlight
onPress={this.props.onPress}
style={this.props.btnViewStyle}
underlayColor='rgba(0,0,0,0)'>
<Text style={this.props.btnTextStyle}>
{this.props.text}
</Text>
</TouchableHighlight>
);
}
}
module.exports = LongButton;
Xcode warning message upon adding item on alert
app[27881:11151280] the behavior of the UICollectionViewFlowLayout is not defined because:
app[27881:11151280] the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
app[27881:11151280] The relevant UICollectionViewFlowLayout instance is <_UIAlertControllerCollectionViewFlowLayout: 0x7ff0685b1770>, and it is attached to ; layer = ; contentOffset: {0, 0}; contentSize: {0, 0}> collection view layout: <_UIAlertControllerCollectionViewFlowLayout: 0x7ff0685b1770>.
2016-04-06 07:50:01.545 decisionapp[27881:11151280] Make a symbolic breakpoint at UICollectionViewFlowLayoutBreakForInvalidSizes to catch this in the debugger.
Updates:
I tried this but its not working either. Could it be the alert causing these problems? Its just taking forever to render the alert after clicking on the btn.
class SurveyQn extends Component {
constructor(props) {
super(props);
this.state = {
options: [{option: 'Pizza'}],
dataSource : new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
})
};
}
componentWillMount() {
var data = this.state.options;
this.state.dataSource.cloneWithRows(data);
}
_renderItem(item) {
return (
{item.option}
);
}
_addItem() {
AlertIOS.alert(
'Add new option',
null,
[
{
text: 'Add',
onPress: (text) => {
var options = this.state.options;
options.push({option: text})
this.setState({ options: options})
}
},
],
'plain-text'
);
}
render(){
return (
<View style={styles.listView}>
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderItem.bind(this)}/>
</View>
<TouchableHighlight
onPress={this._addItem.bind(this)}
style={styles.buttonView}
underlayColor='rgba(0,0,0,0)'>
<Text style={styles.buttonText}>
Add option
</Text>
</TouchableHighlight>
</View>
);
}
}
Before diving into complex EcmaScript notation, you can use simple notation. Here is a simple example of ListView. Please go through it and understand how it works.
var API = require('./API');
module.exports = React.createClass({
getInitialState: function(){
return {
rawData: [],
dataSource: new ListView.DataSource({
rowHasChanged: (row1, row2) => row1 !== row2
}),
loaded: false,
}
},
componentWillMount: function(){
this.loadData();
},
loadData: function(){
API.getItems()
.then((data) => {
this.setState({
rawData: this.state.rawData.concat(data),
dataSource: this.state.dataSource.cloneWithRows(data),
loaded: true,
});
});
},
render: function(){
return(
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderItem}
style={styles.listView}>
</ListView>
);
},
renderItem: function(item){
return (
<View>
<Text>Custom Item</Text>
</View>
);
},
}
In API.js, I am fetching data from an API.
getItems: function(){
var REQUEST_URL = 'http://api.example.org/item/get?api_key=xxxx;
return fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
return responseData.results.sort(sortByDate);
});
}
The code may not work, since I have not tested. But you can refer my sample project on github. Repo

Resources