[React Native] React Navigation - 10. [Drawer] Style 설정

2022. 1. 19. 16:05React Native/Basic

 

 


 


 


10. [Drawer] Style 설정

side drawer의 스타일을 설정하는 방법에 대해 알아보자!

 

Stack Screen을 다룰 때는 각 스크린별로 스타일을 주기 위해서 Stack.Screen 태그 안에 options라는 프로퍼티를 사용했었고 여러 스크린에 공통으로 적용되는 스타일의 경우 Stack.Navigator 태그 안에 ScreenOptions라는 프로퍼티를 사용했다.

 

Drawer Navigator의 경우는 side drawer를 정의된 모든 스크린에서 열 수 있다. 즉, 공통으로 사용되는 부분이기 때문에 스타일도 공통으로 적용될 거고 Drawer.Navigator 태그 안에 스타일을 설정한다.

 

drawerType: 'front' - 뒤에 있는 화면은 고정된 채 side drawer가 화면을 오버레이 해서 덮는다.
drawerType: 'slide' - side drawer가 튀어 나온 만큼 뒤에 있는 화면도 옆으로 밀린다.
drawerType: 'permanent' - 영원한 것. 계속해서 side drawer가 열려서 닫히지 않는다. 화면이 엄청 커서 차라리 side drawer를 열어두는 게 편한 경우에 사용한다.
drawerPosition: 'right' - side drawer를 오른쪽에서 열 수 있다. 그런데 ver.6 에서는 drawer navigator의 서랍 모양 버튼을 눌러서 열 수도 있는데 이 서랍 모양 버튼은 왼쪽에 있다.
drawerStyle: backgroundColor - side drawer의 배경색을 정한다.
drawerStyle: width - side drawer의 너비를 정한다.
drawerContentOptions - 누르면 해당 스크린으로 이동하는 각 스크린 메뉴가 있는데 이렇게 linking 되는 것들을 drawerContent라고 한다. 여기에 스타일을 주는 방법이다.(ver.6 에서는 사라졌다.)
drawerActiveTintColor - 선택된 항목의 글자색을 정한다.
drawerActiveBackgroundColor - 선택된 항목의 배경색을 정한다.

react navigation ver.5 에서는 Drawer.Navigator 태그 안에 그냥 프로퍼티들을 사용할 수 있었지만 ver.6 로 바뀌면서 screenOptions 프로퍼티 안에 지정해줘야 한다. 또한 drawerContentOptions가 사라지면서 screenOptions 안에 지정해주는 것으로 바뀌었다.

 

https://www.inflearn.com/questions/333149

 

DarawContentOptions - 인프런 | 질문 & 답변

안드로이드로 학습하고 있는 학생입니다.   Drawer.Navigator 옵션중에서 drawerContentOption쪽 사항이 현재와 많이 다른거같은데 React Navigation Docs를 보고 해도 잘 되지 않아서 그런데 새로 적용된 방법

www.inflearn.com

 

drawerContent - drawerContent를 커스텀마이징할 수 있는 함수이다. drawerContent를 렌더링하기 위한 react 요소를 반환한다. 여기선 화면전환을 하고 있으니 navigation route 같은 것들을 반환할 것이다. 

 

drawerContent는 default로 4개의 props를 받는다.

1. drawer navigator에 어떤 route들이 있는지 알기 위한 state

2. 화면 이동을 위한 navigation

3. drawer Screen에 옵션을 담기 위한 descriptors

4. drawer가 열렸는지 닫혔는지 판단하기 위한 progress

 

하나하나 알 필요는 없고 default로 props가 주어진다고 하니 drawerContent라는 함수에는 이 props들이 전해져야 겠구나로 생각하면 된다.

 

side drawer는 drawerContent를 통해서 default로 ScrollView 안에 ItemList를 렌더링 한다.

 

