TabBarIOS in ReactNative not working, items overlapping each other - javascript

So im making an app and this is my code:
import React, { Component } from 'react';
import {
View,
Text,
TabBarIOS,
StyleSheet,
Dimensions
} from 'react-native';
//import Styles from './LayoutStyle.js';
class Layout extends Component {
constructor(){
super()
this.state = {selectedTab: 'tabThree'}
}
setTab(tabId){
this.setState({selectedTab: tabId})
}
render() {
return(<View style={Styles.Layout}>
<TabBarIOS>
<TabBarIOS.Item
systemIcon='history'
selected={this.state.selectedTab === 'tabOne'}
onPress={() => this.setTab('tabOne')}>
<View>
<Text>Jure1</Text>
</View>
</TabBarIOS.Item>
<TabBarIOS.Item
systemIcon='bookmarks'
selected={this.state.selectedTab === 'tabTwo'}
onPress={() => this.setTab('tabTwo')}>
<View>
<Text>Jure2</Text>
</View>
</TabBarIOS.Item>
<TabBarIOS.Item
systemIcon='more'
selected={this.state.selectedTab === 'tabThree'}
onPress={() => this.setTab('tabThree')}>
<View>
<Text>Jure3</Text>
</View>
</TabBarIOS.Item>
</TabBarIOS>
</View>
);
}
}
const Styles = StyleSheet.create({
Layout: {
alignItems: "center",
justifyContent: "center",
height: Dimensions.get('window').height,
width: Dimensions.get('window').width,
},
TabBar: {
backgroundColor: 'grey'
}
});
export default Layout;
Well what i expected was an app where you have a TabBar on the bottom with three different items to choose from and it should look like i would in a native ios app. Well thats not the case, what i get is this:
Well what should i do? How do i style this item to not overlap? Any ideas?

The layout style is causing the inner content to get centred oddly, change Layout style to this:
Layout: {
flex:1,
}
Additionally, when trying to draw a scene from the tab clicked you will want to use a render function inside the TabBarIOS.Item object, react native provides some good examples of how to do this in the documentation: https://facebook.github.io/react-native/docs/tabbarios.html
I would highly recommend placing a navigator for each object which allows you to have much more control over the scene changes:
<TabBarIOS.Item
systemIcon='history'
title= 'Jure1'
selected={this.state.selectedTab === 'tabOne'}
onPress={() => this.setTab('tabOne')}>
<View style = {{flex:1}}>
<Navigator
renderScene={this._renderScene}
/>
</View>
</TabBarIOS.Item>

Related

React Native: How to call a function from another component

I am making a simple app to practice using modals. I have my modal component in a separate file from App.js. I have a button inside the modal and outside of the modal that should toggle the visibility of the modal. To handle the visibility toggle, I have a method in App.js, setVisibility, that takes in a boolean arg and sets the isVisibility state. When I had the modal component defined within App.js earlier everything was working fine, but I'm not sure about accessing and setting the state of a component from another file.
My modal component:
import React, { Component } from "react";
import { View, Modal, TouchableHighlight, Text } from 'react-native';
export default class AppModal extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: this.props.isVisible
}
this.toggleVisibility = this.toggleVisibility.bind(this);
}
toggleVisibility(show) {
this.props.setVisibility(show);
}
render() {
return (
<View>
<Modal
animationType='slide'
visible={this.state.isVisible}
onRequestClose={() => this.toggleVisibility(false)}
>
<View style={{alignItems: 'center', justifyContent: 'center', flex: 1}}>
<Text>Inside the modal</Text>
<TouchableHighlight style={{padding: 10}} onPress={() => this.toggleVisibility(false)} >
<Text>Press me</Text>
</TouchableHighlight>
</View>
</Modal>
</View>
)
}
}
My app.js:
import React, { Component } from 'react';
import { Text, View, TouchableHighlight } from 'react-native';
import AppModal from './AppModal'
export default class App extends Component {
constructor(props) {
super(props);
this.state = {
isVisible: false
}
this.setVisibility = this.setVisibility.bind(this);
}
setVisibility(show) {
this.setState({
isVisible: show
})
}
render() {
return (
<View style={{flex: 1}}>
<AppModal toggle={this.setVisibility} isVisible={this.state.isVisible} />
<View style={{justifyContent: 'center', alignItems: 'center', flex: 1}}>
<Text>Outside of the modal</Text>
<TouchableHighlight style={{padding: 10}} onPress={() => {this.setVisibility(true); console.log(this.state);}} >
<Text>Press me</Text>
</TouchableHighlight>
</View>
</View>
)
}
}
Now I get an error when I press the button in the modal which tells me that 'this.props.setVisibility is not a function'.
Please let me know if I can explain my question better. Thank you in advance!
You send the toggling callback method as toggle={this.setVisibility}, not setVisibility={this.setVisibility}, so your callback must be:
toggleVisibility(show) {
this.props.toggle(show);
}

