React Native ScrollView with absolute position on Android device is not scrollable - android

First of all I would like to mention that the code works fine on iOS but not on Android.
I'm trying to make my own custom dropdown list.
When you pressing on Input the Dropdown opens just beneath it with position absolute.
You can play around with it here: https://snack.expo.dev/#eko_test/dropdown
and see example snippets below.
<Input
value={inputValue}
placeholder={placeholder}
onTouchStart={() => setShowItems((prevState) => !prevState)}
onTouchEnd={() => Keyboard.dismiss()}
onChangeText={onSearchItem}
/>
{showItems && (
<ScrollView
style={styles.itemsContainer}
contentContainerStyle={{ padding: 6 }}
keyboardShouldPersistTaps="always"
>
{usedItemList.length > 0 ? (
<View>
<Text style={styles.hintText}>Last used</Text>
<DropdownList
items={savedItemList}
onItemSelect={onListItemSelect}
/>
<View style={styles.separator} />
</View>
) : undefined}
<DropdownList items={itemList} onItemSelect={onListItemSelect} />
</ScrollView>
)}
const DropdownList: FC<DropdownListProps> = ({ items, onItemSelect }) => {
return (
<View>
{items.map((item) => (
<DropdownItemComponent
key={item.id}
item={item}
onItemPress={() => onItemSelect(item)}
/>
))}
</View>
);
};
itemsContainer: {
position: "absolute",
top: 35,
width: "100%",
backgroundColor: Colors.black,
borderBottomWidth: 1.6,
borderBottomColor: Colors.green,
maxHeight: 160,
},

Related

How to scroll all flatlists nested in a section list?

I have a FlatList nested in a SectionList as shown below.
There is always 3 sections (rows) and each section has a FlatList with a horizontal scroll.
Expected
On button click, invoking the scrollToEnd() function, to scroll all 3 flatlists from each section to end.
Problem
Only the bottom or last flatlist scrolls to the end.
I cannot figure out why this is - I thought the ref in the flatlist may only be referencing the last Flatlist rendered and not the other two, maybe? If so, any tips or suggestions are welcome. Thank you.
...
const flatlistRef = useRef();
const scrollToEnd = () => {
flatlistRef.current.scrollToEnd({ animating: true });
};
...
<SectionList
contentContainerStyle={styles.sectionListContainer}
stickySectionHeadersEnabled={false}
sections={myData}
renderSectionHeader={({ section }) => (
<>
<FlatList
horizontal
data={section.data}
contentContainerStyle={
styles.flatlistContainer
}
renderItem={({ item }) => (
<Button
onPress={() => updateData(item.id)}
>
<ListItem item={item} />
</Button>
)}
showsHorizontalScrollIndicator={false}
ref={flatlistRef}
/>
</>
)}
renderItem={({}) => {
return null;
}}
/>
I have also working on this but I found a solution where I can create a Section.List by using react-native-paper.
But you can also use the map function, Here is the code of that
import React from "react";
import {View,Text} from "react-native";
const App = () =>{
return(
<View style={{flex: 1}}>
{data.map((item, index) => (
<View key={index} style={{borderBottomColor: 'black', borderBottomWidth: 2}}>
<Text style={{fontSize: 30, fontWeight: 'bold'}}>{item.title}</Text>
{item.items && <>
{item.items.map((item, index) => (
<View key={index} style={{backgroundColor: '#7fc', borderBottomColor: 'blue', borderBottomWidth: 2}}>
<Text style={{fontSize: 20, marginLeft: 40, color: 'blue'}}>{item.title}</Text>
{item.items && <>
{item.items.map((item, index) => (
<View key={index} style={{backgroundColor: 'yellow', borderBottomColor: 'red', borderBottomWidth: 2}}>
<Text style={{fontSize: 16, marginLeft: 80,}}>{item.title}</Text>
</View>
))}
</>}
</View>
))}
</>}
</View>
))}
</View>
)
}
export default App;
I hope It will help.

Expo Android get blank space when keyboard show