CustomDrawerContent = props => {
  return (
    <DrawerContentScrollView {...props}>
      <DrawerItemList {...props} />
      <DrawerItem
        label="Help"
        onPress={() => Linking.openURL('http://www.google.com')}
      />
      <DrawerItem label="Info" onPress={() => alert('Info window')} />
    </DrawerContentScrollView>
  );
};

class 위에 CustomDrawerContent를 정의하고 drawerContent로 사용한다. spread operator를 사용하여 props들을 전달받는다.

Linking.openURL - 웹페이지 이동을 할 수 있다.

Drawer.Navigator 안에 아래 코드를 적으면 CustomDrawerContent를 사용할 수 있다.

drawerContent={props => <CustomDrawerContent {...props} />}>

 

 

side drawer의 content에 그림을 삽입하는 방법을 알아보자.

3가지 방법이 있다.

그림을 삽입하는 거라 stack navigator와 동일하게 options 이용할 거다.

1. Drawer.Navigator 태그 안에 drawerContent 프로퍼티에 호출되는 함수에서 사용하는 방법

2. Drawer.Screen 태그에서 options라는 프로퍼티를 사용하는 방법

해당 방법으로 진행 불가. 

<Drawer.Screen
    name="Home"
    component={DrawerHomeScreen}
    options={{
      drawerIcon: () => {
        <Image
          source={require('./src/assets/pics/home_icon.png')}
          style={{width: 40, height: 40}}
        />;
      },
    }}
/>

위의 코드처럼 작성했으나 동작하지 않았다. 혹시나 이 부분에 대해서 해결 방안을 아신다면 댓글로 남겨주시면 감사합니다 :)

 

3. Drawer.Screen에서 컴포넌트로 불러오는 class에서 사용하는 방법.

해당 방법으로 진행 불가.

user_drawer.js에서 drawerStyle을 추가해서 사용하면 User 컨텐츠에서는 아이콘이 생기지 않는다. 이건 작성한 함수가 호출되지 않아서 그렇다. 클래스가 앱이 렌더링될 때 반영되지 않았기 때문이다. 즉, user_drawer.js에서 export되는 DrawerUserScreen이라는 클래스가 앱이 렌더링 될 때 반영이 되어야 하고, 이게 컴포넌트로 호출이 되는 User 컨텐츠가 터치되거나 이동되어야 한다. 쉽게 말해서 User 컨텐츠로 가면 아이콘이 생긴다는 말이다.

 

 

 

 

 

home_drawer.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {StyleSheet, Text, View, Button} from 'react-native';

class DrawerHomeScreen extends Component {
  render() {
    return (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
        }}>
        <Text>Home Screen</Text>
        <Button
          title="To User Screen"
          onPress={() => {
            this.props.navigation.navigate('User');
          }}
        />
      </View>
    );
  }
}

const styles = StyleSheet.create({});

export default DrawerHomeScreen;

user_drawer.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {StyleSheet, Text, View, Button, Image} from 'react-native';

import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import Logo from './assets/pics/home_icon.png';

