4.1 스타일링
- 리액트 네이티브에서는 JS를 이용해 스타일링함.
- 컴포넌트에는 style 속성이 있고, 이 속성에 인라인 스타일을 적용하는 방법과 스타일시트(StyleSheet)에 정의된 스타일을 사용하는 방법이 있음.
인라인 스타일링
: HTML의 인라인 스타일링처럼 컴포넌트에 직접 스타일을 입력하는 방식
- HTML 인라인 스타일링과 달리 문자열이 아닌 객체 형태로 전달해야 함.
<Text
style={{
padding: 10,
fontSize: 26,
fontWeight: '600',
color: 'black',
}}
>
Inline Styling - Text
</Text>
- 비슷한 역할을 하는 컴포넌트에 동일한 코드가 반복될 수 있고, 어떤 이유로 해당 스타일이 적용되었는지 코드만으로 명확하게 이해하기 어려움.
클래스 스타일링
: 스타일시트에 정의된 스타일을 사용하는 방식
const App = () => {
return (
<View>
<Text style={styles.text}>Inline Styling - Text</Text>
</View>
);
};
const styles = StyleSheet.create({
text: {
padding: 10,
fontsize: 26,
fontWeight: '600',
color: 'black',
},
});
- 코드가 깔끔해지고, 어떤 이유로 사용하는 스타일인지 확인하기 편함.
- 스타일링 변경을 하기 용이함.
여러 개의 스타일 적용
1. 스타일시트 여러 개 사용 -> 배열로 적용
<View>
<Text style={styles.text}>Inline Styling - Text</Text>
<Text style={[styles.text, styles.error]}>Inline Styling - Error</Text>
</View>
- 주의 : 뒤에 오는 스타일이 앞에 있는 스타일을 덮어씀.
2. 인라인 스타일 + 클래스 스타일
- 인라인 스타일 > 스타일 객체 순으로 우선순위가 낮아짐.
- 스타일 객체 배열 안에서는 순서가 뒷쪽일 수록 우선순위가 높아짐.
<View>
<Text style={[styles.text, { color: "red" }]}>Inline Styling - Error</Text>
</View>
외부 스타일 이용하기
- styles.js 파일에 StyleSheet들을 정의해두고 필요한 곳에 호출해서 사용.
// src/styles.js
import { StyleSheet } from 'react-native';
export const viewStyles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
export const textStyles = StyleSheet.create({
text: {
padding: 10,
fontSize: 26,
color: 'black',
},
error: {
color: 'red',
},
});
// src/App.js
import React from 'react';
import { View, Text } from 'react-native';
import { viewStyles, textStyles } from './styles';
const App = () => {
return (
<View style={viewStyles.container}>
<Text style={[textStyles.text, { color: 'green' }]}>
Text
</Text>
<Text style={[textStyles.text, textStyles.error]}>
Error Text
</Text>
</View>
);
};
export default App;
4.2 리액트 네이티브 스타일
flex와 범위
// src/App.js
const App = () => {
return (
<View style={viewStyles.container}>
<Header />
<Contents />
<Footer />
</View>
);
};
// src/components/Layout.js
export const Header = () => {
return (
<View style={[styles.container, styles.header]}>
<Text style={styles.text}>Header</Text>
</View>
);
};
export const Contents = () => {
return (
<View style={[styles.container, styles.contents]}>
<Text style={styles.text}>Contents</Text>
</View>
);
};
export const Footer = () => {
return (
<View style={[styles.container, styles.footer]}>
<Text style={styles.text}>Footer</Text>
</View>
);
};
const styles = StyleSheet.create({
container: {
width: '100%',
height: 80,
alignItems: 'center',
justifyContent: 'center',
},
header: { ... },
contents: {
height: 640,
...
},
footer: { ... },
text: { ... },
});
- height를 픽셀로 설정해서 기기에 따라 화면에 보이는게 다름.
-> flex를 통해 비율로 설정
- flex = 0 : 설정된 width / height 에 따라 결정
- flex > 0 : flex 값에 비례하여 크기 조정됨.
- header : contents : footer 비율을 1:2:1로 설정하고 싶으면?
// src/components/Layout.js
...
const styles = StyleSheet.create({
container: { ... },
header: {
flex: 1,
...
},
contents: {
flex: 2,
...
},
footer: {
flex: 1
...
},
text: { ... },
});
- 원래 의도한대로 header = 80px, footer = 80px로 하려면?
// src/components/Layout.js
...
const styles = StyleSheet.create({
container: {
height: 80,
...
},
header: { ... },
contents: {
flex: 1,
...
},
footer: { ... },
text: { ... },
});
정렬
flexDirection
- column : 세로 방향 정렬(default)
- column-reverse : 세로 방향 역순 정렬
- row : 가로 방향 정렬
- row-reverse : 가로 방향 역순 정렬
- 주의 : 본인이 아니라 자식 컴포넌트가 쌓이는 방향임.
justifyContent
: flexDirection과 동일한 방향
- flex-start : 시작점에서부터 정렬(default)
- flex-end : 끝에서부터 정렬
- center : 가운데 정렬
- space-between : 컴포넌트 사이의 공간을 동일하게 만들어서 정렬
- space-around : 컴포넌트 각각의 주변 공간을 동일하게 만들어서 정렬
- space-evenly : 컴포넌트 사이와 양 끝에 동일한 공간을 만들어서 정렬
alignItems
: flexDirection과 수직 방향
- flex-start, flex-end, center : justifyContent와 동일
- stretch : alignItems 의 방향으로 컴포넌트 확장
- baseline : 컴포넌트 내부의 텍스트(text) 베이스라인(baseline)을 기준으로 정렬
그림자
* 플랫폼마다 다르게 적용되는 스타일 속성
iOS 기준
- shadowColor : 그림자 색 설정
- shadowOffset : width와 height값을 지정하여 그림자 거리 설정
- shadowOpacity : 그림자의 불투명도 설정
- shadowRadius : 그림자의 흐림 반경 설정
안드로이드 기준
- elevation : 값이 클수록 그림자가 더 진하고 멀리 떨어진 것처럼 보임. (0 이상의 정수)
- 각 플랫폼마다 적용 여부가 다른 속성은 Platform 모듈을 이용해 플랫폼마다 별도로 설정하기
const styles = StyleSheet.create({
shadow: {
...
Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 10, height: 10, },
shadowOpacity: 0.5,
shadowRadius: 10,
},
android: { elevation: 20, },
}),
}
});
- Platform을 사용하지 않고 작성해도 각 속성들이 적용되는 플랫폼에서만 동작하지만, 코드의 역할을 명확히 알기 위해 사용하는 것을 추천
4.3 styled-component
- JS 스타일 객체 사용이 리액트와 달라 불편한 경우 이점으로 작용할 수 있음.
- npm install styled-components 로 컴포넌트 설치
- 기본 형태 : styled.[컴포넌트 이름]` ~ `;
- 이러한 문법 형태를 태그드 템플릿 리터럴(Tagged Template Literals)이라고 함.
사용 방법
import styeld, { css } from 'styled-components/native';
const whiteText = css`
color: #fff;
font-size: 14px;
`;
const MyBoldTextComponent = styled.Text`
${whiteText}
font-weight: 600;
`;
- whiteText처럼 css를 이용하여 재사용 가능한 코드를 분리해서 관리할 수 있음.
const whiteText = styled.Text`
color: #fff;
font-size: 14px;
`;
const MyBoldTextComponent = styled(whiteText)`
font-weight: 600;
`;
- 완성된 컴포넌트를 상속받아 이용할 수도 있음.
- 이때는 styled` ` 이 아니라 styled( )로 감싸야 함.
paddingVertical, marginHorizontal
paddingVertical : paddingTop & paddingBottom을 모두 설정
paddingHorizontal : paddingLeft & paddingRight를 모두 설정
margin의 경우도 동일한 방식으로 동작
props 사용하기
- 컴포넌트에 전달되는 props 값에 따라 스타일을 바꾸고 싶으면?
const Button = props => {
return (
<Pressable
style={{ backgroundColor: props.title === 'Hanbit' ? 'red' : 'blue' }}
>
<Text>{props.title}</Text>
</Pressable>
);
};
- styled-components에서는 ` ` 안에 props에 접근할 수 있음.
const ButtonContainer = styled.Pressable`
background-color: ${props =>
props.title === 'Hanbit' ? 'red' : 'blue'};
...
`;
const Button = props => {
return <ButtonContainer title={props.title} />;
};
attrs 사용하기
: 스타일을 정의하는 곳에서 컴포넌트의 속성을 설정할 수 있음.
const StyledInput = styled.TextInput.attr(props => ({
placeholder: 'Enter a text.',
placeholderTextColor: props.borderColor,
}))`
border-color: ${props => props.borederColor};
...
`;
const Input = props => {
return <StyledInput borderColor={props.borderColor} />;
};
- 항상 attrs로 메인 코드 양을 줄이는 것이 좋은 것은 아님. 컴포넌트가 어떻게 사용되는가를 표현하기 위해 컴포넌트에 직접 속성을 전달할 수도 있음.
ThemeProvider
: Context API를 활용해 애플리케이션 전체에서 styled-components를 이용할 때 미리 정의한 값들을 사용할 수 있도록 props로 전달함.
* Context API에 대한 내용은 7장 참고
// src/theme.js
export const theme = {
purple: '#9b59b6',
blue: '#3498db'
};
// src/components/Button.js
const ButtonContainer = styled.Pressable`
background-color: ${props =>
props.title === 'Hanbit' ? props.theme.blue : props.theme.purple};
...
`;
// src/App.js
const App = () => {
return (
<ThemeProvider theme={theme}>
<ButtonContainer title='Hanbit' />
</ThemeProvider>
);
};
- 두 개의 색을 정의해두고 사용자의 선택에 따라 theme에 알맞은 값을 설정하는 것만으로도 애플리케이션의 색 테마를 쉽게 바꿀 수 있음. -> 예시 : light/dark 테마
// src/theme.js
export const lightTheme = {
background: '#fff',
text: '#fff',
purple: '#9b59b6',
blue: '#3498db',
};
export const darkTheme = {
background: '#34495e',
text: '#34495e',
purple: '#9b59b6',
blue: '#3498db',
};
// src/App.js
const Container = styled.View`
background-color: ${props => props.theme.background};
...
`;
const App = () => {
const [isDark, setIsDark] = useState(false);
const _toggleSwitch = () => setIsDark(!isDark);
return (
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<Switch value={isDark} onValueChange={_toggleSwithch} />
</ThemeProvider>
);
};
참고 사항 : StyleSheet VS styled-components
StyleSheet은 props를 사용할 수 없어 정적인 스타일 정의에 적합하다.
동적인 테마 값을 사용하려면 styled-components를 사용하거나 인라인 스타일링을 사용하는 것이 적합하다.
본문에서 설명하는 내용과 사용한 이미지는 책 '처음 배우는 리액트 네이티브'를 참고하였습니다.
'처음 배우는 리액트 네이티브' 카테고리의 다른 글
5장 할 일 관리 애플리케이션 (0) | 2025.01.22 |
---|---|
추가 : React-Native styled-components 설치 오류 해결 방법 (0) | 2025.01.19 |
추가 : React와 React Native의 차이 (1) | 2025.01.16 |
3장 컴포넌트 (2) | 2025.01.16 |
2장 리액트 네이티브 시작하기 (1) | 2025.01.15 |