screens/RootStack.js
import React from 'react';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import MainTab from './MainTab';
import WriteScreen from './WriteScreen';
const Stack = createNativeStackNavigator();
function RootStack() {
return (
<Stack.Navigator>
<Stack.Screen
name={'MainTab'}
component={MainTab}
options={{headerShown: false}}
/>
<Stack.Screen
name={'Write'}
component={WriteScreen}
options={{headerShown: false}}
/>
</Stack.Navigator>
);
}
export default RootStack;
일단 WriteScreen의 기본적으로 보이는 헤더를 숨겼습니다.
다음으론 WriteScreen에서 사용할 헤더를 직접 만들겠습니다.
components/WriteHeader
import React from 'react';
import {View, StyleSheet, Pressable} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {useNavigation} from '@react-navigation/native';
function WriteHeader() {
const navigation = useNavigation();
const onGoBack = () => {
navigation.goBack();
};
return (
<View style={styles.block}>
<View style={styles.iconButtonWrapper}>
<Pressable
style={styles.iconButton}
onPress={onGoBack}
android_ripple={{color: '#ededed'}}>
<Icon name={'arrow-back'} size={24} color={'#424242'} />
</Pressable>
</View>
<View style={styles.buttons}>
<View style={[styles.iconButtonWrapper, styles.marginRight]}>
<Pressable
style={styles.iconButton}
android_ripple={{color: '#ededed'}}>
<Icon name={'delete-forever'} size={24} color={'#ef5350'} />
</Pressable>
</View>
<View style={styles.iconButtonWrapper}>
<Pressable
style={styles.iconButton}
android_ripple={{color: '#ededed'}}>
<Icon name={'check'} size={24} color={'#009688'} />
</Pressable>
</View>
</View>
</View>
);
}
const styles = StyleSheet.create({
block: {
height: 48,
paddingHorizontal: 8,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
iconButtonWrapper: {
width: 32,
height: 32,
borderRadius: 16,
overflow: 'hidden',
},
iconButton: {
alignItems: 'center',
justifyContent: 'center',
width: 32,
height: 32,
borderRadius: 16,
},
buttons: {
flexDirection: 'row',
alignItems: 'center',
},
marginRight: {
marginRight: 8,
},
});
export default WriteHeader;
styles.block에서 flex-direction : 'row' 로 설정하여 컴포넌트들을 가로방향으로 바꿨습니다.
여기서 justifyContent : 'space-between' 이라는 스타일을 주었는데요
이는 요소 사이마다 일정한 간격이 주어지는 스타일로
Flex를 공부하셨다면 충분히 알 수 있는 스타일 입니다.
지금 컴포넌트를 보면 비슷한 코드가 여러번 작성되는 것을 확인할 수 있습니다.
이를 컴포넌트로 만들어서 재사용하는 리팩토링을 해보도록 하겠습니다.
components/TransparentCircleButton.js
import React from 'react';
import {View, StyleSheet, Platform, Pressable} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
function TransparentCircleButton({name, color, hasMarginRight, onPress}) {
return (
<View
style={[styles.iconButtonWrapper, hasMarginRight && styles.marginRight]}>
<Pressable
style={({pressed}) => [
styles.iconButton,
Platform.OS === 'ios' &&
pressed && {
backgroundColor: '#efefef',
},
]}
onPress={onPress}
android_ripple={{color: '#ededed'}}>
<Icon name={name} size={24} color={color} />
</Pressable>
</View>
);
}
const styles = StyleSheet.create({
iconButtonWrapper: {
width: 32,
height: 32,
borderRadius: 16,
overflow: 'hidden',
},
iconButton: {
alignItems: 'center',
justifyContent: 'center',
width: 32,
height: 32,
borderRadius: 16,
},
marginRight: {
marginRight: 8,
},
});
export default TransparentCircleButton;
이 컴포넌트는 4개의 Props를 받아옵니다.
이제 WriteHeader.js를 수정해주겠습니다
conponents/WriteHeader.js
import React from 'react';
import {View, StyleSheet, Pressable} from 'react-native';
import Icon from 'react-native-vector-icons/MaterialIcons';
import {useNavigation} from '@react-navigation/native';
import TransparentCircleButton from './TransparentCircleButton';
function WriteHeader() {
const navigation = useNavigation();
const onGoBack = () => {
navigation.goBack();
};
return (
<View style={styles.block}>
<View style={styles.iconButtonWrapper}>
<TransparentCircleButton
onPress={onGoBack}
name="arrow-back"
color={'#424242'}
/>
</View>
<View style={styles.buttons}>
<TransparentCircleButton
name="delete-forever"
color={'#ef5350'}
hasMarginRight
/>
<TransparentCircleButton name={'check'} color={'#009688'} />
</View>
</View>
);
}
const styles = StyleSheet.create({
block: {
height: 48,
paddingHorizontal: 8,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
},
buttons: {
flexDirection: 'row',
alignItems: 'center',
},
});
export default WriteHeader;
screens/WriteScreen.js
import React from 'react';
import {View, StyleSheet} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import WriteHeader from '../components/WriteHeader';
function WriteScreen() {
return (
<SafeAreaView style={styles.block}>
<WriteHeader />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
block: {
flex: 1,
backgroundColor: 'white',
},
});
export default WriteScreen;
이렇게 사용까지 해주시면 나타나게 됩니다.
나타나셨나요?
현재 네비게이션의 헤더를 없애고 저희가 직접 만든 헤더를 사용하고 있기 때문에
SafeAreaView를 사용하여 ios의 상태바와 영역과 내용이 겹치지 않게 해주어야합니다.
WriteEditor 만들기
이번에는 글을 쓸 수 있는 컴포넌트를 만들어 볼 것입니다.
components/WriteEditor.js
import React from 'react';
import {View, StyleSheet, TextInput} from 'react-native';
function WriteEditor({title, body, onChangeTitle, onChangeBody}) {
return (
<View style={styles.block}>
<TextInput
placeholder={'제목을 입력하세요'}
style={styles.titleInput}
returnKeyType={'next'}
onChangeText={onChangeTitle}
value={title}
/>
<TextInput
placeholder={'당신의 오늘을 기록해보세요'}
style={styles.bodyInput}
multiline
textAlignVertical="top"
onChangeText={onChangeBody}
value={body}
/>
</View>
);
}
const styles = StyleSheet.create({
block: {
flex: 1,
padding: 16,
},
titleInput: {
paddingVertical: 0,
fontSize: 18,
marginBottom: 16,
color: '#263238',
fontWeight: 'bold',
},
bodyInput: {
flex: 1,
fontSize: 16,
paddingVertical: 0,
color: '#263238',
},
});
export default WriteEditor;
두번째 TextView에 multiline Props에 값이 지정되지 않은 것은 true로 지정됩니다.
이제 여러줄을 작성할 수 있습니다.
이제 이 컴포넌트를 WriteScreen에 보이게 합니다.
screens/WriteScreen.js
import React from 'react';
import {View, StyleSheet} from 'react-native';
import {SafeAreaView} from 'react-native-safe-area-context';
import WriteHeader from '../components/WriteHeader';
import WriteEditor from "../components/WriteEditor";
function WriteScreen() {
return (
<SafeAreaView style={styles.block}>
<WriteHeader />
<WriteEditor />
</SafeAreaView>
);
}
const styles = StyleSheet.create({
block: {
flex: 1,
backgroundColor: 'white',
},
});
export default WriteScreen;
다음과 같이 나타나셨나요?
'코딩생활 > ReactNative' 카테고리의 다른 글
[React Native] 3-6 글 목록 보여주기 (0) | 2023.03.16 |
---|---|
[React Native] 3-6 LogContext로 배열 상태 관리하기 (0) | 2023.03.15 |
[React Native] 3-4 새 글 작성하기 (0) | 2023.03.14 |
[React Native] 3-3 useContext Hooks 함수 (0) | 2023.03.13 |
[React Native] 3-2 Context API (0) | 2023.03.13 |
댓글