class DrawerUserScreen extends Component {
  drawerStyle = () => {
    this.props.navigation.setOptions({
      drawerIcon: () => {
        <Image source={Logo} style={{width: 40, height: 40}} />;
      },
    });
  };
  render() {
    this.drawerStyle();
    return (
      <View
        style={{
          flex: 1,
          alignItems: 'center',
          justifyContent: 'center',
        }}>
        <Text>User Screen</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({});

export default DrawerUserScreen;

App.js

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {Component} from 'react';
import {StyleSheet, Text, View, Image, Button, Linking} from 'react-native';
import {DrawerActions, NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {
  createDrawerNavigator,
  DrawerContentScrollView,
  DrawerItem,
  DrawerItemList,
} from '@react-navigation/drawer';
import HomeScreen from './src/home';
import UserScreen from './src/user';
import LogoTitle from './src/logo';
import DrawerHomeScreen from './src/home_drawer';
import DrawerUserScreen from './src/user_drawer';
import PictogramHome from './src/assets/pics/home_icon.png';
const Stack = createNativeStackNavigator();
const Drawer = createDrawerNavigator();

CustomDrawerContent = props => {
  return (
    <DrawerContentScrollView {...props}>
      <DrawerItemList {...props} />
      <DrawerItem
        label="Help"
        onPress={() => Linking.openURL('http://www.google.com')}
        icon={() => <LogoTitle />}
      />
      <DrawerItem label="Info" onPress={() => alert('Info window')} />
    </DrawerContentScrollView>
  );
};

class App extends Component {
  // logoTitle = () => {
  //   return (
  //     <Image
  //       style={{width: 40, height: 40}}
  //       source={require('./src/assets/pics/home_icon.png')}
  //     />
  //   );
  // };

  render() {
    return (
      <NavigationContainer>
        <Drawer.Navigator
          initialRouteName="Home"
          screenOptions={{
            drawerType: 'front',
            drawerPosition: 'right',
            drawerStyle: {
              backgroundColor: '#c6cbef',
              width: 200,
            },
            drawerActiveTintColor: 'red',
            drawerActiveBackgroundColor: 'skyblue',
          }}
          drawerContent={props => <CustomDrawerContent {...props} />}>
          <Drawer.Screen
            name="Home"
            component={DrawerHomeScreen}
            options={{
              drawerIcon: () => {
                <Image
                  source={PictogramHome}
                  style={{width: 40, height: 40}}
                />;
              },
            }}
          />
          <Drawer.Screen name="User" component={DrawerUserScreen} />
        </Drawer.Navigator>
      </NavigationContainer>
      // <NavigationContainer>
      //   <Stack.Navigator
      //     initialRouteName="Home"
      //     screenOptions={{
      //       headerStyle: {
      //         backgroundColor: '#a4511e',
      //       },
      //       headerTintColor: '#ffffff',
      //       headerTitleStyle: {
      //         fontWeight: 'bold',
      //         color: '#f3d612',
      //       },
      //     }}>
      //     <Stack.Screen
      //       name="Home"
      //       component={HomeScreen}
      //       options={{
      //         title: 'Home Screen',
      //         headerTitle: () => <this.logoTitle />,
      //         headerRight: () => (
      //           <Button
      //             title="info"
      //             onPress={() => alert('I am a button!!')}
      //             color="orange"
      //           />
      //         ),
      //       }}
      //     />
      //     <Stack.Screen
      //       name="User"
      //       component={UserScreen}
      //       initialParams={{
      //         userIdx: 50,
      //         userName: 'Gildong',
      //         userLastName: 'Go',
      //       }}
      //       options={{
      //         title: 'User Screen',
      //         headerStyle: {
      //           backgroundColor: 'pink',
      //         },
      //         headerTintColor: 'red',
      //         headerTitleStyle: {
      //           fontWeight: 'bold',
      //           color: 'purple',
      //         },
      //       }}
      //     />
      //   </Stack.Navigator>
      // </NavigationContainer>
    );
  }
}

const styles = StyleSheet.create({});

export default App;

 

react-navigation이 v6으로 업데이트 되고 나서인지 위의 2, 3번으로 시도했을 때 아이콘이 생기지 않는다.

 

혹시 2,3번 방법으로 이미지를 넣는 방법을 아시는 분은 댓글로 알려주시면 감사합니다 :)

 

 


참고 자료

https://www.inflearn.com/course/%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%84%A4%EC%9D%B4%ED%8B%B0%EB%B8%8C-%EA%B8%B0%EC%B4%88/dashboard

 

iOS/Android 앱 개발을 위한 실전 React Native - Basic - 인프런 | 강의

Mobile App Front-End 개발을 위한 React Native의 기초 지식 습득을 목표로 하고 있습니다. 진입장벽이 낮은 언어/API의 활용을 통해 비전문가도 쉽게 Native Mobile App을 개발할 수 있도록 제작된 강의입니다

www.inflearn.com