React native button presses not working on android - android

So I know this has been gone over in multiple other threads but this one is kind of unique, I've built this app using React Native that uses swipe gestures to animate views sliding in an out of the view. iOS is nearly flawless but when running on android anything past the first view in the stack button presses inside of the views stop working, I believe that this is because the parent view is essentially sliding out of the view and so non of the touches are registering. I'm kind of stumped on how to fix this, this is kind of an adhoc implementation so maybe theres react native package that I overlooked.
<Animated.View style={{
transform: [{
translateX: xOffset.interpolate({
inputRange: [0, 2],
outputRange: [0, -Dimensions.get('window').width * 2]
})
}]
}}>
<RenderViews />
</Animated.View>
const RenderViews = props => {
return (
<View style={{
flexDirection: 'row',
}}>
<Preset1 />
<Preset2 />
<Manual />
</View>
)
};

I ended up implementing react-native-swiper which handles all of the swipe logic and button presses are working again on android.
https://github.com/leecade/react-native-swiper

you have use tovalue to start the animation
example
Animated.timing(
// Animate value over time
this.state.fadeAnim, // The value to drive
{
toValue: 1, // Animate to final value of 1
},
).start();
You should probably listen to the screen events
And run an animation event when there is a change

Related

React Native Expo Flatlist pull to refresh gesture not triggering on iOS but works fine on Android

I have a flatlist component rendered inside a flex: 1 view, that doesn't perform pull to refresh on iOS. The gesture itself doesn't work, as the list refuses to get pushed down, but works fine on Android.
Here is my flatlist code, and the only code in the screen.
<FlatList<any>
style={{
flex: 1,
// marginTop: 10,
}}
contentContainerStyle={{ flexGrow: 1 }}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
data={ordersDetails?.docs}
keyExtractor={(item) => item._id}
renderItem={renderItem}
bounces={false}
refreshControl={
<RefreshControl
refreshing={loading}
onRefresh={() => {
fetchOrders(getOrdersListRefreshing);
}}
/>
}
initialNumToRender={10}
onEndReachedThreshold={0.01}
onEndReached={() => {
fetchOrders(getOrdersListNoLoading);
}}
removeClippedSubviews
maxToRenderPerBatch={5}
updateCellsBatchingPeriod={200}/>;
renderItem is nothing but a text component.
Sorry I am a bit new to React Native.
Thanks in advance!
you can remove style props and containerStyle props and bounce
There is no need for a separate flex value of flex style. And if you put bounce to false ios, you can't refresh it.

Flatlist React native card's onPress does not trigger on Android

I am using Expo for my app. I have a horizontal Flatlist where I render my data react native paper's Card. I saw Card have onPress function. I used that to navigate the another page. But onPress function does not trigger on Android device. I know React native's touchable-opacity have positioning issue on Android. I tried hitSlop and inline styling zIndex but still does not work. I also wrap my card with react-native's touchable-opacity and play with positioning still did not help me, only it works when i used react-native-gesture-handler's touchable-opacity but then it does not work on IOS. Hope anyone can help me...
import React from 'react';
import { Card } from 'react-native-paper';
import { useNavigation } from '#react-navigation/native';
interface Iprops {
item: string;
}
export default function RenderCard({ item }: Iprops) {
const navigation = useNavigation();
return (
<Card
hitSlop={{ "bottom": 30, "top": 30, "right": 30, "left": 30 }}
onPress={() => {
navigation.navigate(`detail`, { // THIS DOES NOT TRIGGER ON ANDROID
"id": `${item.pk}`
});
}}
style={{ "marginBottom": 20 }}>
<Card.Cover
source={{ "uri": `${item.img_url}` }} />
<Card.Actions>
<Card.Title title={item.name} subtitle="Card Subtitle" />
</Card.Actions>
</Card>
);
}
I've noticed that using onPressIn or onPressOut does work on Android within an absolute positioned flatlist, but onPress does not work. I hope this might be of help to someone out there looking for an answer.
You'll need to use the TouchableOpacity element from react-native-gesture-handler.
Like you told, you should add touchable opacity to the element you are rendering on the card. TouchableOpacity can be tricky. So, first give it a styling of borderWidth:1 and borderColor to see the actual touchable area on the screen. Then you start to bring them together with the icon or the image or whatever you are rendering. TouchableOpacity works but the positioning can be tricky. You have to understand it to use it better. Think touchableOpacity as a view with borders then it'll be easier to grasp. Also, if you dont give touchableOpacity an absolute position in the styling it will be out of the screen somewhere, I was never be able to bring it to somewhere that I can see to position it. So you can add 'position' as well.
I gave up on positioning and render my component's based on Platform.
Platform.OS === `ios` ?
<Card
onPress={() => {
navigation.navigate(`detail`, {
"id": `${item.pk}`
});
}}
style={{ "marginBottom": 20 }}>
<Card.Cover source={{ "uri": `${item.img_url}` }} />
<Card.Actions>
<Card.Title title={item.name} subtitle="Card Subtitle" right={Beer} />
</Card.Actions>
</Card> :
<TouchableOpacity
onPress={() => {
navigation.navigate(`detail`, {
"id": `${item.pk}`
});
}}
>
<Card style={{ "marginBottom": 20 }}>
<Card.Cover source={{ "uri": `${item.img_url}` }} />
<Card.Actions>
<Card.Title title={item.name} subtitle="Card Subtitle" right={Beer} />
</Card.Actions>
</Card>
</TouchableOpacity>;