Touchable Opacity not responding in stack navigator screen - React Native

I'm building a React Native app, it uses React Navigation. I use TouchableOpacity throughout the app, however, in a stack navigator screen, it doesn't seem to work at all. Touching the element doesn't change the opacity and the onpress function doesn't work. The screen itself displays fine and all other screens in my app have TouchableOpacity's that work fine.
Using button doesn't respond either, I'm thinking this is a react navigation issue potentially? There is no issues transitioning to the screen though?
Here is my screen;
import React, {Component} from 'react';
import { View, Text, TouchableOpacity, Alert, Button} from 'react-native';
class RaceScreen extends React.Component {
constructor(props) {
super(props);
this.state = {
}
}
render() {
return (
<View style={{ flex: 1, alignItems: 'center', backgroundColor:'rgba(30,30,30,0.98)'}}>
<TouchableOpacity onPress = {() => console.log('Hello')}>
<View style={{ margin:50, height:100, width: 200, backgroundColor:'red', alignItems:'center', justifyContent:'center' }}>
<Text style={{ color:'white' }}>
Go back
</Text>
</View>
</TouchableOpacity>
<Button title="Go back button" onPress = {() => console.log('Hello')}>
</Button>
</View>
);
}
}
export default RaceScreen
I've found that the Touchable components typically don't respond well to text children. You simply need to wrap it inside a View:
import React, {Component} from 'react';
import { View, Text, TouchableOpacity, Alert} from 'react-native';
export default class RaceScreen extends React.Component {
render() {
return (
<View style={{ flex: 1, alignItems: 'center', backgroundColor:'rgba(30,30,30,0.98)'}}>
<TouchableOpacity onPress = {() => console.log('Hello')}>
<View style={{ margin:50, height:100, width: 200, backgroundColor:'red', alignItems:'center', justifyContent:'center' }}>
<Text style={{ color:'white' }}>
Go back
</Text>
</View>
</TouchableOpacity>
</View>
);
}
}
I finally figured it out. In the createStackNavigator method from react-navigation, transparentCard:true is a deprecated property and was causing the bug. I was using version 3 documentation on a version 4 package of react navigation.
Looking at there site, they have just released version 5 which is great!
A note to the less experienced developers like myself, making sure you're aware of the version of each package you are using is critical for some of these difficult bugs. Don't let it get you down though, react native is elite!

React Native - Animate width shrink

