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.
Related
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.
Everyone.
I need your help.
I made one app with react native expo cli.
But one issue occurred.
I used the ScrollView for horizontal pagination.
*<SafeAreaView>
<ScrollView
snapToInterval={wp("100%")}
horizontal
pagingEnabled
nestedScrollEnabled
decelerationRate="fast"
>
{[...Array(this.state.pageCount)].map((num, index) => {
return (
<View
key={"view" + index}
style={{
width: wp("100%"),
height: "100%",
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
alignContent: "center",
justifyContent: "center",
}}
>
{this.state.categories
.slice(index * 6, index * 6 + 6)
.map((item, key) => (
<TouchableOpacity
key={"touch" + key}
style={styles.itemStyle}
onPress={() => this.openModal(item)}
onLongPress={() => this.selectItem(item)}
>
<Image
source={{ uri: item.Foto }}
style={{ height: 120, width: "90%" }}
resizeMode="cover"
/>
<Text style={{ fontSize: 18 }}>{item.Precio}</Text>
<Text style={{ fontSize: 12 }}>{item.Gemas}</Text>
</TouchableOpacity>
))}
</View>
);
})}
</ScrollView>
</SafeAreaView>*
But the pagination only works on Android Phone and doesn't work on iPhone.
Please help me.
Your <ScrollView> should have style flex: 1, to allow the view fit the screen size.
The width of the Views inside the Scroll should have a numerical value. A width of 100% inside a scrollview is undefined. Your approach should be related to the dimension of the screen.
// import dimensions lib
import Dimensions from 'react-native';
...
...
...
// capture the width of the screen
const screenWidth = Dimensions.get('screen').width;
...
...
...
{[...Array(this.state.pageCount)].map((num, index) => {
return (
<View
key={"view" + index}
style={{
width: screenWidth,
height: "100%",
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
alignContent: "center",
justifyContent: "center",
}}
>
{this.state.categories
.slice(index * 6, index * 6 + 6)
.map((item, key) => (
<TouchableOpacity
key={"touch" + key}
style={styles.itemStyle}
onPress={() => this.openModal(item)}
onLongPress={() => this.selectItem(item)}
>
<Image
source={{ uri: item.Foto }}
style={{ height: 120, width: "90%" }}
resizeMode="cover"
/>
<Text style={{ fontSize: 18 }}>{item.Precio}</Text>
<Text style={{ fontSize: 12 }}>{item.Gemas}</Text>
</TouchableOpacity>
))}
</View>
);
})}
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>
}
/>
I would like use DrawerLayoutAndroid module on React-Native app. For use openDrawer programmaticaly, i use useRef hook.
On run this method, my Drawer show only black "overflow", but not the navigation.
If i swip to the right, my Drawler menu will be show :/
My code :
const Layout = ({ children }) => {
let drawler = useRef(null);
return (
<DrawerLayoutAndroid
drawerWidth={300}
drawerPosition={DrawerLayoutAndroid.positions.Left}
ref={drawler}
renderNavigationView={() => (
<View style={{ flex: 1, backgroundColor: '#fff' }}>
<Text style={{ margin: 10, fontSize: 15, textAlign: 'left' }}>
I'm in the Drawer!
</Text>
</View>
)}>
<View style={{ flex: 1 }}>
<ScrollView>
<View style={styles.container}>
<Button onPress={() => drawler.current.openDrawer()}> // Show only overflow, not the menu
Open drawler
</Button>
{children}
</View>
</ScrollView>
</View>
</DrawerLayoutAndroid>
);
};
Anyone can help me ?
I solved the issue with useCallback
const [drawer, setDrawer] = useState();
const refDrawer = useCallback(element => {
setDrawer(element);
}, []);
Don't forget set ref={refDrawer} attribute to the DrawerLayoutAndroid component.
I'm trying to have a list and then a button, but if I try to have a button and then a list like so:
return (
<View style={styles.mainContainer}>
<View>
<TouchableOpacity style={styles.Button} onPress={() => this.props.navigate(1)}>
{buttonText}
</TouchableOpacity>
</View>
<ScrollView>
<View style={{ height: 250, backgroundColor: 'red' }}>
</View>
<View style={{ height: 250, backgroundColor: 'blue' }}>
</View>
<View style={{ height: 250, backgroundColor: 'green' }}>
</View>
</ScrollView>
</View>
);
You see that green isn't being fully shown:
This doesn't happen if the button isn't there.
And if I move
<View>
<TouchableOpacity style={styles.Button} onPress={() => this.props.navigate(1)}>
{buttonText}
</TouchableOpacity>
</View>
to be after the ScrollView, I don't see the button.
So to sum it up, I want the button to be stickied to the bottom while having every element in the scroll view to be fully shown. How can it be done?
This is the style of the button BTW:
Button: {
borderWidth: 1,
borderRadius: 10,
padding: 10,
marginTop: 5,
margin: 3,
backgroundColor: '#4267b2',
borderColor: '#ffffff',
alignItems: 'center'
}
he proper way to achieve this is by using flex
this is an example for 1 : 10 flex body to header ratio
render() {
return (
<View style={styles.mainContainer}>
<View style={styles.bodyContainer}>
<ScrollView >
<View style={{ height: 250, backgroundColor: 'red' }}>
</View>
<View style={{ height: 250, backgroundColor: 'blue' }}>
</View>
<View style={{ height: 250, backgroundColor: 'green' }}>
</View>
</ScrollView>
</View>
<View style={styles.headerContainer}>
<Button style={{ backgroundColor: 'blue', alignSelf:'center' }}
title="THIS IS A BUTTON" />
</View>
</View>
);
}
}
const styles = StyleSheet.create({
mainContainer: {
flex: 1,
flexDirection: 'column'
},
headerContainer: {
flex: 1,
},
bodyContainer: {
flex: 10
}
});
You can stick your button view with a position: absolute, set its height and add a margin-bottom of this height on the scrollview.
Render
return (
<View style={styles.mainContainer}>
<ScrollView style={styles.list}>
<View style={{ height: 250, backgroundColor: 'red' }}>
</View>
<View style={{ height: 250, backgroundColor: 'blue' }}>
</View>
<View style={{ height: 250, backgroundColor: 'green' }}>
</View>
</ScrollView>
<View style={styles.fixedBottom}>
<TouchableOpacity style={styles.Button} onPress={() => this.props.navigate(1)}>
{buttonText}
</TouchableOpacity>
</View>
</View>
);
Style
...
fixedBottom: {
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
height: 50, // <== the height on your view containing the button
backgroundColor: 'gray',
},
list: {
alignSelf: 'stretch',
flex: 1,
marginBottom: 50, // <== here the margin to see the full list
},
...
Here is a live demo.