How to modify the padding in SafeAreaView? - react-native

I am trying to position element in the left-upper corner of the screen (there is some margin around). Because of the notch on the iPhone X I am using SafeAreaView. Unfortunately the SafeAreaView padding is enormous, it goes way out of the status bar / notch area. Because of that the element which should visually be in the corner it's now much lower than on other devices.
I looked into StatusBar.currentHeight, but that is supported only for Android. Another option was to use https://github.com/react-native-community/react-native-safe-area-view which has a forceInset parameter. Unfortunately, setting it as { top: xx } makes it work like a normal View with a top padding for all devices (the ones without notch as well).
How can I have a SafeAreaView but with a modified top padding?

I had a similar problem months ago, so I wrote an util to give me the correct height of top/bottom SafeArea to add as padding to a normal react-native View, and then play with them by adding/removing more padding. Here is the code:
import { Dimensions, Platform } from 'react-native'
export function isIphoneX () {
const iphoneXLength = 812
const iphoneXSMaxLength = 896
const windowDimensions = Dimensions.get('window')
return (
Platform.OS === 'ios' &&
!Platform.isPad &&
!Platform.isTVOS &&
(windowDimensions.width === iphoneXLength ||
windowDimensions.height === iphoneXLength ||
windowDimensions.width === iphoneXSMaxLength ||
windowDimensions.height === iphoneXSMaxLength)
)
}
const DimensionsStyle = {
safeAreaTopHeight: Platform.OS === 'ios' ? (isIphoneX() ? 44 : 20) : 0,
safeAreaBottomHeight: Platform.OS === 'ios' && isIphoneX() ? 35 : 0,
tabBarHeight: Platform.OS === 'ios' ? 17 : 20,
bottomAreaHeight: Platform.OS === 'ios' && isIphoneX() ? 34 : 0
}
export default DimensionsStyle
This code works because we know that iPhone X and iPhone XS have a 812p height, and iPhone XSMax and XR have 896p height.
Then you can simply import this util into your view and use it like this:
import Dimension from '../../../utils/DimensionUtils' // path of the util
//
// rest of the code
//
const styles = StyleSheet.create({
container: {
paddingTop: Dimension.safeAreaTopHeight // here you can edit the height of the safeare :))
}
})

Related

Populte WYSIWYG editor after react native fetch

I am trying to incorporate this WYSIWYG package into my react native project (0.64.3). I built my project with a managed workflow via Expo (~44.0.0).
The problem I am noticing is that the editor will sometimes render with the text from my database and sometimes render without it.
Here is a snippet of the function that retrieves the information from firebase.
const [note, setNote] = useState("");
const getNote = () => {
const myDoc = doc(db,"/users/" + user.uid + "/Destinations/Trip-" + trip.tripID + '/itinerary/' + date);
getDoc(myDoc)
.then(data => {
setNote(data.data()[date]);
}).catch();
}
The above code and the editor component are nested within a large function
export default function ItineraryScreen({route}) {
// functions
return (
<RichEditor
onChange={newText => {
setNote(newText)
}}
scrollEnabled={false}
ref={text}
initialFocus={false}
placeholder={'What are you planning to do this day?'}
initialContentHTML={note}
/>
)
}
Here is what it should look like with the text rendered (screenshot of simulator):
But this is what I get most of the time (screenshot from physical device):
My assumption is that there is a very slight delay between when the data for the text editor is actually available vs. when the editor is being rendered. I believe my simulator renders correctly because it is able to process the getNote() function faster.
what I have tried is using a setTimeOut function to the display of the parent View but it does not address the issue.
What do you recommend?
I believe I have solved the issue. I needed to parse the response better before assigning a value to note and only show the editor and toolbar once a value was established.
Before firebase gets queried, I assigned a null value to note
const [note, setNote] = useState(null);
Below, I will always assign value to note regardless of the outcome.
if(data.data() !== undefined){
setNote(data.data()[date]);
} else {
setNote("");
}
The last step was to only show the editor once note no longer had a null value.
{
note !== null &&
<RichToolbar
style={{backgroundColor:"white", width:"114%", flex:1, position:"absolute", left:0, zIndex:4, bottom: (toolbarVisible) ? keyboardHeight * 1.11 : 0 , marginBottom:-40, display: toolbarVisible ? "flex" : "none"}}
editor={text}
actions={[ actions.undo, actions.setBold, actions.setItalic, actions.setUnderline,actions.insertLink, actions.insertBulletsList, actions.insertOrderedList, actions.keyboard ]}
iconMap={{ [actions.heading1]: ({tintColor}) => (<Text style={[{color: tintColor}]}>H1</Text>), }}
/>
<RichEditor
disabled={disableEditor}
initialFocus={false}
onChange={ descriptionText => { setNote(descriptionText) }}
scrollEnabled={true}
ref={text}
placeholder={'What are you planning to do?'}
initialContentHTML={note}
/>
}
It is working properly.

