leecade / leecade/react-native-swiper

image shift by about 1 cm when swiping left or right and shift increase the more we swipe

Open
#1,175 18 comments 6 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

🐛bug
Dominant language
JavaScript
Stars
10.5k
Forks
2.3k
PR merge metrics
No merged PRs in 30d

Description

Which OS ?

Mac OS 10.15.2
iOS: 13.3.1

Version

Which versions are you using:

  • react-native-swiper v? 1.6.0
  • react-native v0.?.? 0.61.5
Expected behaviour

If we start with image at position 0, then we swipe left, image 1 is supposed to show without any shift or offset. Then any subsequent swipes shows next images.

Actual behaviour

If we start with image at position 0, then we swipe left, image 1 shows shifted by about 1 cm and shows a part of image 2. When we tap on image 1, the shift is removed and the image is back into position. when we shift again to the left, image 2 is showing shifted more than previous showing more of image 3. The more we shift, the more the shift get bigger.
The only thing that made this behavior disappear is when we remove the onIndexChanged method. But, we need this method to to keep the current index of the image, so that if we want to delete an image from the image array, we know which is the current image index to delete.
Please note this behavior does not happen on android.

How to reproduce it>

To help us, please fork this component, modify one example in examples folder to reproduce your issue and include link here.

  • Here is the piece of code I am using:

