I have a problem when I separate some flat-list to different components. How can I arrange render flat-list like the sample form (Picture " Sample UI")? I try and it doesn't work. It rendered flat list A then flat list B. Please help me solve it. Have another way can solve it.
Thanks.
My code is here.
Header component
import React, {Component} from 'react'
import {View,Text,StyleSheet,FlatList,Image} from 'react-native'
import data from '../data/FlatListData.json'
//Component render flat-list. Show name of artist and albums.
export default class Header extends Component{
renderItem(item) {
return(
<View style = {styles.flatlist}>
<Image
source = {{uri: item.item.thumbnail_image}} style ={styles.imageThumbnail}>
</Image>
<View style= {{
flex: 1,
flexDirection: 'column'
}}>
//show title
<Text style = {styles.textTitle}>{item.item.title}</Text>
//show name of artist
<Text style = {styles.textArtist}>{item.item.artist}</Text>
</View>
</View>
);
}
render(){
return(
<View style = {{flex: 1}}>
<View style = {{flex: 1}}>
<FlatList
data = {data}
renderItem = {this.renderItem}
keyExtractor = { (item) => item.title.toString() }
/>
</View>
</View>
);
}
}
//style
const styles = StyleSheet.create({
container: {
marginTop: 20,
justifyContent: 'center',
alignItems: 'center',
borderColor: '#d6d7da',
borderRadius: 4,
borderWidth: 0.5,
fontSize: 1,
height: 50,
marginLeft: 10,
marginRight:10
},
text: {
fontSize: 20,
},
flatlist: {
flex: 1,
flexDirection: 'row',
marginRight: 20,
marginLeft: 20,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 4,
borderWidth: 0.4,
borderColor: '#d6d7da',
marginTop: 20,
height: 60
},
imageThumbnail: {
width: 50,
height: 50,
margin: 5
},
image: {
width: 320,
height: 240,
margin: 5
},
})
Image Component
import React, {Component} from 'react'
import {View,Text,StyleSheet,FlatList,Image} from 'react-native'
import data from '../data/FlatListData.json'
// Component show image of albums
export default class ImageCom extends Component{
renderItem(item) {
return(
<View style = {styles.flatlist}>
//Image of albums
<Image
source = {{uri: item.item.image}} style ={styles.image}>
</Image>
</View>
);
}
render(){
return(
<View style = {{flex: 1}}>
<View style = {{flex: 1}}>
<FlatList
data = {data}
renderItem = {this.renderItem}
keyExtractor = { (item) => item.title.toString() }
/>
</View>
</View>
);
}
}
//style sheet
const styles = StyleSheet.create({
flatlist: {
flex: 1,
flexDirection: 'row',
marginRight: 20,
marginLeft: 20,
alignItems: 'center',
justifyContent: 'center',
borderRadius: 4,
borderWidth: 0.4,
borderColor: '#d6d7da',
marginTop: 5,
height: 250
},
image: {
width: 320,
height: 240,
margin: 5
},
})
App.js
import React, {Component} from 'react'
import {View,Text,StyleSheet,FlatList} from 'react-native'
import Tabbar from './src/components/Tabbar'
import Header from './src/components/Header'
import ImageCom from './src/components/ImageCom'
//Combine components and show it on UI
export default class App extends Component{
render() {
return(
<View style = {styles.container}>
<Tabbar /> //Hello
<Header /> //Artist and albums
<ImageCom /> //Image of albums
</View>
);
}
}
const styles = StyleSheet.create ({
container: {
flex: 1,
},
});
hi as #angelos_lex said you dont require two flatlists i tink so you can display that image component image in header component only
export default class Header extends Component{
renderItem(item) {
return(
<View style = {{flexDirection:'colomn'}}> **//give require styles**
<View style = {styles.flatlist}>
<Image
source = {{uri: item.item.thumbnail_image}} style = {styles.imageThumbnail}>
</Image>
<View style= {{ flex: 1,flexDirection: 'column' }}>
//show title
<Text style = {styles.textTitle}>{item.item.title}</Text>
//show name of artist
<Text style = {styles.textArtist}>{item.item.artist}</Text>
</View>
</View>
<Image source = {{uri: item.item.image}} style ={styles.image}/> **// i am not sure what uri should be given**
</View>
);
**// remaining code**
Why you need two separate flatlists for this?
Since you want it with order: header_No1->image_No1->footer_No1 then header_No2->image_No2->footer_No2, then one Flatlist is enough, which will render "header" "image" and "footer" components inside.
Related
As you can see in the image below, I have to give some top margin in order to "not" hide my half of the content under the navigation header, isn't header supposed to be a "safe area" for the below content, to be on the safe side I provided the SafeAreaView but still my content goes under the Header and unfortunately I have to give some hardcoded margin top value to avoid hiding.
The above image is when I comment marginTop.
Above image is when I add marginTop: 70
Code:
NotificationScreen.tsx:
import {
View,
SafeAreaView,
Text,
StatusBar,
} from 'react-native';
import Animated, {FadeIn, FadeOut} from 'react-native-reanimated';
import OrderItem from '../../components/OrderItem';
const NotificationScreen = () => {
const [orders, setOrders] = useState([]);
useEffect(() => {
// calling API...
}, []);
return (
<SafeAreaView style={styles.container}>
<StatusBar backgroundColor="transparent" translucent />
<Text style={{color: 'lightgray', fontSize: 18}}>My Orders: </Text>
<Animated.FlatList
data={orders}
entering={FadeIn}
leaving={FadeOut}
contentContainerStyle={{
alignItems: 'center',
}}
keyExtractor={(_: any, index) => 'key' + index}
renderItem={({item}) => <OrderItem key={item.id} data={item} />}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {
marginTop: 70, // if I remove this, the content goes under the header as shown in image.
flex: 1,
padding: 10,
backgroundColor: COLORS.primary,
},
});
export default NotificationScreen;
One more query, why my OrderItem not taking the full width of FlatList (see image, the gray box is not takin the full width...), I have provided width: 100% to my OrderItem container:
OrderItem.tsx:
const OrderItem = ({data}) => {
return (
<View style={styles.container}>
<View style={styles.textBlock}>
<Text style={styles.label}>Strategy: </Text>
<Text style={styles.info}>{data.strategyTitle}</Text>
</View>
// ... same views as shown in image
</View>
);
};
const styles = StyleSheet.create({
container: {
width: '100%',
paddingVertical: 10,
paddingHorizontal: 10,
alignItems: 'center',
justifyContent: 'space-between',
backgroundColor: COLORS.lightGray,
borderRadius: 10,
},
textBlock: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
label: {
color: 'grey',
fontSize: 16,
},
info: {
color: 'white',
fontSize: 16,
},
});
export default OrderItem;
The SafeAreaView does not work currently for Android devices. You need to have something like this to avoid this issue:
import { Platform,StatusBar } from "react-native";
const styles = StyleSheet.create({
container: {
paddingTop: Platform.OS == "android" ? StatusBar.currentHeight : 0,
},
});
<SafeAreaView style={styles.container}>
</SafeAreaView>
And for the OrderItem not taking all available width, remove from Animated.FlatList this:
contentContainerStyle={{alignItems: 'center'}}
I have stored the value locally using array, And I want to delete a single item by using Trash icon. But I need to delete the multi selected items from the array.
So I placed the button "Delete selected". But I am not able to select multiple items and I don't know how to write the functionality to delete multiple items. I'm new for the React Native so kindly help.
Here is my code
import React, { Component } from "react"
import { View, Text, TouchableOpacity, TouchableHighlight, TextInput, StyleSheet, FlatList,onRemove } from 'react-native'
import {Card,CardItem,Right} from 'native-base';
import Swipeout from 'react-native-swipeout'
import Icon from 'react-native-vector-icons/FontAwesome';
import MultiSelect from 'react-native-multiple-select';
class Screen3 extends Component{
constructor(props) {
super(props);
this.state = {
loading: false,
firstname:[],
onPress:true,
unique1:[],
unique:[],
selectedItems : [],
renderData:item,
key1:0
};
}
componentDidMount=()=>{
const{navigation}=this.props
const data=navigation.getParam('data','')
const unique=data.filter((value,index,self)=>self.indexOf(value)===index)
var key=0
const unique1=[]
for(var i=0;i<unique.length;i++){
key=key+1
var result={"name":unique[i],"key":key}
this.state.unique1.push(result)
this.state.key1=this.state.key1+1
this.setState({key1:this.state.key1})
}
}
onPressHandler(item) {
let renderData=[...this.state.renderData];
for(let data of renderData){
if(data.item==item){
data.selected=(data.selected==null)?true:!data.selected;
break;
}
}
this.setState({renderData});
}
deleteItem = (item,index) => {
console.log(item.name,index)
this.state.unique=this.state.unique1
let filtered=this.state.unique.filter((item1) => item1.key !== item.key)
console.log(filtered)
this.setState({unique1:filtered})
}
render(){
return (
<View>
<Text style={styles.heading}>
Manage Screen
</Text>
<TouchableOpacity style = {styles.Button}
onPress={()=>this.deleteItem(item,index) } >
<Text style={styles.button}>Delete selected</Text>
</TouchableOpacity>
<FlatList
data={this.state.unique1}
showsVerticalScrollIndicator={false}
extraData={this.state.key1}
style={{ marginTop: 16 }}
renderItem={({ item, index }) => (
// <TouchableOpacity onPress={() => this.handleData(item)}>
<TouchableOpacity onPress={() => this.onPressHandler(item,index)}>
item!=null?
<Card
style={{
elevation: 10,
marginBottom: 15,
}}
>
<View style={{ flex: 1 }}></View>
<CardItem bordered >
style={
item.selected==true
? {
padding: 10,
borderRadius: 5,
backgroundColor: '#000000',
}
: {
borderRadius: 5,
backgroundColor: '#a1a1a1',
}}
<Text>{item.name}</Text>
<Right style={{alignSelf:'flex-end' } }>
<TouchableOpacity onPress={() => this.deleteItem(item,index)}>
<Icon size={25} name={Platform.OS ==='android' ? "trash" : "ios-trash"} color="red"/>
</TouchableOpacity>
</Right>
</CardItem>
</Card>:null
// </TouchableOpacity>
)
}
/>
</View>
)
}
}
export default Screen3
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
heading: {
fontSize: 23,
paddingVertical:80,
textAlign: 'center',
marginBottom: 30,
marginTop: -40,
},
button:{
width:('39%'),
height:('4%'),
alignItems:'center',
borderWidth:1,
borderRadius:2,
marginTop:-80,
marginHorizontal:10,
marginLeft:110,
justifyContent:'center',
backgroundColor: '#b0c4de',
padding: 9,
fontSize: 15,
margin: 15,
height: 40,
width: 160,
alignItems: 'center'
}
}
)
You would need a different function to delete multiple items and that function would call your deleteItem() function. A simple, but not so efficient way would be to loop through your selectedItems and find them in your data array and then remove each selected item with deleteItem(). You can then improve from there if it's not efficient enough.
I am making a react native app and for some reason when I tap on the text input to type something it disappears under the keyboard. I want it to come to the top of the keyboard like the way Instagram messenger and other messenger apps do it. I tried using keyboardAvoidView and setting the behavior to padding and height but none of it worked.
import {
View,
Text,
StyleSheet,
SafeAreaView,
TextInput,
TouchableOpacity,
} from "react-native";
import CommunityPost from "../components/CommunityPost";
import { Context as CommunityContext } from "../context/CommunityContext";
const Key = ({ navigation }) => {
const { createCommunityPost, errorMessage } = useContext(CommunityContext);
const [body, setBody] = useState("");
return (
<View style={styles.container}>
<SafeAreaView />
<CommunityPost />
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
multiline={true}
placeholder="Type..."
placeholderTextColor="#CACACA"
value={body}
onChangeText={setBody}
/>
<TouchableOpacity
style={{ justifyContent: "center", flex: 1, flexDirection: "row" }}
onPress={() => createCommunityPost({ body })}
>
<Text style={styles.sendText}>Send</Text>
</TouchableOpacity>
</View>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "flex-start",
backgroundColor: "#2B3654",
justifyContent: "flex-end",
},
inputContainer: {
justifyContent: "flex-end",
flexDirection: "row",
},
sendText: {
color: "white",
fontSize: 25,
},
input: {
fontSize: 25,
color: "white",
borderColor: "#2882D8",
borderWidth: 1,
borderRadius: 15,
width: "80%",
marginBottom: 30,
marginLeft: 10,
padding: 10,
},
});
export default Key;
You must KeyboardAvoidingView component provided by react native.
<KeyboardAvoidingView
behavior={Platform.OS == "ios" ? "padding" : "height"}
style={styles.container}
>
<SafeAreaView />
<CommunityPost />
<View style={styles.inputContainer}>
<TextInput
style={styles.input}
multiline={true}
placeholder="Type..."
placeholderTextColor="#CACACA"
value={body}
onChangeText={setBody}
/>
<TouchableOpacity
style={{ justifyContent: "center", flex: 1, flexDirection: "row" }}
onPress={() => createCommunityPost({ body })}
>
<Text style={styles.sendText}>Send</Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
For these situations we can use one of these methods:
1.wrapping Component with <ScrollView></ScrollView>
2.wrapping Component with <KeyboardAvoidingView></KeyboardAvoidingView>
Sometimes our wrong given styles can make these happens too such as : Having a fixed value for our styles, check your margins and use one of the given methods
I hope it helps
Try using keyboardVerticalOffset and test it with different values.
For more info check this out
For those who want to keep the code clean, just use the FlatList component and add a View component involving the component with the states: {flex: 1, height: Dimensions.get ("window"). Height}.
Below left a component ready for anyone who wants to use, just wrap your component in this way:
<FormLayout>
{... your component}
</FormLayout>
Here is the solver component:
import React from 'react'
import { View, StyleSheet, FlatList, Dimensions } from 'react-native'
import Background from './Background'
const FormLayout = ({ children }) => {
const renderContent = <View style={styles.container}>
{children}
</View>
return <FlatList
ListHeaderComponent={renderContent}
showsVerticalScrollIndicator={false}
/>
}
const styles = StyleSheet.create({
container: {
flex: 1,
height: Dimensions.get('window').height * 0.95
}
})
export default FormLayout
I was trying to make a "photo galley app" where each image is a "button" that toggle on the boolean property for Modal tag. The problem is that the images are rendered by a FlatList which pass props to component "GenerateImage.js", but at the same time, I need to pass the state and dispatch function as a parameter as well.
File who render the FlatList:
import React, { Component } from 'react'
import { FlatList, View, StyleSheet, TouchableOpacity, Text, AppRegistry } from 'react-native'
import { connect } from 'react-redux'
import GenerateImage from '../components/GenerateImage'
import commonStyles from '../commonStyles'
import Modal from '../components/Modal'
const Photos = ({ params }) => {
return (
<View style={{ flex: 1 }}>
<Modal isVisible={params.showFullImage} />
<View style={styles.buttonsContainer}>
<TouchableOpacity style={styles.touchContainer}>
<Text style={styles.button}>Hoje</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.touchContainer}>
<Text style={styles.button}>Mês</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.touchContainer}>
<Text style={styles.button}>Ano</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.touchContainer}>
<Text style={styles.button}>Álbuns</Text>
</TouchableOpacity>
</View>
<View style={{ flex: 30 }}>
<FlatList data={params.images} keyExtractor={item => `${item.id}`}
renderItem={({item}) => <GenerateImage {...item} />} numColumns={2} />
</View>
</View>
)
}
const styles = StyleSheet.create({
buttonsContainer: {
flex: 3,
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#1c2431',
},
touchContainer: {
marginHorizontal: 20,
backgroundColor: '#439ce8',
borderRadius: 30,
width: 65,
alignItems: 'center',
justifyContent: 'center',
padding: 5
},
button: {
color: 'white',
fontFamily: commonStyles.Font,
fontSize: 14
}
})
export default connect(state => ({ params: state[0] }))(Photos)
GenerateImage.js:
import React from 'react'
import { View,
StyleSheet,
Image,
PixelRatio,
Dimensions,
TouchableOpacity } from 'react-native'
import { connect } from 'react-redux'
const GenerateImage = (props, {param, dispatch}) => {
function toggleModal(param) {
return {
type: 'TOGGLE_MODAL_ON',
}
}
return (
<View style={styles.container}>
<View style={styles.imgContainer}>
<TouchableOpacity activeOpacity={0.7} onPress={() => dispatch(toggleModal(param))}>
<Image source={props.image} style={styles.imgContainer} />
</TouchableOpacity>
</View>
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginVertical: 5,
marginHorizontal: 4
},
imgContainer: {
height: Dimensions.get('window').height * 0.25,
width: Dimensions.get('window').width * 0.48,
//borderRadius: 8,
//flex: 1,
//orderWidth: 1,
},
image: {
resizeMode: 'contain',
aspectRatio: PixelRatio.get()
},
})
export default connect(state => ({ param: state[0].showFullImage }))(GenerateImage)
So, how can I pass both data?
I am a newbie to react native, I want to make this layout possible I have following code but it puts the logo inside grid
What I am looking for is this
import React, { Component } from 'react';
import GridView from 'react-native-super-grid';
export default class ProfileScreen extends Component {
static navigationOptions = {
title: 'Details',
};
render() {
const { navigate } = this.props.navigation;
const items = [
{ name: require('./images/shopping-cart.png'),code: '#2ecc71' }, { name: require('./images/home.png'), code: '#2ecc71' },
{ name: require('./images/money-bag.png'), code: '#2ecc71' }, { name: require('./images/alert.png'), code: '#2ecc71' }
];
return (
<ImageBackground
source={require('./images/marble.jpg')}
style={styles.backgroundImage}>
<View style={styles.mainLayout}>
<Image resizeMode={'cover'} style = {styles.logoFit} source={require('./images/Logo1.png')}/>
<GridView
itemDimension={130}
items={items}
style={styles.gridView}
renderItem={item => (
<View style={styles.itemContainer}>
<View style={styles.CircleShapeView}>
<Image style={styles.iconItem} source={item.name}/>
</View>
</View>
)}
/>
</View>
</ImageBackground>
);
}
}
const dimensions = Dimensions.get('window');
const imageHeight = Math.round(dimensions.width * 9 / 16);
const imageWidth = dimensions.width;
const styles = StyleSheet.create({
backgroundImage: {
flex: 1,
resizeMode: 'cover', // or 'stretch'
},
CircleShapeView: {
width: 100,
height: 100,
borderRadius: 100,
backgroundColor: '#00BCD4',
justifyContent: 'center',
alignItems: 'center'
},
gridView: {
paddingTop: 50,
flex: 1,
},
itemContainer: {
justifyContent: 'center',
alignItems:'center',
height:130
},
iconItem: {
alignItems:'center',
justifyContent: 'center'
},
logoFit: {
width: imageHeight,
height: imageWidth
},
mainLayout: {
flex: 1,
flexDirection: 'column',
justifyContent: 'space-between'
}
});
Get rid of that grid component. You don't need it for such a simple thing. It's complicating things, and as it's not a regular/common component we don't know how it's affecting things.
This looks quite simple:
<View>
<View style={{}}>
<Image />
</View>
<View style={{flexDirection:'row'}}>
<View>
<Text>row 1, col 1</Text>
</View>
<View>
<Text>row 1, col2Text>
</View>
</View>
<View style={{flexDirection:'row'}}>
<View>
<Text>row 2, col 1</Text>
</View>
<View>
<Text>row 2, col2Text>
</View>
</View>
<View style={{}}>
<Button title="Login" />
</View>
</View>
Here's another similar question - How to create 3x3 grid menu in react native without 3rd party lib?
Inside navigationOptions You should remove the title property and define a header property and put your Image there. Like this
static navigationOptions = {
header:(<Image resizeMode={'cover'} style = {styles.logoFit} source={require('./images/Logo1.png')}/>)
};
Or... YOu can just make the header null as
static navigationOptions = {
header:null
};
and your current code would work as you want it to be.