I'm trying to set the contentOffset.y value = 0 and I don't know how can anyone help me
I want the user to be able to scroll down but scroll up to the max value = 0
desired image
I don't want a gap like this
below is my code
const windowWidth = Dimensions.get('window').width;
const ProductDetail = ({route, navigation: {goBack}}) => {
const insets = useSafeAreaInsets();
const {product} = route.params;
return (
<ScrollView
style={{flex: 1}}
onScroll={e => console.log(e.nativeEvent.contentOffset.y)}
scrollEventThrottle={16}>
<TouchableOpacity
style={{
position: 'absolute',
left: spacing.s,
zIndex: 1,
marginTop: insets.top,
}}
onPress={() => {
goBack();
}}>
<Icon icon="Back" style={{width: 50, height: 50}} />
</TouchableOpacity>
<FlatList
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
data={product.image}
renderItem={({item, index}) => {
return (
<View key={index}>
<Image source={item} style={{width: windowWidth, height: 410}} />
</View>
);
}}
/>
Related
I am using horizontal ScrollView to show few items on screen, this scroll view has pagination enabled and I am able to show pagination on the screen as well.
Below is my code:
const SwipeScreen = () => {
const { width, height } = Dimensions.get('window');
const [sliderState, setSliderState] = useState({ currentPage: 0 });
const setSliderPage = (event) => {
const { currentPage } = sliderState;
const { x } = event.nativeEvent.contentOffset;
const indexOfNextScreen = Math.floor(x / width);
if (indexOfNextScreen !== currentPage) {
setSliderState({
...sliderState,
currentPage: indexOfNextScreen,
});
}
};
const { currentPage: pageIndex } = sliderState;
const scrollViewRef = useRef(null);
const toNextPage = () => {
sliderState.currentPage += 1;
scrollViewRef.current?.scrollTo({
x: window.width * sliderState.currentPage,
animated: true,
});
};
return (
<>
<ScrollView
style={{ flex: 1 }}
ref={scrollViewRef}
horizontal={true}
scrollEventThrottle={16}
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
onScroll={(event) => {
setSliderPage(event);
}}
>
<View style={{ width, height }}>
<Text>Item 1</Text>
<Button title='Next' color='#f194ff' onPress={toNextPage} />
</View>
<View style={{ width, height }}>
<Text>Item 2</Text>
<Button title='Next' color='#f194ff' onPress={toNextPage} />
</View>
<View style={{ width, height }}>
<Text>Item 3</Text>
<Button title='Next' color='#f194ff' onPress={toNextPage} />
</View>
<View style={{ width, height }}>
<Text>Item 4</Text>
<Button title='Next' color='#f194ff' onPress={toNextPage} />
</View>
<View style={{ width, height }}>
<Text>Item 5</Text>
</View>
</ScrollView>
<View style={styles.paginationWrapper}>
{Array.from(Array(5).keys()).map((key, index) => (
<View
style={[
styles.paginationDots,
{ opacity: pageIndex === index ? 1 : 0.2 },
]}
key={index}
/>
))}
</View>
</>
);
};
const styles = StyleSheet.create({
textColor: {
color: 'red',
},
paginationWrapper: {
position: 'absolute',
bottom: 200,
left: 0,
right: 0,
justifyContent: 'center',
alignItems: 'center',
flexDirection: 'row',
},
paginationDots: {
height: 10,
width: 10,
borderRadius: 10 / 2,
backgroundColor: '#0898A0',
marginLeft: 10,
},
});
export default WelcomeSwipeImgScreen;
I also wanted a next button, on whose click next item is shown on screen. For this I have written toNextPage function, but its not working. I am not able to figure out where I am going wrong with this
Is it possible to achieve a component drop on react native?
Something like this. Sorry for the paint skills. Thank you in advance .
You can create a custom component like below, You can change the render label to support the view you want.
This sample needs the data to be like the below object but you can create your own object.
const dataArray = [{value: 'Car', id: 1,},{value: 'Van',id: 2},{ value: 'Bus',id: 3}];
//Usage
<CustomDropDown data={dataArray} />
const CustomDropDown = (props) => {
const [open, setOpen] = React.useState(false);
const [selected, setSelected] = React.useState(-1);
const renderLabel = (item) => {
return (
<View
style={{
width: 200,
height: 60,
borderWidth: 1,
borderRadius: 10,
padding: 5,
marginVertical: 3,
}}>
<Text style={{ fontSize: 20 }}>{item.value}</Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
<Text>{item.value}</Text>
<Text style={{ fontSize: 15 }}>{item.value}</Text>
</View>
</View>
);
};
const renderItem = (item) => {
return (
<TouchableOpacity
onPress={() => {
setSelected(item.id);
setOpen(!open);
//Call back to external state
}}>
{renderLabel(item)}
</TouchableOpacity>
);
};
return (
<View>
<TouchableOpacity style={{}} onPress={() => setOpen(!open)}>
{selected === -1 && <Text>Place holder text</Text>}
{selected !== -1 &&
renderLabel(props.data.find((x) => x.id === selected))}
</TouchableOpacity>
{open && (
<View
style={{
position: 'absolute',
top: 70,
}}>
{props.data.map((item) => renderItem(item))}
</View>
)}
</View>
);
};
at end of flatlist padding right and margin right is not effective its not showing space after end of flatlist i am using horizontal flat list
<FlatList
horizontal
contentInset={{right: 20}}
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
data={item.listData}
renderItem={({item, index}) => {
var lastCell =
mainListData.length - 1 == index ? true : false;
var firstCell = index == 0 ? true : false;
console.log(firstCell, lastCell);
return (
<CategoryComponent
data={item}
onPress={() => {
this.props.navigation.navigate('RecipeList');
}}
isLastCell={lastCell}
isFirstCell={firstCell}
/>
);
}}
/>
category component returns below style
<TouchableOpacity
style={{
width: 'auto',
marginLeft: isFirstCell
? 0.064 * deviceWidth
: 0.043 * deviceWidth,
marginRight: isLastCell ? 0.064 * deviceWidth : 0
}}
onPress={onPress}>
<View style={styles.showCollectionnView}>
<Image source={data.image}
style={{
height: 144,
width: 144,
borderRadius: 10,
position: 'absolute'
}}/>
</View>
<Text style={styles.nameText}>{data.name}</Text>
<Text style={styles.otherText}>{data.recipes}</Text>
</TouchableOpacity>
You should use contentContainer style for flatlist
<FlatList
contentContainerStyle={{paddingRight:100}}
//... other props
/>
You can increase as per your requirement.
I'm trying to achieve when I scroll bigger image, green border on smaller ones will go to the next one. I have 2 different flatlist for this. Tried to write item.key to state with onMomentumScrollEnd but didnt work. Here is my
<FlatList
data={this.state.productImage}
horizontal
pagingEnabled
showsHorizontalScrollIndicator={false}
onMomentumScrollEnd={item => { this.setState({ active: item.key });
console.log(item.key) }}
renderItem={({ item }) =>
<View>
<Image source={item.source} style={{ width:
Dimensions.get('window').width, height:
Dimensions.get('window').height / 2 }} />
</View>}
keyExtractor={item => item.key}
/>
<FlatList
data={this.state.productImage}
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ flexDirection: "row", alignItems: "center",
marginHorizontal: theme.SIZE.pageMargin, marginVertical: 20 }}
renderItem={({ item }) =>
<TouchableOpacity >
<Image source={item.source} style={[this.state.active === item.key
&& styles.activeImage, styles.productImages]} />
</TouchableOpacity>}
keyExtractor={item => item.key}
/>
Edit: After fighting with this I've solved
onMomentumScrollEnd={(event) => {
let xPosition = Math.round(event.nativeEvent.contentOffset.x)
let imageWidth = Math.round(Dimensions.get('window').width)
let keyOfShownImg = (Math.round((xPosition + imageWidth) / imageWidth))
this.setState({ active: keyOfShownImg })
}}
Actually you nearly got the solution. Here you can use onViewableItemChanged prop to achieve this.
I tried out the solution. Take a look here
import * as React from 'react';
import { Text, View, StyleSheet, FlatList, Image } from 'react-native';
import Constants from 'expo-constants';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
visibleIndex: 0,
data: [
'https://homepages.cae.wisc.edu/~ece533/images/airplane.png',
'https://homepages.cae.wisc.edu/~ece533/images/arctichare.png',
'https://homepages.cae.wisc.edu/~ece533/images/arctichare.png',
'https://homepages.cae.wisc.edu/~ece533/images/arctichare.png',
],
};
this.onViewableItemsChanged = this.onViewableItemsChanged.bind(this);
}
renderBigList = ({ item, index }) => {
return (
<Image
style={{ width: 300, height: 300, resizeMode: 'contain' }}
source={{ uri: item }}
/>
);
};
renderSmallList = ({ item, index }) => {
return (
<View
style={{
borderColor:
index === this.state.visibleIndex ? 'green' : 'transparent',
borderRadius: 10,
borderWidth: 2,
margin: 3,
}}>
<Image
style={{ width: 100, height: 100, resizeMode: 'contain' }}
source={{ uri: item }}
/>
</View>
);
};
onViewableItemsChanged = (viewableItemData, changed) => {
//console.log(viewableItemData);
if (viewableItemData.viewableItems.length) {
let keyOfVisibleItem = viewableItemData.viewableItems[0].index;
console.log(keyOfVisibleItem);
this.smallListRef.scrollToIndex({
index: keyOfVisibleItem,
animated: true,
});
this.setState({ visibleIndex: keyOfVisibleItem });
}
};
render() {
return (
<View style={styles.container}>
<FlatList
keyExtractor={(item, index) => '' + index}
style={{ height: '50%' }}
data={this.state.data}
extraData={this.state}
renderItem={this.renderBigList}
horizontal={true}
onViewableItemsChanged={this.onViewableItemsChanged}
viewabilityConfig={{
itemVisiblePercentThreshold: 90,
}}
showsHorizontalScrollIndicator={false}
/>
<FlatList
ref={ref => (this.smallListRef = ref)}
keyExtractor={(item, index) => '' + item}
style={{ height: 50 }}
data={this.state.data}
extraData={this.state}
renderItem={this.renderSmallList}
horizontal={true}
showsHorizontalScrollIndicator={false}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
paddingTop: Constants.statusBarHeight,
padding: 8,
backgroundColor: 'white',
},
});
I have a problem with react-native-swiper on Android ONLY. The same code works for iOS!
Below is an image of what is happening:
The area is blue is supposed to be a square and all images should be within it. Something like this (I only render 1 image here):
This is what my code looks like:
renderSwiper = () => {
const images = this.props.data.item[1].images;
let swiperImages = images.map((image, index) => {
let priority = FastImage.priority.normal;
if (index === 0)
priority = FastImage.priority.high;
return (
<TouchableWithoutFeedback key={index} onPress={this.routeToListingDetails} >
<FastImage
style={styles.imageStyle}
source={{uri: image, priority: priority}}
/>
</TouchableWithoutFeedback>
)
})
return (
<View style={{ aspectRatio: 1, width: '100%'}}>
<Swiper
loop={false}
paginationStyle={styles.swiperPaginationStyle}
>
{swiperImages}
</Swiper>
</View>
);
}
render(){
return (
<View style={styles.container} >
<View style={{ borderColor: 'blue', borderWidth: 2 }}>
{this.renderSwiper()}
</View>
</View>
)
}
const styles = StyleSheet.create({
container:{
width:'50%',
alignItems:'center',
marginBottom:'4%',
padding:'2%',
},
imageStyle:{
resizeMode: "cover",
width: "100%",
aspectRatio:1
}
})