1. Device ๋ด์ฅ ๊ฐค๋ฌ๋ฆฌ ์ ์ : expo์ imagePicker๋ผ๋ ๋ก์ง์ด์ฉ
(1) ๋ก์ง
(2) ์ฝ๋๋ฆฌ๋ทฐ
๋ด๋ถ ์ฝ๋๋ค์ธ๋ฐ async ํจ์, await ๋ฑ pickImage๋ฅผ ๊ตฌํํ๋ ๋ด๋ถ ๋ก์ง๋ค ์ค ๋ชจ๋ฅด๋ keyWord๋ค์ด ๋ง๋ค.
ํด๋น ๋ด์ฉ๋ค์ ์๋ ค๋ฉด promise ๋ผ๋ ํค์๋ ๋ถํฐ ๊ณต๋ถํด์ผ ํ๋ค. ์ด๋ ์๊ฐ์ด ๋ง์ด ๊ฑธ๋ฆฌ๋ฏ๋ก, ๋จผ์ ์ด๋ฒ ๊ฐ์ ์ ๋ด์ฉ์ ๋น ๋ฅด๊ฒ ์ ๋ฆฌํ ํ ๋์์์ ๊ณต๋ถํ๋๋ก ํ๊ฒ ๋ค.
(3) ์๋กญ๊ฒ ์๊ฒ ๋ ๊ฒ - image Picker ๋ก์ง ๋ถํด๋ฅผ ํตํ์ฌ
https://docs.expo.dev/versions/latest/sdk/imagepicker/
2. imagePicker๊ฐ ํ๋์ ์ฌ์ง ๋ฟ๋ง ์๋๋ผ ์ฌ๋ฌ ๊ฐ์ ์ฌ์ง์ ๊ฐ์ง๊ณ ์์ ์ ์๋๋ก ์ปค์คํฐ๋ง์ด์ง
+ imagePicker๊ฐ ๋ฐ์ ์ฌ๋ฌ ์ฌ์ง๋ค์ ํ๋ฉด์ ๋์ฐ๊ธฐ (flatList ์ด์ฉ)
(1) ๋ก์ง
(2) ์ฝ๋๋ฆฌ๋ทฐ
setImage์์ ๊ธฐ์กด image ๋ฐฐ์ด์ ์์๋ค์ ๋ฃ๊ธฐ ์ํด ์ ๊ฐ ์ฐ์ฐ์ ์ฌ์ฉ, ๊ทธ ํ result (ํ์ฌ ์ฐ์ ๊ฑฐ ) ๋ฃ์.
(3) ์๋กญ๊ฒ ์๊ฒ ๋ ๊ฒ
์์
3. ํ ์ค์ ํ๋ฉด 3๊ฐ ๋จ๋๋ก ์ปค์คํฐ๋ง์ด์ง
(1) ๋ก์ง
(2) ์ฝ๋๋ฆฌ๋ทฐ
(3) ์๋กญ๊ฒ ์๊ฒ ๋ ๊ฒ
Dimensions๋ ์๋์ฐ ์ฐฝ์ด๋ ์คํฌ๋ฆฐ์ ํฌ๊ธฐ ๋์ด๋ฅผ ์์๋ด๋ API ์ด๋ค.
๊ฐ์ ๋ฐฉ์์ผ๋ก height๋ ์ป์ ์ ์๋ค.
const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
const ScreenWidth = Dimensions.get('screen').width;
const ScreenHeight = Dimensions.get('screen').height;
4. ์ญ์ ๋ก์ง
(1) ๋ก์ง
a. ๋จผ์ ์ปค์คํ ํ useGallery ๋ด์ ์ํ๋ณ์ image๋ฅผ String ๋ฐฐ์ด์์ ๊ฐ์ฒด๋ค์ ๋ฐฐ์ด๋ก ๋ฐ๊พธ์ด์ค์ผ ํ๋ค.
์ญ์ ๋ฅผ ์ํด์ ํ์ํ ์ฌ์ง๋ค๋ง์ ๊ณ ์ ๋ฒํธ id๋ฅผ ์ค์ ํด์ค์ผ ํด์ ๊ตฌ์กฐ์ฒด ํํ๋ก ์์๋ฅผ ๋ฐ๊พธ์ด ์ฃผ์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
why? ์ id๊ฐ ๋ฐ๋ก ํ์ํ๊ฐ? uri ๊ฐ์ผ๋ก ํน์ ํด์ ์ฌ์ง์ ์ง์ฐ๋ฉด ๋์ง ์๋?
๊ฐค๋ฌ๋ฆฌ์ ๋๊ฐ์ ์ฌ์ง์ 2๊ฐ ์ฌ๋ฆฌ๋ ๊ฒฝ์ฐ๋ฅผ ์๊ฐํด๋ณด์. ๋ง์ฝ uri๋ฅผ ๊ธฐ์ค์ผ๋ก ์ฌ์ง ์ญ์ ๋ก์ง์ด ๊ฐ๋ ๋๋ค๋ฉด ๋ ์ค ํ๋์ ์ฌ์ง์ ์ญ์ ํด๋ ๋ ๋ค ์ญ์ ๋ ๊ฒ์ด๋ค. ๋์ uri๊ฐ ๊ฐ๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋์ id๋ผ๋ ๋ณ์๋ฅผ ๊ฐ์ฒด ๋ด๋ถ์ ์๋ก ๋ง๋ค์ด์ค๋ค.
Lastid๋ฅผ ๋ง๋ค์ด ๋ฐฐ์ด ๋ง์ง๋ง ์์์ธ ๊ฐ์ฒด์ id๋ฅผ ์์๋ธ๋ค.
Lastid+1 ํด์ ์๋ก์ด ์ฌ์ง์ด ๋ฐฐ์ด์ ๋ค์ด์ฌ ๋๋ง๋ค ๊ต๋ถํ๋ค.
๊ทธ๋ฌ๋ฉด ์ฌ์ง๋ณ๋ก ๊ณ ์ ํ id๊ฐ ์๊ธด๋ค.
(2) ์ฝ๋๋ฆฌ๋ทฐ
export const useGallery = () => {
const [images, setImages] = useState([]);
const pickImage = async () => {
// No permissions request is necessary for launching the image library
let result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.All,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
console.log(result);
// ๋ง์ฝ์ ์ทจ์๋ฅผ ๋๋ฅธ๊ฒ ์๋๋ผ๋ฉด
if (!result.canceled) {
const lastId = images.length === 0 ? 0 : images[images.length - 1].id;
//id๋ 1๋ถํฐ ์์ํ๊ณ ๋ฐฐ์ด์ index๋ 0๋ถํฐ ์์ํ๋ค. ํท๊ฐ๋ฆฌ์ง ๋ง์.
// ์ฌ๊ธฐ์๋ images[์ต๋๊ธธ์ด-1]์ id๋ฅผ ๊ตฌํด ์ฌ์ฉํ๋ค. index๋ ๋ฐ๋ก ์ฌ์ฉํ์ง ์๋๋ค.
const newImage = {
id: lastId + 1,
uri: result.assets[0].uri,
};
setImages([...images, newImage]); // result์ assets์ ์ฒซ๋ฒ์งธ ์์๊ฐ์ uri๋ฅผ image ๊ฐ์ผ๋ก ์ค์ ํด๋ฌ๋ผ.
}
};
const deleteImage = (imageId) => {
Alert.alert("์ด๋ฏธ์ง๋ฅผ ์ญ์ ํ์๊ฒ ์ต๋๊น?", "", [
{
style: "cancel",
text: "์๋์!",
},
{
text: "๋ค!",
onPress: () => {
const newImages = images.filter((image) => image.id !== imageId);
setImages(newImages);
},
},
]);
};
return {
images,
pickImage,
deleteImage,
};
};
const onLongPressImage = (imageId) => {
deleteImage(imageId);
};
const renderItem = ({ item: { id, uri }, idex }) => {
return (
<TouchableOpacity onLongPress={() => onLongPressImage(id)}>
<Image
source={{ uri: uri }}
style={{ width: columnSize, height: columnSize }}
/>
</TouchableOpacity>
);
};
(3) ์๋กญ๊ฒ ์๊ฒ ๋ ๊ฒ
์์.
5. + ๋ฒํผ์ ๋ฐ๋ก ๋ง๋ค์ด์ ํด๋น ๋ฒํผ์ ๋๋ฅผ ์ ๋ด์ฅ ๊ฐค๋ฌ๋ฆฌ๋ก ์ ์ ๊ฐ๋ฅํ๋๋ก ๋ง๋ค๊ธฐ
(1) ๋ก์ง
(2) ์ฝ๋๋ฆฌ๋ทฐ
return === -1 ์ผ ๋๋ + ๋ฒํผ ๋ง๋ค๊ณ
๋๋จธ์ง๋ ์๋ ๊ทธ๋๋ก ์ฌ์ง uri ๋ฐ์์ ์ฌ์ง ๊ตฌํ
(3) ์๋กญ๊ฒ ์๊ฒ ๋ ๊ฒ
์์