처음 배우는 리액트 네이티브

4장 스타일링

youbing 2025. 1. 16. 21:51

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 : widthheight값을 지정하여 그림자 거리 설정
  • 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
StyleSheetprops를 사용할 수 없어 정적인 스타일 정의에 적합하다.
동적인 테마 값을 사용하려면 styled-components를 사용하거나 인라인 스타일링을 사용하는 것이 적합하다.

 

 

 

본문에서 설명하는 내용과 사용한 이미지는 책 '처음 배우는 리액트 네이티브'를 참고하였습니다.