React Native v0.42 flexbox error in ScrollView - android

My React Native render code is:
<ScrollView
contentContainerStyle={{
minHeight: 100,
flexDirection: "column",
alignItems: "stretch",
marginTop: 16,
}}
alwaysBounceVertical={false}
showsVerticalScrollIndicator={false}
>
<View style={{flex: 0.5, backgroundColor: "green"}}>
<View style={{height: 10, backgroundColor: "yellow"}}/>
</View>
<View style={{flex: 0.5, backgroundColor: "blue"}}/>
</ScrollView>
The code above should render 2 views, of height 50 each, top one green and bottom one yellow. Inside the top view, there should be a yellow view of height 10.
Instead, it renders the top view with height 60 and bottom box with height 50. The top box has a box inside with height 10. The colours are all correct.
However, if I change the height:10 part to height:"20%", it works all fine.
How can I solve this problem?
Thanks.

You could either position your yellow view absolutely:
<ScrollView
contentContainerStyle={{
minHeight: 100,
flexDirection: "column",
alignItems: "stretch",
marginTop: 16,
}}
alwaysBounceVertical={false}
showsVerticalScrollIndicator={false}
>
<View style={{flex: 0.5, backgroundColor: "green"}}>
<View style={{
height: 10,
backgroundColor: "yellow",
position: 'absolute',
top: 0, left: 0, right: 0
}}/>
</View>
<View style={{flex: 0.5, backgroundColor: "blue"}}/>
</ScrollView>
or use a fixed height on the ScrollView:
<ScrollView
contentContainerStyle={{
height: 100,
flexDirection: "column",
alignItems: "stretch",
marginTop: 16,
}}
alwaysBounceVertical={false}
showsVerticalScrollIndicator={false}
>

The solution to this problem is to wrap the "green" view in a component like (I am using typescript):
class VerticalScrollingContentContainer extends
React.PureComponent<{style?: Styles},
{mainViewHeight: number, isMeasured: boolean}> {
constructor(props: any) {
super(props);
this.state = {
mainViewHeight: 0,
isMeasured: false,
};
}
layoutReceived = (width: number, height: number) => {
let newHeight = height > width ? height : width;
this.setState(
oldState => ({mainViewHeight: newHeight, isMeasured: true})
);
}
render() {
let isMeasured = this.state.isMeasured;
let mainViewHeight = this.state.mainViewHeight;
let innerContainerLayout = {
flexDirection: "column",
};
if (!isMeasured) {
innerContainerLayout = {
...innerContainerLayout,
flex: 1
};
} else {
innerContainerLayout = {
...innerContainerLayout,
minHeight: mainViewHeight
};
}
return (
<ScrollView
style={{flex: 1}}
contentContainerStyle={innerContainerLayout as any}
alwaysBounceVertical={false}
showsVerticalScrollIndicator={false}>
<View
style={[
{
flexGrow: 1,
alignItems: "flex-start",
flexDirection: "column",
},
this.props.style
]}
onLayout={(e) => {
this.layoutReceived(e.nativeEvent.layout.width, e.nativeEvent.layout.height); }}>
{this.props.children}
</View>
</ScrollView>
);
}
}

Related

ScrollView not Scrolling - ReactNative

I have the following ScrollView, but my attempt just won't scroll. I am not sure what am going about it wrong in my implementation. Hope you can help.
Thank you all in advance.
class RecentMediaUploadsWidget extends Component {
renderImage = (imgURI) => {
return (
<TouchableOpacity>
<View>
<Image
style={styles.imageStyle}
source={{ uri: ("file:///" + imgURI) }}
/>
</View>
</TouchableOpacity>
)
}
render() {
return (
<View style={styles.containerWrapper}>
<ScrollView>
<View style={styles.mainContainerStyle}>{this.props.itemsPaths.map(this.renderImage)}</View>
</ScrollView>
</View>
);
}
}
export default RecentMediaUploadsWidget;
And the styles is showing below
var styles = StyleSheet.create({
containerWrapper: {
flexDirection: 'column',
alignSelf: 'flex-start',
},
mainContainerStyle: {
flexDirection: 'row',
flex: 1,
},
imageStyle: {
width: imgWidth, height: imgWidth,
overflow: "hidden",
alignSelf: 'stretch',
},
})
instead of using style inside <ScrollView> use contentContainerStyle
eg:
<ScrollView
contentContainerStyle={{ flexGrow: 1, width: WIDTH, height: HEIGHT, justifyContent:
'space-between' }}
>

