I am new to react native development. I am trying to make the design in the image below:
How can I achieve the box affect? I was trying with box shadow but I was not getting the correct look. It looks like the 'box' is indented into the screen and the cards scroll underneath it. Has anyone ever done something like this? Or can you point me in the right direction?
This is my code for my home screen:
return isLoading ? (
<LoadingComponent />
) : (
<>
<SafeAreaView style={Layout.fill}>
<View style={[Layout.alignItemsStart, Gutters.largeTMargin, Gutters.largeLMargin]}>
<Text style={common.headingTextStyle}>{welcomeUser}</Text>
<Text style={[Gutters.regularTMargin, common.subHeadingTextStyle]}>Available</Text>
</View>
<SafeAreaView
style={[
Layout.fill,
Layout.center,
// styles.jobsBox,
Gutters.regularHMargin,
Gutters.regularVMargin,
]}
>
<ScrollView
style={[
Layout.fullSize,
Gutters.regularLPadding,
Gutters.regularRPadding,
Gutters.largeBMargin,
]}
>
{_.map(jobs, (job) => (
<Job jobData={job} key={_.get(job, 'id')} />
))}
</ScrollView>
</SafeAreaView>
</SafeAreaView>
</>
);
};
Shadows in react native are tricky particularly because of android. However there are 2 great libraries that can help you with making shadows using CSS format, and cross platform. react native shadow 2 and react native drop shadow
The best library I tried is react native neomorph shadow and its cross-platform library:
import { Shadow } from 'react-native-neomorph-shadows';
...
{_.map(jobs, (job) => (<Shadow
inner // <- enable inner shadow
useArt // <- set this prop to use non-native shadow on ios
style={{
shadowOffset: {width: 10, height: 10},
shadowOpacity: 1,
shadowColor: "grey",
shadowRadius: 10,
borderRadius: 20,
backgroundColor: 'white',
width: 100,
height: 100,
// ...include most of View/Layout styles
}}
>
<Job jobData={job} key={_.get(job, 'id')} />
</Shadow>)}
Try the below shadow style-
shadow: {
borderColor: color.palette.warmGrey,
borderWidth: StyleSheet.hairlineWidth,
shadowColor: color.palette.black,
shadowOffset: {
width: 0,
height: 3,
},
shadowOpacity: 0.27,
shadowRadius: 4.65,
elevation: 3,
padding: 10,
backgroundColor: color.palette.white,
},
Related
I'm looking for a way to tint the user's screen a certain shade, and change this tint overtime. (Think F.lux or Night Shift or any number of currently available blue light reducers). Is there any way to do this with React Native and/or Expo? I know iOS doesn't allow users to do this without Jailbreaking, but I believe this could be possible for Android at least? Thank you for your time.
App-wide filter solution (Android and web only, and the filter goes off if you switched to a different app)
You could make a filter with a <View/> React component that I named "filter" in the example below.
This does not work on iOS because I didn't find a way to let iOS know that all user clicks are for elements below the filter, not the filter itself.
In the example below, your whole app is represented by <YourApp/> which is in this example a simple button.
import React, { useState } from "react";
import { View, Button } from "react-native";
export default function () {
let [opacity] = useState(0.8);
const YourApp = () => (
<Button onPress={() => alert("clicked !!")} title="Click me" />
);
return (
<View
name="filterContainer"
style={{
flex: 1,
width: "100%",
height: "100%",
position: "absolute",
alignItems: "center",
justifyContent: "center",
}}
>
<View
name="filter"
style={{
flex: 1,
width: "100%",
height: "100%",
pointerEvents: "none",
position: "absolute",
elevation: 2,
zIndex: 2,
backgroundColor: "green",
opacity: opacity,
}}
></View>
<View
name="appContainer"
style={{
flex: 1,
position: "absolute",
elevation: 1,
zIndex: 1,
}}
>
<YourApp />
</View>
</View>
);
}
System-wide brightness change (but no tint change, and this is iOS and Android only)
If you're using Expo, you could use SYSTEM_BRIGHTNESS (https://docs.expo.io/versions/latest/sdk/permissions/#permissionssystem_brightness).
NB : The system brightness in most simulators and on web browsers does not work. It only works on real devices.
Here is an example how to set system brightness to 10% :
import * as Permissions from "expo-permissions";
import * as Brightness from "expo-brightness";
async function getAndSetSystemBrightnessAsync() {
const { status } = await Permissions.askAsync(Permissions.SYSTEM_BRIGHTNESS);
if (status === "granted") {
// Set system brightness to 10 %
await Brightness.setSystemBrightnessAsync(0.1);
const bright = await Brightness.getSystemBrightnessAsync();
console.log(bright);
} else {
// Web browsers
console.error("System brightness permission not granted");
}
}
useEffect(() => {
// Ask for system brightness permission
getAndSetSystemBrightnessAsync();
}, []);
I am trying to create a view post ui for a social media feature of our app. We have a post (the flatlist header component), the comments (the flatlist), and a fixed bottom text input that leverages zIndex to be placed over the flatlist to post comments. The problem is I cannot for the life of me figure out how to properly use a keyboard avoiding view to somehow push this fixed input up when the keyboard is shown. Is there any way to do this or maybe a simpler approach to this ui that I'm missing? I have tried using the keyboard height and adding it to the bottom positioning of the input but its slow and definitely isn't viable.
Code:
<View style={{flex: 1}}>
<View
style={{
...styles.container,
marginTop: 0,
zIndex: 1,
}}>
<FlatList
style={{minHeight: '100%'}}
data={new Array(15)}
renderItem={({item, index}) => <CommentRow index={index} />}
keyExtractor={(item, index) => `${index}`}
ListHeaderComponent={renderHeader}
contentContainerStyle={{paddingBottom: 70}}
/>
</View>
<View
style={{
position: 'absolute',
bottom: 0,
backgroundColor: 'white',
width: '100%',
zIndex: 2,
padding: 15,
borderTopWidth: 1,
borderColor: '#f2f2f2',
}}>
<View style={styles.inputContainer}>
<TextInput style={styles.input} placeholder="Add a comment.." />
<View style={styles.inputTextContainer}>
<Text style={styles.inputText}>Post</Text>
</View>
</View>
</View>
</View>
);
I'm not a fan of keyboard avoiding view because of some bad experiences I had. However, I'll give some tips on how to achieve the same effect with React Native core Animated Library.
Since your view is elevating (Style it as an absolute view) and when the keyboard appears, you can get the height of the keyboard with Keyboard addListener's callback.
componentDidMount(){
this.keyboardDidShowListener = Keyboard.addListener('keyboardDidShow', this._keyboardDidShow);
}
_keyboardDidShow(e) {
const keyboardHeight = e.endCoordinates.height,
}
Once you get the keyboard height, you can animate the absolute view using translateY to the position that aligns with the keyboard without any gaps. This will provide an nice animation similar to that you tried to accomplish with keyboard avoiding view. I've done that in few apps as well and it works great.
For anyone looking to do anything like this - what I ended up doing is using an useEffect hook to monitor when "keyboardWillShow" and then created a function to animate the view above the keyboard once its about to show. A lot of the answers I had seen used "keyboardDidShow" but it makes the UI slow and really ugly. Here's the code:
useEffect(() => {
Keyboard.addListener('keyboardWillShow', _keyboardWillShow);
Keyboard.addListener('keyboardWillHide', _keyboardWillHide);
// cleanup function
return () => {
Keyboard.removeListener('keyboardWillShow', _keyboardWillShow);
Keyboard.removeListener('keyboardWillHide', _keyboardWillHide);
};
}, []);
const _keyboardWillShow = (e) => {
const keyboardHeight = e.startCoordinates.height;
Animated.timing(topValue, {
toValue: -keyboardHeight,
duration: 50,
useNativeDriver: true,
}).start();
};
const _keyboardWillHide = (e) => {
Animated.timing(topValue, {
toValue: 0,
duration: 0,
useNativeDriver: true,
}).start();
};
Where topValue is a stateful Animated value. All you need to do after this is add the topValue variable to your animated view using transform and you're done!
I have very strange problem after upgrade react-native library in my app from version 0.59.9 to 0.61.0. The problem occurred only on Android (simulators and device).
Firstly, I should mention that the problem has not occurred since the first turn on the application. The most often appear after logging to app. After processing the data, the rendering of elements in the application unexpectedly changes.
The problem looks like:
As you can see, the image overrides backgroundColor, but strangely it does not cover the inscription inside. Have any of you encountered such a problem? How to solve it? What can it be caused by?
I put the code snippet below. Once again, I emphasize: The problem does not occur when the application is initialized, and everything worked correctly before upgrading the libraries.
const ProfileHead = () => (
<View>
<LinearGradient
colors={["rgba(3, 7, 20, 0)", "#030714"]}
style={styles.backgroundGradient}
start={{ x: 0.0, y: 0.0 }}
end={{ x: 0.0, y: 1.0 }}
locations={[0, 1]}
/>
<Image
source={require("../../assets/images/focusly_08.jpg")}
style={styles.imageBackground}
/>
</View>
);
<MainContainer style={{ paddingTop: 0 }} navbarHidden={true}>
<StretchScroll
stretchHeight={300}
stretchComponent={<ProfileHead />}
style={styles.scroll}
>
<View style={styles.userProfile}>
<ProfileOval title={user.name ? user.name.charAt(0) : ""} />
<Header style={styles.header}>{user.name}</Header>
</View>
...
backgroundGradient: {
position: "absolute",
width: Dimensions.get("window").width,
height: 200,
zIndex: 2,
},
imageBackground: {
width: Dimensions.get("window").width,
position: "absolute",
height: 200,
},
scroll: {
zIndex: 3,
},
userProfile: {
alignItems: "center",
marginTop: 130,
},
Try upgrading to v0.61.2
According to the changelog:
This release fixes shadow issues that were happening on Android as well as improves StatusBar API to better support iOS 13 dark mode.
I am trying to build a ReactNative Application with an animated button. The problem is that this animation does not work correctly the first time after the App is started. There is some white flickering. But after the animation ran wrong the first time everything works as expected:
I have already tried to preload the image in several ways, but without any success.
This is my minimal working example, note that if there are several different images the flickering occurs if a new image is loaded (e.g. I have two blue buttons and after I tapped the first one, the second one will work fine, but if I then tap an orange button it once again flickers for the first time, at least if I have not tapped another orange button after app start.):
import React, { Component } from 'react';
import {StyleSheet, Text, TouchableWithoutFeedback, View, Image, ScrollView,
Button, BackHandler} from 'react-native';
export default class Touchables extends Component {
constructor(props) {
super(props);
this.state = {alarm1: (<Image source={require("./assets/alarmoff.png")}
style={styles.imageButton}/>),
}
}
componentWillMount(){
//trying to preload all Images, but it does not help.
(<Image source={require("./assets/alarmon.png")} style=
{styles.imageButton}/>)
}
render() {
return (
<ScrollView style={styles.contentContainer}>
<View style={{flex: 3, flexDirection: 'row'}}>
<View style={styles.container}>
<TouchableWithoutFeedback onPressIn={() => this.setState({alarm1:
<Image source={require("./assets/alarmon.png")} style={styles.imageButton}/>})} onPressOut={() => this.setState({alarm1: <Image source={require("./assets/alarmoff.png")} style={styles.imageButton}/>})}>
<View style={styles.button}>
{this.state.alarm1}
</View>
</TouchableWithoutFeedback>
<Text style={styles.text}>This button flickers on first click. Restart App completly to see the issue. Reloading is not enough.</Text>
</View>
</View>
<View>
<Button
onPress={() => BackHandler.exitApp()}
title="Exit App"
color="#841584"
accessibilityLabel="Android only I guess."
/>
</View>
</ScrollView>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 2,
backgroundColor: '#fff',
alignItems: 'center',
justifyContent: 'center',
marginBottom: 30
},
button: {
backgroundColor: '#fff',
borderRadius: 20,
padding: 10,
marginBottom: 20,
shadowColor: '#303838',
shadowOffset: { width: 0, height: 5 },
shadowRadius: 10,
shadowOpacity: 0
},
contentContainer: {
paddingVertical: 20,
flex: 1,
backgroundColor: '#fff',
},
text:{
color: '#000',
marginBottom: 30
},
imageButton: {
flex: 1,
width: 240,
height: 200,
marginBottom: -15,
marginTop: 10,
resizeMode: 'cover'
}
});
So my question is how can I stop the image from flickering after app start?
The full version of the little demo app I have build to show my problem is available on my Github Repository
There may be a performance issue while loading different resolution images. You can use https://github.com/DylanVann/react-native-fast-image module to load images.
you can add and link it as below
# Install
yarn add react-native-fast-image
# Automatic linking. (other linking methods listed below)
react-native link react-native-fast-image
after that u can import it and use it using like below example
import FastImage from 'react-native-fast-image'
const YourImage = () =>
<FastImage
style={styles.image}
source={{
uri: 'https://unsplash.it/400/400?image=1',
headers:{ Authorization: 'someAuthToken' },
priority: FastImage.priority.normal,
}}
resizeMode={FastImage.resizeMode.contain}
/>
I copied this example from that repo. you can find documentation also there. Try it. It will increase image loading performance. Then most probably flickering issue will be resolved.
For me, it was causing flickering issues when I put the Image component in a FlatList ListHeaderComponent component. So,
Code causing flickering:
ListHeaderComponent={HeadComponent}
The HeadComponent was basically inside render and had the code const HeadComponent = () => { return (<Image...
Code that fixed flickering:
ListHeaderComponent={this.renderHeader}
The renderHeader is a function that returned the same thing as HeadComponent using code renderHeader () { return (<Image...
Hope this helps someone.
It was causing flickering issues when I put the Image component in a FlatList ListHeaderComponent component
In order to solve the issue I added useCallBack hook
const ListComponent = useCallBack(() => {
// your code
}, [])
ListHeaderComponent={ListComponent}
For me it solved the flickering issue
Well I have a workaround (sort of..).
In my componentDidMount() I do now set the button to its pressed state, wait for some time until the image is displayed and scaled, and then I set the state to off again, like so:
componentDidMount(){
this.setState({alarm1: <Image source={require("./assets/alarmon.png")} style={styles.imageButton}/>})
setTimeout(()=>{this.setState({alarm1: <Image source={require("./assets/alarmoff.png")} style={styles.imageButton}/>})}, 1000);
}
I tried to lower the timeout to less than a second, but then on my old (and slow) phone the flickering started again on first press after app load.
This obviously leads to the button state beeing changed after the app loaded, but if all buttons flicker once after app start, that is better than every button flickering on first press in my opinion.
I would however be glad if anybody could tell me the real way, how to resolve this.
For anyone who still have this problem : this is another way to fix
<Image
source={{ uri: your_path }}
defaultSource={{ uri: your_path }}
resizeMode="cover"
style={{width: 100,height: 100}} />
A stupid way:
<ImageBackground
defaultSource={require('./ui/pay0.png')}
source={require('./ui/pay0.png')}
style={{flex: 1, position: 'relative', zIndex: 9999, elevation: 5}}
/>
{/* Cache the remaining pictures to prevent flickering */}
<ImageBackground
source={require('./ui/pay1.png')}
style={{position: 'absolute', width: 1, height: 1}}
/>
If you are using expo, you can use Asset.loadAsync. See: https://docs.expo.io/versions/latest/sdk/asset.
In App.js, I like to wait for all static assets to be loaded before showing any screen.
I have encountered a problem porting my app from iOS to android. I have built a minimal bug case with which it can be reproduced.
My app is very simple and consists of one component:
const Main = () => (
<View>
<View style= {styles.green}>
<View style={styles.blue}/>
</View>
</View>
)
export default Main;
const styles = StyleSheet.create({
green: {
height:200,
marginTop: 200,
backgroundColor: 'green',
},
blue:{
position:'absolute',
height: 100,
width: 100,
top: -50,
backgroundColor: 'blue',
},
})
But strangely this component renders differently on iOS and Android
iOS
Android
I would like it to render like on iOS on both devices. You can check code on this repo https://github.com/42void/ReactNativeBug to easily reproduce it.
Thank you!
In Android overflow property defaults to 'hidden' and cannot be changed.
From 0.23 known issues, apparently isn't fixed yet.