Difference between assigning dimensions and percentage attribute in layout props - react-native

When i try to run the app, my app behaves differently to the below two methods
height: 15%(Dimensions.get('window').height);
// above is not program just my sum up
and
height:'15%'
when I try to set the height to my text input with two methods my apps behave differently, is there any reasons behind it ?
I am in react-native 0.61.4

Giving from Dimension always takes the screen window's height/width. However, giving with the string % percentage would not take the whole screen window's height, width. If there is a wrapper around the View (or element object) it will calculate the wrapper's height/width. For example:
<View style={{ height: 100, width: 300 }}>
<View style={{ height: "10%", width: "10%" }} />
</View>
Inside of the View has 10 height & 30 width it will calculate from parent view. However, if you will take it from Dimension, it will calculate from the whole screen window's height/width.

Related

React-Native wrong dimension length in Android?

I'm facing an issue where apparently, when using useWindowDimensions() on React-Native, the length of the shortest dimension is incorrect.
Minimum reproducible example: Create an app from scratch using npx react-native run-android and paste the following on App.js:
export default function App() {
return (
<View style={{flex: 1}}>
<View
style={{
height: 100,
width: 100,
backgroundColor: 'red',
position: 'absolute',
top: useWindowDimensions().height - 20,
}}>
</View>
</View>
);
}
Explanation: there's a red-colored view of size 100 x 100 positioned absolutely on the screen. By doing top: useWindowDimensions().height - 20, I'm telling the view to move all the way to the bottom, and just to "peek" 20 dps.
On portrait orientation, it works:
But on landscape, it doesn't work. The view doesn't peek from the bottom
In fact, the view is still hidden at the bottom. Subtracting 20 from the height of the screen was not enough. I played around and found that I need to subtract at least 28 to make it visible:
What's going on? I would have expected that useWindowDimensions().height returned 28 less than what it did. Is this a bug? Or am I missing/not considering something else?
Note: at the beginning I thought it could be because of Android's status bar or navigation/action bar. But that doesn't make sense...because IT WORKS with a Portrait Orientation.

How can I detect when the user gets a View and do something after getting this position on React Native?

I have a ScrollView with some Views inside it, but I want to start an animation when the user gets to specific View and after it starts my animation.
Example:
<ScrollView style={{ width: DeviceWidth, height: DeviceWidth * 0.5 }}>
{/* When user position scroll is here,
is where I want to start the animation,
not since the page is loaded */}
<View style={{
width: DeviceWidth * 0.4,
height: DeviceWidth * 0.4,
resizeMode: "contain",
}}>
<ProgressBarAnimated
width={barWidth}
value={65}
backgroundColor="#F68D29"
height={40}
barAnimationDuration={6000}
/>
</View>
</ScrollView>
Instead of using a ScrollView you can instead use a FlatList, this gives you a lot more support for the type of indexing you're trying to do.
To detect when a user reaches a specific point you can use onViewableItemsChanged and the define which viewable items need to be on screen in order to trigger your animation.
FlatLists also support a number of build in animations like scrollToEnd or ScrollToIndex which may be helpful.

React Native: Perfectly align Text in circle

I have a circle button (made with borderRadius) in React Native. The text in the component should be centered both vertically and horizonatlly.
Horyzontally it's fine, but the vertical alignment seems to fail whatever I do. Even if it looks good on large cicles with small fontSize, the small circles proof it wrong!
<View style = {{
alignItems:'center',
justifyContent:'center',
backgroundColor:'yellow',
borderColor: this.props.color,
width:size, height:size,
borderRadius:size,
borderWidth:borderWidth,
}}>
<Text style = {{
textAlign: 'center',
backgroundColor:'none',
fontSize:fontSize,
lineHeight:fontSize,
}}>
{this.props.title}
</Text>
</View>
Although already answered elsewhere, I'm unable to center text (in this case) in a circle properly.
As one can see on the image with the green background of the <Text>-Component, the text is just not centered perfectly. Even though the itself is perfecttly aligned...
Here is a snack for Expo with the whole code reduced to the necessary and with different example sizes: https://repl.it/#PaulHuchner/Centered-Text-in-Circles
I have tried the previous answer with only Text and calculating line-height. which looks like a little overkill and didn't work for me. So here's my answer.
I am using View as the container with justifyContent:center
<View style={{
width: 40,
height: 40,
borderRadius: 20,
borderWidth: 1,
borderColor: 'black',
borderStyle: 'solid',
justifyContent: 'center'}}>
<Text style={{fontSize: 20,textAlign: 'center'}}>20</Text></View>
You're trying to set the same fontSize and lineHeight as the circle's diameter, which has borderWidth of 10 included to it.
Due to the borderWidth, the text is being cut and overlayed over the circle. The lineHeight assigned to the cut Text is more than required, hence it is displayed misaligned.
Therefore you need to reduce the fontSize and the lineHeight based on the borderRadius of the circle, to function properly for all dimensions.
<Text style = {{
textAlign: 'center',
backgroundColor:'green',
fontSize:fontSize - 2 * borderWidth, //... One for top and one for bottom alignment
lineHeight:fontSize - (Platform.OS === 'ios' ? 2 * borderWidth : borderWidth), //... One for top and one for bottom alignment
}}>
Here's a snack link
The solution that worked the best for me was instead of using a Text Element, instead, use a plus Icon. The difference is that the viewBox of "+" as a character isn't centered.
If that is confusing look at these three letters
A+a
Notice that "A" is taller than "+" and also "a". So instead, use a PLUS icon instead and it will be perfectly centered such as 24x24 px. This drove me mad!

