How to display vertical scroll indicator always in react native scrollview - react-native

I am trying to display vertical scroll indicator always. Because I have 4 pages in my screen, But, After loading screen and scroll first page, The vertical scroll indicator is disappearing which is default behaviour of scrollview. So, I have try to show some flashScrollIndicators() But, still it is disappearing.
setScrollView = (scrollView) => {
// NOTE: scrollView will be null when the component is unmounted
this.scrollView = scrollView;
this.scrollView.flashScrollIndicators();
};
render() {
return (
<ScrollView ref={this.setScrollView} style={{ marginTop: 10, flexGrow: 1, flex: 1 }} contentInset={{ bottom: 20 }}>
);
}
Any suggestions, My requirement is I have to display scroll indicator always in my screen.

flashScrollIndicators() will flash the indicator for one or two seconds. You would need to keep calling it to see it (for example with setInterval). But this will make it flash like a Christmas tree, since it will flash every-time it is called, not stay solid.
If what you want the bar to be always solid, then you could use my suggestion for iOS (without native code). Android has the persistentScrollbar prop, which is simple enough to use.

Related

How do I make an absolut positioned touchable element on top of a FlatList catch only press events and let other events propagate to the FlatList?

I have a FlatList in React Native with fullscreen image and video items (with pagingEnabled). I want to have a short descriptive touchable text floating on top of the FlatList, to open up a view with some information about the image/video when pressed.
To make the user experience nice, I'd like to be able to scroll the FlatList through the touchable text as well. I.e. if the user happen to start their scrolling motion on top of the text, the FlatList would scroll but if it is a simple press event I'd like to open the view with details about the image/video.
No mater what I try I end up with either the text being able to react to the press OR the FlatList being able to scroll. I have tried different configurations with a custom PanResponder and pointerEvents but seem to always end up with a state were one thing does not work. Do you guys have any smart ideas? I am probably just stuck in the wrong train of thought.
This is a simplified view of my component structure:
<View>
<View style={{ position: 'absolute', bottom: 100, zIndex: 10 }}>
<TouchableOpacity onPress={() => console.log('press')}>
<Text>Some Descriptive Text</Text>
</TouchableOpacity>
</View>
<FlatList pagingEnabled horizontal {...otherFlatListProps} />
</View>

React Native: keyboard covers cursor. Some-weird-times

Why numbers in plain text breaks normal keyboard behaviour? It's so crazy!
I have a hughe text field that overflows screen size.
I tried to make it with just TextInput, but when I overscroll it to the top or to the bottom, app manages this like just touch event and pops up keyboard when it actually do not needed. Sometimes even usual scrolling becomes considered as text selection. This is undesirable behavior.
So, I put TextInput inside ScrollView and that issues goes away, but becomes a weird new one. When I touch some word (only letters characters) at the bottom of the screen, the keyboard pops up and text scrolls up to help me see the cursor above the keyboard. With words it behaviours as I want (photo below).
The problem is here>> But when I point some number, alpha-numeric, or blank row in the bottom of my text, the keyboard appears, but the text doesn't jump up. So I can't see the cursor and must scroll down manually (photo below: see the cursor leaved upon keyboard area).
Why numbers are blocking this stuff?
Environment: React Native 69.6, Expo 46, Android smartphone, Android Studio
My sipmlified code:
import React from "react";
import { StyleSheet, TextInput, ScrollView } from "react-native";
export default function MyScreen() {
return (
<ScrollView
style={{ flex: 1 }}
contentContainerStyle={{
// flex: 1, <--- if uncomment this, I come back to the first issue
paddingHorizontal: 10,
paddingVertical: 5,
}}
>
<TextInput
multiline={true}
style={{ fontSize: 16 }}
value={`Lorem Ipsum...`}
/>
</ScrollView>
);
}
I tried different combinations of KeyboardAvoidingView, KeyboardAwareScrollView, different layouts and Views nestings. KeyboardAvoidingView helps with cursor but it disorders my layouts. I think, the resolving should be simple. How to deal with it?

How to prevent *locked* parent scroll-view from scrolling when nested child scroll-view scrolls to end of its view?

In a react-native project, there is a parent flatlist/scrollview. inside each item in this parent list, there exists a nested scroll view.
Expected behavior: When the parent scroll view is locked, the parent should NEVER scroll, only the child scrollview should be allowed to scroll. and when the outer bound of the child scroll view is met (meaning youve scrolled to the bottom or all the way back to the top of child view), the parent remains locked
What actually happens: with parent view scroll-locked, scrolling the child scrollview to the very bottom/top will scroll the parent scroll view, once the child scroll view reaches its scroll-boundary
Steps to reproduce behavior:
flick one of the child scroll views downward until it reaches the bottom
(even though youve reached the downward boundary) attempt to scroll the child down even more
observe the fact the parent scroll view now scrolls instead, even though the parent scroll view is locked
How can the parent scroll view be truly prevented from scrolling when nested-scroll-view reaches the end of its view?
only noticed this on android, but could possibly exist on ios as well.
here is a minimum reproducible example: https://staging.snack.expo.dev/b3XuJ6iA3
You are nesting multiple ScrollViews inside a FlatList, which is a convenience wrapper around ScrollView (compare with the documentation) , but you are setting nestedScrolEnabled to true in the child ScrollViews. You need to set it on the parent ScrollView (the FlatList).
The following code completely disables scrolling for the parent FlatList while allowing scrolling in all nested ScrollViews.
const _renderItem = ({item, index}) => {
return (
<View style={{height: 300, borderColor: 'blue', borderWidth: 1, marginBottom: 20}}>
<Text> Non scroll View area </Text>
<ScrollView contentContainerStyle={{height: 500, borderColor: 'red', borderWidth: 3}}></ScrollView>
</View>
)
}
return (
<View style={styles.container}>
<FlatList data={data} renderItem={_renderItem} scrollEnabled={false} nestedScrollEnabled={true}/>
</View>
);
}
Here is a working snack of your code with the changes mentioned above which I have successfully tested on Android (Samsung Galaxy S9) and iOS (iPhone 12).