Add "radius" to bottom side of image

This is design that I want to implement for my mobile application:
And this is what is currently accomplished to implement:
Implemented design
As you can see folowing some online examples i manage to curve the picture but its curved on both ends instead of just on the bottom.
This is my style code:
const mainStyle = StyleSheet.create({
container: {
flex: 1,
flexDirection: "column",
backgroundColor: "#d3c586",
alignItems: "center",
justifyContent: "space-between",
},
cardContainer: {
flex: 1,
alignSelf: "center",
backgroundColor: "#d3c586",
alignItems: "center",
justifyContent: "space-between",
overflow: "hidden",
},
cardImageContainer: {
flex: 0.6,
borderRadius: width,
width: width,
height: width,
bottom: 0,
overflow: 'hidden',
},
cardImage: {
height: height / 2,
width: width,
bottom: 0,
marginLeft: 0,
}};
This is a list of items that can be swiped and i render it from this function:
renderItem ({item, index}) {
return (
<View style={mainStyle.cardContainer}>
<View style={mainStyle.cardImageContainer}>
<TouchableOpacity onPress={(event) => this.handleDoubleTap(item)} onLongPress={(event) => this.handlePictureShare(item)}>
<LoadImage style={mainStyle.cardImage} source={{uri: item.url}} thumbnailSource={{uri: item.url}}/>
</TouchableOpacity>
</View>
<View style={mainStyle.cardTextContainer}>
<Text numberOfLines={25} style={{fontSize: 19}}>{item.fact}</Text>
</View>
</View>
)
}
I do not have a lot of experience with CSS since most of my work is on the backend.
Check these links BorderBottomLeftRadius BorderBottomRightRadius
This way you can only give radius bottom of your image.
You can try like this:
import React, { Component } from 'react';
import { View } from 'react-native';
export default class FlexDirectionBasics extends Component {
render() {
return (
// Try setting `flexDirection` to `column`.
<View style={{flex: 1, flexDirection: 'row', alignItems: 'center', justifyContent: 'center'}}>
<View style={{width: 100, height: 100, backgroundColor: 'steelblue', borderBottomColor: 'black', borderBottomEndRadius: 10, borderBottomStartRadius: 10 }} />
</View>
);
}
}

React Native showing text twice in Apple, Once in Android

I have a react native code, using expo, with a graph with text. In Apple, this application is showing it twice. In Android, once.
Here is the code:
import { ScrollView, StyleSheet, Text, View, Alert, Dimensions } from 'react-native';
...
// Charts
import * as scale from 'd3-scale'
import { ProgressCircle, LineChart, XAxis, Grid } from 'react-native-svg-charts';
.... <Other Code> ...
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<View style={{ padding: 10 }}>
<ProgressCircle
style={{ height: 150, width: 150 }}
startAngle={-Math.PI * 0.5}
endAngle={Math.PI * 0.5}
progress={this.state.perFirstTier}
progressColor={constants.BGC_GREEN}
strokeWidth={10}>
{* THIS IS WHAT IS DOUBLED*}
<Text key ='percentage' style={{
position: "absolute",
marginLeft: 65, marginTop: 50
}}>{(this.state.perFirstTier * 100).toFixed(0)}%</Text>
</ProgressCircle>
<View style={{ marginTop: -40, flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={styles.description}>{i18n.t('activityDashboard.firstGoalDesc')}</Text>
{/* Show colored badge if 100%*/}
{this.state.perSecondTier == 1
? <Image style={styles.medalImage} source={require('../../utils/images/silver_medal.png')}></Image>
: <Image style={styles.medalImage} source={require('../../utils/images/grey_medal.png')}></Image>
}
</View>
</View>
Here is an image comparison of Apple versus Android:
Why is this happening, and how can I make it only show once?
Because progress is already declared in the ProgressCircle component, and it's rendered inside it. Just remove the Text component from the ProgressCircle. I guess it has overflow hidden on Android so it's not displayed there.
if all else fails, try adding a rendering condition for iOS platform.
<ProgressCircle
style={{ height: 150, width: 150 }}
startAngle={-Math.PI * 0.5}
endAngle={Math.PI * 0.5}
progress={this.state.perFirstTier}
progressColor={constants.BGC_GREEN}
strokeWidth={10}
>
{/* THIS IS WHAT IS DOUBLED */}
{Platform.OS === 'ios'
? <View />
: (
<View>
<Text
key ='percentage'
style={{
position: "absolute",
marginLeft: 65,
marginTop: 50
}}
>
{(this.state.perFirstTier * 100).toFixed(0)}%
</Text>
</View>
)
}
</ProgressCircle>
I had a similar issue trying to render YAxis as < Text > on iOS14. I used < Text > because had a hard time using YAxis for putting the label at the top of the chart bar.
My specs:
{
"expo": "~39.0.2",
"react-native-svg-charts": "^5.4.0",
"react-native-svg": "12.1.0"
}
Code:
const Values = ({ x, y, data }) => {
return (
data.map((value, index) => {
return (
<Text
key={index}
style={{
color: '#6e6969',
fontSize: 10,
position: 'absolute',
left: x(index) + 1,
top: y(value) - 15
}}
>
{value}
</Text>
)
})
)}
<BarChart
style={styles.chart}
data={data.plot}
spacing={0.2}
svg={{ fill: 'rgba(134, 65, 244, 0.8)' }}
contentInset={{ top: 20, bottom: 20, left: 0, right: 0 }}
>
<Values />
</BarChart>
<XAxis
style={{ marginHorizontal: -10 }}
data={data.plot}
formatLabel={(value, index) => data.labels[index]}
contentInset={{ left: 30, right: 30 }}
svg={{ fontSize: 10, fill: colors.medium }}
/>
Result
What I needed to do was wrapper the < Text > into a < View > and the issue was solved:
Changed code:
const Values = ({ x, y, data }) => {
return (
data.map((value, index) => {
return (
<View key={index}>
<Text
style={{
color: '#6e6969',
fontSize: 10,
position: 'absolute',
left: x(index) + 1,
top: y(value) - 15
}}
>
{value}
</Text>
</View>
)
})
)}
Result
Both codes worked fine on Android, though.

zIndex is not working on android

As I want to overlap this icon with two other Views, as shown in the image. this code is working on IOS platform but not on android. please suggest if there is any solution for Android.
var tabs = ['Activity', 'Files', 'People'];
this.state = {
tabs
};
return (
<Container style={{backgroundColor: '#F5F5F5'}}>
<View style={styles.topStrip}>
{
this.state.tabs.map((tab, index) => (
<View key={index} >
<TouchableOpacity>
<Text style={styles.streamName}>{tab}</Text>
</TouchableOpacity>
</View>
))
}
<View style={{position: 'absolute', backgroundColor: 'transparent', alignItems: 'center', justifyContent: 'center', zIndex: 5, elevation: 24, marginTop: 15, marginLeft: 300}}>
<EIcon size={40} color='#2196f3' name={'circle-with-plus'} />
</View>
</View>
<View style={{zIndex: -1}}></View>
</Container>
);
}
}
const styles = StyleSheet.create({
topStrip: {
alignItems: 'center',
},
streamName: {
marginTop: 7,
marginBottom: 6,
flexDirection: 'row',
alignSelf: 'center'
}
}
});
<View
style={{
paddingLeft: ITEM_HEIGHT * 3,
flex: 1,
position: "absolute",
top: 0,
right: 0,
bottom: 0,
left: 0,
zIndex: -1
}}
>
<Image
style={styles.centerCircle}
resizeMode="contain"
source={Images.ballSmall}
/>
</View>
In android, to use zIndex you need css with position-properties with top,left,right,bottom css
Tested On: Zenfone 3, Android 7, React Native 0.55.4
This issue is not caused by zIndex (although it does cause problem on Android).
Your icon is put inside the upper container view. React Native on Android does not support overflow: visible. That's why you see your icon being clipped outside the container.
You may put the icon on the "page" component level to solve this issue.
You may also refer to https://stackoverflow.com/a/50991892/6025730.

