[Android] onPress event aren't triggered in long list
List items are rendered outside of parent height and the TouchableOpacity's onPress event aren't triggered
I'm using shadowlist v0.4.22 with react-native-screens v4.4.0 and @react-navigation/stack
Screenshot
Code:
<View style={[styles.container, {backgroundColor: thumbnailColor}]}>
<Shadowlist
data={data.episodeList.map((item, index) => ({ ...item, id: index.toString() }))}
renderItem={() => (
<TouchableOpacity style={styles.episodeButton} onPress={() => {
console.log('onPress')
props.navigation.navigate('FromUrl', {
link: stringify('link'),
})
}}>
<Text style={[globalStyles.text, styles.episodeText, { color: complementThumbnailColor }]}>
{stringify('title')}
</Text>
</TouchableOpacity>
)}
keyExtractor={item => item.id}
/>
</View>
Hey @FightFarewellFearless,
Thanks for testing this out and sharing your report! I tried to reproduce the layout issue with navigation and screens, but I couldn’t get it to break (navigation react-navigation v7, react-native-screens v4.5). Could you provide some reproduction steps or at least share the styles you're using? It’s likely the problem is with layout calculations or adjustments which I'm willing to fix.
However, I was able to reproduce the bug where the onPress event isn't triggered. It happens when you click on any appended or prepended elements after scrolling in my case. They seem to lose their InstanceHandle reference, which prevents the events from being dispatched. I’ll look into potential solutions for this.
Im not sure what is causing the layout issue, im testing on react-native 0.76.5, and even with simple flex: 1 style, it breaks in my case, i'll try to reproduce this in a minimal template. And for the onPress issue, in my case it's not getting triggered every time, even with a very basic Touchable component
Btw, what react-native version are you using?
And for the onPress issue, in my case it's not getting triggered every time, even with a very basic Touchable component
Yes, I was able to reproduce this in the latest version.
https://github.com/azimgd/shadowlist/blob/3ab6449118d3ce4f68f1cdd0b8500bb5a318237f/example/package.json#L15
I've tried the latest version u just published, and the issue is still there, even with the example code:
Code in the example folder
import { useRef, useCallback, useEffect } from 'react';
import { View, StyleSheet, Text, Pressable } from 'react-native';
import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
import {
Shadowlist,
type OnStartReached,
type OnEndReached,
type OnVisibleChange,
type OnScroll,
type ShadowlistProps,
type SLContainerRef,
} from 'shadowlist';
const ITEMS_COUNT = 50;
const IS_INVERTED = false;
const IS_HORIZONTAL = false;
const INITIAL_SCROLL_INDEX = 0;
const FINAL_SCROLL_INDEX = 0;
const ListHeaderComponent = () => (
<View style={styles.static}>
<Text style={styles.text}>Header</Text>
</View>
);
const ListFooterComponent = () => (
<View style={styles.static}>
<Text style={styles.text}>Footer</Text>
</View>
);
const ListEmptyComponent = () => (
<View style={styles.static}>
<Text style={styles.text}>Empty</Text>
</View>
);
export default function App() {
const data = new Array(ITEMS_COUNT).fill(0).map((_, index) => ({
id: index.toString(),
}));
const ref = useRef<SLContainerRef>(null);
useEffect(() => {
if (!FINAL_SCROLL_INDEX) return;
setTimeout(() => {
ref.current?.scrollToIndex({ index: FINAL_SCROLL_INDEX });
}, 1000);
}, []);
const onVisibleChange = useCallback<DirectEventHandler<OnVisibleChange>>(
(event) => {
event.nativeEvent.visibleEndIndex;
},
[]
);
const onScroll = useCallback<DirectEventHandler<OnScroll>>((event) => {
event.nativeEvent.contentOffset.y;
}, []);
const renderItem: ShadowlistProps['renderItem'] = () => {
return (
<Pressable onPress={() => { console.log('onPress') }}>
<Text style={styles.text}>{`{{id}}`}</Text>
</Pressable>
);
};
return (
<View style={styles.container}>
<Shadowlist
ref={ref}
renderItem={renderItem}
data={data}
keyExtractor={(item) => item.id}
onVisibleChange={onVisibleChange}
onScroll={onScroll}
ListHeaderComponent={ListHeaderComponent}
ListHeaderComponentStyle={styles.static}
ListFooterComponent={ListFooterComponent}
ListFooterComponentStyle={styles.static}
ListEmptyComponent={ListEmptyComponent}
ListEmptyComponentStyle={styles.static}
inverted={IS_INVERTED}
horizontal={IS_HORIZONTAL}
initialScrollIndex={INITIAL_SCROLL_INDEX}
numColumns={1}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#333333',
paddingTop: 60,
},
text: {
color: '#333333',
backgroundColor: '#1dd1a1',
padding: 16,
},
static: {
height: 120,
backgroundColor: '#576574',
},
});
I still have the onPress problem and i think the layout issue too, i think some of my dependencies are conflicting with shadowlist? not sure. I'll try with clean project
Thanks for the update, this is what I get on my end which seems to layout fine?
Android example
Thanks for the update, this is what I get on my end which seems to layout fine?
try changing the height of the container
I see it now, thanks!
import { useRef, useCallback, useEffect } from 'react';
import { View, StyleSheet, Text, Pressable } from 'react-native';
import type { DirectEventHandler } from 'react-native/Libraries/Types/CodegenTypes';
import {
Shadowlist,
type OnStartReached,
type OnEndReached,
type OnVisibleChange,
type OnScroll,
type ShadowlistProps,
type SLContainerRef,
} from 'shadowlist';
const ITEMS_COUNT = 50;
const IS_INVERTED = false;
const IS_HORIZONTAL = false;
const INITIAL_SCROLL_INDEX = 0;
const FINAL_SCROLL_INDEX = 0;
const ListHeaderComponent = () => (
<View style={styles.static}>
<Text style={styles.text}>Header</Text>
</View>
);
const ListFooterComponent = () => (
<View style={styles.static}>
<Text style={styles.text}>Footer</Text>
</View>
);
const ListEmptyComponent = () => (
<View style={styles.static}>
<Text style={styles.text}>Empty</Text>
</View>
);
export default function App() {
const data = new Array(ITEMS_COUNT).fill(0).map((_, index) => ({
id: index.toString(),
}));
const ref = useRef<SLContainerRef>(null);
useEffect(() => {
if (!FINAL_SCROLL_INDEX) return;
setTimeout(() => {
ref.current?.scrollToIndex({ index: FINAL_SCROLL_INDEX });
}, 1000);
}, []);
const onVisibleChange = useCallback<DirectEventHandler<OnVisibleChange>>(
(event) => {
event.nativeEvent.visibleEndIndex;
},
[]
);
const onScroll = useCallback<DirectEventHandler<OnScroll>>((event) => {
event.nativeEvent.contentOffset.y;
}, []);
const renderItem: ShadowlistProps['renderItem'] = () => {
return (
<Pressable onPress={() => { console.log('onPress') }}>
<Text style={styles.text}>{`{{id}}`}</Text>
</Pressable>
);
};
return (
<View style={styles.container}>
<Shadowlist
ref={ref}
renderItem={renderItem}
data={data}
keyExtractor={(item) => item.id}
onVisibleChange={onVisibleChange}
onScroll={onScroll}
ListHeaderComponent={ListHeaderComponent}
ListHeaderComponentStyle={styles.static}
ListFooterComponent={ListFooterComponent}
ListFooterComponentStyle={styles.static}
ListEmptyComponent={ListEmptyComponent}
ListEmptyComponentStyle={styles.static}
inverted={IS_INVERTED}
horizontal={IS_HORIZONTAL}
initialScrollIndex={INITIAL_SCROLL_INDEX}
numColumns={1}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
height: 120,
backgroundColor: '#333333',
paddingTop: 60,
borderWidth: 8,
borderColor: 'red',
},
text: {
color: '#333333',
backgroundColor: '#1dd1a1',
padding: 16,
},
static: {
height: 120,
backgroundColor: '#576574',
},
});
Here's what i got
Trying to overscroll the list seems to "fix" the layout temporarily
I see it now, thanks!
Do you still need a minimal repro template?
I'll create one if you want
Nope, thank you @FightFarewellFearless. I'll let you know once fixed.
Thank you very much @azimgd
Hey @FightFarewellFearless, this should be fixed on 0.4.24
Hey @FightFarewellFearless, this should be fixed on
0.4.24
Thanks! i'll try this on the weekend. Thank you for making this awesome library!
Hey @FightFarewellFearless, this should be fixed on
0.4.24
Hello @azimgd, just tried this update recently and the onPress bug aren't fully fixed. Let say i have a very big list with at least 500 items, let say, the first 100 item's onPress event is triggered, but the rest item is not getting triggered, i think this is because of the press state or something similar, you can try with TouchableOpacity and scroll through the long list, notice the opacity isn't change at the initial list, but when you continue scrolling, the opacity of the touchable is changed and get stucked (see the screenshot below)
I started a discussion here to get more insights. Interestingly, this is reproducible on Android but not on iOS. I’m working on getting it fixed soon.
Thank you, can't wait for this library to become stable 🚀🚀
Hey @FightFarewellFearless, I merged a PR with the fix couple of days ago. I plan to deploy the new version by the end of this week.
👍
Hey @FightFarewellFearless, I merged a PR with the fix couple of days ago. I plan to deploy the new version by the end of this week.
Just tested your dynamic-components branch—the onPress issue is fixed, but the opacity issue with Touchable still persists. I also found another styling-related issue: the list height doesn’t account for React Navigation’s bottom tabs. In other words, the list extends beyond the visible area when using bottom tabs. I tried adding paddingBottom and marginBottom to the list style, but that didn’t fix the issue.