Nativebase : change thumbnail default size

I can't change the default size of the thumbnail from NativeBase. I can display the default circle, which is the small and the large one, but I want to display a bigger circle than the default size. Here's my code for the thumbnail :
<Thumbnail size={200} style={{margin: 30}} source={require('../../../public/images/profile/yellow.jpg')} />
The props size doesn't work, the thumbnail remains small.
My NativeBase version : 2.3.5
Native Base Component doesn't have a size props, you should add width and height, and one more thing you shouldn't forget please add borderRadius divided by 2 to ensure the shape is retain Circle
<Thumbnail style={{width: 30, height: 30, borderRadius: 30/2}} source={require('../../../public/images/profile/yellow.jpg')} />
You can simply increase the Thumbnail size by using this trick. Just take the property of scale with <Thumbnail/>.
Just copy-paste the below code in your app
<Thumbnail
scaleX={3} scaleY={3} style={{margin: 30}}
source={require('../../../public/images/profile/yellow.jpg')}/>
You can change the scale values as per your need. Let me know if this fixes your issue.
The Thumbnail component from NativeBase doesn't have the size attribute. Try to set width and height properties of the style attribute
<Thumbnail style={{width: 100, height: 100, margin: 30}} source={require('../../../public/images/profile/yellow.jpg')} />
NativeBase Thumbnail component comes with small and large props for size. You can also set width and height to have image with other dimensions

Clickable Background underneath a ScrollView [React Native]

So, I want to create a layout similar to whats below. [Refer the Image]
So the background has a full screen MapView (React Native Maps) with Markers over it, which needs to be clickable.
And there is a Scrollview with full screen height over the MapView which initially has some top-margin associated with its contents.
But the issue if I arrange my Views this way, the Markers on the map are not clickable in the initial state.
<View>
<MapView>
<Marker clickEventHere></Marker>
<Marker clickEventHere></Marker>
</MapView>
<ScrollView fullscreen>
<View marginTop></View>
</ScrollView>
<View>
I am unsure if its really possible to solve this out.
Initial State
After Scrolling
Solution Tried
yScrolled = event.nativeEvent.contentOffset.y;
yValue = this.state.yValue - yScrolled;
upwardScroll = yScrolled > 0;
if(upwardScroll && (yValue > 0)){
this.setState({
yValue: yValue
});
}
if(yScrolled === 0){
yScrolled = -10;
}
if(!upwardScroll && (yValue <= scrollViewMarginTop)){
yValue = this.state.yValue - yScrolled;
console.debug("UPDATE DOWNWARD");
this.setState({
yValue: yValue
});
}
I'd start with adding absolute positioning to your ScrollView, (position: absolute) starting at whatever y coordinate you would like. I would make this y value a state, eg
yValue: new Animated.Value(start_value) or simply yValue: start_value
I would then use ScrollView's prop onScroll event to handle the change in this y coordinate, for example for the first 100 pixels of a scroll it would simply change the yValue instead of scrolling the view.
This should enable you to press the markers you have in your parent view, and use the same component structure that you have provided.
Note: You would need to do this for collapsing the scrollview also.
Note2: if this doesn't give you the result you were looking for, i'd suggest looking into using some sort of collapsable component for this task, eg https://github.com/oblador/react-native-collapsible
Hope this helps
EDIT: To collapse the scrollview you could first identify if the scroll direction is downwards ( which i think youve done via upwardScroll ) and then..
1) Either simply add the content offset to your yValue
2) If you used Animated.Value for yValue, you can have an animate function that animates the scrollview downwards to your desired position. I think this would look nicer as the user would only need a simple downwards flick to collapse the view, which seems like the industry standard.
There is also a library that is called react-native-touch-through-view that can do this for you. This it how it works basically:
<View style={{ flex: 1 }}>
// Your map goes here
</View>
<TouchThroughWrapper style={{
position: 'absolute'',
top: 0,
left: 0,
width: '100%',
height: '100%',
}}>
<ScrollView
style={{
backgroundColor: 'transparent',
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
// Maybe in your case is flex: 1 enough
}}
bounces={false}
showsVerticalScrollIndicator={false}
>
<TouchThroughView
style={{
height: 400, // This is the "initial space" to the top
}}
/>
// The "slide up stuff" goes here
</ScrollView>
</TouchThroughWrapper>
For example, this then can look like this:
So the map is overlayed by the TouchThroughView that passes all the events right to the view behind. In my case this worked better than using pointer-events box-none.