React Native - Continuously animated view throttles CPU on android emulator - javascript

I've created an icon that are supposed to pulsate continuously in my app. Sometimes there will also be multiple "live" icons on the same screen, indicating that something is live.
The problem is that when the icon is animating, this results in a CPU rise to over 500% for the Android Emulator (qemu-system-x86_64) and it is not getting any lower as long as the icon is animating.
For iOS it seems like it working out quite nice.
Here is my code:
class AnimatedRealtimeIcon extends React.Component<Props> {
animationPulse: new Animated.Value(0)
componentDidMount() {
Animated.loop(Animated.timing(this.animationPulse, {
toValue: 1,
duration: 2500,
useNativeDriver: true,
isInteraction: false,
})).start()
}
interpolateTo = outputRange => this.animationPulse.interpolate({
inputRange: [0, 1],
outputRange,
})
render() {
return (<View style={ styles.dotContainer }>
<View style={
[styles.dot,
{
position: 'absolute',
}
]}
/>
<Animated.View style={
[styles.dot, {
transform: [ {
scale: this.interpolateTo([0.5, 3]),
}],
position: 'absolute',
opacity: this.interpolateTo([1, 0]),
}]}
/>
</View>)
}
}
const styles = StyleSheet.create({
dotContainer: {
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 4,
},
dot: {
backgroundColor: '#9BA4D2',
alignItems: 'center',
justifyContent: 'center',
height: 6,
width: 6,
borderRadius: 4
},
})
Does anyone out there have any suggestion on how to optimize a view that will be continuously animated in React Native? I tried using a gif as well, but it seems like that also resulted in a very high CPU usage.
I just upgraded to react-native: 0.57.0 and react: 16.6.0 but that did not help.
Thanks in advance for any help 😃

Related

Reduce height and vertical padding for a react-native-paper TextInput

I have the following code:
import React, { Component } from 'react';
import { View, StyleSheet } from 'react-native';
import { Button, TextInput } from 'react-native-paper';
export default class Header extends Component {
state = {
text: '',
};
render() {
return (
<View style={styles.container}>
<TextInput value={this.state.text} style={styles.input} />
<Button mode="contained" style={styles.button}>Add Todo</Button>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
alignSelf: 'stretch',
backgroundColor: '#c1deff',
},
input: {
flex: 1,
},
button: {
flex: 0,
},
});
which outputs the following screen:
My goal is to reduce the height for the TextInput. It also looks like it has some vertical padding. Is it possible to decrease that as well? I'm just trying to save space on the screen and in my opinion is taking lot of it area.
EDIT 01
I tried with the following style:
input: {
flex: 1,
height: 40,
borderColor: 'gray',
borderWidth: 1,
}
but didn't work, because I got the following result:
which as you can see, doesn't look good (obvious).
Thanks!
add height and justifyContent in style
input: {
flex: 1,
height: 40,
justifyContent:"center"
}
You can set height for it if you want:
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1, justifyContent:"center"}}
onChangeText={(text) => this.setState({text})}
value={this.state.text}
/>
Source: https://facebook.github.io/react-native/docs/textinput
Also try searching in Github for some custom inputtext. They may have what you need. Good luck!
As you can see from the source code, you can only change the input size by modifying the render prop
To adjust the height add the style height: 40 and to adjust vertical padding add the style paddingHorizontal: 0
Your tag should then look like the following:
<TextInput value={"Something"} style={{ flex: 1, height: 40, paddingHorizontal: 0}} />
use margin with negative value like
contentStyle={{ marginHorizontal: -10, marginVertical: -2 }}

React-Native Shadow after upgrading to 0.56