React Native scroll view not showing

I have a scroll view at the top level of the view hierarchy. I'm trying to get it to show its content but I haven't had any luck.
I see that the documentation says scroll views need a bounded height to work. I can't seem to get it to have a bounded height. This is what I have so far.
'use strict';
const React = require('react-native');
const {
StyleSheet,
Text,
View,
BackAndroid,
TextInput,
TouchableNativeFeedback,
ScrollView
} = React;
const ActionButton = require('./action-button'),
Dimensions = require('Dimensions');
module.exports = React.createClass({
handleBackButtonPress () {
if (this.props.navigator) {
this.props.navigator.pop();
return true;
}
return false;
},
componentWillMount () {
BackAndroid.addEventListener('hardwareBackPress', this.handleBackButtonPress);
},
componentWillUnmount () {
BackAndroid.removeEventListener('hardwareBackPress', this.handleBackButtonPress);
},
onInputFocus (refName) {
setTimeout(() => {
let scrollResponder = this.refs.getScrollResponder();
scrollResponder.scrollNativeHandleToKeyboard(
React.findNodeHandle(this.refs[refName]),
110,
true
);
}, 50);
},
render: function() {
return (
<View style={styles.scrollWrapper}>
<ScrollView ref='scrollView' style={styles.scroller}>
<View style={styles.container}>
<View style={styles.header}>
<Text>New Post</Text>
<View style={styles.actions}>
<ActionButton handler={this.handleBackButtonPress} icon={'fontawesome|close'}
size={15} width={15} height={15} />
</View>
</View>
<View style={styles.content}>
<TextInput underlineColorAndroid={'white'}
placeholder={'Who\'s your professor?'}
ref='professor'
onFocus={this.onInputFocus.bind(this, 'professor')}
/>
<TextInput multiline={true}
underlineColorAndroid={'white'}
placeholder={'What do you think?'}
ref='post'
onFocus={this.onInputFocus.bind(this, 'post')}
/>
</View>
<View style={styles.footer}>
<TouchableNativeFeedback
background={TouchableNativeFeedback.SelectableBackground()}>
<View style={{width: 50, height: 25, backgroundColor: 'green'}}>
<Text>Submit</Text>
</View>
</TouchableNativeFeedback>
</View>
</View>
</ScrollView>
</View>
);
}
});
const styles = StyleSheet.create({
scrollWrapper: {
flex: 1
},
scroller: {
flex: 1
},
container: {
flex: 1,
flexDirection: 'column',
justifyContent: 'flex-start',
backgroundColor: 'white',
padding: 5,
},
post: {
flex: 1,
},
actions: {
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
alignSelf: 'center'
},
header: {
flex: 1,
position: 'absolute',
top: 0,
left: 0,
right: 0,
height: 35,
padding: 5,
flexDirection: 'row'
},
content: {
flex: 1,
position: 'absolute',
top: 35
},
footer: {
flex: 1,
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: 35
}
});
EDIT: So I changed the background colors of all the components to something obvious. I was able to simplify the view, so now the ScrollView is the root of the component. The container view (the immediate child of the ScrollView) is the one who isn't filling all the available space. I'm still playing around with it but any help is much appreciated.
To fix this, you need to set flex: 1 to the parent's view. Then, for ScrollView, use contentContainerStyle={{flexGrow: 1}} rather than using style.
<View style={{flex: 1}}>
<ScrollView contentContainerStyle={{flexGrow: 1}}>
...
</ScrollView>
</View>
If you are using position: absolute, you need to specify a left:0, right:0 for it to work with your current setup, though I am not entirely sure position: absolute is needed at all. Try this:
content: {
flex: 1,
position: 'absolute',
top: 35,
left:0,
right:0,
bottom:0
},
Try setting removeClippedSubviews={false} as a property of and see what happens.

Categories

Resources