How to create swipeable bottom sheet in React Native? - react-native

How to implement exactly the same swipeable bottom sheet in React Native:
react-swipeable-bottom-sheet (demo gif above) lib is working only in React.
I know react-native-overlay-section but it is opening to the top of the window with bounce animation.
EDIT
I also tried react-native-touch-through-view, but there is a known issue with touches through the TouchThroughView...
<View style={styles.container}>
<View style={styles.contentContainer}>
<FlatList
data={this.state.list}
renderItem={(data) => {
<View>
<Text>{"Bla bla bla"}</Text>
<TouchableOpacity onPress={()=> this.onPress()}>
<Text>{"THIS IS NOT WORKING ON ANDROID"}</Text>
</TouchableOpacity>
</View>
}} />
</View>
<TouchThroughWrapper style={styles.scrollWrapper}>
<ListView
style={styles.scroller}
dataSource={actionsList}
renderHeader={() => <TouchThroughView style={styles.touchThroughView} />}
renderRow={(rowData) => {
return (
<Text style={styles.itemRow}>{rowData}</Text>
)
}}>
</ListView>
</TouchThroughWrapper>

You can achieve your requirement with the help of following package.
https://www.npmjs.com/package/react-native-touch-through-view
This package allows scroll views and table views to scroll over interactable content without poor performing size and bounds animations.

Related

Can't use both Scrollview and Flatlist within same React Native component