React Native: Is there a way to make components scrollable/sticky without using ScrollView?

New to react native. Here is what I am trying to do:
Render a page with three components: top panel, middle row, and content box.
When the user scrolls down, the top panel is scrolled and disappears, middle row is scrolled but is sticky to the top of the screen, and the content box is scrolled all the way down until the end of the content.
Below code serves my intention. However, when I use this code, I get warnings about nesting virtualized views.
return (
<View style={style.profileContainer}>
<ScrollView
stickyHeaderIndices={[1]}
showsVerticalScrollIndicator={false}
>
<TopPanel /> // This is a view component and is scrolled up as the user scrolls down.
<MiddleRow /> // This is a view component that is sticky to the top of the screen
<BottomArray /> //This is a FlatList
</ScrollView>
</View>
)
Below code gets rid of the warning but all the scroll/sticky behaviors of the top/middle components disappear. They just remain fixed as the user scrolls down.
return (
<View style={style.profileContainer}>
<SafeAreaView style={{flex:1}}>
<TopPanel /> // This is a view component and is fixed as the user scrolls down.
<MiddleRow /> // This is a view component and is fixed as the user scrolls down.
<BottomArray /> //This is a FlatList
</SafeAreaView>
</View>
)
Is there a way to make the top panel scrollable and middle row sticky without relying on ScrollView? This is one of the key interfaces of the app and I'd like to keep it alive.
Thanks!
I think if you put the Middle Row inside a Scroll View, that will help. I am new to react-native, so I am pretty sure this won't help you a lot and I think you would have already tried it.
If i understand correctly what you are looking to achieve, you can wrap the 3 boxes inside a view, have the top and middle inside a view and the content inside a scrollview:
<View>
<View><Text>TOP SECTION</Text></View>
<View><Text>Sticky section</Text></View>
<ScrollView><Text>...Content</Text></ScrollView>
</View>
then using animate you can animate the size (for the top section) and the position (of the sticky section) based on the scroll position of the content section.
first you define you scrollY as a ref:
const scrollY= useRef(new Animated.Value(0)).current;
then you convert the views to Animated and "link" the scrollY ref to the scrolling of the scrollview:
<View>
<Animated.View><Text>TOP SECTION</Text></Animated.View>
<Animated.View><Text>Sticky section</Text></Animated.View>
<Animated.ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{ nativeEvent: { contentOffset: { y: scrollY } } }], // attach the scroll to scrollY
{ useNativeDriver: true },
)}>
>
<Text>...Content</Text>
</Animated.ScrollView>
</View>
at this point you can define the function that handle position, size, opacity and so on based on the scrollY position, assuming you know the header height, this function interpolate (map the values) the scroll position of the scrollview from 0 to the height of the header, giving an innverse output range (from 0 to -header heigth):
const headerTranslateY = scrollY.interpolate({
inputRange: [0, HEADER_HEIGHT],
outputRange: [0, -HEADER_HEIGHT],
extrapolate: 'clamp',
});
this function can be attached to the trasform property of the style of the view that you want to animate:
<Animated.View styles={[styles.customstyle, {transform: [{ translateY: headerTranslateY }]}]><Text>TOP SECTION</Text></Animated.View>
basically with interpolate you constatly set values of something, based (in this case) of the scrolling offset of your scrollview (you can read more here on interpolation https://reactnative.dev/docs/animations#interpolation)

Absolute position for android

I'm trying to create a screen that looks like the attached picture. The styling code I used works only for iOS but doesn't work for Android.
The sample code with preview can be found here: https://snack.expo.io/#tushark/absolute-android
Please check for both iOS and android.
Here is the layout I want to create.
I've create a new Expo project from a sample code you give here: https://snack.expo.io/S1yDf4Q47
On the AbsoluteView Component add another View to handle the display screen:
<View style={styles.container}>
<View style={{borderColor:'transparent'}}> // add borderColor, or the screen looks weird on android (i don't know why)
{View of card, row, title and content styles}
</View>
<OrangeButton
label="CONFIRM"
onPress={() => console.log('Pressed')}
styleButton={styles.loginBtn}
/>
</View>
and the Button Component I change the Bottom: -20 to top: width / 3,
and the layout look's like :
Android :
iOS:
I would recommend leaving the orange button outside of the card container and using an absolute position with device height to position it, you can also do the same for the card container to give the button the same position relevant to the card container on any device.
ex.
top: Dimensions.get('window').height/8