Place a view relative to other view in React Native - react-native

I try to create something like this:
As you see, the text should be placed relative to the marker representing the current day (centered above). When you're at the first few and the last few days, it should stay inside the frame rather than being centered above the tall marker.
How do I achieve this?
This is my current code:
Component
export default class DateLine extends Component {
render() {
const dots = (<View style={Styles.dotsContainer} >
{[...Array(DaysInCurrentMonth())].map((x, i) =>
<View key={i.toString()} style={[Styles.dot, (CurrentDayInMonth() === (i + 1) ? Styles.tallDot : null), (CurrentDayInMonth() < (i + 1) ? Styles.grayDot : null)]} />
)}
</View>);
return (
<View style={Styles.container}>
<Text style={Styles.text}>{GetDateWithMonthAsText(Date()).toUpperCase()}</Text>
{dots}
</View>
);
}
}
Style:
export default StyleSheet.create({
container: {
alignSelf: 'stretch',
marginHorizontal: 15
},
dotsContainer: {
height: 10,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-end'
},
dot: {
backgroundColor: Colors.darkBlueGrey,
height: 5,
width: 5,
borderRadius: 2.5
},
tallDot: {
height: 10
},
grayDot: {
backgroundColor: Colors.pinkishGreyTwo
},
text: {
fontWeight: '600'
}
});

Not a perfect but fast solution that you can easily improve:
export default class DateLine extends Component {
_renderDay (x, i) {
let currentDay = CurrentDayInMonth();
if(currentDay > (i + 1)) {
return <PassedDay />;
}
if(currentDay === (i + 1)) {
return <ActiveDate dateTitle={ GetDateWithMonthAsText(Date()).toUpperCase() } />;
}
return <InactiveDay />;
}
render() {
return (
<View style={ Styles.container }>
<View style={ Styles.dotsContainer } >
{[...Array(DaysInCurrentMonth())].map(this._renderDay)}
</View>
</View>
);
}
}
export function PassedDay() {
return (<View>
<View style={{backgroundColor: '#1f1749', width: 5, height: 5, borderRadius: 5, marginHorizontal: 2.5,}} />
</View>);
}
export function ActiveDate(dateTitle) {
return (<View style={{position: 'relative'}}>
<View style={{position: 'absolute', minWidth: 70, bottom: 15, left: 0, right: 0,}}>
<Text>
{dateTitle}
</Text>
</View>
<View style={{backgroundColor: '#1f1749', width: 5, height: 10, borderRadius: 5, marginHorizontal: 2.5,}} />
</View>);
}
export function InactiveDay() {
return (<View>
<View style={{backgroundColor: 'gray', width: 5, height: 5, borderRadius: 5, marginHorizontal: 2.5,}} />
</View>);
}
The point is: you can manipulate your 'DOM' via react-native's positions in same manner as html.
Hope, it will help.

Related

Wrapped TouchableNativeFeedback component with View doesn't show anything on screen with flex:1 on both

The style is added to the wrapping view because TouchableNativeFeedback didn't work either. I have tried alignItems, justifyContent, flexGrow and other experimentations but still doesn't behave properly. GridItem style is the one I want to use but nothing shows in the screen; not even misaligned contents or something similar.
const CategoryGridTile = props => {
let TouchableCmp = TouchableOpacity;
if (Platform.OS == 'android' && Platform.Version >= 21) {
TouchableCmp = TouchableNativeFeedback;
}
return (
<View style={styles.gridItem}>
<TouchableCmp
style={{ flex: 1 }}
onPress={props.onSelect}
>
<View style={{ ...styles.container, ...{ backgroundColor: props.color } }}>
<Text style={styles.title} numberOfLines={2}>{props.title}</Text>
</View>
</TouchableCmp>
</View>
);
};
const styles = StyleSheet.create({
gridItem: {
flex: 1,
margin: 15,
height: 150,
borderRadius:10,
overflow:'hidden'
},
container: {
flex: 1,
borderRadius: 10,
shadowColor: 'black',
shadowOpacity: 0.26,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 10,
elevation: 3,
padding: 15,
justifyContent: 'flex-end',
alignItems: 'flex-end'
},
title: {
fontFamily: 'open-sans-bold',
fontSize: 18,
textAlign: 'right'
}
});
can you try this...
TouchableCmp is working
const CategoryGridTile = () => {
let TouchableCmp = TouchableOpacity;
if (Platform.OS == 'android' && Platform.Version >= 21) {
TouchableCmp = TouchableNativeFeedback;
}
return (
<View style={styles.gridItem}>
<TouchableCmp style={{flex: 1}} onPress={() => alert('onpress')}>
<View style={{...styles.container, ...{backgroundColor: 'pink'}}}>
<Text style={styles.title} numberOfLines={2}>
text here
</Text>
</View>
</TouchableCmp>
</View>
);
};
I've removed prop elements to check, you can add later if this works for you

