-
-
Notifications
You must be signed in to change notification settings - Fork 982
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Flashlist is not scrolling #2582
Comments
Hey! 👋 The issue doesn't seem to contain a minimal reproduction. Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem? |
This is because of the nested gestures, you should use |
@bbernag Can you please give a example? |
This doesn't work |
You need to pass down the ref to the FlashList, here's an example |
@bbernag But I have two flashlists, One for the List component as you see in my code and another in which everything is rendered the main one. (Renders the BottomSheet which renders the List component) I'm confused to get that ref of those. |
The docs says |
@bbernag So I create two refs using useRef in my BottomSheet component as pass it in waitFor in GestureDetector. Right?🙏 |
@bbernag Using this also works |
One solution i tried is giving .activeOffsetY([-30, 0]) to my GestureDetector but it affects the animations Can you please give me a better approach for this |
Hi @xts-bit! Adding |
@m-bert Also, onPress is not working when I use this code when i comment out it works what problem with this code
|
I can check your code, but could you please prepare copy-pastable repro (or share a link to your repository)? It will be much easier to check what's going on. |
@m-bert I tried to make a copy-pastable repro please check
|
Okay, I've looked at it and noticed few things:
<View style={{ height, width, backgroundColor: 'pink' }}>
<FlashList
data={data}
renderItem={renderItem}
nestedScrollEnabled={true}
pagingEnabled
viewabilityConfig={{
itemVisiblePercentThreshold: 0
}}
estimatedItemSize={20}
/>
</View> in your <GestureHandlerRootView style={{ height, width, backgroundColor: 'pink' }}>
<FlashList
data={data}
renderItem={renderItem}
nestedScrollEnabled={true}
pagingEnabled
viewabilityConfig={{
itemVisiblePercentThreshold: 0,
}}
estimatedItemSize={20}
/>
</GestureHandlerRootView> so that gestures will work properly and you won't have to use another
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.bottomSheetContainer, rBottomSheetStyle]}>
<View style={styles.line} />
{children}
</Animated.View>
</GestureDetector>
To summarize, I've fixed some problems with your repro and by adding Here is the corrected code: import React, {
useCallback,
useEffect,
useRef,
useImperativeHandle,
} from 'react';
import {
View,
Text,
Image,
Dimensions,
StyleSheet,
Button,
} from 'react-native';
import {
GestureHandlerRootView,
Gesture,
GestureDetector,
} from 'react-native-gesture-handler';
import Animated, {
Extrapolate,
interpolate,
useAnimatedStyle,
useSharedValue,
withSpring,
} from 'react-native-reanimated';
import { FlashList } from '@shopify/flash-list';
const { height, width } = Dimensions.get('window');
const MAX_TRANSLATE_Y = -height + 50;
type BottomModalProps = {
children?: React.ReactNode;
};
export type BottomModalRefProps = {
scrollTo: (destination: number) => void;
isActive: () => boolean;
};
const BottomModal = React.forwardRef<BottomModalRefProps, BottomModalProps>(
({ children }, ref) => {
const translateY = useSharedValue(0);
const active = useSharedValue(false);
const scrollTo = useCallback((destination: number) => {
'worklet';
active.value = destination !== 0;
translateY.value = withSpring(destination, { damping: 50 });
}, []);
const isActive = useCallback(() => {
return active.value;
}, []);
useImperativeHandle(ref, () => ({ scrollTo, isActive }), [
scrollTo,
isActive,
]);
const context = useSharedValue({ y: 0 });
const gesture = Gesture.Pan()
.activeOffsetY([-10, 10])
.onStart(() => {
context.value = { y: translateY.value };
})
.onUpdate((event) => {
translateY.value = event.translationY + context.value.y;
translateY.value = Math.max(translateY.value, MAX_TRANSLATE_Y);
})
.onEnd(() => {
if (translateY.value > -height / 3) {
scrollTo(0);
} else if (translateY.value < -height / 1.5) {
scrollTo(MAX_TRANSLATE_Y);
}
});
const rBottomSheetStyle = useAnimatedStyle(() => {
const borderRadius = interpolate(
translateY.value,
[MAX_TRANSLATE_Y + 50, MAX_TRANSLATE_Y],
[25, 5],
Extrapolate.CLAMP
);
return {
borderRadius,
transform: [{ translateY: translateY.value }],
};
});
return (
<GestureDetector gesture={gesture}>
<Animated.View style={[styles.bottomSheetContainer, rBottomSheetStyle]}>
<View style={styles.line} />
{children}
</Animated.View>
</GestureDetector>
);
}
);
const List = () => {
const generateObjects = () => {
const objects = [];
for (let i = 1; i <= 50; i++) {
const object = {
id: i.toString(),
title: `Item ${i}`,
};
objects.push(object);
}
return objects;
};
return (
<View style={styles.container}>
<View style={{ flex: 1, maxHeight: '90%' }}>
<FlashList
nestedScrollEnabled={true}
data={generateObjects()}
estimatedItemSize={100}
contentContainerStyle={{ padding: 37 }}
renderItem={({ item }) => (
<>
<Text>{item.title}</Text>
</>
)}
keyExtractor={(item) => item.id}
/>
</View>
</View>
);
};
const Display = () => {
const ref = useRef<BottomModalRefProps>(null);
const HandleonPress = () => {
const isActive = ref?.current?.isActive();
if (isActive) {
ref?.current?.scrollTo(0);
} else {
ref?.current?.scrollTo(-550);
}
};
useEffect(() => {
setTimeout(() => {
HandleonPress();
}, 2000);
}, []);
return (
<View style={{ backgroundColor: 'gray' }}>
<Image
source={{
uri: 'https://i.natgeofe.com/n/4f5aaece-3300-41a4-b2a8-ed2708a0a27c/domestic-dog_thumb_square.jpg',
}}
style={styles.backgroundProduct}
/>
<View
style={{ position: 'absolute', top: '20%', alignContent: 'center' }}>
<Button title="Press me" onPress={() => console.log('Hello, World')} />
</View>
<View style={{ position: 'absolute', height: '100%', width: '100%' }}>
<BottomModal ref={ref}>
<List />
</BottomModal>
</View>
</View>
);
};
const Home = () => {
let data = [1, 2];
const renderItem = useCallback(({ item, index }) => {
return <Display />;
}, []);
return (
<GestureHandlerRootView style={{ height, width, backgroundColor: 'pink' }}>
<FlashList
data={data}
renderItem={renderItem}
nestedScrollEnabled={true}
pagingEnabled
viewabilityConfig={{
itemVisiblePercentThreshold: 0,
}}
estimatedItemSize={20}
/>
</GestureHandlerRootView>
);
};
const styles = StyleSheet.create({
backgroundProduct: {
height,
width,
},
bottomSheetContainer: {
height: height,
width: '100%',
backgroundColor: 'white',
position: 'absolute',
top: height,
borderRadius: 25,
},
line: {
width: 75,
height: 4,
backgroundColor: 'grey',
alignSelf: 'center',
marginVertical: 15,
borderRadius: 2,
},
container: {
backgroundColor: 'white',
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
height: '70%',
},
});
export default Home; |
@m-bert Thanks! But still onPress is not working any idea? on iOS |
Yes, look at point 3 in my previous response. If you open hierarchy view in Xcode you'll see that there is RCTView that lies on top of your button. Try changing <View style={{ position: 'absolute', height: '100%', width: '100%' }}>
<BottomModal ref={ref}>
<List />
</BottomModal>
</View> to <BottomModal ref={ref}>
<List />
</BottomModal> inside |
@m-bert Yep, It fixes my issue, but are you sure that |
What do you mean by "affect my list scrolling"? Adding When it comes to setting state, you already have .onEnd(() => {
if (translateY.value > -height / 3) {
scrollTo(0);
// Here set desired state to false
} else if (translateY.value < -height / 1.5) {
scrollTo(MAX_TRANSLATE_Y);
}
}); |
it gives |
Oh, makes sense, I overlooked that it all happens on the UI thread. One way would be to add Btw. in your code you have |
. @m-bert Yeah but it's not working, i tried this approach but it doesn't work when the user manually closes the modal. Can you please check.
|
If you meant that red text is not changing, then surely it's not - it is inside another component. What you can do is try to import import { runOnJS } from 'react-native-reanimated';
type BottomModalProps = {
children?: React.ReactNode;
closingFn?: () => void;
};
...
.onEnd(() => {
if (translateY.value > -height / 3) {
scrollTo(0);
runOnJS(closingFn!)();
} else if (translateY.value < -height / 1.5) {
scrollTo(MAX_TRANSLATE_Y);
}
});
...
<BottomModal ref={ref} closingFn={() => setIsModalActive(false)}>
<List />
</BottomModal> Note that Also I think we are getting out of scope of this issue. If the problem is solved, could you please close it? |
Yep, I did close this, But Thanks for the help Michał :) |
You're welcome! I'm glad I could help :) |
Description
THE ISSUE IS ONLY ON ANDROID
Flashlist is not scrolling when I wrap the List component to BottomSheet component, However when I comment out the BottomSheet component it works fine. So the issue is related to the BottomSheet component.
The List component itself is been rendered inside a flashlist, This is how I'm using it
BottomSheet component:
List Component:
Steps to reproduce
Take your mouse in the list and just Drag down the list it won't work on Andriod but works fine on iOS.
Snack or a link to a repository
null
Gesture Handler version
2.12.1
React Native version
0.72.4
Platforms
Android
JavaScript runtime
Hermes
Workflow
React Native (without Expo)
Architecture
Fabric (New Architecture)
Build type
Debug mode
Device
Android emulator
Device model
Google Pixel 4
Acknowledgements
Yes
The text was updated successfully, but these errors were encountered: