I have To-Do list elements which can expand and collapse by pressing the associated button.
By pressing on the EXPAND Button the height of the Animated ScrollView gets adjusted. From 0 to 100 when expanding and from 100 to 0 when collapsing. When we expand two list-objects at the same time, the screen begins to flicker.
Here the code of one single todo-element (it is abbreviated, means the DONE button is not in it):
import React, { useState, useRef, memo } from 'react';
import { Animated, Text, View, Button, ScrollView } from 'react-native';
import longText from '../data/data';
const ListObject = (props) => {
//Object Expand and Collapse feature
const expandValue = useRef(new Animated.Value(0)).current;
const [expandState, setExpand] = useState(false);
const expandAnimation = () => {
Animated.timing(expandValue, {toValue: 100, duration: 1000, useNativeDriver: false}).start();
setExpand(true);
}
const collapseAnimation = () => {
Animated.timing(expandValue, {toValue: 0, duration: 1000, useNativeDriver: false}).start();
setExpand(false);
}
return (
<View style={{ margin: props.margin }}>
<View style={{
flexDirection: 'row',
backgroundColor: 'grey',
borderRadius: 10,
}}>
<Button title='EXPAND' style={{
flex: 1,
backgroundColor: 'blue',
}}
onPress={ expandState ? collapseAnimation : expandAnimation }
/>
</View>
<Animated.ScrollView style={{
flex: 1,
paddingHorizontal: 40,
backgroundColor: 'grey',
borderRadius: 10,
maxHeight: expandValue
}}>
<Text>{ props.text }</Text>
</Animated.ScrollView>
</View>
);
}
export default memo(ListObject);
Here is the code for the App. To make a collection of all todo-elements, I map over a list and assign a key to each element:
mport React, { useRef, useState } from 'react';
import { Animated, StyleSheet, ScrollView, Text, View, SafeAreaView, Button } from 'react-native';
import longText from './src/data/data';
import ListObject from './src/components/list-object'
const styles = StyleSheet.create({
safeContainer: {
flex: 1.2
},
headerContainer: {
flex: 0.2,
flexDirection: 'column',
justifyContent: 'center',
backgroundColor: 'lightblue',
},
headerFont: {
fontSize: 50,
textAlign: 'center',
},
scrollContainer: {
flex: 1
}
});
const App = () => {
const numbers = [1,2,3,4,5,6,7,8,9];
const listItems = numbers.map((number) =>
<ListObject key={number.toString()} margin={10} headerText='I am the header of the to-do element' text={longText} />
)
return (
<SafeAreaView style={ styles.safeContainer } >
<View style={ styles.headerContainer }>
<Text style={ [styles.headerFont] }>LIST MAKER</Text>
</View>
<ScrollView style={ styles.scrollContainer }>
{listItems}
</ScrollView>
</SafeAreaView>
);
};
export default App;
I expected no flickering. The flickering appears also on my physical Android device. I have searched for similar problems and checked other libraries how they implement it.
For this, you can use react-native-collapsible
import Accordion from 'react-native-collapsible/Accordion';
const [activeSections, setActiveSessions] = useState([])
const _updateSections = (activeSections) => {
setActiveSessions(activeSections.includes(undefined) ? [] : activeSections)
}
<Accordion
sections={data}
activeSections={activeSections}
duration={400}
renderHeader={_renderHeader}
renderContent={_renderContent}
onChange={_updateSections}
touchableComponent={TouchableOpacity}
renderAsFlatList={true}
expandMultiple={true}
/>
For better performance and a smooth experience use this one.
I found the mistake by myself, it's a beginner's mistake.
Instead of managing the state of the component in the component itself, I had to lift the state up to the parent.
Here the link to the ReactJS learning doc.
Related
I am fairly new to react native, but I have some experience. I am creating my own app for both ios and android by following along a tutorial that I had already completed and making my own modifications. As I was in the middle of creating an app, I forgot to add a background image. After struggling with this for several days, I'm desperate, so I decided to ask my question on here.
I am trying to add the background image to my App.js file. The image loads properly, but my page content ( which is inside <LifelineNavigator />) is either hidden or has disappeared for android. And for ios, the content seems to be in a small centered flexbox. Also, I am trying to remove the white background.
Any suggestions would definitely help. Thanks so much! God bless!
Here is my code:
import React, { useState } from "react";
import { StyleSheet, View, ImageBackground } from "react-native";
import * as Font from "expo-font";
import AppLoading from "expo-app-loading";
import { enableScreens } from "react-native-screens";
import LifelineNavigator from "./src/navigation/LifelineNavigator";
enableScreens();
const fetchFonts = () => {
return Font.loadAsync({
"Gotham-Medium": require("./src/assets/fonts/Gotham-Font/Gotham-Medium.otf")
const image = {
uri: "https://i.ibb.co/8z6QbTS/Lifeline-Gradient-Background-24.png",
};
const App = () => {
const [fontLoaded, setFontLoaded] = useState(false);
if (!fontLoaded) {
return (
<AppLoading
startAsync={fetchFonts}
onFinish={() => setFontLoaded(true)}
onError={(err) => console.log(err)}
/>
);
}
return (
<View >
<ImageBackground source={image} style={styles.image}>
<View style={ styles.container }>
<LifelineNavigator />
</View>
</ImageBackground>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
// backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
image: {
width: "100%",
height: "100%" ,
}
});
export default App;
IOS Screenshot
Android Screenshot
import React from "react";
import { ImageBackground, StyleSheet, Text, View } from "react-native";
const image = { uri: "https://reactjs.org/logo-og.png" };
const App = () => (
<View style={styles.container}>
<ImageBackground source={image} resizeMode="cover" style={styles.image}>
<Text style={styles.text}>Inside</Text>
</ImageBackground>
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
},
image: {
flex: 1,
justifyContent: "center"
},
text: {
color: "white",
fontSize: 42,
lineHeight: 84,
fontWeight: "bold",
textAlign: "center",
backgroundColor: "#000000c0"
}
});
export default App;
follow this documentation > https://reactnative.dev/docs/imagebackground
it may solve your problem
The images are getting croped how can i prevent that from happening? Notice that only appears half of the image. This is a Android device. Idont know if this happens in IOS too. But a fix for android would be great
My FlatList component
import React from 'react';
import { Text, View, StyleSheet, FlatList, Image } from 'react-native';
const shows_first = [
{
key: 1,
name: 'Suits',
image: 'https://static.tvmaze.com/uploads/images/medium_portrait/0/2432.jpg'
},
{
key: 2,
name: 'Modern Family',
image: 'https://static.tvmaze.com/uploads/images/medium_portrait/0/628.jpg'
},
]
const renderItem = (item) => {
return (
<Image style={{ width: 120, height: 100 }} source={{ uri: item.image }} />
)
}
const List = () => {
return (
<View style={{ flex: 1, marginTop: 110 }}>
<FlatList
horizontal={true}
ItemSeparatorComponent={() => <View style={{ width: 5 }}></View>}
renderItem={({ item }) => renderItem(item)}
data={shows_first}
></FlatList>
</View>
)
}
export default List;
You should use a resize mode to chose how you want to display your image.
If you are sure that all your images are going to be posters better give a height and width that suits the image.
Check the code below
const renderItem = (item) => {
return (
<Image style={{ width: 80, height: 120 ,resizeMode: 'center'}} source={{ uri: item.image }} />
)
}
You will need to style your image to fit as per aspect ration so to do that you will have to add resizeMode='contain'
Working example: https://snack.expo.io/#msbot01/cranky-scones
import * as React from 'react';
import { Text, View, StyleSheet, FlatList, Image} from 'react-native';
import Constants from 'expo-constants';
// You can import from local files
import AssetExample from './components/AssetExample';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
const DATA = [
{
key: 1,
name: 'Suits',
image: 'https://static.tvmaze.com/uploads/images/medium_portrait/0/2432.jpg'
},
{
key: 2,
name: 'Modern Family',
image: 'https://static.tvmaze.com/uploads/images/medium_portrait/0/628.jpg'
}
];
export default function App() {
return (
<View style={styles.container}>
<FlatList
data={DATA}
horizontal={true}
renderItem={({ item }) =>
<View style={styles.item}>
<Image style={{ width: 120, height: 100 }} source={{ uri: item.image }} resizeMode='contain'/>
</View>
}
keyExtractor={item => item.id}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8,
},
paragraph: {
margin: 24,
fontSize: 18,
fontWeight: 'bold',
textAlign: 'center',
},
});
I'm using react-native-circular-action-menu for popout navigation buttons. On iPhone it looks as expected (note the circle buttons):
But on Android it's being constrained into a box:
Here is the relevant code for this component:
import React, { Component } from 'react';
import {
View,
StyleSheet,
Text,
Image,
Dimensions
} from 'react-native';
import colors from '../../../styles/colors';
import formStyles from '../../../styles/formStyles';
import ActionButton from 'react-native-circular-action-menu';
import Icon from '../../../assets/components/svgIcons.js';
import { connect } from 'react-redux';
import * as actions from '../../../actions';
import apiHelper from "../../../utils/api";
import { NavigationActions, StackNavigator } from 'react-navigation';
class ProfileCircleNav extends Component {
renderImage() {
return(
<Image
source={require("../../../assets/images/LexodyL.png")}
style={{height: 70, width: 70}}
/>
)
}
renderButton() {
if(!this.state.blocked) {
return(
<View style={{minHeight: 200, width: 350}}>
<ActionButton
buttonColor={colors.rgbaGreen}
outRangeScale={.5}
btnOutRange={colors.halfGreen}
bgColor={'transparent'}
position={"right"}
radiua={200}
icon={this.renderImage()}
onPress={this.props.onPress}
style={{zIndex: 12}}
>
<ActionButton.Item buttonColor={'transparent'} title="Request Lex" onPress={() => {this.createMeeting()}}>
<View style={styles.actionButton}>
<Icon
name='Calendar'
strokeWidth="3"
stroke={'#fff'}
fill={'#fff'}
/>
<Text style={formStyles.textStandard}>Schedule</Text>
<Text style={formStyles.textStandard}>Lex</Text>
</View>
</ActionButton.Item>
<ActionButton.Item buttonColor={'transparent'} style={styles.actionButtonIcon} title="Chat" onPress={() => this.startConvo()}>
<View style={styles.actionButton}>
<Icon
name='Chat'
strokeWidth="3"
stroke={'#fff'}
fill={'#fff'}
/>
<Text style={formStyles.textStandard}>Chat</Text>
</View>
</ActionButton.Item>
</ActionButton>
</View>
)
}
}
render() {
return (
<View style={{
bottom: Dimensions.get('window').height*.50,
backgroundColor: 'transparent',
}}>
{this.renderButton()}
</View>
);
}
}
const styles = StyleSheet.create({
actionButtonIcon: {
height: 500,
fontSize: 50,
},
actionButton: {
backgroundColor: colors.green,
height: 100,
width: 100,
borderRadius: 50,
alignItems: 'center',
justifyContent: 'center',
}
});
const mapStateToProps = (state) => {
return {
currentUser: state.currentUser
}
}
export default connect(mapStateToProps, actions)(ProfileCircleNav);
I've been trying to figure this out for hours - what am I missing here? Why is it a square on Android?
so the issue you have is that height here has no effect.
actionButtonIcon: {
height: 500,
fontSize: 50,
},
what you have to do is use the prop size to ActionButton.Item. I think a size bigger or equal than the borderRadius of 100 you are trying to apply.
<ActionButton.Item buttonColor={'transparent'} size={100} title="Request Lex" onPress={() => {this.createMeeting()}}>
Here is a working example: https://snack.expo.io/ByG7nsVwQ
You can see the prop used in the code right here
I have this screen in react native
import React, { Component } from 'react';
import { AppRegistry,TouchableOpacity, Text ,Button,Image,TextInput,PropTypes,StyleSheet,View,NavigatorIOS,TouchableHighlight} from 'react-native';
class LoginView extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>
HYGEX
</Text>
<View>
<TextInput
placeholder="Username"
style={styles.formInput}
/>
<TextInput
placeholder="Password"
secureTextEntry={true}
style={styles.formInput1}
/>
<TouchableHighlight style={styles.button}
onPress={() => this.move()}>
<Text style={styles.buttonText}>Login</Text>
</TouchableHighlight>
</View>
</View>
);
}
move() {
//what i can do here to go to Socrce screen ???
}
}
Something like login screen, now when I click into TouchableHighlight
I need to open this screen
'use strict';
import React, { Component } from 'react';
import { AppRegistry, ListView, Text, View } from 'react-native';
class HygexListView extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows([
'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
])
};
}
render() {
return (
<View style={{flex: 1, paddingTop: 22}}>
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
</View>
);
}
}
module.exports = HygexListView;
I tried to implement move method but I failed! Any idea why?
Does react-native have a method to change the screen when click into TouchableHighlight?
As others pointed out, you have to use an instance of Navigator to transition between screens. Maybe you can have a look at the example apps in the React Native repo. I also find this router package quite easy to set up, and it also includes an example app that you can use as a starting point.
Edit
As a simple example using react-native-router-flux, you can edit the Example.js file in the Example directory to look like this:
import React, {
Component,
} from 'react';
import {
StyleSheet,
Text,
View,
} from 'react-native';
import LoginView from './LoginView';
import HygexListView from './HygexListView';
import {
Scene,
Router,
Actions,
} from 'react-native-router-flux';
const styles = StyleSheet.create({
container: { flex: 1, backgroundColor: 'transparent', justifyContent: 'center',
alignItems: 'center',
},
tabBarStyle: {
backgroundColor: '#eee',
},
tabBarSelectedItemStyle: {
backgroundColor: '#ddd',
},
});
// define this based on the styles/dimensions you use
const getSceneStyle = (/* NavigationSceneRendererProps */ props, computedProps) => {
const style = {
flex: 1,
backgroundColor: '#fff',
shadowColor: null,
shadowOffset: null,
shadowOpacity: null,
shadowRadius: null,
};
if (computedProps.isActive) {
style.marginTop = computedProps.hideNavBar ? 0 : 64;
style.marginBottom = computedProps.hideTabBar ? 0 : 50;
}
return style;
};
class Example extends Component {
render() {
return (
<Router getSceneStyle={getSceneStyle}>
<Scene key="login" component={LoginView} initial={true}/>
<Scene key="hygex" component={HygexListView } />
</Router>
);
}
}
export default Example;
Then, in your component's move function, you have to do the following:
move(){
Actions.hygex(); // This will perform a slide transition, but you can customize it. Have a look at the docs for that.
I have not tested the code, so there might be some typos/missing imports/code, but it should give you an idea of what you have to do.
}
You have to implement a Navigator, which is roughly a component that manages all stuff related to screens, and header bar with back button and etc.
As you are a beginner, I suggest you to look at the docs on this link:
https://facebook.github.io/react-native/docs/navigator.html
Sorry for the short answer, I'm on my phone.
Good luck!
"use strict";
var React = require("react-native");
var {
Component,
StyleSheet,
Text,
TextInput,
TouchableHighlight,
View,
} = React;
var SecureView = require("./SecureView");
class LoginView extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: ""
};
}
render() {
return (
<View style={styles.container}>
<Text style={styles.title}>
Sign In
</Text>
<View>
<TextInput
placeholder="Username"
onChange={(event) => this.setState({username: event.nativeEvent.text})}
style={styles.formInput}
value={this.state.username} />
<TextInput
placeholder="Password"
secureTextEntry={true}
onChange={(event) => this.setState({password: event.nativeEvent.text})}
style={styles.formInput}
value={this.state.password} />
<TouchableHighlight onPress={(this.onSubmitPressed.bind(this))} style={styles.button}>
<Text style={styles.buttonText}>Submit</Text>
</TouchableHighlight>
</View>
</View>
);
}
onSubmitPressed() {
this.props.navigator.push({
title: "Secure Page",
component: SecureView,
passProps: {username: this.state.username, password: this.state.password},
});
}
};
var styles = StyleSheet.create({
container: {
padding: 30,
marginTop: 65,
alignItems: "stretch"
},
title: {
fontSize: 18,
marginBottom: 10
},
formInput: {
height: 36,
padding: 10,
marginRight: 5,
marginBottom: 5,
marginTop: 5,
flex: 1,
fontSize: 18,
borderWidth: 1,
borderColor: "#555555",
borderRadius: 8,
color: "#555555"
},
button: {
height: 36,
flex: 1,
backgroundColor: "#555555",
borderColor: "#555555",
borderWidth: 1,
borderRadius: 8,
marginTop: 10,
justifyContent: "center"
},
buttonText: {
fontSize: 18,
color: "#ffffff",
alignSelf: "center"
},
});
module.exports = LoginView;
You have to use navigator. please read the documentation as mentioned below. and if you will need then i will share you my code.
Here is an example: NavigatorExample
Hi everyone,
I am new to Android development using react-native and I got this error which I have no idea where this come from because I am not using ScrollView at all!
I am trying to render a list on the initial screen and its data is coming from an api call.
My code is
import React, { Component } from 'react';
import {
Image,
ListView,
TouchableHighlight,
Text,
View,
StyleSheet
} from 'react-native';
import Api from '../../Utils/api';
import CategoryRow from './CategoryRow';
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 12,
flexDirection: 'row',
alignItems: 'center',
},
text: {
marginLeft: 12,
fontSize: 16,
},
photo: {
height: 40,
width: 40,
borderRadius: 20,
},
separator: {
flex: 1,
height: StyleSheet.hairlineWidth,
backgroundColor: '#8E8E8E',
}
});
class Main extends React.Component {
constructor(props){
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows(['row 1', 'row 2'])
}
}
componentDidMount(){
Api.getCategories()
.then((res) => {
this.setState({
dataSource: ds.cloneWithRows(res)
})
})
.catch();
}
render() {
return(
<ListView
style={styles.container}
dataSource = {this.state.dataSource}
renderRow={(data) => <CategoryRow {...data} />}
/>
)
}
}
module.exports = Main;
And the code for categoryRow is:
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 12,
flexDirection: 'row',
alignItems: 'center',
},
text: {
marginLeft: 12,
fontSize: 16,
},
photo: {
height: 40,
width: 40,
borderRadius: 20,
},
});
const CategoryRow = (props) => (
<View style={styles.container}>
<Text style={styles.text}>
${props.name}
</Text>
</View>
);
export default CategoryRow;
Example of data :
[
{
"categoryId": 1,
"code": "15",
"name": "Photography",
"description": "Are you a photo junkie? Then join the “snap pack” and travel to some of the most photogenic places on earth. Our photography trips put you on an itinerary specially geared towards getting the perfect pic, with a group of like-minded travellers. Learn new tricks, share your knowledge, and never worry about taking the time to get the shot. Bonus: someone always has an extra lens cap.",
"categoryTypeId": 1,
"categoryType": {
"categoryTypeId": 1,
"name": "Activity"
}
}
]
Can someone please help me to find out where is the problem and how to resolve this error?
I think ListView uses the ScrollView props. See here http://facebook.github.io/react-native/releases/0.35/docs/listview.html#scrollview
From the error, it seems you should specify alignItems: 'center' in the contentContainerStyle prop of the ListView. Remove it from styles.container
<ListView contentContainerStyle={{alignItems: 'center'}}>
....
</ListView>
render() {
return(
<View style={{
alignItems: 'center'
}}>
<ListView
style={styles.container}
dataSource = {this.state.dataSource}
renderRow={(data) => <CategoryRow {...data} />}
/>)
</View>
}