I can't get any result or errors when i'm drawing signatures on expo app

i'm creating a small react native app using expo, I am trying to run the example given at https://www.npmjs.com/package/react-native-signature-canvas for drawing signatures, i'm getting an interface but i can't draw and i'm not getting any result.
My code:
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import Signature from 'react-native-signature-canvas';
class SignatureScreen extends React.Component {
constructor(props) {
super(props);
this.state = { signature: null };
}
handleSignature = signature => {
this.setState({ signature });
};
render() {
const style = `.m-signature-pad--footer
.button {
background-color: blue;
color: #FFF;
}`;
return (
<View style={{ flex: 1 }}>
<View style={styles.preview}>
{this.state.signature ? (
<Image
resizeMode={"contain"}
style={{ width: 335, height: 114 }}
source={{ uri: this.state.signature }}
/>
) : null}
</View>
<Signature
onOK={this.handleSignature}
descriptionText="Sign"
clearText="Clear"
confirmText="Save"
webStyle={style}
/>
</View>
);
}
}
export default SignatureScreen;
const styles = StyleSheet.create({
preview: {
width: 335,
height: 114,
backgroundColor: "#F8F8F8",
justifyContent: "center",
alignItems: "center",
marginTop: 15
},
previewText: {
color: "#FFF",
fontSize: 14,
height: 40,
lineHeight: 40,
paddingLeft: 10,
paddingRight: 10,
backgroundColor: "#69B2FF",
width: 120,
textAlign: "center",
marginTop: 10
}
});
Am I missing something?
could you try this code?
handleSignature = signature => {
console.log(signature);
this.setState({ signature });
};
...
render() {
return (
<View style={{ flex: 1 }}>
<View style={styles.preview}>
{this.state.signature ? (
<Image
resizeMode={"contain"}
style={{ width: 335, height: 114 }}
source={{ uri: this.state.signature }}
/>
) : null}
</View>
<SignatureScreen onOK={this.handleSignature} />
</View>
);
}
}

React Native Flatlist overlapping footer?

I'm getting started with React Native and writing an app. The problem I'm having a problem with the layout/styling. This is a simplified version to show my difficulty.
The Flatlist doesn't know where it's bottom is, it is overlapping the Footer component. I've messed around with it but can't get it to work properly.
import React, { Component } from 'react'
import { FlatList, StyleSheet, Text, View } from 'react-native'
class Header extends Component {
render() {
return (
<View style={styles.headerContainer}>
<Text style={styles.headerText}> </Text>
<Text style={styles.headerText}>
This is the page header!
</Text>
</View>
)
}
}
class Footer extends Component {
render() {
return (
<View style={styles.footerContainer}>
<Text style={styles.footerText}>
This is the page footer!
</Text>
</View>
)
}
}
let myData = [];
for (let i=1; i<=30; i++) {
myData.push({ key: ('My item ' + i) })
}
export default class App extends Component {
render() {
return (
<View style={styles.container}>
<Header />
<View style={styles.listWrapper}>
<FlatList
contentContainerStyle={styles.listContainer}
data={myData}
renderItem={({item}) => <Text style={styles.listItem} >{item.key}</Text>}
contentInset={{top: 0, left: 0, bottom: 50, right: 0}}
/>
</View>
<Footer />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'pink'
},
headerContainer: {
backgroundColor: '#333',
height: 60,
},
headerText: {
textAlign: 'center',
fontSize: 20,
color: '#999'
},
listWrapper: {
flex: 1
},
listContainer: {
backgroundColor: 'lightblue',
},
listItem: {
color: 'red',
fontSize: 28
},
footerContainer: {
backgroundColor: '#333',
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
flex: 1,
height: 20
},
footerText: {
textAlign: 'center',
fontSize: 14,
color: '#999'
}
})
The only solution I have is to add the prop:
ListFooterComponent={<View style={{ height: 20 }} />}
to the Flatlist, giving it the same height as the Footer, so it would take up that space. That works, but it seems inelegant. Is there a better way to do it, like with the CSS?
Thanx.

TextInput length counter in react-native

