React Native/React Native_study

[리액트 네이티브를 다루는 기술 #4] 3장 할일 목록 만들기1 (p.133 ~ 160)

bocoder
728x90
반응형

@ List

** 3.1.5 이미지 사용하기

* 3.2 TextInput으로 사용자 키보드 입력받기

** 3.2.1 KeyboardAvodingvire로 키보드가 화면을 가리지 않게 하기

** 3.2.2 useState로 텍스트 상태 값 관리하기

** 3.2.3 커스텀 버튼 만들기

** 3.2.4 TextIput에 onSubmitEditing 및 returnKeyType 설정하기

* 3.3 정리

 

@ Note

1. 스타일링 단위

 - ppi (pixel per inch) : 1inch에 몇 px이 들어갈 수 있는지 의미

 - dpi (dots per inch) : ppi와 유사하며 인쇄물에서 사용하는 단위

 - react native 스타일링 시 크기는 dp 로 설정

  > dp (density-independent pixel) : 1inch당 픽셀 밀도에 따라 크기가 일관된 UI를 보여줄 수 있는 단위

     dp = px * 160 / ppi

     px = dp * ppi / 160  

  > ex)

     iPhone 11 Pro 에서 너비 200 사이즈에 선명한 이미지 보여 줄 때

     200 * 458 / 160 =572.5px 이미지 사용해야 선명함 --> circle@3x.png 사용

      1) circle.png = 200px x 200px

      2) circle@2x.png = 400px x 400px

      3) circle@3x.png = 600px x 600px 

 

2. assets > icons & images 다운

assets.zip
0.11MB

 - reference : https://bit.ly/chapter-3-images

 

@ Result

0123
ios / android

 

012
ios / android

 

# App. js

import React from 'react';
import {StyleSheet, KeyboardAvoidingView, Platform} from 'react-native';

import DateHead from './components/DateHead';
// for IOS StatusBar
import {SafeAreaProvider, SafeAreaView} from 'react-native-safe-area-context';

import AddTodo from './components/AddTodo';
import Empty from './components/Empty';

function App() {
  const today = new Date();

  return (
    <SafeAreaProvider>
      <SafeAreaView edges={['bottom']} style={styles.block}>
        <KeyboardAvoidingView
          // behavior={Platform.OS === 'ios' ? 'padding' : undefined}  // 삼항연산자 이용 시
          behavior={Platform.select({ios: 'padding', android: undefined})}
          style={styles.avoid}>
          <DateHead date={today} />
          <Empty />
          <AddTodo />
        </KeyboardAvoidingView>
      </SafeAreaView>
    </SafeAreaProvider>
  );
}

const styles = StyleSheet.create({
  block: {
    flex: 1,
    backgroundColor: 'white',
  },
  avoid: {
    flex: 1,
  },
});

export default App;

 

# components > AddTodo.js

import React, {useState} from 'react';
import {
  View,
  StyleSheet,
  TextInput,
  Image,
  Platform,
  TouchableOpacity,
  TouchableNativeFeedback,
  Keyboard,
} from 'react-native';

function AddTodo() {
  const [text, setText] = useState('');

  const onPress = () => {
    setText('');
    Keyboard.dismiss(); // button 눌렀을 시 키보드 사라짐
  };

  const button = (
    <View style={styles.buttonStyle}>
      <Image source={require('../assets/icons/add_white/add_white.png')} />
    </View>
  );

  return (
    <View style={styles.block}>
      <TextInput
        placeholder="할일을 입력하세요."
        style={styles.input}
        value={text}
        onChangeText={setText}
        onSubmitEditing={onPress} // Enter 눌렀을 시 키보드 사라짐
        returnKeyType="done" // Enter 타입 지정
      />

      {/* 삼항연산자 이용 */}
      {/* {Platform.OS === 'ios' ? (
        // ios : 터치 시 투명도 변경
        <TouchableOpacity activeOpacity={0.5}>
          <View style={styles.buttonStyle}>
            <Image
              source={require('../assets/icons/add_white/add_white.png')}
            />
          </View>
        </TouchableOpacity>
      ) : (
        // android : 터치 시 물결
        <View style={styles.circleWrapper}>
          <TouchableNativeFeedback>
            <View style={styles.buttonStyle}>
              <Image
                source={require('../assets/icons/add_white/add_white.png')}
              />
            </View>
          </TouchableNativeFeedback>
        </View>
      )} */}

      {Platform.select({
        ios: <TouchableOpacity onPress={onPress}>{button}</TouchableOpacity>,
        android: (
          <View style={styles.circleWrapper}>
            <TouchableNativeFeedback onPress={onPress}>
              {button}
            </TouchableNativeFeedback>
          </View>
        ),
      })}
    </View>
  );
}

const styles = StyleSheet.create({
  block: {
    backgroundcolor: 'white',
    height: 64,
    paddingHorizontal: 16, // 좌우 여백
    bordercolor: '#bdbdbd',
    borderTopWidth: 1,
    borderBottomWidth: 1,
    alignItems: 'center', //상하 정렬
    flexDirection: 'row',
  },
  input: {
    flex: 1, // TextInput 란 확장
    fontSize: 16,
    paddingVertical: 8, // 상하 터치영역 확장
  },
  buttonStyle: {
    alignItems: 'center',
    justifyContent: 'center',
    width: 48,
    height: 48,
    backgroundColor: '#26a69a',
    borderRadius: 24,
  },
  circleWrapper: {
    overflow: 'hidden', // 지정한 영역 외 바깥 영역 숨김
    borderRadius: 24,
  },
});

export default AddTodo;

 

# components > DataHead.js

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

// for IOS StatusBar
import {useSafeAreaInsets} from 'react-native-safe-area-context';

function DateHead() {
  const d = new Date();
  const year = d.getFullYear();
  const month = d.getMonth() + 1; // getMonth 범위 : 0 ~ 11 까지
  const day = d.getDate();

  const formatted = `${year}년 ${month}월 ${day}일`;

  const {top} = useSafeAreaInsets();

  return (
    <>
      <View style={[styles.statusBarPlaceholder, {height: top}]} />
      <StatusBar backgroundColor="#26a69a" barStyle="light-content" />
      <View style={styles.block}>
        {/* <Text style={styles.dateText}>{formatted}</Text> */}
        <Text style={styles.dateText}>
          {year}년 {month}월 {day}일
        </Text>
      </View>
    </>
  );
}

const styles = StyleSheet.create({
  statusBarPlaceholder: {
    backgroundColor: '#26a69a',
  },
  block: {
    padding: 16,
    backgroundColor: '#26a69a',
  },
  dateText: {
    fontSize: 24,
    color: 'white',
  },
});

export default DateHead;

 

# components > Empty.js

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

function Empty() {
  //   const source = {uri: 'https://via.placeholder.com/150'};

  return (
    <View style={styles.block}>
      {/* <Image
        source={require('../assets/images/circle.png')}
        style={styles.image}
        resizeMode="cover"
      /> */}
      {/* <Image source={source} style={styles.image} resizeMode="cover" /> */}

      <Image
        source={require('../assets/images/young_and_happy.png')}
        style={styles.image}
        resizeMode="cover"
      />

      <Text style={styles.description}>할일이 없습니다.</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  block: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  image: {
    width: 240,
    height: 179,
    marginBottom: 16,
  },
  description: {
    fontSize: 24,
    color: '#9e9e9e',
  },
});

export default Empty;

 

728x90
반응형