React Native get available height for content - javascript

I have a custom component which needs its height to be set explicitely. I'm having trouble with calculating the available space on different devices.
The top bar is no problem cause I use the StatusBar height, but on the bottom, the iPhone X has some space for that "bar" and I don't know how to calculate this (I could match the device but maybe there are more devices with this space on the bottom).
Is there any way to calculate this? I'm using Expo btw.

I don't know what is your primary goal but here are my suggestions:
If you want to calculate the available height you can create a View with style {flex:1} then use onLayout built-in function of a View. Here how it works:
onLayout=({nativeEvent})=>{
// Here is height
console.warn(nativeEvent.layout.height)
}
<View style={styles.container}>
<YourComponents/>
{/*The part you want to calculate height*/}
<View style={{flex:1}} onLayout={onLayout}/>
</View>
If you want to just avoid the notch of the device you can use SafeAreaView. Here is the full documentation. PS. react-native's built in SafeAreaView component has been moved to react-native-safe-area-view

Related

ReactJS MaterialUI Stepper breaks on overflow

I have been trying to convince the Material UI Stepper component to fit my needs, that is to say display severl steps and overflow, but it continues doing this:
I don't know how to explain the error... the separators are doing weird things on horizontal overflow. Here is the sandbox. How can I get this working?
TL;DR: 1) Word-break your labels (<StepLabel style={{ wordBreak: "break-all" }}>) so they don't invade layouts among steps and 2) provide an initial width to the stepper (<Stepper ... style={{ width: 64*16 }}>) so it does not use the parent width to do so.
I fixed your pastebin:
NL;PR: You had two styles missing to handle long words and content within a scrollable container:
For 1) the labels' words were bigger than the allotted space to render the steps since 550px is too tight for 16 steps, so they broke the layout, play it safe by not letting lengthy words overflow the label.
For 2) consider given the Stepper component a proportional value (64 (stepper min-width)* 16(stepper count)), and since you want to have a scroller, the width of the scrollable container is used as the initial width of the content, thus you must specify the content(Stepper) so it is not shrunk too much before overflowing.
Note: Those styles I provided are examples, you can customize them to your needs. Also, consider passing those changes via classes.

In React Native, is there a way to make a deeply nested element a full-screen element?

I have a React Native Expo app in which I'd like to make an element full-screen with essentially the following styles:
{
bottom: 0,
left: 0,
position: 'absolute',
right: 0,
top: 0
}
The problem is, I want to do this for an element that is deeply nested within the structure of my screen. As a simplified example, the structure of my current screen is something like the following:
<View>
<View>
<View>
<ComponentA>
<ComponentB>
<ComponentC>
</ComponentC>
<ComponentC>
</ComponentC>
<ComponentC>
</ComponentC>
</ComponentB>
</ComponentA>
</View>
</View>
</View>
What I want to do is set up something in ComponentC so that when you tap a button in that component, it causes an element within that same component to display full-screen.
Apparently though, in React Native, all elements are position: relative by default. As such, when I apply the styles above to the element I want to be full-screen in ComponentC, it doesn't show up as full-screen, but rather as filling the entirety of that particular ComponentC only.
Is there any way to get around this? I was thinking about taking the part of ComponentC that I want to have full-screen and placing it outside of ComponentC and at the top of my screen structure, but then, it's completely separated from ComponentC itself, and then I'd have to also coordinate that separate element so that it works with all of the various ComponentCs on the screen. Also, when I tried doing that, I ran into a bunch of issues with trying to properly maintain state.
Maybe I'm just taking the wrong approach to begin with, but is there a way to get what I want with some simple styling so that a deeply nested element can still be displayed full-screen, or am I going to have to engineer some complex thing to do what I want, and if it's the latter, any recommendations on how to approach this? Thank you.
To show something full screen no matter where you are in the hierarchy, you can use the Modal component: https://reactnative.dev/docs/modal.
Note: this solution will not work out-of-the-box if you want the relatively positioned element to fluidly transition into full screen (so-called hero or shared-element transition) - not sure if that is what you are after.
If you want to split your component, you can communicate from ComponentC to the top component directly with DeviceEventEmitter
in ComponentC:
import {
DeviceEventEmitter
} from 'react-native'
In the function which handle the onPress action of your button you can call DeviceEventEmitter like that:
DeviceEventEmitter.emit('whateverName', { myData: {} })
Then in the top component
DeviceEventEmitter.addListener('whateverName', (myData) => );

React - Highcharts Full Screen black bar

I'm trying to implement an application using highcharts/highstock and I'm facing a problem trying to use the full screen function.
I need to set a fixed hight to my charts and be able to view each chart from my page as a full screen one, but since the height is fixed it stays the same when full screen loads, I've tried the approach from this post but it's not working, if I set height to 100% the chart overflows the page and gets crooped depending on the aspect ratio of the screen.
I´ve also found this working demo, I can't replicate this one. I'm not sure how he's calling the component, also I don't know how the export module (hamburguer menu) is showing up if it's never called.
render() {
return <div className="chart" ref={ref => this.container = ref} />
}
on my application I'm calling the component this way
render() {
return (
<HighchartsReact
highcharts={Highcharts}
constructorType="stockChart"
options={options}
allowChartUpdate
callback={this.afterChartCreated}
/>
)
}
I tried passing an ID to this element to try to set height via CSS but it doesn't work.
I was trying to replicate my application with a working example, I could only do it on a codesandbox because of import structure, but for some reason full screen is not working there, it prompts this message
Full screen is not supported inside a frame.
This demo creates the chart without using Highcharts React wrapper - it's a combination of pure Highcharts JS and React - that's why export menu shows without called it. The Highcharts React wrappers work similarly, but more in 'React way' and gives other opportunities to manage the component.
Back to your issue - I think that a better approach will be defining the height of the Highcharts component as inline React styling. You can achieve by setting it in containerProps object.
<CardContent style={{ padding: 0 }}>
<HighchartsReact
highcharts={Highcharts}
containerProps={{ style: { height: "400px" } }}
options={options}
allowChartUpdate
/>
</CardContent>
Demo: https://codesandbox.io/s/fix-full-screen-253sq?file=/src/CustomGUIChart.js
To test it use the open in new window codesandbox option (button just above the exporting menu hamburger).