I have a TextInput with maxLength 100 in my scene, and I want to add a counter below which shows something like "38/100", auto-updating with 'onChangeText'.
So I have to figure out the length of the input value, somehow store it in this.state.textLength while storing the value itself to this.state.text, but I don't know how to do this in "onChangeText = {(text) => ...}" function.
Here is my simplified code:
export class RequestScene extends Component {
constructor() {
super();
this.state={
text: '',
textLength: 0,
category: '',
time: ''
};
}
render(){
return(
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center'
}}>
<View style={{
height: 200
}}>
<TextInput style={{
height: 200,
width: 360,
borderColor: 'lightgray',
borderWidth: 1,
padding: 3,
borderRadius: 3,
fontSize: 24}}
maxLength={100}
placeholder='무슨 상황인지 간단하게 써주세요'
multiline={true}
// this is where I am stuck. What should I do with 'textLength'?
onChangeText={
(text)=>this.setState({text})
(text)=>this.setState({textLength})
}
/>
<Text style={{
fontSize:10,
color:'lightgrey',
textAlign: 'right'
}}>
// currently this counter only shows '0/100'
{this.state.textLength}/100
</Text>
The onChangeText() function returns a string. You can do something like:
const maxLength = 100;
this.setState({
textLength: maxLength - text.length,
text, // same as `text: text`
});
To make your code easier to read, you can call a separate method within your onChangeText handler which updates textLength the following way:
export class RequestScene extends Component {
constructor() {
super();
this.maxLength = 100;
this.state={
textLength: 0,
};
}
onChangeText(text){
this.setState({
textLength: this.maxLength - text.length
});
}
render(){
return (
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center'
}}>
<View style={{
height: 200
}}>
<TextInput style={{
height: 200,
width: 360,
borderColor: 'lightgray',
borderWidth: 1,
padding: 3,
borderRadius: 3,
fontSize: 24}}
maxLength={100}
placeholder='무슨 상황인지 간단하게 써주세요'
multiline={true}
onChangeText={this.onChangeText.bind(this)}
/>
<Text style={{
fontSize:10,
color:'lightgrey',
textAlign: 'right'
}}>
// currently this counter only shows '0/100'
{this.state.textLength}/100
</Text>
</View>
</View>
);
}
}
To get length of input field try
handleEmailOtp = emailOtpString => {
this.setState({emailOtp: emailOtpString});
const otpLength = emailOtpString.length.toString(); //here
otpLength == 6
? this.setState({otpTyped: true})
: this.setState({otpTyped: false});
};
import React, { Component } from 'react'
import { View, Text, TextInput } from 'react-native'
export default class App extends Component {
state = {
text: ''
}
render() {
return (
<View style={{ padding: 10 }}>
<TextInput style={{ borderWidth: 1 }} numberOfLines={3} maxLength={100} multiline={true} onChangeText={(text) => this.setState({ text: text })} />
<Text>{100 - this.state.text.length}/100 Characters</Text>
</View>
)
}
}

Not able to refer to drawer layout in react native