In the header of my React Native app, I have a conditional icon and a Searchbar.
static navigationOptions = ({ navigation }) => {
const { params = {} } = navigation.state;
return {
headerTitle: (
<View
style={{
flex: 1,
backgroundColor: Platform.OS === 'ios' ? '#e54b4d' : '',
alignItems: 'center',
flexDirection: 'row',
paddingHorizontal: 10,
height: StatusBar.currentHeight,
}}>
{params.isIconTriggered && <Icon name="chevron-left" size={28} />}
<SearchBar
round
platform={'default'}
placeholder="Search"
containerStyle={{
flex: 1,
backgroundColor: 'transparent',
}}
/>
</View>
),
headerStyle: {
backgroundColor: '#e54b4d',
},
};
};
Normally the Searchbar will take the full width of the header which is what I want. If the condition isIconTriggered is true, an icon will appear in front of the Searchbar and the width of the SearchBar will shrink enough so that the icon is visible next to it.
However, there is no transition or animation when this happens and it does not feel nor look nice. I would like to add an animation to the Searchbar so the width shrinks gradually and smoothly when the condition is triggered and the icon appears.
Is that possible to achieve and how can I achieve this?
Try to learn Animated API of react native.
Here is how i done it with button trigger.
import React, {Component} from 'react';
import {StyleSheet, View, TextInput , Button, SafeAreaView, Animated} from 'react-native';
import FA from 'react-native-vector-icons/FontAwesome5'
const AnimatedIcon = Animated.createAnimatedComponent(FA)
// make your icon animatable using createAnimatedComponent method
export default class Application extends Component {
animVal = new Animated.Value(0);
// initialize animated value to use for animation, whereas initial value is zero
interpolateIcon = this.animVal.interpolate({inputRange:[0,1], outputRange:[0,1]})
interpolateBar = this.animVal.interpolate({inputRange:[0,1],outputRange:['100%','90%']})
// initialize interpolation to control the output value that will be passed on styles
// since we will animate both search bar and icon. we need to initialize both
// on icon we will animate the scale whereas outputRange starts at 0 end in 1
// on search bar we will animate width. whereas outputRange starts at 100% end in 90%
animatedTransition = Animated.spring(this.animVal,{toValue:1})
// we use spring to make the animation bouncy . and it will animate to Value 1
clickAnimate = () => {
this.animatedTransition.start()
}
// button trigger for animation
//Components that will use on Animation must be Animated eg. Animted.View
render() {
return (
<SafeAreaView>
<View style={styles.container}>
<View style={styles.search}>
{/* our icon */}
<Animated.View style={{width: this.interpolateBar}}>
<TextInput placeholder='search here' style={styles.input}/>
</Animated.View>
<AnimatedIcon name='search' size={28} style={{paddingLeft: 10,paddingRight:10, transform:[{scale: this.interpolateIcon}]}}/>
</View>
<Button title='animate icon' onPress={this.clickAnimate}/>
</View>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
container: {
backgroundColor:'#F79D42',
// flex: 1,
height:'100%',
paddingTop:20,
flexDirection: 'column',
// justifyContent: 'center',
alignItems:'center'
},
input:{
width: '100%',
height:40,
backgroundColor:'gray',
textAlign:'center'
},
search:{
flexDirection:'row-reverse',
width:'90%',
height:40,
alignItems:'center'
}
});
Solution using react-native-elements SearchBar component.
Wrapped the SearchBar Component inside Animated.View.
to explicitly animate the search bar
Like This:
<Animated.View style={{width: this.interpolateBar}}>
<SearchBar
placeholder="Type Here..."
containerStyle={{width: '100%'}}
/>
</Animated.View>
You can achieve this using Animated API of React Native.
You can check this tutorial for an overview of changing the size of elements with animation.
React-Native-Animatable is super cool!
Try this one out:
Create A custom animation object
import * as Animatable from 'react-native-animatable';
Animatable.initializeRegistryWithDefinitions({
const myAnimation = {
from: {
width: 200
},
to: {
width: 100
}
}
})
Use is as Animation value within a view or as a reference within a function call.
Within a view:
<Animatable.View useNativeDriver animation={myAnimation}/>
As a reference variable:
<Animatable.View useNativeDriver ref={ref=>(this.testAnimation = ref)}/>
Method:
testMethod = () => {
this.testAnimation.myAnimation();
}

Using react-native-modalbox in ListView causes modalbox to only fill the list item space instead of full screen?

When I use the package react-native-modalbox with a FlatList (each list item can spawn a distinct modal when tapped), the modal that is spawned only fills the area of the list item instead of going full screen like it normally should.
A working snack that shows the issue is here:
https://snack.expo.io/BkICbjwWQ
For completeness I'll paste the code in here as well:
import React, { Component } from 'react';
import { Text, View, StyleSheet, FlatList, Button } from 'react-native';
import { Constants } from 'expo';
import Modal from "react-native-modalbox";
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-elements'; // Version can be specified in package.json
export default class App extends Component {
render() {
let myRefs = [];
return (
<View style={styles.container}>
<FlatList
data={[{key: 'a'}, {key: 'b'}]}
renderItem={({item}) => <View>
<Modal
style={[styles.modal]}
ref={(modalItem) => {myRefs[item.key] = modalItem;} }
swipeToClose={true}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>Basic modal</Text>
</Modal><Text>{item.key}</Text><Button title="Basic Modal" onPress={() => myRefs[item.key].open()} style={styles.btn}>Basic modal</Button></View>}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
});
I basically have the same question/problem as (react-native-modalbox stuck in child component context) but there was no answer to that question and he did not provide enough details with a minimum working example.
Your modal component is inside the rendered item. This causes it to be bound to the item. Although you can fix this issue by using appropriate props or some custom styling, this is not efficient. You would have 1000 modal components if you had 1000 items in your list.
You should move out your modal component and make it sibling to the FlatList. This way you would have only single modal. You can change the contents of the modal with a state value.
Sample
export default class App extends Component {
render() {
let myRefs = [];
return (
<View style={styles.container}>
<Modal
style={[styles.modal]}
ref={modalItem => { myRefs['modal'] = modalItem; }}
swipeToClose={true}
onClosed={this.onClose}
onOpened={this.onOpen}
onClosingState={this.onClosingState}>
<Text style={styles.text}>Basic modal</Text>
</Modal>
<FlatList
data={[{ key: 'a' }, { key: 'b' }]}
renderItem={({ item }) => (
<View>
<Text>{item.key}</Text>
<Button
title="Basic Modal"
onPress={() => myRefs['modal'].open()}
style={styles.btn}>
Basic modal
</Button>
</View>
)}
/>
</View>
);
}
}

Conditional Rendering of child elements in React

I am trying to write a reusable Header Component in React-Native. I want to write it in a ways that the left and right button can be passed as child components. To know where to render which button I want to pass a prop like rightIcon or leftIcon. However I don't know how to access these props.
This is my App.js file
import React from 'react';
import {StyleSheet, TouchableHighlight, View} from 'react-native';
import Header from "./src/Header";
import {Ionicons} from '#expo/vector-icons';
export default class App extends React.Component {
render() {
return (
<View style={styles.container}>
<Header headerText={"Barcode Scanner"}>
<TouchableHighlight righticon>
<Ionicons name="md-barcode" size={36} color="white"></Ionicons>
</TouchableHighlight>
</Header>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
});
And this is the Header Component
import React from 'react';
import {Text, View} from 'react-native';
export default class Header extends React.Component {
render() {
const {textStyle, viewStyle, rightButton} = styles;
return (
<View style={viewStyle}>
<Text style={textStyle}>{this.props.headerText}</Text>
<View style={rightButton}>
{this.renderRightChild()}
</View>
</View>
);
}
renderRightChild = () => {
console.log("Check if rightIcon Prop is set");
}
}
const styles = {
viewStyle: {
backgroundColor: '#5161b8',
justifyContent: 'center',
alignItems: 'center',
height: 80,
paddingTop: 25,
shadowColor: '#000',
shadowOffset: {width: 0, height: 2},
shadowOpacity: 0.2,
elevation: 2,
position: 'relative'
},
textStyle: {
color: '#fff',
fontSize: 20
},
rightButton: {
position: 'absolute',
top:
35,
right:
20
}
}
;
I already tried to use React.Children.toArray but this always throws an error that the request entity is too large.
Thanks for all the answers
I guess you can always use a render prop that way you can not only decide whether to render left/right icon component but the component rendering the icon does not even have to know what to render:
The term “render prop” refers to a simple technique for sharing code
between React components using a prop whose value is a function.
return (
<View style={styles.container}>
<Header
headerText={"Barcode Scanner"}
renderRightIcon={() => (
<TouchableHighlight righticon>
<Ionicons name="md-barcode" size={36} color="white" />
</TouchableHighlight>
)}
/>
</View>
);
Then you can use call the right icon as a function:
return (
<View style={viewStyle}>
<Text style={textStyle}>{this.props.headerText}</Text>
{renderLeftIcon && (
<View style={leftButton}>
{renderLeftIcon()}
</View>)
}
{renderRightIcon && (
<View style={rightButton}>
{renderRightIcon()}
</View>)
}
</View>
);
You render both components, the right and left and you put an if condition inside state.
Header Component render method
render() {
const { leftOrRight } = this.props // right - true, left - false
return(
...
{ leftOrRight ? <RightIcon /> : <LeftIcon />}
);
}
Inside Component that calls Header
import Header from './somepath ...';
class Something extends React.Component {
this.state = { leftOrRight }
render() {
return(
<Header leftOrRight = {this.state.LeftOrRight}/>
);
}
}
You could have a function that sets leftOrRight in your parent class
One way to do this is write a Header Component and pass all the things, as props, which you can then access them in Header Components Props like..
<Header title="HeaderTitle"
leftButtonTitle="LeftButton"
rightButton={canBeAObjectWithSomeInfo}
leftButtonClick={handleClick} />
and then in your header component(can be class or a function)
const Header = ({}) => (
<View>
<View onPress={this.props.handleClick}>{this.props.leftButton}</View>
<View>{this.props.title}</View>
<View onPress={this.props.handleRightClick}>{this.props.rightButton}</View>
</View>
)
something like this you can have and then you can design header accordingly

Categories

Resources