
alignItems: 'center'속성을 부모 컨테이너에 추가하면 된다.
만약 부모 컨테이너가 Flexbox 레이아웃을 사용하고 있다면,alignItems: 'center'와ustifyContent: 'center'를 사용하여 자식을 가운데에 배치할 수 있다.
버튼 하나를 고정시켜야 되는데 옆에 있는 이미지의 배치에 따라서 버튼 위치가 달라지는 문제가 발생했다. 🤔
❇️ 해결 방법
ScrollView 내에서 next 버튼의 위치를 고정시키는 대신,
View 요소를 사용하여 스크롤 가능한 영역과 고정된 영역을 나눴다. 이렇게 하면 next 버튼이 항상 고정되게 할 수 있다.
View를 추가하여 ScrollView와 고정된 하단 버튼을 분리했다.outerContainer: {
flex: 1,
backgroundColor: 'white',
},수정 전 코드
import React, {useState, useEffect} from 'react';
import {
View,
Text,
StyleSheet,
Image,
TouchableOpacity,
ScrollView,
Modal,
TouchableWithoutFeedback,
Alert,
} from 'react-native';
import {useNavigation, useRoute} from '@react-navigation/native';
import {useSelector, useDispatch} from 'react-redux';
import {assignHashTag} from '../../api/HashTagAssign';
import {HashTagListCheck} from '../../api/HashTagListCheck';
const Filter4 = () => {
const navigation = useNavigation();
const route = useRoute(); // useRoute 훅을 사용하여 경로 정보 가져오기
const {groupedImages} = route.params; // Filter3에서 전달된 데이터(여러 그룹 이미지들)
const [modalVisible, setModalVisible] = useState(false);
const [currentGroupId, setCurrentGroupId] = useState(null);
const [currentGroupImages, setCurrentGroupImages] = useState([]); // 현재 그룹의 모든 이미지 저장
const [selectedTags, setSelectedTags] = useState([]); // 각 그룹의 선택된 해시태그 저장
const hashtagList = useSelector(state => state.HashTagReducer.hashtagList); // 해시태그 목록을 가져옴
const dispatch = useDispatch();
const handleNavigation = () => {
navigation.navigate('Filter5', {
groupedImages,
});
};
// 해시태그 목록 요청
useEffect(() => {
dispatch(HashTagListCheck());
}, [dispatch]);
// 이미지 그룹 클릭할 때 호출 -> 현재 그룹 id, 이미지 저장
const handleGroupPress = groupId => {
setCurrentGroupId(groupId); // 선택한 그룹 ID 저장
setCurrentGroupImages(groupedImages[groupId]); // 현재 그룹의 모든 이미지 저장
setModalVisible(true);
};
// 해시태그를 선택할 때 호출 -> 선택한 해시태그 저장 및 API 호출
const handleSelectTag = async tag => {
const imageUrls = currentGroupImages.map(url => url.split('?')[0]);
try {
const requestBody = {
imageUrls,
hashtagId: tag.id,
};
const data = await assignHashTag(requestBody);
console.log('해시태그 저장 성공:', data);
setModalVisible(false);
} catch (error) {
console.error('해시태그 저장 중 오류 발생:', error);
Alert.alert(
'Error',
해시태그 저장 중 오류가 발생했습니다: ${error.message},
);
}
};
return (
<ScrollView contentContainerStyle={styles.container}>
<View style={styles.header}>
<Image
style={styles.step_3}
source={require('../../assets/icon/step_3.png')}
resizeMode="contain"
/>
<Text style={styles.text}>그룹을 클릭하고 해시태그를 지정하세요!</Text>
</View>
<View style={styles.gridContainer}>
{groupedImages.map((group, index) => (
<React.Fragment key={index}>
{index % 2 === 0 && index !== 0 && (
<View style={styles.separator} />
)}
<View style={styles.imageContainer}>
<TouchableOpacity
style={styles.imageWrapper}
onPress={() => handleGroupPress(index)}>
<Image
source={{uri: group[0]}} // 첫 번째 이미지를 썸네일로 사용
style={styles.image}
/>
<Text style={styles.imageCount}>
{${group.length}장} {/* 이미지 개수*/}
</Text>
</TouchableOpacity>
</View>
</React.Fragment>
))}
</View>
{modalVisible && (
<Modal visible={modalVisible} animationType="slide" transparent={true}>
<TouchableWithoutFeedback onPress={() => setModalVisible(false)}>
<View style={styles.modalBackground}>
<TouchableWithoutFeedback>
<View style={styles.modalContainer}>
<ScrollView contentContainerStyle={styles.hashList}>
{hashtagList.map(item => (
<TouchableOpacity
key={item.id.toString()}
style={[
styles.hashItem,
selectedTags[currentGroupId] === item.text &&
styles.selectedHashItem,
]}
onPress={() => handleSelectTag(item)}>
<Text
style={[
styles.hashText,
selectedTags[currentGroupId] === item.text &&
styles.selectedHashText,
]}>
{#${item.text}}
</Text>
</TouchableOpacity>
))}
</ScrollView>
<View style={styles.modalButtons}>
<TouchableOpacity
onPress={() => setModalVisible(false)}
style={styles.modalButtonContainer1}></TouchableOpacity>
</View>
</View>
</TouchableWithoutFeedback>
</View>
</TouchableWithoutFeedback>
</Modal>
)}
<TouchableOpacity onPress={handleNavigation}>
<Image // <-- 수정 전
style={styles.next}
source={require('../../assets/icon/next2.png')}
resizeMode="contain"
/>
</TouchableOpacity>
</ScrollView>
);
};
...
export default Filter4;
<Image // <-- 수정 전
style={styles.next}
source={require('../../assets/icon/next2.png')}
resizeMode="contain"
/>
버튼 이미지가 ScrollView 안에 있었다.
수정 후 코드
import React, {useState, useEffect} from 'react';
import {
View,
Text,
StyleSheet,
Image,
TouchableOpacity,
ScrollView,
Modal,
TouchableWithoutFeedback,
Alert,
} from 'react-native';
import {useNavigation, useRoute} from '@react-navigation/native';
import {useSelector, useDispatch} from 'react-redux';
import {assignHashTag} from '../../api/HashTagAssign';
import {HashTagListCheck} from '../../api/HashTagListCheck';
const Filter4 = () => {
const navigation = useNavigation();
const route = useRoute(); // useRoute 훅을 사용하여 경로 정보 가져오기
const {groupedImages} = route.params; // Filter3에서 전달된 데이터(여러 그룹 이미지들)
const [modalVisible, setModalVisible] = useState(false);
const [currentGroupId, setCurrentGroupId] = useState(null);
const [currentGroupImages, setCurrentGroupImages] = useState([]); // 현재 그룹의 모든 이미지 저장
const [selectedTags, setSelectedTags] = useState([]); // 각 그룹의 선택된 해시태그 저장
const hashtagList = useSelector(state => state.HashTagReducer.hashtagList); // 해시태그 목록을 가져옴
const dispatch = useDispatch();
const handleNavigation = () => {
navigation.navigate('Filter5', {
groupedImages,
});
};
// 해시태그 목록 요청
useEffect(() => {
dispatch(HashTagListCheck());
}, [dispatch]);
// 이미지 그룹 클릭할 때 호출 -> 현재 그룹 id, 이미지 저장
const handleGroupPress = groupId => {
setCurrentGroupId(groupId); // 선택한 그룹 ID 저장
setCurrentGroupImages(groupedImages[groupId]); // 현재 그룹의 모든 이미지 저장
setModalVisible(true);
};
// 해시태그를 선택할 때 호출 -> 선택한 해시태그 저장 및 API 호출
const handleSelectTag = async tag => {
const imageUrls = currentGroupImages.map(url => url.split('?')[0]);
try {
const requestBody = {
imageUrls,
hashtagId: tag.id,
};
const data = await assignHashTag(requestBody);
console.log('해시태그 저장 성공:', data);
setModalVisible(false);
} catch (error) {
console.error('해시태그 저장 중 오류 발생:', error);
Alert.alert(
'Error',
`해시태그 저장 중 오류가 발생했습니다: ${error.message}`,
);
}
};
return (
<View style={styles.outerContainer}>
<ScrollView contentContainerStyle={styles.container}>
<View style={styles.header}>
<Image
style={styles.step_3}
source={require('../../assets/icon/step_3.png')}
resizeMode="contain"
/>
<Text style={styles.text}>그룹을 클릭하고 해시태그를 지정하세요!</Text>
</View>
<View style={styles.gridContainer}>
{groupedImages.map((group, index) => (
<React.Fragment key={index}>
{index % 2 === 0 && index !== 0 && (
<View style={styles.separator} />
)}
<View style={styles.imageContainer}>
<TouchableOpacity
style={styles.imageWrapper}
onPress={() => handleGroupPress(index)}>
<Image
source={{uri: group[0]}} // 첫 번째 이미지를 썸네일로 사용
style={styles.image}
/>
<Text style={styles.imageCount}>
{`${group.length}장`} {/* 이미지 개수*/}
</Text>
</TouchableOpacity>
</View>
</React.Fragment>
))}
</View>
{modalVisible && (
<Modal visible={modalVisible} animationType="slide" transparent={true}>
<TouchableWithoutFeedback onPress={() => setModalVisible(false)}>
<View style={styles.modalBackground}>
<TouchableWithoutFeedback>
<View style={styles.modalContainer}>
<ScrollView contentContainerStyle={styles.hashList}>
{hashtagList.map(item => (
<TouchableOpacity
key={item.id.toString()}
style={[
styles.hashItem,
selectedTags[currentGroupId] === item.text &&
styles.selectedHashItem,
]}
onPress={() => handleSelectTag(item)}>
<Text
style={[
styles.hashText,
selectedTags[currentGroupId] === item.text &&
styles.selectedHashText,
]}>
{`#${item.text}`}
</Text>
</TouchableOpacity>
))}
</ScrollView>
<View style={styles.modalButtons}>
<TouchableOpacity
onPress={() => setModalVisible(false)}
style={styles.modalButtonContainer1}></TouchableOpacity>
</View>
</View>
</TouchableWithoutFeedback>
</View>
</TouchableWithoutFeedback>
</Modal>
)}
</ScrollView>
// ScrollView 에서 분리시켰다.
<View style={styles.fixedFooter}>
<TouchableOpacity onPress={handleNavigation}>
<Image
style={styles.next}
source={require('../../assets/icon/next2.png')}
resizeMode="contain"
/>
</TouchableOpacity>
</View>
</View>
);
};
버튼 이미지를 ScrollView 에서 분리시키면 된다!