I have my Js file like this.
"use strict"
var React = require('react-native')
var {
AppRegistry,
Component,
StyleSheet,
Text,
View,
TouchableNativeFeedback,
Image,
DrawerLayoutAndroid,
Navigator,
ListView,
ToolbarAndroid
} = React;
var ToolbarAndroid = require('ToolbarAndroid');
var Drawer = require('react-native-drawer');
import Screen2 from './Screen2';
import Screen3 from './Screen3';
class Screen1 extends Component {
openDrawer(){
this.refs['DRAWER'].openDrawer()
}
_handlePress(screen_name,loggedIn) {
this.refs.DRAWER.closeDrawer(),
this.refs.navigator.push(
{id: screen_name,
})
}
renderScene(route, navigator) {
switch(route.id){
case 'Screen1': return (
DrawerLayoutAndroid
drawerWidth={300}
ref={'DRAWER'}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => navigationView}>
<View style={styles.container}>
<ToolbarAndroid
navIcon={require('image!ic_menu_white')}
titleColor="white"
style={styles.toolbar}
onIconClicked={() => this.openDrawer()}
onActionSelected={this.onActionSelected} />
</View>
<ListView contentContainerStyle={styles.list}
dataSource={this.state.dataSource}
renderRow={this.renderItem.bind(this)}
/>
</DrawerLayoutAndroid>
);
case 'Screen2': return (<Screen2 navigator={navigator} />)
case 'Screen3': return (<Screen3 navigator={navigator} />)
}
}
render(){
navigationView = (
<View style={styles.header}>
<View style={styles.HeadingContainer}>
<TouchableNativeFeedback>
<View style={styles.HeadingItem}>
<Text style={styles.menuText}>
Welcome!
</Text>
<Text style={styles.menuText}>
Guest
</Text>
</View>
</TouchableNativeFeedback>
</View>
<View style={{flex: 4, backgroundColor: 'white'}}>
<TouchableNativeFeedback onPress={this._handlePress.bind(this,'Screen1')}>
<View style={styles.menuContainer}>
<Text style={styles.menu}>Albums</Text>
<Image
source={require('image!ic_menu_arrow')}
style={{flex : 1,width: 10, height: 10, margin: 20}} />
</View>
</TouchableNativeFeedback>
<TouchableNativeFeedback onPress={this._handlePress.bind(this,'Screen2')}>
<View style={styles.menuContainer}>
<Text style={styles.menu}>Member Validation</Text>
<Image
source={require('image!ic_menu_arrow')}
style={{flex : 1,width: 10, height: 10, margin: 20}} />
</View>
</TouchableNativeFeedback>
<TouchableNativeFeedback onPress={this._handlePress.bind(this,'Screen3')}>
<View style={styles.menuContainer}>
<Text style={styles.menu}>Settings</Text>
<Image
source={require('image!ic_menu_arrow')}
style={{flex : 1,width: 10, height: 10, margin: 20}} />
</View>
</TouchableNativeFeedback>
</View>
</View>
);
return(
<
<Navigator
initialRoute={{id: 'Screen1'}}
renderScene={this.renderScene.bind(this)}
ref='navigator'
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}} />
);
}
}
var styles = StyleSheet.create({
list: {
justifyContent: 'center',
flexDirection: 'row',
flexWrap: 'wrap'
},
renderLoading: {
padding: 30,
marginTop: 65,
alignItems: 'center'
},
container: {
flexDirection: 'column',
backgroundColor: '#FAFAFA',
},
backgroundImage: {
flex: 1,
resizeMode: 'cover', // or 'stretch'
},
rightContainer: {
flex: 1,
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
margin:20
},
movie: {
height: 150,
flex: 1,
alignItems: 'center',
flexDirection: 'column',
},
titles: {
fontSize: 10,
marginBottom: 8,
width: 90,
textAlign: 'center',
},
header: {
flex: 1,
flexDirection: 'column',
},
menuContainer: {
flexDirection: 'row',
},
HeadingItem: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
padding: 10,
},
HeadingContainer: {
flex: 1,
backgroundColor: '#00a2ed',
},
menuText: {
fontSize: 14,
color: 'black',
},
menu: {
flex: 4,
fontSize: 12,
color: 'black',
margin: 20,
},
toolbar: {
backgroundColor: '#00a2ed',
height: 56,
},
});
export default Screen1;
Now I am not able to refer to Drawer reference variable 'DRAWER'.It gives me error undefined is not an object.Not able to open or close drawer.
I want DrawerLayout for Screen1 only so I am rendering it in RenderScene method.
If i implement DrawerLayout in render method,then I am able to refer to reference Drawer.
Can we create reference in render method only.IF yes how to solve this problem.
Accessing drawer object using state object of component.
"use strict"
var React = require('react-native')
var {
AppRegistry,
Component,
StyleSheet,
Text,
View,
TouchableNativeFeedback,
Image,
DrawerLayoutAndroid,
Navigator,
ListView,
ToolbarAndroid
} = React;
var ToolbarAndroid = require('ToolbarAndroid');
var Drawer = require('react-native-drawer');
import Screen2 from './Screen2';
import Screen3 from './Screen3';
class Screen1 extends Component {
constructor(props) {
super(props);
this.state = {
drawer: null,
};
}
setDrawer = (drawer) => {
this.setState({
drawer
});
};
openDrawer(){
this.state.drawer.openDrawer()
}
_handlePress(screen_name,loggedIn) {
this.state.drawer.closeDrawer(),
this.refs.navigator.push(
{id: screen_name,
})
}
renderScene(route, navigator) {
switch(route.id){
case 'Screen1':
const { drawer } = this.state;
return (
<DrawerLayoutAndroid
drawerWidth={300}
ref={(drawer) => { !this.state.drawer ? this.setDrawer(drawer) : null }}
drawerPosition={DrawerLayoutAndroid.positions.Left}
renderNavigationView={() => navigationView}>
<View style={styles.container}>
<ToolbarAndroid
navIcon={require('image!ic_menu_white')}
titleColor="white"
style={styles.toolbar}
onIconClicked={() => this.openDrawer()}
onActionSelected={this.onActionSelected} />
</View>
<ListView contentContainerStyle={styles.list}
dataSource={this.state.dataSource}
renderRow={this.renderItem.bind(this)}
/>
</DrawerLayoutAndroid>
);
case 'Screen2': return (<Screen2 navigator={navigator} />)
case 'Screen3': return (<Screen3 navigator={navigator} />)
}
}
render(){
navigationView = (
<View style={styles.header}>
<View style={styles.HeadingContainer}>
<TouchableNativeFeedback>
<View style={styles.HeadingItem}>
<Text style={styles.menuText}>
Welcome!
</Text>
<Text style={styles.menuText}>
Guest
</Text>
</View>
</TouchableNativeFeedback>
</View>
<View style={{flex: 4, backgroundColor: 'white'}}>
<TouchableNativeFeedback onPress={this._handlePress.bind(this,'Screen1')}>
<View style={styles.menuContainer}>
<Text style={styles.menu}>Albums</Text>
<Image
source={require('image!ic_menu_arrow')}
style={{flex : 1,width: 10, height: 10, margin: 20}} />
</View>
</TouchableNativeFeedback>
<TouchableNativeFeedback onPress={this._handlePress.bind(this,'Screen2')}>
<View style={styles.menuContainer}>
<Text style={styles.menu}>Member Validation</Text>
<Image
source={require('image!ic_menu_arrow')}
style={{flex : 1,width: 10, height: 10, margin: 20}} />
</View>
</TouchableNativeFeedback>
<TouchableNativeFeedback onPress={this._handlePress.bind(this,'Screen3')}>
<View style={styles.menuContainer}>
<Text style={styles.menu}>Settings</Text>
<Image
source={require('image!ic_menu_arrow')}
style={{flex : 1,width: 10, height: 10, margin: 20}} />
</View>
</TouchableNativeFeedback>
</View>
</View>
);
return(
<
<Navigator
initialRoute={{id: 'Screen1'}}
renderScene={this.renderScene.bind(this)}
ref='navigator'
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}} />
);
}
}
var styles = StyleSheet.create({
list: {
justifyContent: 'center',
flexDirection: 'row',
flexWrap: 'wrap'
},
renderLoading: {
padding: 30,
marginTop: 65,
alignItems: 'center'
},
container: {
flexDirection: 'column',
backgroundColor: '#FAFAFA',
},
backgroundImage: {
flex: 1,
resizeMode: 'cover', // or 'stretch'
},
rightContainer: {
flex: 1,
},
year: {
textAlign: 'center',
},
thumbnail: {
width: 53,
height: 81,
},
listView: {
paddingTop: 20,
backgroundColor: '#F5FCFF',
margin:20
},
movie: {
height: 150,
flex: 1,
alignItems: 'center',
flexDirection: 'column',
},
titles: {
fontSize: 10,
marginBottom: 8,
width: 90,
textAlign: 'center',
},
header: {
flex: 1,
flexDirection: 'column',
},
menuContainer: {
flexDirection: 'row',
},
HeadingItem: {
flex: 1,
flexDirection: 'column',
alignItems: 'center',
padding: 10,
},
HeadingContainer: {
flex: 1,
backgroundColor: '#00a2ed',
},
menuText: {
fontSize: 14,
color: 'black',
},
menu: {
flex: 4,
fontSize: 12,
color: 'black',
margin: 20,
},
toolbar: {
backgroundColor: '#00a2ed',
height: 56,
},
});
export default Screen1;
The best and easy solution of your problem is make separate file for Navigating different scenes which contains only Navigator component, there you can navigate different scenes with suitable condition.
Make different files as:
1. navigator.js
2. screen1.js
3. screen2.js
in navigator.js keep the code as
<Navigator
initialRoute={{id: 'Screen1'}}
renderScene={this.renderScene.bind(this)}
ref='navigator'
configureScene={(route) => {
if (route.sceneConfig) {
return route.sceneConfig;
}
return Navigator.SceneConfigs.FloatFromRight;
}} />
also do switch case statement here:
renderScene(route, navigator) {
switch(route.id){
case 'Screen1': return (<Screen1 navigator={navigator}>
);
case 'Screen2': return (<Screen2 navigator={navigator} />)
case 'Screen3': return (<Screen3 navigator={navigator} />)
}
Then make individual component of screen1, screen2, screen3 and place all components like
<DrawerLayout><Toolbar/><ListView/></DrawerLayout>
in which screen you want in their respective render() function, also you can call openDrawer() like function in your specific screen.
This way you can reduced your messy code organization and complete your code.
Hope this will help your problem.