I'm trying to use a Scrollview to scroll horizontally a mapped array and also a Flatlist to scroll vertically a list of items from another array but the combination of the 2 don't seem to work.
This is not a case on wrapping a Flatlist inside a Scrollview which causes a well known problem, I'm not getting the VirtualizedLists warning here.
Here's my code in the rendering section:
return (
<View style={styles.screen}>
<Scrollview style={styles.containerRow}>
{selectedGenres.map((item) => {
return (
<TouchableOpacity
onPress={() => {
genreHandler(item.id, item.name);
}}
style={styles.containerRow}
key={item.id}
>
<View style={styles.filterGenderLayout}>
<Text style={styles.genderButton}>{item.name}</Text>
</View>
</TouchableOpacity>
);
})}
</Scrollview>
<View style={styles.container}>
<View style={styles.containerRow}>
<FlatList
numColumns={3}
data={result}
keyExtractor={(item) => item.id.toString()}
onEndReached={loadMoreCommit}
onEndReachedThreshold={0.5}
renderItem={(itemData) => (
<StarsItem
id={itemData.item.id}
poster={itemData.item.poster_path}
title={itemData.item.title}
onStarsSelection={fetchMovieHandler}
showtitle={false}
/>
)}
/>
</View>
</View>
</View>
As you can see the Scrollview and Flatlist are not nested but I get an error as invalid element. If I use a normal View tag instead of Scrollview, everything looks fine except that I cannot scroll my first list horizontally.
Any suggestion on how to fix this?
I tried to use Flatlist on both however I need the first to scroll horizontally and the second vertically with numColumns={3} meaning I get a different error.

React Native onLongPress triggered onPress if pressed component is re-rendered

I am implementing an image gallery. There's a list of squared images, if user longPress an image component it will re-render to a selected image component which show a blur background and a tick on top of the image.
Here's the normal image component:
<TouchableOpacity
key={index}
onPress={this.normalModeImgClick(img, index)}
onLongPress={this.startSelectMode(index)}
>
<Image style={styles.img} source={{uri: img.resized_xs_url}}/>
</TouchableOpacity>
Here's the component at select mode:
<TouchableOpacity
key={itemIndex}
style={styles.selectedImgWrapper}
onPress={this.selectModeImgClick(imgItem, itemIndex)}
>
<Image style={styles.img} source={{uri: imgItem.img.resized_xs_url}}/>
{imgItem.selected &&
<View style={styles.selectedImgCover}>
<Image style={styles.selectedIcon} source={require('../../assets/icon_tick.png')}/>
</View>
}
</TouchableOpacity>
As you can see, if you longPress a normal image component startSelectMode will trigger, and that image will re-render and turned to a select mode component. However, selectModeImgClick will also be triggered which it is not supposed to (as the user is still doing the longPress action).
How to prevent this happening?
Accidentally discovered an alternative right after I posted the question, solved by adding an empty onLongPress function props to the selected mode component like this:
<TouchableOpacity
key={itemIndex}
style={styles.selectedImgWrapper}
onPress={this.selectModeImgClick(imgItem, itemIndex)}
// Override 'onLongPress' with an empty function
onLongPress={() => {}}
>
<Image style={styles.img} source={{uri: imgItem.img.resized_xs_url}}/>
{imgItem.selected &&
<View style={styles.selectedImgCover}>
<Image style={styles.selectedIcon} source={require('../../assets/icon_tick.png')}/>
</View>
}
</TouchableOpacity>
Since the component is not designed to have a longPress action, I'm looking forward to better solutions:

In react-native, is it anyway I can pull data from my JSON into my component?

Here is a thing, I'am struggling about using RN .
I would like to use flatlist to generate my content.
the flatlist contents can be pressed so It makes to go another page open.
I need animation freedom so the content can be pop up anywhere such as from the bottom, left, right.
I would like to use one layout which I was already built.
such a concept are, using renderingItem into view, than generating data in my component. here is concept I tried to do
<View style={styles.flatList}>
<FlatList
data={newsFeedData}
horizontal={false}
showsVerticalScrollIndicator={false}
renderItem={({item, index})=>{ return
<View>
<TouchableOpacity
activeOpacity={1}
onPress={this.newsFeedCards.bind(this)}>
<View style={styles.mgView}>
<ListItem item={item} image={item} index={index}/>
</View>
</TouchableOpacity>
</View>
}}/>
</Animated.View>
<View data={newsFeedData}
style={styles.pageDetail}
renderItem={(item, idex)=>{
return <PageDetail
item={item} image={item} image={item}></PageDetail>
}}>
</View>
Please help me anyone know the trick of this concept. I really appreciate your help!

ScrollView cuts off last object on the page

I built a view that is populated dynamically using array mapping. After doing this, I realized that the View would be too large to contain all the array items on one screen.
Here is my code.
<View style={[styles.flexColumn]}>
{Characters.map((character, i) =>
<View key={i} style={[styles.flexRow]}>
<View>
<Text>
{character.Name}
</Text>
</View>
</View>
)}
</View>
So I tried adding a scroll view as the parent like this:
<ScrollView>
<View style={[styles.flexColumn]}>
{Characters.map((character, i) =>
<View key={i} style={[styles.flexRow]}>
<View>
<Text>
{character.Name}
</Text>
</View>
</View>
)}
</View>
</ScrollView>
This does add some scrollability to the view, but it's still cutting off a portion of the last object in the array.
Is there a way to fix this?
Thanks!
ScrollView is intended for showing scrollable content at once. Since you are populating content dynamically, you should be using FlatList. Something similar to the following would work:
...
_keyExtractor = character => character.Name
_renderItem = ({character}) => (
<Text>
{character.Name}
</Text>
)
render() {
return (
<FlatList
data={Characters}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
)
}
...
Detailed explanation is available in the docs.
If you are by any reason still forced to stick to Scrollview, the problem is probably related to the styling. I suppose styles.flexColumn should be applied to the ScrollView itself via contentContainerStyle, rather than to its' child View.

React Native detect tap on View

I’m writing a React Native app and I want to detect tap/clicks anywhere on the screen so I put an onClick handler on my <View> element but it doesn’t seem to be working. Here is my render function:
<View style={styles.container} onClick={this.onClick}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</View>
What do I need to do?
For making any element to handle touch/click events in a React-Native UI, you need to put the element inside a TouchableOpacity, TouchableWithoutFeedback, TouchableNativeFeedback or TouchableHighlight element:
<TouchableHighlight onPress = { this.onClick }>
<View style={styles.container}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</View>
</TouchableHighlight>
Hope that helps.
In React Native version > 55.3 you make check onPress events into your View if use onStartShouldSetResponder props.
Like example:
<View
style={{ flex: 1 }}
onStartShouldSetResponder={() => console.log('You click by View')}
>
<ScrollView
refreshControl={
<RefreshControl
refreshing={this.state.refreshing}
onRefresh={this.onRefresh} />
}
>
<Text>Awesome</Text>
</ScrollView>
</View>
In example I showed how you can get onPress event on View and not blocking other event behind them. Refresh control still work correct.
In my case the following works fine. You can use onTouchStart and onTouchEnd handlers on any View via props, for example:
<View onTouchStart={() => this.doSomething()} />
More information
This worked for me...
onTouchEnd={() => alert('TAPPED')}
The easiest way to do that:
<TouchableOpacity style={styles.container} onPress={()=> whateverFunc(parameter)}>
<Text style={styles.welcome}>
Tap to change the background
</Text>
</TouchableOpacity>
So, you need to replace the 'View' component to a 'TouchableOpacity' or any other Touchable component and you also need to replace the 'onClick' prop to 'onPress'. That's all. The wrapping of a view with a TouchableWhatever component is not necessary at all.