RefreshControl styling in react-native - react-native

I make some feedlines using Viewpager.
I wanna second picture's refresh style.
buy my code shows the first picture's style.
how can i change refreshControl to be second picture style...? or using styled-components
<ScrollView
contentContainerStyle={[{ flex: 1 }]}
refreshControl={
<RefreshControl
tintColor={Color.white}
colors={Color.white}
refreshing={this.state.loading}
onRefresh={() => this.pullToReload()}
/>
}>
<ViewPager
style={{ flex: 1 }}
initialPage={0}
orientation={'vertical'}
onPageScroll={(e) => {
const pos = e.nativeEvent.position;
const { offset } = e.nativeEvent;
if (pos <= 0 && offset <= 0) {
{/* how to know onEndReached??.. */}
}
}}>
{this.state.feedList.map((item) => (
<Feed item={item} index={item.id} />
))}
</ViewPager>
</ScrollView>

Related

Last Image is being cropped, when using ScrollView in react-native

I am trying to build something like instagram posts, that is continuous images that can be scrolled. But the last image is being cropped, that is only the upper half of it is being visible, there are several posts, regarding the same, but those didnt help, (contentContainerStyle={{flexGrow: 1,}}, adding height to a invisible view). Can someone please point out what is going wrong?
EDIT: I have changed scrollview to flatlist and still face the same problem, can you suggest what else to do?
EDIT 2: realised that the <Header /> and <Stories /> above the flatlist are not letting it scroll completely, that is the height that
it is not scrolling is proportional to height of <Header /> and <Stories />
post.js
const Post = ({post}) => {
return (
<View style={{flex:1}}>
<Divider width = {0.5}/>
<PostHeader post={post}/>
<PostImage post={post} />
<PostFooter post={post}/>
</View>
)
}
const PostImage = ({post}) => {
return (
<View style={styles.postContainer}>
<Image style={styles.image} source={{uri: post.post_url}}></Image>
</View>
)
}
const styles = StyleSheet.create({
container: {
},
dp: {
width: 35,
height: 35,
margin:5,
borderRadius: 20,
borderWidth : 1,
borderColor : '#ff8501'
},
postContainer: {
width: '100%',
height: 400,
},
image: {
height: '100%',
resizeMode: 'cover',
}
})
homescreen.js
const HomeScreen = () => {
return (
<SafeAreaView >
<Header />
<Stories />
{/* <ScrollView>
{
POSTS.map((post, index) => {
return (
<Post key={index} post={post} />
)
})
}
</ScrollView> */}
<FlatList data={POSTS} renderItem={({item}) => <Post post={item} />} />
</SafeAreaView>
)
}
If you want to render repetitive view so why you are not using Faltlist instead of Scrollview. For repetitive view react native provide one component which is called Flatlist and pass you array data in render item it will give you better performance as well.
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
/>
</SafeAreaView>
const renderItem = ({ item }) => (
<Divider width = {0.5}/>
<PostHeader post={item}/>
<PostImage post={item} />
</View>
);
const styles = StyleSheet.create({
container: {
flex: 1,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
});
According to React Native docs FlatList is the Component you should use:
ScrollView renders all its react child components at once, but this has a performance downside.
Imagine you have a very long list of items you want to display, maybe several screens worth of content. Creating JS components and native views for everything all at once, much of which may not even be shown, will contribute to slow rendering and increased memory usage.
This is where FlatList comes into play. FlatList renders items lazily, when they are about to appear, and removes items that scroll way off screen to save memory and processing time.
FlatList is also handy if you want to render separators between your items, multiple columns, infinite scroll loading, or any number of other features it supports out of the box.
const Post = () => {
renderItemHandler = ({post, index}) => (
<View key={index} >
<Divider width={0.5}/>
<PostHeader post={post}/>
<PostImage post={post} />
</View>
)
return (
<SafeAreaView style={{flex: 1}}>
<View style={{height: "90%"}}>
<Flatlist
data={POSTS}
renderItem={renderItemHandler}
keyExtractor={item => item.id}
/>
</View>
</SafeAreaView>
)
}

Prevent react-native-map from re-rendering after states change [Reat-Native]

In my app I'm using react-native-maps and every time states change the map reloads. How can I avoid this behaviour? I've tried to use React.memo but it seems to don't work.
[update]
I've tried to put the MapView directly inside the return and it doesn't reload, why?
Feel free to link me everything. Here's my code:
[functional component]
const MapViewContainer = () => {
return (
<MapView
initialRegion={initialRegion}
provider="google"
ref={mapRef}
style={styles.map}
>
{/* {items.map((item, index) => {
return <Marker {...{ item, index }} />;
})} */}
</MapView>
);
};
const MemorizeMap = React.memo(MapViewContainer, areEqual);
return (
<View style={styles.container}>
<MemorizeMap />
<Button
title="update"
style={{ flex: 1 }}
onPress={() => {
setOpacity(0);
}}
/>
</View>

How can I animate a component to another component?

I want to animate a card to the game table.
How can I move the component of the card to that of the game table?
Onpress
Result
I tried to with:
this.state.cards.find(c => c.id == id).ref.layout.animate({
from: { bottom: -20, bottom: 0 },
to: { bottom: 416, bottom: 196 },
But the .animate method is based on the x and y of the parent view and not on the x y of the screen.
Here is the part of my code:
<View style={styles.board}>
<ImageBackground source={require('../../assets/ornement.png')} resizeMode='contain' style={styles.ornement}>
<View onLayout={ref => this.test = ref}>
<Text style={boardStyle.message}>Test</Text>
</View>
<View style={boardStyle.boardContent} ref={event => this.view = event}>
{this.state.board.map((r, i) => <Image key={i} style={boardStyle.image} resizeMode='contain' source={CardUtils.PathOfimgCard(r.fullName)} />
)}
</View>
</ImageBackground>
</View>
<View style={styles.deck}>
{this.state.deck.map((r, i) =>
<Card onRef={(ref) => this.state.cards.push({ id: r.id, ref: ref })} key={i} ctx={r} action={this.play} select={this.state.cardSelect.find(c => c.id == r.id) != null} id={r.id} path={CardUtils.PathOfimgCard(r.fullName)} style={deckStyle} />
)}
</View>
The Card component:
<Animatable.View ref={event => this.layout = event} iterationCount={3} delay={5000} direction="alternate" style={this.props.style.touchZone} >
<TouchableOpacity onPress={() => this.props.action(this.props.id)} >
<View ref={event => this.view = event}>
<ImageBackground source={this.props.path} style={this.props.select ? this.props.style.active : this.props.style.image} resizeMode='contain' >
{!this.props.ctx.canPlay ? <Image style={[this.props.select ? this.props.style.active : this.props.style.image, styles.image]} resizeMode='contain' source={require('../../assets/black.png')} /> : <Image></Image>}
</ImageBackground>
</View>
</TouchableOpacity>
</Animatable.View>
thank you in advance

FlatListFooter can't be displayed

I want to add footer to my flatList :
i try this code :
renderFooter = () => {
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "#CED0CE"
}}
>
<Button> This is footer </Button>
</View>
);
}
<FlatList
data={menuData}
renderItem={({item}) => <DrawerItem navigation={this.props.navigation} screenName={item.screenName} icon={item.icon} name={item.name} key={item.key} />}
ListFooterComponent ={this.renderFooter}
/>
But no footer appears when running.
Any help please
You used the component
ListFooterComponent
in right way. you need to check your render method for footer. I faced the same issue and i follow this example, and it helps me. I hope it will help you.
Simple way/hack. In the menuData array, you just add a flag (i called) to the child object to indicate that it's a last item. For eg:
If you can modify your menuData structure, added lastItem prop true to indicate that it's the last item :
const menuData = [
{name:'menu1', screenName:'screen1', icon:'../assets/icon1.png'},
{name:'menu2', screenName:'screen2', icon:'../assets/icon2.png', lastItem:true}
];
and then
renderFlatItems = ({item}) => {
const itemView = null;
if (!items.lastItem) {
itemView = <DrawerItem navigation={this.props.navigation} screenName={item.screenName} icon={item.icon} name={item.name} key={item.key} />
} else {
itemView = <View style={{padding:100}}><Button> This is footer </Button> </View>
}
return {itemView};
}
then use it in the Flatlist like so
<FlatList
data={menuData}
renderItem={this.renderFlatItems}
/>
If you want a footer that remains at the bottom of the screen "Above" the list, then you can just add a View after the FlatList.
<View>
<FlatList style={{flex: 1}} />
<View
style={{
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height: 50,
}}
/>
</View>

How to customize look/feel of React Native ListView's RefreshControl

React Native's ListView has a built-in pull-to-refresh control called RefreshControl. It's super easy to use.
I'd like to customize the look and feel of the control to use a different visual design, such as using a material design progress indicator.
How can I customize the look of the RefreshControl in React Native?
You can outsmart it by doing:
setting transparent properties to ListView
Adding component with absolute position
Example:
<View style={{height:Dimensions.get('window').height}}>
{/* custom refresh control */}
<View
style={{position:'absolute',
width:Dimensions.get('window').width, height:60,
alignItems:'center', justifyContent:'center'}}>
<Progress.CircleSnail
color={['red', 'green', 'blue']}
duration={700} />
</View>
{/* list view*/}
<ListView
dataSource={this.state.dataSource}
refreshControl={
<RefreshControl
onLayout={e => console.log(e.nativeEvent)}
// all properties must be transparent
tintColor="transparent"
colors={['transparent']}
style={{backgroundColor: 'transparent'}}
refreshing={this.state.refreshing}
onRefresh={() => {
this.setState({refreshing:true});
setTimeout(() => {
this._addRows()
}, 2000);
}}
/>
}
renderRow={(rowData) => <Text>{rowData}</Text>} />
</View>
This is the result:
You can totally do this. It requires some work though.
You can start by writing something like this.
<View style={styles.scrollview}>
<View style={styles.topBar}><Text style={styles.navText}>PTR Animation</Text></View>
<View style={styles.fillParent}>
<Text>Customer indicator goes here...</Text>
</View>
<View style={styles.fillParent}>
<ListView
style={{flex: 1}}
dataSource={this.state.dataSource}
renderRow={(rowData) => <View style={styles.row}><Text style={styles.text}>{rowData}</Text></View>}
ref='PTRListView'
/>
</View>
</View>
When you'll pull to refresh, you should see the text "Custom indicator goes here..."
Following this pattern, you can place your component instead of just a view and a text.
For the credits, thanks to this article for the idea.
I did it using react-native-pull-to-refresh-custom lib
First create custom loader ListRefreshLoader
import React from 'react';
import {StyleSheet, View} from 'react-native';
import colors from '../../assets/colors';
import {wp} from '../../styles/responsiveScreen';
import Circuler from './Circuler';
const ListRefreshLoader = ({refreshing}) => {
return (
<View>
{refreshing ? (
<View style={styles.container}>
<Circuler color={colors.gray} size={wp(6)} />
</View>
) : null}
</View>
);
};
const styles = StyleSheet.create({
container: {
width: wp(15),
height: wp(15),
alignSelf: 'center',
justifyContent: 'center',
alignItems: 'center',
},
});
export default ListRefreshLoader;
Then use following way
import PullToRefresh from 'react-native-pull-to-refresh-custom';
import ListRefreshLoader from '../../components/Loader/ListRefreshLoader';
<PullToRefresh
HeaderComponent={() => <ListRefreshLoader refreshing={refreshing} />}
headerHeight={60}
refreshTriggerHeight={60}
refreshingHoldHeight={60}
refreshing={refreshing}
onRefresh={onRefresh}
style={styles.list}>
<FlatList
data={friendsList}
viewabilityConfig={{
itemVisiblePercentThreshold: 90,
}}
maxToRenderPerBatch={100}
removeClippedSubviews
style={styles.list}
keyExtractor={(item, index) => index.toString()}
showsVerticalScrollIndicator={false}
persistentScrollbar
renderItem={renderItem}
ItemSeparatorComponent={() => {
return <View style={styles.listSeperator} />;
}}
ListEmptyComponent={totalUserFriends === 0 ? renderEmpty() : null}
ListHeaderComponent={
totalUserFriends !== 0 || searchText !== '' ? (
<ListSearch
placeHolder={`${t('Search')}...`}
searchText={searchText}
style={styles.searchStyle}
fontName={'roboto-regular'}
onSearchChange={(text) => setSearchText(text)}
onClearSearch={() => {
setSearchText('');
}}
onEndEditing={() => setSearchText(searchText)}
/>
) : null
}
/>
</PullToRefresh>
I have written custom RefreshControl by merging below 2 methods
viewablityConfig of flatlist/sectionList will help in identifying the top element of the data.
if (viewableItems[0]?.item?.url === firstCategoryUrl) {
updateIsFocusOnTopOfScreen(true);
} else {
updateIsFocusOnTopOfScreen(false);
}
After Identifying user is on top of the screen use panResponder to the flatlist/sectionList -> this is to identify the user is pulling the screen to bottom based on the this.pan.y._value increasing call your custom onRefresh method
const mover = Animated.event([null, { dx: this.pan.x, dy: this.pan.y }]);
onPanResponderMove: (e, gestureState) => {
mover(e, gestureState);
this.customRefreshControl(this.pan.y._value);
},