PanResponder API를 통해 사용자의 이벤트(스와이프, 탭, 핀치, 스크롤링 등)에 따라 앱 상태를 조작할 수 있습니다. 

 

요번에는 panresponder를 이용하여 사용자의 드래그 앤 드랍 이벤트를 처리할 수 있는 예제를 만들어 보겠습니다. 

 

panresponder.js 생성

1. 우선 여느 component와 같이 'react-native'에서 Dimensions, PanResponder을 import 합니다. 

 

2. Dimensions를 통해 화면의 너비, 높이 값을 가져옵니다. 
const { width, height } = Dimensions.get('window')

 

3. 사용자의 이벤트를 받기 전 view의 위치를 저장하는 oPosition 객체를 생성하고 화면의 중앙에 위치할 수 있도록 초기 값을 셋팅해줍니다. oPosition 객체는 사용자의 release 이벤트가 발생하면 해당 위치의 값으로 설정 됩니다.

* 이벤트 받을 객체(크기 200)의 왼쪽 윗 부분을 기준 점으로 지정

oPosition: {
        x: (width / 2) - 100,
        y: (height / 2) - 100,
      }

4. 사용자의 move 이벤트가 발생 시 현재 위치를 저장하는 position 객체를 생성하고 3과 같이 화면 중앙 값으로 초기 값을 저장합니다.

 

5. 내가 정의한 onPanResponderMove와 onPanResponderRelease 메서드를 PandResponder의 move, release 이벤트 함수로 사용할 수 있도록 정의하고 PanResponder.create에서 PandResponder의 이벤트 함수들과 사용자 정의 함수를 연결해줍니다.

* PanResponder를 생성 시 onStartShouldSetPanResponder에 true 값은 요소를 터치 할 때 지정한 move, release 함수가 활성화 됨을 의미 합니다.

 

6. _handlePanResponderMove (onPanResponderMove)의 로직을 만들어 줍니다.

객체가 사용자의 이동 이벤트를 받으면 evt와 gesture 파라미터를 받게 되는데 evt의 경우 객체내 터치 좌표, 연속된 이벤트의 배열 등 사용자 이벤트 자체 정보를 포함하는 반면 gesture의 경우 이벤트의 움직임과 관련 정보를 포함하고 있어 요번 예제에서는 gesture 정보를 사용합니다. 

move 이벤트의 원점 - 이동된 점으로 이동한 거리를 계산하고 

let ydiff = gestureState.y0 - gestureState.moveY 

position의 y 값을 이동전 y 값 - 이동 값을 통해 move 이벤트의 이동 위치로 저장합니다. 

y: this.state.oPosition.y - ydiff
   

7, _handlePanResponderRelease (onPanResponderRelease)에 release 이벤트가 발생 시 oPosition을 사용자가 객체를 드랍 했을 때의 위치로 저장하고 새로 이벤트를 받을 수 있도록 합니다. 

<View {...this._panResponder.panHandlers}
	style={[styles.box, { marginLeft: this.state.position.x, marginTop: this.state.position.y }
    ]} />

panResponder의 panHandlers를 지정하여 사용자 이벤트를 받을 수 있는 객체로 지정하고 객체의 왼쪽 위 좌표를 기준으로 margin 값을 주어 이벤트 대상 객체의 위치를 지정합니다.

 

빨간 박스의 View를 눌러 위치를 이동시키면 좌표 정보가 상단에 표시되고 마우스를 떼면 해당 위치에 박스가 위치하는 것을 볼 수 있음

 

이렇게 panresponder를 이용하여 사용자 이벤트를 재정의해서 등록하여 이벤트를 활성화 시키고 특정 view에 연결하는 방법을 알아 보았습니다. 

'React native' 카테고리의 다른 글

크로스 플렛폼 - NetInfo API  (0) 2020.01.19
크로스 플렛폼 - Geolocation  (0) 2020.01.19
크로스 플랫폼 - Clipboard API  (0) 2020.01.19
크로스 플랫폼 - AsyncStorage  (0) 2020.01.12
크로스 플랫폼 - AppState API  (0) 2020.01.12

NetInfo API를 이용하여 기기의 네트워크의 연결 유무를 알 수 있습니다. 

 