React-Native-Video disables TouchableOpacity in Android

I am working on a react native app which involves a video player (react-native-video), and some simple controls I set up myself. on iOS this works fine, but on Android the TouchableOpacity elements, which I use for controls and navigation, don't seem to detect touches. (Navigation is handles by react-native-fluid-transitions in my app). When I turn on the inspector, a screen-covering View seems to be on top of my controls. However, this is not the case on iOS and I have also not configured such a view.
I installed Atom to use it's inspector feature to see the actual order of my views. It looks as follows:
VideoView is the name of my component, Video is the actual video player and the TouchableOpacity I highlighted is the button I'm trying to get to work. In this view hierarchy, no views seem to be on top of anything. I have also compared this breakdown to other components where my buttons actually work and it looks the same.
My code looks as follows:
return (
<View style={internalStyles.container}>
<Video style={internalStyles.videoContainer}
ref={(ref) => {
this.props.player = ref
}}
source={{uri: url}}
controls={false}
onEnd={() => this.videoEnded()}
paused={this.state.paused}
muted={false}
repeat={false}
resizeMode={"contain"}
volume={1.0}
rate={1.0}
ignoreSilentSwitch={"obey"}
/>
{this.renderControls()}
{Renderer.getInstance().renderNavigationButton()}
</View>
);
where renderControls is a function that renders the pause button, and Renderer is a singleton component containing render function for items I use in more components of my app. This all works fine on iOS, but not on Android. react-native-video seems to be incompatible with react-native-fluid-transitions as everything works when I remove one of either.
Does anyone know what might cause this behavior? Any help would be highly appreciated.
Try removing the activeOpacity prop from TouchableOpacity component.
Or you can use platform specific code to set values for activeOpacity prop
import { Platform, TouchableOpacity } from 'react-native'
<TouchableOpacity
activeOpacity={Platform.OS==='android' ? 0 : 0.2}
>
<Text>submit</Text>
</TouchableOpacity>
Wrap the component in a view and disable pointer events.
<View pointerEvents="none">
<Video source={{ uri: source }} />
</View>
import {TouchableOpacity} from 'react-native';
<TouchableOpacity>some text</TouchableOpacity>
For me it was solved by putting zIndex:1000
<TouchableOpacity
onPress={this.handlePause}
style={{
position: "absolute",
alignItems: "center",
justifyContent: "center",
alignSelf: "center",
elevation: 2,
backgroundColor: "#FFF",
width: 60,
height: 60,
borderRadius: 30,
flex: 1,
zIndex: 1000,
}}
>

Inverting a FlatList