React Native Platform OS is not working suddenly

I am using Platform.OS to check ios and android. It is working fine, But suddenly it returns me 0 instead of 'ios' or 'android'. After some RND I found that when the app is loading the first time, it returns me 'android' but when I switch the screen and check Platform.OS then it returns me 0 value. I am wondered why it is happening.
I am sharing the console result.
when the app is reloading the first time.
LOG Platform.OS
LOG android
after that navigate to the other screen and then check Platform OS.
LOG Platform.OS
LOG 0
I am sharing the code snippet to check Platform
import { Platform } from 'react-native';
componentDidMount() {
console.log('Platform.OS');
console.log(Platform.OS);
}
It looks like you used Platform.OS "=" instead of "==" someplace within the code.
Example :
wrong way:
(Platform.OS ='android')?console.log("this the wrong way):console.log('Oops')
right way
(Platform.OS=='android')?console.log("Youpi it works):console.log('in your dream, this gonna happen again')
Same thing happened with me.
I noted that in one place I have check platform condition using single equal operator by mistake like
paddingTop: (Platform.OS = 'android'
? 16
: 4)
and then after whenever I have checked platform, I always getting 16.
So make sure if anywhere you have check condition, like Platform.OS = 'android' replace it with Platform.OS == 'android'
As #Rajesh Nasit exposed, I had a similar problem, when I wrote
console.log("Platform.OS:" + Platform.OS)
I allways was getting in the console "Platform.OS: 100%"
And the followed error (in Expo CLient App) => 'Unhandled promised error :Invalid platform was passed "100%" '.
Then after reversed my code and checking all the changes I've made, I found the line what was the responsible for thar error.
I had in my StyleSheet the following line
width: Platform.OS === 'android' ? "100%" : "100%",
I asume React-Native somehow set the value "100%" to the Platform.OS.
At final, I resolved that error as follow:
const styles = StyleSheet.create({
imagebackground: {
...Platform.select({
ios: {
width: "100%",
},
android: {
width: "100%",
},
default: {
width: "100%",
}
}),
marginLeft: 0,
},
Well I hope someone find this answer usefull.

Does react native support repeating-linear-gradient?

I am trying to have a repeating-linear-gradient for my view in React Native. However i couldn't find any information or library that would help me use it.
I found a library named react-native-linear-gradient but it seems to be helpful to only have simple linear gradient.
Thanks for your help in advance
CSS
background: repeating-linear-gradient(
-55deg,
#222,
#222 10px,
#333 10px,
#333 20px
);
In React, styles are specified with an object wherein the key is the camelCase version of the style name, and the value is the style’s value. If the value is not explicitly typeof 'number', the entire value must be a single string. Within that string, normal css style names can be used.
Here is an example:
<ExampleComponent
style={{
background: 'repeating-linear-gradient(-55deg, #222, #222 10px,#333 10px, #333 20px)',
backgroundSize: 'cover',
}}
/>
I have used react-native-linear-gradient for my splash screen
fist I have set 4 different colors and make it a gradient with white color.
const gradient1 = [Colors.secondary1Color, Colors.white];
const gradient2 = [Colors.primary1Color, Colors.white];
const gradient3 = [Colors.secondaryColor, Colors.white];
const gradient4 = [Colors.primaryColor, Colors.white];
I first set this.state = {changeGradient: true}
then I have this changeGradient function which changes the const gradient colors ever had a second
changeGradient = async () => {
console.log("changeGradient", await this.state.gradient);
if (this.state.changeGradient) {
setTimeout(async () => {
await this.setState(({ gradient }) => ({ gradient: gradient === gradient1 ? gradient2 : gradient === gradient2 ? gradient3 : gradient === gradient3 ? gradient4 : gradient1 }));
this.changeGradient();
}, 500);
}
};
Then, I render in the Lineargradient component
<LinearGradient colors={this.state.gradient} style={styles.container}>
</LinearGradient >
You're good to go!!!
Hope this helps you!

React Native: Animation not working properly on android

I have been trying to fix issue for the past 2 days, it works fine on iOS
constructor(){
super();
this.animation = new Animated.Value(0)
this.state = {
expanded: false,
};
}
toggle(){
let initialValue = this.state.expanded? 1 : 0 ,
finalValue = this.state.expanded? 0 : 1
this.setState({
expanded: !this.state.expanded,
});
this.animation.setValue(initialValue)
Animated.timing(
this.animation,
{
toValue: finalValue,
}
).start();
}
render(){
return(
<Animated.View style={{{flex: 1, marginTop: 28, paddingLeft: 25, transform: [{ scale: this.animation }, {perspective: 1000 }]}}}>
....
</Animated.View>
);
}
This component is child , used in parent like this: <FeedBack ref={ref => this.feedback = ref}/> without any conditions to check to show or not (because animation scale is set to Zero in the constructor, so no need)
the toggle() method is being called from parent when a button pressed.
Now this works fine on iOS , when component loads, the view is not there until a button is pressed (then scaled). but on android when the component loads, the view already there. When I press the button, the animated view disappears and re-appears (with animation scaling) and subsequent toggles work fine. The problem in android is that even though initialValue of the scale is Zero, the view is still there when it first loads.
This has been an issue with react-native on the android side for a while now (sigh). It seems that setting the value to 0 strips it of its characteristics, basically deeming it as null and then reverting to using its actual value once it had animated to > 0
A work around is to set animation like so
this.animation = new Animated.Value(0.01);
You can follow the issue here

How to use React Native PixelRatio utility class?

I have an app written initially for iPhone 6 symulator which has a componend syled with following example values:
const styles = StyleSheet.create({
headerNav: {
width: 40,
height: 40
},
headerLogoImage: {
width: 140,
height: 140
},
footerNavText: {
padding: 15,
fontSize: 25
}
});
Unfortunately when I launched the app on iPad symulator, the size proportions completely collapsed. I know that there is something like PixelRation but documentation is very limited and unclear.
Any idea / suggestions how can I translate these width / height / padding & fontSize to proper values using this PixelRatio class?
fontSize needs to be divided by PixelRatio.getFontScale(). This will account for different screen densities in iOS and Android.
footerNavText: {
fontSize: 25 / PixelRatio.getFontScale()
}
https://facebook.github.io/react-native/docs/pixelratio.html
You could do something like:
footerNavText: {
padding: PixelRatio.get()*3,
fontSize: PixelRatio.get()*4
}
Check what get() method returns for each of the devices you wish to use and style accordingly.
For more info visit https://facebook.github.io/react-native/docs/pixelratio.html
// create this utils.ts file
import { PixelRatio } from "react-native";
// dp(123) converts 123px (px as in your mockup design) to dp.
export const dp = (px: number) => {
return px / PixelRatio.get();
};
// sp(54) converts 54px (px as in your mockup design) to sp
export const sp = (px: number) => {
return px / (PixelRatio.getFontScale() * PixelRatio.get());
};
Use it like the following way in your styles
const styles = StyleSheet.create({
footerNavText: {
padding: dp(123),
fontSize: sp(54)
}
})
Note
Do not use dp for fontSize. dp just depends on device screen density (dpi)
sp is used for fontSize only. sp is also just like dp but the difference is that it also depends on user's font settings in his device along with the device screen density (dpi).