function myFunc(props) {

// this is the initial index of 1 image out of the array of images which is set as featured image
let initFeaturedImageIndex = -1; // means initially no images in the array set as featured image

// this is the initial index of the current image displayed in the swiper
let initPhotoCurrentIndex = -1; // means array empty. If array have 1 or more images, its initial value is 0

// this is the array that holds all the images that should be shown in the swiper
const [photos, setPhotos] = useState();

// this is an object that holds both the featured image index and the current image index
const [featPhotoCurrIndex, setFeatPhotoCurrIndex] = useState({
	featuredImageIndex: initFeaturedImageIndex,
	photoCurrentIndex: initPhotoCurrentIndex
});
// this is an array that holds the images deleted from the array of images & do not show in the swiper
const [deletedPhotos, setDeletedPhotos] = useState([]);

// things for photos //
const options = {
	title: "Select Photos",
	cancelButtonTitle: "Cancel",
	takePhotoButtonTitle: "Camera",
	chooseFromLibraryButtonTitle: "Gallery",
	quality: 0.3
	//noData: true,
};

const [imgLoading, setImgLoading] = useState(false);

const selectPhoto = () => {
	setImgLoading(true);
	ImagePicker.showImagePicker(options, response => {
	if (response.didCancel) {
		//console.log('User cancelled image picker');
	} else if (response.error) {
		//console.log('ImagePicker Error: ', response.error);
		Alert.alert("Error Reading Image", response.error);
	} else {
		let fileName = "";
		if (response.fileName) {
			fileName = response.fileName;
		} else {
			let lastSlashIndex = response.uri.lastIndexOf("/");
			fileName = "IMG_" + response.uri.substr(lastSlashIndex + 1);
		}

			let newPhotos = [...photos, { type: "uri", uri: response.uri, imageid: 0, fileName: fileName, data: response.data } ];

		if (newPhotos.length == 1) {
  				setFeatPhotoCurrIndex({
    					featuredImageIndex: featPhotoCurrIndex.featuredImageIndex,
    					photoCurrentIndex: 0
  				});
			}
			setPhotos(newPhotos);
	}
	setImgLoading(false);
	});
};

const delPhoto = index => {
	if (index != -1) {
		let newPhotos = photos;
		// if image is from server, save it in deletedPhotos array to delete it later from server
		if (newPhotos[index].type == "url") {
			setDeletedPhotos([...deletedPhotos, newPhotos[index]]);
		}
		// delete current photo
		newPhotos.splice(index, 1);

		// update featuredImageIndex
		let featuredImgIndx = featPhotoCurrIndex.featuredImageIndex;
	 	if (index == featuredImgIndx) {
				featuredImgIndx = -1;
		} else if (index < featuredImgIndx) {
				featuredImgIndx = featuredImgIndx - 1;
		}

		// update photoCurrentIndex
		let photoCurrIndx = featPhotoCurrIndex.photoCurrentIndex;
		if (index == photos.length) {
				photoCurrIndx = index - 1;
		}

		if (photoCurrIndx == -1) {
				featuredImgIndx = -1;
		}

		// refresh view
		setFeatPhotoCurrIndex({
				featuredImageIndex: featuredImgIndx,
				photoCurrentIndex: photoCurrIndx
		});

		// set photos array to new array
		setPhotos(newPhotos);
	}
};

const featuredImageChanged = () => {
	if ( featPhotoCurrIndex.featuredImageIndex == featPhotoCurrIndex.photoCurrentIndex ) {
		setFeatPhotoCurrIndex({
			featuredImageIndex: -1,
			photoCurrentIndex: featPhotoCurrIndex.photoCurrentIndex
		});
	} else {
		setFeatPhotoCurrIndex({
			featuredImageIndex: featPhotoCurrIndex.photoCurrentIndex,
			photoCurrentIndex: featPhotoCurrIndex.photoCurrentIndex
		});
	}
};

const renderPagination = (index, total, context) => {
	return (

		<Text style={{ color: "white" }}>

			{index + 1}/{total}

	);
};

onPhotoIndexChange = (index) => {
	setFeatPhotoCurrIndex({
		featuredImageIndex: featPhotoCurrIndex.featuredImageIndex,
		photoCurrentIndex: index
	});
}

return (
	<ScrollView keyboardShouldPersistTaps="always">
		<View style={{ ...styles.container }}>

			<View
				style={{...styles.imagesView, flex: 1, flexDirection: "column", justifyContent: "space-between"}}
			>

      				{photos.length != 0 ? (
        					<View style={{ flex: 1 }}>
          						{imgLoading ? (
            							<ActivityIndicator style={{ flex: 1 }} size="large" />
          						) : (
            							<Swiper
              							key={photos.length}
              							containerStyle={{ flex: 1 }}
              							index={featPhotoCurrIndex.photoCurrentIndex}
              							renderPagination={renderPagination}
              							loop={false}
              							onIndexChanged={ index => onPhotoIndexChange(index) }
            							>
              							{photos.map((photo, i) => {
                								return (
                  									<View
                    										key={i}
                    										style={{flex:1}}
                    										title={<Text numberOfLines={1} />}
                  									>

                    									   <Image
                      									resizeMode="cover"
                      									key={i}
                      									style={{ width: width - 52, height: 290 }}
                      									source={{ uri: photo.uri }}
                    									   />
                  									</View>
                								);
              							})}

            							</Swiper>
          						)}
        					</View>
      				)}

      				<CheckBox
        					title="Featured Image"
        					style={{ heigh: 100 }}
        					checked={ featPhotoCurrIndex.featuredImageIndex == featPhotoCurrIndex.photoCurrentIndex && featPhotoCurrIndex.photoCurrentIndex != -1 ? true : false }
        					onPress={() => {
          						featuredImageChanged();
        					}}
      				/>
    				</View>

    				<View style={styles.photoButtonView} flexDirection={"row"}>
      				<View style={{ flex: 0.49 }}>
        					<Button
          						buttonStyle={{ ...styles.photoButton, backgroundColor: "blue" }}
          						title="Add Photo"
          						onPress={() => {
            							selectPhoto();
          						}}
        				/>

      				</View>

      				<View style={{ flex: 0.49 }}>
        					<Button
          						buttonStyle={{ ...styles.photoButton, backgroundColor: "red" }}
          						title="Del Photo"
          						disabled={photos.length != 0 ? false : true}
          						onPress={() => {
            							Alert.alert( "Delete Selected Photo", "Are you sure you want to delete this photo",
              							[ {
                  								text: "OK",
                  								onPress: () => {
                    									delPhoto(featPhotoCurrIndex.photoCurrentIndex);
                  								}
                							},
                							{ text: "Cancel", onPress: () => null } ],
              							{ Cancelable: false }
            							);
          						}}
        					/>
      				</View>
    				</View>

		</View>
	</ScrollView>
);

}

const styles = StyleSheet.create({

container: {
	paddingLeft: 16,
	paddingRight: 16
},

imagesView: {
	width: width - 40,
	height: 360,
	marginTop: 5,
	marginBottom: 5,
	padding:5,
	borderColor: "gray",
	borderWidth: 1,
	justifyContent: "center",
	backgroundColor: "transparent"
},

photoButtonView: {
	justifyContent: "space-between",
	alignItems: "center",
	marginTop: 5,
	marginBottom: 5,
	borderRadius: 5
},

photoButton: {
	borderColor: "gray",
	borderWidth: 1,
	borderRadius: 5,
	padding: 10
},

paginationStyle: {
	position: "absolute",
	bottom: 10,
	right: 10
},

paginationText: {
	color: "white",
	fontSize: 20
}

});

Steps to reproduce
  1. Load above code on a new project
  2. Build and run on iOS device or simulator
  3. Add some images to the swiper, then try to swipe

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by reproducing the supplied code in a new project on iOS, using the example-style setup and the onIndexChanged callback. Compare swiping with and without that callback, then inspect the Swiper behavior involved in the supplied index and image-array state. Done means repeated swipes no longer accumulate an image offset while the current index still updates and deletion remains possible.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, react-native
Domain
mobile
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.