I'm currently working on a react native app for android, and have access to the new FlatList. It has some very needed features. However, my listview is inverted using the react-native-invertable-scroll-view. This does not seem to work properly with FlatList. The scrolling is not properly reversed.
Does anyone know how to invert a FlatList? Or perhaps how to load a Flatlist, and then force a scroll to the bottom without the user noticing it? My own attempts to force a scroll down are often delayed.
This now comes out of the box in FlatList!
Just use:
<FlatList
inverted
data=...
renderItem=...
/>
This causes the first item to appear at the bottom of the list, and the list starts at the bottom, showing the first item.
If you need the last item to show at the bottom, just reverse the array that you are providing in the data prop.
render() {
const messages = this.props.messages.reverse();
return (
<FlatList
renderItem={this._renderItem}
data={ messages }
keyExtractor={this._keyExtractor}
style={{ transform: [{ scaleY: -1 }] }}
/>
); }
_keyExtractor = (item, index) => item.id+''+index;
_renderItem = ({item}) => (
<View style={{ transform: [{ scaleY: -1 }]}}>
<ChatItem />
</View>)
Enjoy it)
As described in the other answers, currently the best way to go about doing this is to apply a transformation to the FlatList's containing view that inverts it.
return (
<View style={{ transform: [{ scaleY: -1 }] }} >
<FlatList
renderItem={this._renderItem}
...
/>
</View>
);
Then apply the same transformation to each list item to ensure that they are correctly reoriented.
_renderItem = (info) => {
return (
<View style={{ transform: [{ scaleY: -1 }] }}>
{this.props.renderItem(info)}
</View>
);
}
I've written a package that does exactly that, all you need to do is use this in place of a standard FlatList component and pass the inverted property.
https://www.npmjs.com/package/react-native-invertible-flat-list

ListView's onEndReached, in react native, is not working as expected

This is my code for a component's render.
render() {
let loadMore;
let hasMore = this.props.end && this.props.photos.length < this.props.end;
if (hasMore) {
loadMore = (
<View style={globalStyles.ContChild}>
<Button
onPress={() => this.loadMoreItems()}
containerStyle={globalStyles.bottomButton}
style={globalStyles.buttonText}
>
Load more
</Button>
</View>
);
}
return (
<View>
<ListView
dataSource={this.ds.cloneWithRows(this.props.photos)}
renderRow={this._renderPhoto}
contentContainerStyle={{
flexDirection: 'row',
flexWrap: 'wrap',
marginLeft: 4,
}}
enableEmptySections={true}
initialListSize={12}
pageSize={12 * 3}
onEndReached={hasMore ? (() => this.loadMoreItems()) : null}
onEndReachedThreshold="32"
/>
{loadMore}
</View>
);
}
It is intended that the ListView, when scrolled to the bottom but 32px or less, perform an additional data load.
Right now the data load works via a button labeled "Load More", as it is generated in the if-condition in the render method. The button is conditionally added inside the View component, right below the ListView.
Currently, when you click the button, the loadMore() logic is executed and loads more pictures accordingly. The loaded data is a list of pictures (the listview is a photo gallery).
I wanted to remove the button and use the when the listview is scrolled to the bottom logic, by using the onEndReached handler. Right now both logics coexist in my system, but there is a problem -or misunderstanding since I started yesterday on this project- with the onEndReached logic, even if using the threshold:
Right now the onEndReached logic is executed eagerly, on each render cycle (IIRC a new render cycle is triggered when the data changes, and the data changes on each loadMorecall), as if each render cycle considered that onEndReached should trigger. However: the listview is not scrolled to the end in any case. It is still in the very scrolling top.
My purpose: I don't want the whole pictures be loaded eagerly, but in a scroll-paginated fashion, i.e. when the scrolling bottom is reached, load more elements automatically (with no need to either press the Load More button -since I will remove that button- and no eager loading but scrolling).
My question: What am I doing wrong regarding this event and how could I fix it?
You can try this one:
<ListView
ref={(listView) => { _listView = listView; }}
dataSource={this.ds.cloneWithRows(this.props.photos)}
renderRow={this._renderPhoto}
contentContainerStyle={{
flexDirection: 'row',
flexWrap: 'wrap',
marginLeft: 4,
}}
enableEmptySections={true}
initialListSize={12}
pageSize={12 * 3}
onEndReached={hasMore ? (() => this.loadMoreItems()) : null}
onEndReachedThreshold="32"
/>
I missed to use ref in my ListView, and was facing the same problem. Once I added those, my pagination is working correctly.

Categories

Resources