geolocation에서와 같이 안드로이드에는 권한을 추가해 줘야 합니다. 

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

 

netinfo를 위해 npm module을 설치하고 link를 해줍니다.

npm install --save @react-native-community/netinfo

react-native link @react-native-community/netinfo

*iOS emulator의 경우 ios폴더 내에 pod install로 module을 설치해주자

 

1. netinfo.js를 생성하고 'react-native-community'에서 NetInfo import한다.

생성자에 connectionInfo: {}를 통해 연결 정보 state를 생성한다.

 

2. NetInfo를 통해 초기 연결 상태를 파악하고 state에 저장

NetInfo.fetch().then(connectionInfo => {
       console.log("Connection type", connectionInfo.type)
       console.log("Is connected?", connectionInfo.isConnected)
       this.setState(connectionInfo)
     })

3. 실시간으로 연결 정보를 파악할 수 있도록 리스너를 추가하여 그 결과를 state에 저장

NetInfo.addEventListener(connectionInfo => {
       console.log("Changed Connection type", connectionInfo.type);
       console.log("Is connected?", connectionInfo.isConnected);
       this.setState(connectionInfo)
     });

4. render에서 연결 type을 통해 어떤 연결 모듈을 가지고 있는지 출력하도록 한다.

코드 실행 시 위와 같이 현재 기기의 연결 타입이 출력 됨

iOS의 경우 개발중인 데스크탑의 wifi를 해제하면 none으로 연결 정보가 업데이트 되는 것을 확인 할 수 있다.

'React native' 카테고리의 다른 글

크로스 플렛폼 - PanResponder  (0) 2020.01.26
크로스 플렛폼 - Geolocation  (0) 2020.01.19
크로스 플랫폼 - Clipboard API  (0) 2020.01.19
크로스 플랫폼 - AsyncStorage  (0) 2020.01.12
크로스 플랫폼 - AppState API  (0) 2020.01.12

기기의 위도, 경도를 알아내기 위한 API를 구현해보겠습니다.

 

아래 명령어로 geolocation module을 설치합니다. 

npm install @react-native-community/geolocation -save

 

*설치 후 geolocation module link와 pod install을 진행해야 한다고 에뮬레이터에 가이드가 나올 수 있다 시키는대로 진행하자

 

위치 정보를 이용하기 위한 권한이 iOS의 경우 기본으로 활성화되어 있으나 안드로이드의 경우 AndroidManifest.xml에 아래 권한 요청을 추가해 줘야 합니다. (추가 후 앱 재실행)

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

 

1. geolocation.js를 만들고 geolocation을 추가한다

import Geolocation from '@react-native-community/geolocation'

 

2. 현재위치 정보, 새로운 위치 정보, 위치 정보 watch id를(해제를 위해) 저장하는 state 정의

this.state = { 
            originalCoords: {},
            updatedCoords: {},
            id: ''
        }

3. 현재 위치 정보를 받아오는 로직을 componentDidMount에 정의

Geolocation.getCurrentPosition(
            (info) => {
                this.setState({
                    originalCoords: info.coords
                })
            },
            (err) => console.log('err : ', err)
        )

코드 실행 시 1회 현재 위치 정보를 얻어 state의 originalCoords에 저장, 에러 발생 시 로그 출력

 

4. 위치 정보가 갱신(기기가 이동) 할 때 마다 정보를 업데이트 하는 watch 정의

let id = Geolocation.watchPosition(
            (success) => {
                this.setState({
                    id,
                    updatedCoords: success.coords
                })
            },
            (err) => console.log('err : ', err)
        )

watch의 id를 저장해둬야 나중에 해제가 가능하다

 

5. watch를 해제하는 함수 추가

clearWatch(){
        Geolocation.clearWatch(this.state.id)
    }

4에서 저장한 state 의 id를 사용하여 watch를 해제해준다.

 

6. render에 시작 시 위치, 업데이트 되면서 바뀌는 위치 정보를 표시해주도록 정의한다.

 

실행 시(왼쪽) 초기 위치 정보가 출력되고 위치 이동 시(우측) 업데이트 된 위치 정보가 표시 됨

iOS emulator의 경우 Debug -> Location 메뉴를 통해 emulator의 위치 정보를 변경할 수 있고 변경 시 바로 앱의 위치 정보가 업데이트 됨을 확인 할 수 있다.

 