set horizontal ScrollView s height as indexed content height

I have a horizontal ScrollView inside another vertical Animated.ScrollView.
I am use the horizontal one as tab-view(snap item changing) and its working perfectly but there is a problem now.... I render different views inside each item of scroll view which has specified heights, ScrollView height will get the longest one and all of tab views get the same height despite they don't need such a long height:
<Animated.ScrollView>
<ScrollView //<<<<<<I'm talk about this one
ref={(scr) => this._scrollView = scr}
decelerationRate={0}
snapToInterval={Dimensions.get('window').width}
snapToAlignment={"center"}
pagingEnabled
horizontal <<<<<<<<<<
onContentSizeChange={() => this._scrollView.scrollTo({ x: this.state.index * Dimensions.get('window').width, y: 0, animated: true })}
onMomentumScrollEnd={(event) => this.focuser(event.nativeEvent.contentOffset.x)}
>
<View>...some thing short<View>
<View>..some thing Long<View> //<<<<this one is long
<View>...Some thing short<View>
</ScrollView>
As you see above, the item which I use in second tab has a long height and it stretch the whole height of ScrollView! its no problem now ... its appropriate stretching which I need for this item(this View) but, I don't need such a height for other tab. But they get this height and will able user to Scrolling down. its so ugly.
I want to set the height of ScrollView as the height of Current tab content(Current index content ). whats your solution for that ?
As far as I know, this is a limitation of ScrollView. As a workaround, you might want to try replacing your Views with vertical ScrollViews of fixed size on the page. This way they will all have their individual scrollable height. However, since you're already inside a vertical ScrollView, responding to scrolling events can get a bit tricky.
Update:
Another approach is to adjust the height of individual items based on their number, so that every page is the same length. You can see it in this example.

React Native - how to set fixed width to individual characters (number, letter, etc)

I am having a problem in a React Native app I'm building. I have a stopwatch and since each number character has a different width, when the time is increased the text begins moving all over the place, as opposed to staying in tact with a fixed width.
For example, if you have a mobile iOS device, open the default clock app that is shipped with it and use your stopwatch. You'll notice that each character in the 00:00:00 series has a fixed width, or at least it seems that way. If one of the 0 turns into a 1, even though 1 is seemingly smaller in width, it still fills up the same amount of space and thus the text does not jump all over the place.
In my React Native app, however, this is not the case. 1 takes up less width than 0 or any other number, so it makes the text jump all over the place and it's really annoying.
Here is a good, working version (notice how on each change of a number, the width of the 'container' that the number is in never changes?) This ensures a smooth transition:
Now take a look at my version, a disaster:
I can't seem to find a solution to this.
I feel like one way to solve this would be to have each character in a separate <Text> tag with a set width, but I know that would be completely overkill. There must be an easier way to do this.
Any guidance would be appreciated.
The system font in iOS is San Francisco, which has proportional numbers by default but contains an option for fixed-width (monospaced) numbers. With react-native, you have to use the fontVariant property on your Text component's style:
<Text style={{fontVariant: ['tabular-nums']}}>
1,234,567,890.12
</Text>
I had a hard time finding it because the name isn't explicit and not what is typically used. Here's a link to the the Text props on the RN doc: https://reactnative.dev/docs/text-style-props#fontvariant
Although the question is tagged for iOS, in case anyone is looking for a generic solution that supports monospace text on both iOS and Android (like I was), then here's an additional resource for you!
Font selection:
react-native-training/react-native-fonts on GitHub has a good list of fonts which are on each platform. As you can see, there is no overlap between the monospace fonts which OP provided in their answer. However, Android has a font called 'monospace' which will work for this use case.
OS Conditional statement
Since react native will throw an error if a font in fontFamily does not exist, we will need to conditionally set the fontFamily based on what's available in the OS. Platform.OS from react-native can be used to determine the device OS.
Example
// components/TextFixedWidth.js
import React from 'react'
import { Platform, Text } from 'react-native'
export default function TextFixedWidth ({ children }) {
const fontFamily = Platform.OS === 'ios' ? 'Courier' : 'monospace'
return (
<Text style={{fontFamily}}>{ children }</Text>
)
}
Then
// in a render method somewhere in the app
<TextFixedWidth>
Any monospace text you want!
</TextFixedWidth>
I hope this is helpful :)
Thanks to #ppeterka, I found a super easy solution to this that requires one line of code: use a monospace font.
Here is a list of some available monospace fonts that are shipped with iOS:
Courier
Courier-Bold
Courier-BoldOblique
Courier-Oblique
Courier New
CourierNewPS-BoldItalicMT
CourierNewPS-BoldMT
CourierNewPS-ItalicMT
CourierNewPSMT
Menlo-Bold
Menlo-BoldItalic
Menlo-Italic
Menlo-Regular

Categories