im using Stack.Navigator to provides screen, on main screen using Flatlist render data
getting that error on Android only, difference weird view each time focus , it working fine on iOS
im was trying with other solutions but no luck
const DATA = [
...
];
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const renderItem = ({ item }) => <Item title={item.title} />;
return (
<KeyboardAvoidingView
style={{ flex: 1, backgroundColor: 'red' }}
behavior='height'
keyboardVerticalOffset={-500}
>
<View style={{ flex: 1 }}>
<FlatList style={{ flex: 1 }} data={DATA} renderItem={renderItem} />
<TextInput placeholder='Input' style={styles.textInput} />
<KeyboardSpacer />
<SafeAreaView />
</View>
</KeyboardAvoidingView>
);
and setting on app.json
"softwareKeyboardLayoutMode": "pan"
Im using
"expo": "^43.0.0",
"react-native": "0.64.3",
thank you!

Only running software in Android simulator, Scrollview nested flatlist, unable to scroll

I use srcollview to nest flatlist to render data. After the rendering is successful, however, when running on Android, the view cannot be scrolled, but running on IOS does not.
<View >
<FlatList
data={categoryState}
renderItem={item => <ItemCombination data={item} click={loading} detail={detail} />}
listKey={(item, index) => index.toString()}
numColumns={3}
ListFooterComponent={
<View style={{ width: 794, backgroundColor: '#fff', alignItems: 'center', maxHeight: 300 }} >
{
show ?
showLoading ?
<ActivityIndicator color='#21b6a8' size='large' style={{ marginVertical: 20 }} />
:
{/* unable to scroll */}
<ScrollView style={{ width: Platform.OS === 'web' ? 780 : 794, height: 300 }} showsVerticalScrollIndicator={true} contentContainerStyle={{ alignItems: 'center' }}>
{/* unable to scroll */}
<FlatList
data={menuItems}
renderItem={item => <Item data={item} click={menuItemClick} categoryId={categoryId} />}
keyExtractor={(item, index) => item.id + index.toString()}
numColumns={3}
showsVerticalScrollIndicator={false}
/>
</ScrollView>
:
<View></View>
}
</View>
}
/>
</View>
you can use the built-in nestedscrollenabled prop for the children FlatList component.
<FlatList nestedScrollEnabled />
Nested scrolling is supported by default on iOS. so for android you need to add this.
Flatlist in ListFooterComponent won't work in Android because It has Flatlist's scroll property which scrolls the container of the list with a footer also. Some workaround is like
<FlatList
......
ListFooterComponent={
<View style={{ width: 794, backgroundColor: '#fff', alignItems: 'center', maxHeight: 300 }} >
{
show ?
showLoading ?
<ActivityIndicator color='#21b6a8' size='large' style={{ marginVertical: 20 }} />
:
{/* remove scroll and have map on items to render data footer */}
menuItems.map(item => { render <View> ...</View> }
:
}
</View>
}
/>

Tabs with scrolling animated header - React native

I am following the tutorial in the link: https://medium.com/appandflow/react-native-scrollview-animated-header-10a18cb9469e .
However I can't seem to understand how to add tabs to this such that the tab headers get fixed to top when scrolled up. Can anyone please suggest how to achieve this?
I was able to achieve it using ScrollableTab and Tab in native-base library.
Code looks like this
<Tabs
prerenderingSiblingsNumber={3}
onChangeTab={({ i }) => {
this.setState({ height: this.heights[i], activeTab: i })
}}
renderTabBar={(props) => (
<Animated.View style={{ transform: [{ translateY: tabY }], zIndex: 1, width: "100%", backgroundColor: "white", paddingTop: HEADER_MAX_HEIGHT }}>
<ScrollableTab
{...props}
renderTab={(name, page, active, onPress, onLayout) => (
<TouchableOpacity key={page}
onPress={() => onPress(page)}
onLayout={onLayout}
activeOpacity={0.4}>
<Animated.View
style={{
flex: 1,
height: 100,
backgroundColor: tabBg
}}>
<TabHeading scrollable
style={{
backgroundColor: "transparent",
width: Dimensions.get('window').width / 2
}}
active={active}>
<Animated.Text style={{
fontWeight: active ? "bold" : "normal",
color: 'black',
padding: 10,
fontSize: active ? 20 : 18
}}>
{name}
</Animated.Text>
</TabHeading>
</Animated.View>
</TouchableOpacity>
)}
underlineStyle={{ backgroundColor: 'black' }}
/>
</Animated.View>
)}>
<Tab heading="Tab 1">
{this.tabContent(30, 0)}
</Tab>
<Tab heading="Tab 2">
{this.tabContent(15, 1)}
</Tab>
</Tabs>
use this:
expo install react-native-gesture-handler react-native-reanimated
Then basic usage look like this to replace in <Animated.View ......<Text>....</Text>..... ></Animated.View>:
<TabView
navigationState={{ index, routes }}
onIndexChange={setIndex}
renderScene={SceneMap({
first: FirstRoute,
second: SecondRoute,
})}
/>
I hope it'll help you..!
In case anybody else falls on this thread, I developed a new package, react-native-animated-screen, that does exactly what you need
Check it out
https://www.npmjs.com/package/react-native-animated-screen
import React from 'react';
import { Image, Text, View } from 'react-native';
import AnimatedScreen from 'react-native-animated-screen';
const Component = () => {
return (
<AnimatedScreen.Wrapper>
<AnimatedScreen.Header>
<View>
<Text>Title</Text>
<AnimatedScreen.CollapsibleElement>
<Text>Subtitle</Text>
</AnimatedScreen.CollapsibleElement>
<AnimatedScreen.Element>
<YourTabsComponen />
</AnimatedScreen.Element>
</View>
</AnimatedScreen.Header>
<AnimatedScreen.ScrollView>
<View style={{ height: '300%' }}>
<View>
<Text>Body</Text>
</View>
</View>
</AnimatedScreen.ScrollView>
</AnimatedScreen.Wrapper>
);
};
In the example above only the title and YourTabBComponentare going to remain after scrolling, the subtitle (as all the elements wrapped in a CollapsibleElement) will disappear.
Ideally you could also have the tabs to appear only when entirely scrolled using the interpolate prop or the animatedStyle of the AnimatedScreen.Element
// using interpolate the animation will flow from 0 to scrollY === headerMaxHeight
<AnimatedScreen.Element interpolate={{ opacity: [0, 1], height: [0, 60] }}>
<TabComponent />
</AnimatedScreen.Element>
// alternatevely you can have more control with an animatedStyle
<AnimatedScreen.Element animatedStyle={scrollY => ({
opacity: scrollY.interpolate({
inputRange: [100, 200],
outputRange: [0, 1]
extrapolate: 'clamp'
})
})}>
<TabComponent />
</AnimatedScreen.Element>
In case anybody else falls on this thread, I developed a new package, react-native-animated-screen, that does exactly what you need
Check it out
https://www.npmjs.com/package/react-native-animated-screen
import React from 'react';
import { Image, Text, View } from 'react-native';
import AnimatedScreen from 'react-native-animated-screen';
const Component = () => {
return (
<AnimatedScreen.Wrapper>
<AnimatedScreen.Header>
<View>
<Text>Title</Text>
<AnimatedScreen.CollapsibleElement>
<Text>Subtitle</Text>
</AnimatedScreen.CollapsibleElement>
<AnimatedScreen.Element>
<YourTabsComponen />
</AnimatedScreen.Element>
</View>
</AnimatedScreen.Header>
<AnimatedScreen.ScrollView>
<View style={{ height: '300%' }}>
<View>
<Text>Body</Text>
</View>
</View>
</AnimatedScreen.ScrollView>
</AnimatedScreen.Wrapper>
);
};
In the example above only the title and YourTabBComponentare going to remain after scrolling, the subtitle (as all the elements wrapped in a CollapsibleElement) will disappear.
Ideally you could also have the tabs to appear only when entirely scrolled using the interpolate prop or the animatedStyle of the AnimatedScreen.Element
// using interpolate the animation will flow from 0 to scrollY === headerMaxHeight
<AnimatedScreen.Element interpolate={{ opacity: [0, 1], height: [0, 60] }}>
<TabComponent />
</AnimatedScreen.Element>
// alternatevely you can have more control with an animatedStyle
<AnimatedScreen.Element animatedStyle={scrollY => ({
opacity: scrollY.interpolate({
inputRange: [100, 200],
outputRange: [0, 1]
extrapolate: 'clamp'
})
})}>
<TabComponent />
</AnimatedScreen.Element>

How to achieve something like CoordinatorLayout in React Native?

I want to achieve a behavior like android's CoordinatorLayout enter always for my ToolBar i tried too many solutions some did work but not fully like https://github.com/maolion/mao-rn-android-kit which is really cool but with one setback as it doesn't work with ListView i also tried Animated but the scroll event throttle on android is just not working most of the times it does not even work.
Using mao-rn-android-kit
<CoordinatorLayoutAndroid ref={(component) => this.coordinatorLayout = component} fitsSystemWindows={false}>
<AppBarLayoutAndroid
layoutParams={{
width: 'match_parent',
height: 112
}}
style={{ backgroundColor:"#528eff" }}>
<View layoutParams={{height: 56, width: this.windowWidth, scrollFlags: (
AppBarLayoutAndroid.SCROLL_FLAG_SCROLL |
AppBarLayoutAndroid.SCROLL_FLAG_ENTRY_ALWAYS)}} style={{height: 56}}>
<ToolbarAndroid
titleColor={'#FFF'}
title={this.props.title}
navIcon={images.arrowBack}
onIconClicked={() => this._goBack()}
onActionSelected={() => {}}
actions={[{title: 'Search', icon: images.search, show: 'always'}]}
style={[{backgroundColor: '#528eff', width: this.windowWidth, height: 56}]}/>
</View>
<View layoutParams={{height: 56, width: this.windowWidth}}
style={{flex: 0, flexDirection: 'row', justifyContent: 'center', width: this.windowWidth, backgroundColor: '#528eff'}}>
<TouchableOpacity onPress={() => this.getDocuments('high')}
style={[styles.highNormalLowDocListHeaderStateTextContainer, highSelected.borderStyle]}>
<Text
style={[styles.highNormalLowDocListHeaderStateText, highSelected.textStyle]}>HIGH</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.getDocuments('normal')}
style={[styles.highNormalLowDocListHeaderStateTextContainer, normalSelected.borderStyle]}>
<Text
style={[styles.highNormalLowDocListHeaderStateText, normalSelected.textStyle]}>NORMAL</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => this.getDocuments('low')}
style={[styles.highNormalLowDocListHeaderStateTextContainer, lowSelected.borderStyle]}>
<Text
style={[styles.highNormalLowDocListHeaderStateText, lowSelected.textStyle]}>LOW</Text>
</TouchableOpacity>
</View>
</AppBarLayoutAndroid>
<View
ref={(component) => this.contentLayout = component}
style={{flex: 1, backgroundColor: 'transparent', height: this.windowHeight - 150}}>
<ListView
style={{height: this.windowHeight - 150, overflow: 'hidden'}}
dataSource={this.state.documents}
enableEmptySections={true}
renderRow={(rowData) => this._renderRow(rowData)}
/>
</View>
</CoordinatorLayoutAndroid>
The key to reacting to the scroll position fluidly is using Animated.event along with the onScroll to update an Animated.value
getInitialState: function() {
return {
scrollY: new Animated.Value(0)
}
},
render() {
return (
<ScrollView
scrollEventThrottle={16}
onScroll={Animated.event(
[{nativeEvent:
{contentOffset:
{y: this.state.scrollY}
}
}]
)}>
// etc ...
}
I could then call interpolate on this.state.scrollY and feed this value into a transform style on another component that I wanted to update as the ScrollView scrolled.

Categories

Resources