ClearWatch 버튼을 눌러 위치 정보 갱신을 중지하면 emulator의 위치 설정을 변경해도 더 이상 업데이트가 되지 않는 것을 확인 할 수 있다.

'React native' 카테고리의 다른 글

크로스 플렛폼 - PanResponder  (0) 2020.01.26
크로스 플렛폼 - NetInfo API  (0) 2020.01.19
크로스 플랫폼 - Clipboard API  (0) 2020.01.19
크로스 플랫폼 - AsyncStorage  (0) 2020.01.12
크로스 플랫폼 - AppState API  (0) 2020.01.12

요번 포스팅은 복사, 붙여넣기 기능을 구현해 보도록 하겠습니다. 

 

이 API는 getString(), setString() 두 함수로 간단히 구현할 수 있습니다. 

 

1. clipboard.js를 생성하고 react-native에서 Clipboard, getString component를 import 합니다. 

 

2. componentDidMount 오버라이드 함수에 Clipboard.setString('HelloWorld')으로 초기 clipboard 값을 설정합니다. 

 

3. updateClipboard (string) 함수에서 inputText에 입력이 발생할 때 마다 Clipboard.setString(string)을 이용하여 clipboard에 입력된 텍스트를 넣어둡니다. 

 

4. 지난 비동기 함수 동작 방식으로 async-await를 이용하여 pushClipboardToArray() 함수에서 clipboard에 저장된 텍스트를 component state인 clipboardData 배열에 push 하도록 합니다.

*this.pushClipboardToArray = this.pushClipboardToArray.bind(this)로 async 함수를 binding하여 사용하도록 합니다. 

 

이제 사용자 이벤트(텍스트 입력, 클립보드 내용 저장 버튼)를 위해 render를 구성합니다. 

 

TextInput에서 onChangeText 이벤트가 발생하면 3번의 updateClipboard 함수가 호출 될 수 있도록 익명 함수를 설정합니다.

 

TouchableHighlight를 누르면 binding 시켰던 4번의 pushClipboardToArray 함수를 호출 하도록 구현합니다. 

 

clipboardData.map((d, i) => {
                    return <Text key={i}>{d}</Text>
                })

render 하단에 clipboardData 배열의 map을 이용하여 저장된 데이터를 출력해주는 로직입니다. 

 

map을 이용하면 배열 아이템 하나하나에 대해 전달된 익명 함수를 실행하게 되는데 그 인자로 저장된 데이터 d와 인덱스 i가 전달되고 Text 문을 return하여 데이터를 화면에 출력하게 됩니다. 

 

실행 결과

코드를 실행해보면 위와 같이 바로 버튼을 누르면 초기 설정값인 'HelloWorld'가 출력되고 텍스트를 입력 후 버튼을 누를때 마다 입력한 결과가 목록으로 출력되는 걸 볼 수 있습니다. 

'React native' 카테고리의 다른 글

크로스 플렛폼 - NetInfo API  (0) 2020.01.19
크로스 플렛폼 - Geolocation  (0) 2020.01.19
크로스 플랫폼 - AsyncStorage  (0) 2020.01.12
크로스 플랫폼 - AppState API  (0) 2020.01.12
크로스 플랫폼 - Alert dialog  (0) 2020.01.10

앱의 데이터를 유지하고 저장하는 좋은 방법중 하나이며 비동기 방식입니다. 

 

아래와 같이 AsyncStorage를 설치해줍니다.

npm install --save @react-native-community/async-storage

(0.59부터 async-storage를 따로 추가해줘야함, 0.60 미만 에서는 react-native link를 통해 링크 작업따로 수행)

 

AsyncStorage는 보통 아래와 같은 경우에 많이 사용합니다. 

- 사용자 정보를 저장하여 매번 로그인이 필요없도록 할 때 등 사용자 정보 저장에 용이

- 대용량 데이터를 한번 받아 놓고 재사용

 

먼저 async-storeage에서 AsyncStorage를 import 합니다. 

 

임의의 person 객체를 생성하고 componentDidMount()에서 AsyncStorage.setItem(키, person을 json 형태의 문자열로 변환)을 통해 storage에 저장합니다. 

 