I have upgraded the react-native dependency and have some weird issues with the shadow prop of my views.
It sets the shadow for every child in a View but not on the actual view where it should be. It occurs only on iOS, android keeps working.
I have increased the shadowOpacity to know what is really happening, and as described, every item gets a shadow but not the main container.
render() {
return (
<View style={styles.taskContainer}>
<TouchableOpacity onPress={this.props.onPress}>
<View style={styles.taskContentContainer}>
<Text style={styles.title}>{this.props.task.title}</Text>
<View row spread style={{ marginTop: 5 }}>
{this.state.profileImgUrl ? (
<FastImage
...
taskContainer: {
marginLeft: 10,
marginRight: 10,
marginTop: 11,
//ios
shadowOpacity: 0.15,
shadowRadius: 4,
shadowOffset: {
height: 1,
width: 0
},
//android
elevation: 2.5,
borderRadius: 5,
borderWidth: 0,
marginBottom: 2
},
As trying to improve Android performance I have read about overdrawing and so I have tried to reduce it by not applying any unnecessary backgroundColors to sub-Views. Because the parent-View has the backgroundColor already set, I reduced overdrawing by that method. Now the problem seems that the new update handles Views with shadows and no (or transparent) backgroundColors descending to their child-Views.
Solution:
added "backgroundColor: "white" to the taskContainer style.

How to share space with equal-size components in React-native

I have started recently with Javascript and React-native to test if it could be used in the future in my current company, but I'm facing some UI problems.
I'm making a test app with some, kind of almost useless functions to learn a bit of Javascript and how to link JS with native Android modules, but now I'm stuck with the interface. I used to make interfaces with RelativeLayout (ConstraintLayout now), and that's why I'm a bit frustrated with this HTML-like and CSS (which I don't specially know in depth, to be honest).
Given this UI . . .
. . . I actually want those buttons to share all the blank space on the screen and have the same heigth, but I don't want to set any width or heigth property, since I believe that each phone, with its own screen size and resolution, should handle the size of the components.
And serching around here and there, I discovered a property called flex that supposedly works like Android's LinearLayout weigth, but when I use it on any button, they just disappear:
So, how should/could I solve this?
Here are the "HTML" and styles used:
render() {
return (
<View style={styles.container}>
<View style={styles.containerText}>
<ScrollView
style={styles.scrollTextStyle}
contentContainerStyle={{ flexGrow: 1 }}
>
<Text style={styles.textStyle}>{this.state.textField}</Text>
</ScrollView>
<TextInput
multiline={true}
style={styles.inputStyle}
onChangeText={inputField =>
this.setState({
inputField
})}
value={this.state.inputField}
/>
</View>
<View style={styles.containerButton}>
<Button
style={[styles.buttons, styles.firstButton]}
onPress={() => this.pressedButton(1)}
>
Copy input to text
</Button>
<Button
style={[styles.buttons, styles.secondButton]}
onPress={() => this.pressedButton(2)}
>
Android/iOS Toast
</Button>
<Button
style={[styles.buttons, styles.thirdButton]}
onPress={() => this.pressedButton(3)}
>
Android module (Method)
</Button>
<Button
style={[styles.buttons, styles.fourthButton]}
onPress={() => this.pressedButton(4)}
>
Android module (AsyncTask)
</Button>
</View>
</View>
);
}
const styles = StyleSheet.create({
//Root View
container: {
flex: 1,
flexDirection: "column",
backgroundColor: "#F5FCFF"
},
//Texts View
containerText: {
flex: 2,
justifyContent: "center",
backgroundColor: "#EFEFFF"
},
//Buttons View
containerButton: {
flex: 4,
flexDirection: "column",
backgroundColor: "#FFFFFF",
justifyContent: "space-between"
},
//Components on first View
scrollTextStyle: {
borderWidth: 1,
marginTop: 10,
marginBottom: 5,
marginHorizontal: 10,
flex: 1
},
textStyle: {
backgroundColor: "#CEF",
textAlign: "center",
textAlignVertical: "center",
flex: 1
},
inputStyle: {
borderWidth: 1,
marginTop: 5,
marginBottom: 10,
marginHorizontal: 10,
backgroundColor: "#CEF",
textAlign: "center",
textAlignVertical: "center",
flex: 1
},
//Components on second view
//Common style for all buttons and a different one for each
buttons: {
borderRadius: 5,
textAlign: "center",
textAlignVertical: "center",
fontSize: 20
},
firstButton: {
color: "#FFFFFF",
backgroundColor: "#D1E233"
},
secondButton: {
color: "#FFFFFF",
backgroundColor: "#239923"
},
thirdButton: {
color: "#FFFFFF",
backgroundColor: "#958475"
},
fourthButton: {
color: "#FFFFFF",
backgroundColor: "#651278"
}
});
By the way, I would appreciate any tutorial-like web about user interfaces on React-native, since I only found kind of useless things explaining properties, but no quality full examples.
You can use Dimension
import {Dimensions} from 'react-native';
Dimensions.get('window').height
or use react-native-easy-grid
<Grid>
<Row></Row>
<Row></Row>
</Grid>
It will create 2 equal height row
I would recommend wrapping all of the buttons in a div, and then making the div's height equal to the screen height - the height of your input fields.
Example: var {height, width} = Dimensions.get('window');
Source
This will then give the buttons a container to live in. After that you can use % for the height of the buttons. So if you have 4 buttons you can make the height of each of them 25% which would make them fit any screen.

How to Position a React Native Button at the bottom of my screen to work on multiple ios devices

I am young to react native search the web for tutorials that could help me with this problem but have not find anything. I know how to move the buttons from point A to B on my screen. The thing is I just cant seem to get it to be fixed at the bottom to work on different form factors of my ios emulator.
So far I have tried marginTop which takes down the button to the screen but as soon as a I change the emulator to a different screen size the button goes up a little. I am asking can I get any guidance as how I may set this to work on different ios screens.
submitButton: {
height: 85,
flex: 1,
backgroundColor: "#FFBB34",
borderColor: "#555555",
borderWidth: 0,
borderRadius: 0,
marginTop: 200,
justifyContent: "flex-start"
}
The code above is my button.
You can use absolute position to put things wherever you want...
submitButton: {
position: 'absolute',
bottom:0,
left:0,
}
will put at bottom of screen, left side....
Here is how I placed the floating button at the bottom-right of the screen.
return (
<View style={mainConatinerStyle}>
{this.renderSwiper()}
{this.renderFloatingMenu()}
</View>
);
Use the following styles for container & button:
mainConatinerStyle: {
flexDirection: 'column',
flex: 1
},floatingMenuButtonStyle: {
alignSelf: 'flex-end',
position: 'absolute',
bottom: 35
}
Output:
You can try the code below at https://facebook.github.io/react-native/docs/flexbox.html until that link doesn't work anymore.
Basically you are splitting the screen into 3 pieces, top scrollable, and bottom. The code below is just doing 3 views for simplicity (no scrolling, just replace the middle one with a ScrollView to have somethign more useful.
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
export default class JustifyContentBasics extends Component {
render() {
return (
// Try setting `justifyContent` to `center`.
// Try setting `flexDirection` to `row`.
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'space-between',
}}>
<View style={{height: 50, backgroundColor: 'powderblue'}} />
<View style={{flex:1, backgroundColor: 'skyblue'}} />
<View style={{height: 50, backgroundColor: 'steelblue'}} />
</View>
);
}
the element
<View style={style.viewBtn}>
<TouchableOpacity style={style.btn} onPress={() => {}}>
<Text style={style.txtBtn}>Send</Text>
</TouchableOpacity>
</View>
the CSS
viewBtn: {
position: 'absolute',
bottom: 0,
height: window.height * 0.1,
width: window.width * 1,
backgroundColor: 'white',
justifyContent: 'center',
alignItems: 'center',
},
btn: {
height: window.height * 0.07,
width: window.width * 0.8,
backgroundColor: colors.cornflower,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 10,
},
txtBtn: {
textAlign: 'center',
fontSize: 21,
color: 'white',
fontWeight: 'bold',
},
hope this code help your problem, dont forget to use dimension to set height and weight, but optional to use the dimension

How do I render a shadow?

How do I render a shadow on a View? I've tried many combinations of shadowColor, shadowOffset, shadowOpacity, and shadowRadius, which seem to do nothing. I am sure the style is applied correctly, since other attributes I've set work.
I am using React-Native 0.40 and below code works for me both on IOS and Android.
(Android-only) Sets the elevation of a view, using Android's underlying elevation API. This adds a drop shadow to the item and affects z-order for overlapping views. Only supported on Android 5.0+, has no effect on earlier versions.
class MainApp extends Component {
render() {
return (
<View style={styles.container}>
<View elevation={5} style={styles.buttonContainer}>
<Text style={styles.textStyle}>Shadow Applied</Text>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#FFFFFF'
},
textStyle: {
color: '#FFFFFF'
},
buttonContainer: {
backgroundColor: '#2E9298',
borderRadius: 10,
padding: 10,
shadowColor: '#000000',
shadowOffset: {
width: 0,
height: 3
},
shadowRadius: 5,
shadowOpacity: 1.0
}
})
Tested on iPhone.
Edit
Comment from # James. Thanks.
Note: For those on android, the backgroundColor is critical. I was using View as a container for another element and couldn't get a shadow until I specified a background color.
Use elevation to implement shadows on RN Android. Added elevation prop #27
<View elevation={5}>
</View>
It appears to be a bug in React native that shadowOpacity is set to type CGFloat instead of float according to CALayer doc. use iPhone 5 simulator before it's fixed. (CGFloat is float in older devices. )
The React Native issue which is tracking this is:
https://github.com/facebook/react-native/issues/449
viewStyle : {
backgroundColor: '#F8F8F8',
justifyContent: 'center',
alignItems: 'center',
height: 60,
paddingTop: 15,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.2,
marginBottom: 10,
elevation: 2,
position: 'relative'
},
Use marginBottom: 10
You have to give elevation prop to View
<View elevation={5} style={styles.container}>
<Text>Hello World !</Text>
</View>
styles can be added like this:
const styles = StyleSheet.create({
container:{
padding:20,
backgroundColor:'#d9d9d9',
shadowColor: "#000000",
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 1,
width: 1
}
},
})
panel: {
// ios
backgroundColor: '#03A9F4',
alignItems: 'center',
shadowOffset: {width: 0, height: 13},
shadowOpacity: 0.3,
shadowRadius: 6,
// android (Android +5.0)
elevation: 3,
}
or you can use react-native-shadow for android
All About margins
this works in Android, but did not test it in ios
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
import { View, Platform } from 'react-native'
import EStyleSheet from 'react-native-extended-stylesheet'
const styles = EStyleSheet.create({
wrapper: {
margin: '-1.4rem'
},
shadow: {
padding: '1.4rem',
margin: '1.4rem',
borderRadius: 4,
borderWidth: 0,
borderColor: 'transparent',
...Platform.select({
ios: {
shadowColor: 'rgba(0,0,0, 0.4)',
shadowOffset: { height: 1, width: 1 },
shadowOpacity: 0.7,
shadowRadius: '1.4rem'
},
android: {
elevation: '1.4rem'
}
})
},
container: {
padding: 10,
margin: '-1.4rem',
borderRadius: 4,
borderWidth: 0,
borderColor: '#Fff',
backgroundColor: '#fff'
}
})
class ShadowWrapper extends PureComponent {
static propTypes = {
children: PropTypes.oneOfType([
PropTypes.element,
PropTypes.node,
PropTypes.arrayOf(PropTypes.element)
]).isRequired
}
render () {
return (
View style={styles.wrapper}
View style={styles.shadow}
View style={styles.container}
{this.props.children}
View
View
View
)
}
}
export default ShadowWrapper
by styled component
const StyledView = styled.View`
border-width: 1;
border-radius: 2;
border-color: #ddd;
border-bottom-width: 0;
shadow-color: #000;
shadow-offset: {width: 0, height: 2};
shadow-opacity: 0.8;
shadow-radius: 2;
elevation: 1;
`
or by styles
const styles = StyleSheet.create({
containerStyle: {
borderWidth: 1,
borderRadius: 2,
borderColor: '#ddd',
borderBottomWidth: 0,
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.8,
shadowRadius: 2,
elevation: 1,
marginLeft: 5,
marginRight: 5,
marginTop: 10,
}
})
I'm using Styled Components and created a helper function for myself.
It takes the given Android elevation and creates a fairly equivalent iOS shadow.
stylingTools.js
import { css } from 'styled-components/native';
/*
REMINDER!!!!!!!!!!!!!
Shadows do not show up on iOS if `overflow: hidden` is used.
https://react-native.canny.io/feature-requests/p/shadow-does-not-appear-if-overflow-hidden-is-set-on-ios
*/
// eslint-disable-next-line import/prefer-default-export
export const crossPlatformElevation = (elevation: number = 0) => css`
/* Android - native default is 4, we're setting to 0 to match iOS. */
elevation: ${elevation};
/* iOS - default is no shadow. Only add if above zero */
${elevation > 0
&& css`
shadow-color: black;
shadow-offset: 0px ${0.5 * elevation}px;
shadow-opacity: 0.3;
shadow-radius: ${0.8 * elevation}px;
`}
`;
To use
import styled from 'styled-components/native';
import { crossPlatformElevation } from "../../lib/stylingTools";
export const ContentContainer = styled.View`
background: white;
${crossPlatformElevation(10)};
`;

Categories