위 저장이 성공 시 then()으로 실패 시 catch()로 결과가 떨어집니다. 

 

반대로 AsyncStorage.getItem(key)를 통해 person 객체를 가져오는 함수 getPerson()를 정의합니다. 

 

then()내부에서 JSON.parse(res)를 통해 결과 문자열을 person 객체로 파싱하도록 합니다. 

 

Get President 버튼을 누르면 Storage에 저장된 결과를 보여준다.

 

AsyncStorage의 더 자세한 가이드는 아래 공식 사이트를 참고합니다. (merge의 사용법도 숙지합니다.)

https://facebook.github.io/react-native/docs/asyncstorage

 

그리고 아래와 같이 async, await 키워드를 통해 좀 더 자바 친숙(promise)한 비동기 storage로직을 구현하는 방법도 있습니다. 

async componentDidMount() {
	try{
    	await AsyncStorage.setItem(key, JSON.stringify(person)
        console.log('item stored')
    } catch (err) {
    	console.log('err: ', err)
    } 
}

 

안드로이드의 kotlin도 그렇고 대세는 좀 더 깔끔한 코드를 추구하는 람다방식이므로 예제의 코딩 방식을 익히도록 합시다

'React native' 카테고리의 다른 글

크로스 플렛폼 - Geolocation  (0) 2020.01.19
크로스 플랫폼 - Clipboard API  (0) 2020.01.19
크로스 플랫폼 - AppState API  (0) 2020.01.12
크로스 플랫폼 - Alert dialog  (0) 2020.01.10
Redux - 데이터 처리  (0) 2020.01.07

AppState API는 앱의 상태(active, inactive, background)를 이벤트 리스너를 통해 메서드 호출을 받습니다 

 

AppState의 사용 예

- 앱이 foreground로 변경되었을때 데이터의 갱신

- 주기적인 이벤트 발생시 background, foreground의 상태에 따라 동작 결정

- 앱이 foreground 상태가 됐을 때, 화면의 잠금 상태를  풀기 위해 인증 로직 동작

 

우선 react-native에서 AppState를 import합니다. 

 

componentDidMount() override함수에서 AppState.addEventListener(타입, 핸들러함수)를 통해 리스너를 등록합니다. 

 

handleAppStateChange 핸들러 함수를 정의하고 AppState가 변경될때 마다 log를 찍도록 합니다. 

 

앱 실행 후 iOS는 커맨드+쉬프트+h , 안드로이드는 Home 버튼을 눌러 홈화면으로 이동하면 개발자 도구의 console을 통해 아래와 같은 로그를 확인할 수 있습니다. 

개발자 도구 console.log

공식 가이드를 통해 더 자세한 내용과 예제를 확인해 봅니다.

https://facebook.github.io/react-native/docs/appstate

'React native' 카테고리의 다른 글

크로스 플랫폼 - Clipboard API  (0) 2020.01.19
크로스 플랫폼 - AsyncStorage  (0) 2020.01.12
크로스 플랫폼 - Alert dialog  (0) 2020.01.10
Redux - 데이터 처리  (0) 2020.01.07
Animation  (0) 2020.01.05

앱 개발을 하면서 가장 많이 쓰이는 기능 중 하나인 alert dialog를 띄워 봅니다.

 

Alert component를 react-native에서 import합니다. 

 

showMessage: false //Alert dialog의 유무를 확인하는 state를 정의

 

showAlert() 함수를 정의하여 Alert.alert로 dialog를 띄울 수 있도록 합니다. 

 

요번 예제에서는 Alert.alert(제목, 메세지, dialog button) 형식으로 기본적인 dialog 모양을 갖추도록 합니다. 

 

static alert(title, message?, buttons?, options? type?)

공식 가이드에 따르면 위와 같이 추가적인 옵션({cancelable:false})을 파라미터로 전달할 수 있습니다. 

 

코드에서 정의한 Show Message 버튼을 누르면 showMessage state를 true로 변경하여 render가 호출 되고 true인 경우 Showing message -success 텍스트가 나타나도록 합니다. 

 

iOS용 alert dialog와 android용 alert dialog

'React native' 카테고리의 다른 글

크로스 플랫폼 - AsyncStorage  (0) 2020.01.12
크로스 플랫폼 - AppState API  (0) 2020.01.12
Redux - 데이터 처리  (0) 2020.01.07
Animation  (0) 2020.01.05
Navigation  (0) 2020.01.02

화면을 전환하거나 로딩 indicator등을 구현할 수 있는 Animation을 구현해봅니다.

 

내장 Animated API를 사용하고 이를 이용해 효과를 실행하는 함수를 만들고 특정 이벤트에 앞서 정의한 Animated 함수가 실행 되도록 합니다. 

 

첫번째 예제는 버튼을 눌렀을때 특정 Component를 이동 시키는 애니메이션 입니다.

 

기본 animated App.js

- marginTop = new Animated.Value(20) //Animated를 위한 변수를 생성, 연결하고 이를 아래 Animated.View component에 연결

- Animated.timing(시작 값:marginTop, 설정객체{종료값, 시간})

- <Animated.View> Component 사용 (View, Image, ScrollView, Text 사용가능)

 

App.js를 실행 후 Animate Box를 누르면 사각형이 이동

두번째 예제는 InputText가 Focus, Blur 이벤트에 따라 width를 변경하는 애니메이션을 적용해 보겠습니다. 

 

InputApp.js

- animatedWidth = new Animated.Value(200) //초기 너비를 200으로 Animated 값으로 지정

- 너비 값을 파라미터로 갖는 animate 함수를 정의하고 Animated.timing을 호출 하도록 함

- <Animated.View>의 스타일에 width를 animatedWidth로 지정

- <TextInput>의 onBlur, onFocus 이벤트 핸들러에 animate 메서드를 연결

* ref={input => this.input = input} //input이라는 이름으로 component의 참조 변수 생성

 

InputText에 Focus를 주면 너비가 커지고 Submit을 누르면 blur가 호출되면서 다시 작아짐

다음은 Animated.loop를 이용한 loading indicator를 생성해 보겠습니다.

 

interpolate 메서드를 사용하고 이는 inputRange(원래 애니메이션 효과), outputRange(앞으로 변경될 효과) 설정 객체를 인수로 사용합니다.

 

Easing : 애니메이션의 움직임을 조정(가,감속 효과), 요번 예에서는 회전 속도가 일정하도록 linear easing 사용

 

 LoopApp.js

- setTimeout(() => this.setState({loading: false}), 2000) //2초뒤 애니메이션 종료를 위한 타이머

const rotation = this.animatedRotation.interpolate({
            inputRange: [0,1],   //애니메이션 속도
            outputRange: ['0deg', '360deg'] //360도 회전
        })

 

여러 Component animation 만들기

 

제목 그대로 다수의 component에 애니메이션 효과를 주고 싶을 때가 있습니다. 병렬(Parallel), 순차(Sequence), 간격(Stagger)

* 예제를 하나하나 치는 입장에서는 그러고 싶지 않습니다. 

여기서는 병렬 처리에 대한 애니메이션만 직접 해보고 나머지는 비슷한 방식에 함수만 적절히 사용하시면 됩니다.

 

Parallel.js

- 다수의 Animated.Value 정의

- animate 함수 내 Animated.parallel([ Animated.Value ... ]).start() 정의

- render내 Component 추가

 

코드는 처음 작성했던 애니메이션 코드를 베이스로 호출하는 함수를 Animated.parallel, 인자로 여러 Component를 배열로 주고 있는 정도의 차이입니다. 

* 순차 처리의 경우 Animated.sequence(Animated.Value), 간격 처리의 경우 Animated.stagger(시간간격, Animated.Value)를 사용하시면 됩니다.

 

Animated.Value의 delay 속성 때문에 각 Component가 순차적으로 애니메이션이 실행 되는 듯이 보임

 

애니메이션 사용 팁

1. 애니메이션 효과 재지정

animate = () => {
       this.animatedValue.setValue(300)
       ...
   }

2. 애니메이션 종료 후 콜백함수

Animated.timing(
         this.animatedTitle,
         {
           toValue: 200,
           duration: 800,
         } 
       ).start(() => console.log('animation is complete!'))

3. 네이티브 UI 스레드에서 애니메이션 실행

React native 기본적으로 자바스크립트 스레드에서 애니메이션이 실행되어 느려지거나 동작을 건너뛰어 버리는 이슈가 발생할 수 있습니다. 따라서 동작에 부하가 큰 애니메이션은 네이티브 UI에서 실행해 주는게 안전합니다. 

* 현재 flexbox, margin, padding 속성에는 이 기능을 사용할 수 없습니다.

Animated.timing(
         this.animatedTitle,
         {
           toValue: 200,
           duration: 800,
           useNativeDriver: true
         } 
       ).start()

4. 사용자 애니메이션 Component 만들기

앞에서 언급했듯이 현재 View, Text, Image, ScrollView에만 애니메이션을 적용할 수 있으나 아래 코드 처럼 정의하면 사용자 Component를 생성하면서 애니메이션 속성을 부여할 수 있습니다. 

const Button = Animated.createAnimatedComponent(TouchableHighlight)
<Button onPress={somemethod} style={styles.button}>
    <Text>Hello</Text>
</Button>

 

이상으로 Reactive native의 animation 효과에 대해서 알아보았습니다.

 

다음으로는 로컬 데이터를 관리하는 redux에 대해서 알아보겠습니다. 

'React native' 카테고리의 다른 글

크로스 플랫폼 - Alert dialog  (0) 2020.01.10
Redux - 데이터 처리  (0) 2020.01.07
Navigation  (0) 2020.01.02
고급 Style  (0) 2019.12.29
Style  (0) 2019.12.27

React Navigation library를 이용하여 탭과 스택 방식의 네비게이션을 구현할 예정입니다. 

 

아래 명령어를 통해 필요한 개별 모듈들을 설치합니다. 

 

npm install --save react-native-gesture-handler react-native-reanimated

npm install --save uuid react-navigation react-navigation-stack react-navigation-tabs

 

*react-native의 버전이 0.60 이하라면 react-native link react-native-gesture-handler 처럼 외부 모듈을 링크 해주는 작업을 추가

 

소스파일 구조

https://github.com/action-intent/ReactNative/tree/master/navigator

위 깃허브의 코드 구조를 참고해 주세요.

*프로젝트 생성시 추가되는 index.js는 navigator의 CitiesApp.js을 실행할 수 있도록 수정

 

앱의 전체 테마 색을 위한 theme.js 추가

primary color를 설정하여 색상 변경 시 쉽게 적용할 수 있도록 함

 

index.js 생성

*navigation을 위한 index.js임 프로젝트 생성시 만들어지는 index.js와 다름

createStackNavigator(라우트 설정 관련 인수, 스타일)

 navigationOptions : 화면 상단에 타이틀과 back 버튼

 

CitiesApp.js 생성

cities state : 이름, 나라, 장소배열, ID 속성을 가진 도시 정보 배열

addCity : 도시 정보를 추가 하기 위한 메서드

addLocation : 각 도시의 위치 정보를 추가하기 위한 도시 객체 내 위치 정보 배열

render : Tabs component를 리턴하고 도시 데이터 및 위 두 메서드를 props로 전달

 

components/CenterMessage.js 빈 화면 표시를 위한 stateless component 추가

 

AddCity.js 도시 추가를 위한 화면 추가

submit : 입력된 값이 비어있지 않으면 uuidV4를 이용해 ID를 할당, 빈 locations 배열 생성, addCity를 호출하여 추가된 city 정보 추가

navigate를 호출하여 추가된 Cities 탭으로 이동

 

도시 목록을 표시하는 Cities.js 추가

- CenterMessage를 가져와 빈 리스트 표시

- static navigationOption을 통해 title(rout)바 속성을 설정

- navigate method를 통해 도시 아이템 선택 시 도시 정보를 인자로 City라우트(navigation.state.params)

- render에서는 scrollView를 통해 도시 목록을 보여주고 TouchableWithoutFeedback을 통해 선택한 도시로 이동

 

각 도시의 주요 장소를 추가하고 출력하는 City.js 추가

- navigationOptions에서 route 객체 반환을 위해 콜백 함수 이용

- addLocation method는 navigation param에서 도시 정보를 가져오고 screenProps의 addLocation을 호출하여 location을 추가

- render에서 도시의 location정보를 scrollView를 통해 출력하고 location을 추가할 수 있는 폼을 추가

 

손가락이 저릴 정도로 코드를 추가 했다. 실행해보자. 동작은 잘 되지 않는다. 인터페이스만 확인하자

 

*실행 시 에뮬레이터에서 아래와 같은 메세지와 함께 실행이 되지 않는다면 아래 빌드 터미널을 종료하고 다시 실행해보자.

invariant violation: module rcteventemitter is not a registered callable module (calling receivetouches) callfunctionreturnflushedqueue [native code]:0

실행 결과 화면

*에뮬레이터에서 경고 창 무시하기 react-native run-ios --varient-release 로 실행하면 됨.

 

데이터 유지하기(AsyncStorage)

앱이 종료된 뒤에도 입력한 데이터를 유지할 수 있도록 캐쉬 모듈을 사용합니다.

 

npm install @react-native-community/async-storage

위 명령어를 통해 AsyncStorage 모듈을 설치합니다. AsyncStorage는 안드로이드의 SharedPreference와 비슷하다고 보시면 됩니다. 

 

*설치 후 아래와 같은 메세지와 함께 run-ios가 되지 않으면 프로젝트 내 ios폴더에서 pod install로 에뮬레이터에 모듈을 올려준다.

error Could not find the following native modules: RNCAsyncStorage. Did you forget to run "pod install" ?

 

CitiesApp.js

1. AsyncStorage를 import

2. 저장 key를 정의하고 componentDidMount 메서드에서 캐쉬된 데이터를 불러온다.

3. 데이터 갱신을 위해 addCity, addLocation 메서드에 JSON.stringify를 이용해 cities를 캐쉬 할 수 있도록 한다.

앱을 재실행 하여도 입력한 도시 정보가 유지된다.

 

이상으로 Navigation, Style적용 및 데이터 캐쉬를 위한 예제를 마무리 하였습니다. 

 

어렵더라도 예제 코드를 이해하고 넘어 갈 수 있도록 합니다. 

 

Tab navigation외 stack, drawer navigation이 있는데 찾아서 연습해 봅시다. 

https://reactnavigation.org/docs/en/next/drawer-based-navigation.html#docsNav

'React native' 카테고리의 다른 글

Redux - 데이터 처리  (0) 2020.01.07
Animation  (0) 2020.01.05
고급 Style  (0) 2019.12.29
Style  (0) 2019.12.27
Todo 2  (0) 2019.12.25

Todo 예제에서 무작정 각 component에 style을 적용하는 코드를 추가했었습니다. 

 

이제 React native의 뷰 구조 분리 및 style 적용에 대해서 알아보도록 하겠습니다. 

 

style을 적용하는 방법은 직접 태그에 스타일 속성을 추가하는 인라인 스타일과 StyleSheet를 통한 정의 방식이 있습니다.

* 여러 component에 적용되는 스타일은 StyleSheet를 이용하여 적용하고 특정 component에 적용해야 하는 몇몇 속성들은 인라인 스타일을 사용하여 스타일 코드를 정리할 수 있다.

 

- 스타일을 한번에 여러개 적용 할 때는 <Text style={[ style, style ]}>과 같이 배열 형태로 작성

- 스타일을 여러개 적용 할 때 중복되는 property는 마지막의 것으로 적용 됨(앱 성능을 위해 중복 적용 주의)

- 스타일을 따로 정의하면 코드의 가독성이 올라가고 재사용으로 인한 전체적인 컨셉 수정에 용이(가독성 있는 스타일 네이밍 필요)

- component.js , style.js로 스타일 코드를 따로 분리하여 export, import하여 적용할 수 있음

- 스타일 속성에서는 전체 속성(borderWidth: 3)보다 세부 속성(borderLeftWidth:1)이 우선 순위가 높음

 

그럼 버튼을 눌렀을때 전체 테마를 바꾸는 예제를 스타일 파일을 분리하여 구현해 보도록 하겠습니다. 

 

https://github.com/action-intent/ReactNative/tree/master/Style

* AppStyle.js를 진입점으로 설정해주세요.

난해할 수 있는 부분은 코드에 주석으로 추가하였습니다. (참고로 react의 JSX 코드에는 주석을 넣을 수가 없습니다..)

 

 

 

 

 

 

 

 

위 코드를 다운받아 실행해 보면 White 버튼을 누르면 container와 button의 색이 바뀌고 button label도 변경됩니다.

 

 

 

 

 

 

 

 

 

 

 

이렇게 구현했을 때의 장점은 구현 그대로 앱의 전체 테마를 손쉽게 변경 할 수 있다는 점이고 스타일 코드를 모아 놓아 로직 코드가 간단해 지고 스타일 변경 시 확인해야 할 부분이 분명해 진다는 점입니다.

* 코드의 구조적 분리는 코드의 readability를 높여 유지 보수를 쉽게 하며 협업이 요구되는 프로젝트에서 큰 이점이 된다는 당연한 얘기를 해봅니다.

 

View component에 스타일 적용

view component는 html의 div 태그와 비슷한 것이라 생각하시면 됩니다. 

여기엔 다양한 스타일 속성을 적용할 수 있습니다. 프로필 카드 View 예제를 만들어 보면서 하나하나 알아 보도록 하겠습니다. 

* 같은 github에 AppView.js를 참고하세요.

 

1. 배경색 설정 : backgroundColor로 값은 rgb, rgba(알파), hsl(색상, 채도 명도), hsla, transparent, saturation, lightness

2. 테두리 설정 : borderColor, borderRadius(둥근테두리), borderStyle, borderWidth (e.g borderTopColor: 'red')

* 현재 borderStyle dashed, dotted 속성에 borderWidth를 부분 설정하려고 하면 오류가 난다고 하네요? 그런듯 합니다.

3. Image 가져오기 : <Image> 태그를 이용하고 source={require('image path')} 형태로 불러옴(import에 Image component 추가)

 

 

 

 

 

 

 

 

지금까지 반영한 스타일 코드를 띄우면 다음과 같습니다. 

아.. 뭔가 되려고 함..

 

 

 

 

 

 

 

 

 

 

 

4. margin, padding, position

* 모든 기능이 그렇지만 스타일 적용 후 iOS, 안드로이드 모두 테스트를 해봐야 합니다.  같은 속성이 플렛폼에 따라 다르게 표현될 수 있기 때문..

- margin은 부모 요소와의 간격 padding은 자식 요소와의 간격

- {position: 'absoulte', right: 0, bottom: 0} 부모 요소의 오른쪽 아래에 위치

 

 

 

 

 

 

 

 

cardContainer, cardImageContainer에 alignItems, marging, padding 속성을 추가하고 훨씬 보기 편안해진 모습입니다.

 

 

 

 

 

 

 

 

 

 

 

5. Text style

Text와 위에서 배운 View의 속성은 공통점이 많습니다. View의 대부분의 속성을 Text에서도 사용할 수 있습니다. 

- font의 경우 플렛폼 마다 지원하는 종류가 다를 수 있음. ...platform.select로 플렛폼 별로 스타일 속성을 설정할 수 있음 

- fontSize, fontStyle, fontWeight등의 속성을 사용할 수 있음

 

 

 

 

 

 

 

 

텍스트 스타일 속성을 통해 텍스트가 훨씬 보기 좋아졌음을 알 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

6. 텍스트 장식

텍스트 장식은 플렛폼 마다 지원하는 속성이 다를 수 있습니다.

- lineHeight: Text 높이 지정 

- textAlign: Text 수평정렬

- textDecorationLine: 밑줄, 취소선 등

- textDecorationColor, textDecorationStyle은 iOS만 지원하는 속성으로 밑줄등의 스타일 속성

- textShadowColor, textShadowOffset(음영의 위치), textShadowRadius(투명도)

 

 

 

 

 

 

 

 

 

마지막으로 name에 그림자 속성을 추가해 보았습니다. 작지만 큰 차이가 느껴지는 속성입니다. 

 

 

 

 

 

 

 

 

 

 

지금까지 component의 기본 스타일을 적용하는 방법에 대해서 알아 보았습니다.

 

다음 포스팅에서는 고급 스타일링 기법에 대해서 알아보도록 하겠습니다. 

'React native' 카테고리의 다른 글

Navigation  (0) 2020.01.02
고급 Style  (0) 2019.12.29
Todo 2  (0) 2019.12.25
Todo 1  (0) 2019.12.25
State, Props, Lifecycle  (0) 2019.12.25

+ Recent posts