728x90
반응형

이전 포스팅에서는 구글 파이어 베이스의 Cloud FireStore에

데이터를 추가하고 Storagedp 파일도 같이 저장하는 방법을 알아보았습니다 

 

더 자세한 내용은 아래의 포스팅을 참고하세요

 

 

2022.07.31 - [Server/Firebase] - React Native X Expo X 구글 파이어 베이스 Cloud Firestore 데이터 추가 및 이미지 추가 기능 구현

 

React Native X Expo X 구글 파이어 베이스 Cloud Firestore 데이터 추가 및 이미지 추가 기능 구현

이번에는 구글 파이어 베이스의 Cloud Firestore 데이터 추가 기능을 구현해보겠습니다  추가할 때 이미지도 같이 저장해보도록 하겠습니다 아래의 목차와 같이 진행하겠습니다 Storage 설정 및 폴더

tantangerine.tistory.com

 

무한 스크롤이란?

스크롤을 내릴 때 마지막 하단까지 내려오게 되면 정보를 다시 불러와서

그 정보를 마지막 하단 밑에 붙여주는 효과입니다.

그렇게 되면 사용자로 하여금 스크롤이 무한으로 내려가는 것처럼 느껴지게 되는 것입니다.

 

 

무한 스크롤의 장점은?

기존은 페이징 처리가 되어있어 다음 페이지를 보려면 계속 클릭을 해주어야 합니다.

그렇게 되면 흥미가 떨어질 경우 클릭을 하지 않아 사용자가 이탈하는 경우가 발생합니다.

하지만 스크롤을 내리는 것은 사용자 입장에서는 간단하게 정보를 불러올 수 있으며

스크롤을 내리는 행위로 끊임없이 정보를 노출하면서 사용자의 이탈을 막을 수 있습니다.

 

 

리액트 네이티브 FlatList 및 Firestore Database 무한 스크롤 구현 방법

 

아래의 공식문서를 확인하시면 flatList의 활용하는 방법을 확인하실 수 있습니다

더 상세한 정보를 알고 싶다면 링크를 클릭하시면 됩니다.

 

https://docs.expo.dev/versions/latest/react-native/flatlist/

 

FlatList - Expo Documentation

Expo is an open-source platform for making universal native apps for Android, iOS, and the web with JavaScript and React.

docs.expo.dev

 

ScrollView와 비슷하면서 다른 FlatList

 

 

아래의 코드를 구현해보았습니다

이제 그 속성에 대해서 하나하나 알아보도록 합시다

 

import React, { useState, useEffect } from 'react';
import {
  ActivityIndicator,
  StyleSheet,
  Image,
  View,
  FlatList,
  SafeAreaView,
  Alert,
} from 'react-native';
import { Col, Row, Grid } from 'react-native-easy-grid';
import {
  Container,
  Header,
  Content,
  Left,
  Icon,
  Right,
  Text,
  Button,
} from 'native-base';
import CardComponent from '../components/CardComponent';
import HeaderComponent from '../components/HeaderComponent';
import * as Animatable from 'react-native-animatable';
import { getData, getNextData } from '../config/firebaseApi';
const data = require('../data.json');
export default function MainPage({ navigation }) {
  const [data, setData] = useState([]);
  const [next, setNext] = useState(0);

  useEffect(() => {
    navigation.addListener('beforeRemove', (e) => {
      e.preventDefault();
    });
    readyData();
  }, []);
  const readyData = async () => {
    const data = await getData(setNext);
    setData(data);
  };
  console.log('다음:' + next);
  return (
    <Container>
      <HeaderComponent />
      {data.length == 0 ? (
        <ActivityIndicator size="large" />
      ) : (
        <FlatList
          data={data}
          ListHeaderComponent={() => {
            return (
              <Content style={{ marginTop: 30 }}>
                <Animatable.View
                  animation="pulse"
                  easing="ease-out"
                  iterationCount={3}
                  direction="alternate"
                >
                  <Grid style={styles.banner}>
                    <Col size={1} style={{ padding: 20 }}>
                      <Icon name="paper-plane" style={{ color: 'deeppink' }} />
                    </Col>
                    <Col size={6} style={{ padding: 15 }}>
                      <Text>이야기 하고 싶은 친구들에게</Text>
                      <Text style={{ fontWeight: '700' }}>
                        wegram을 전하세요
                      </Text>
                    </Col>
                  </Grid>
                </Animatable.View>

                <Grid style={{ padding: 20 }}>
                  <Text style={{ color: 'grey' }}>FROM THE DIARY</Text>
                </Grid>
              </Content>
            );
          }}
          onEndReachedThreshold={0.8}
          onEndReached={async () => {
            console.log('바닥 가까이 감: 리프레시');
            if(next > 0){
              let nextData = await getNextData(next, setNext);
              if (nextData == 0) {
                Alert.alert('더이상 글이 없어요!');
              } else {
                let newData = [...data, ...nextData];
                console.log(newData);
                await setData(newData);
              }
            }
          }}
          renderItem={(data) => {
            // console.log(data);
            return (
              <CardComponent navigation={navigation} content={data.item} />
            );
          }}
          numColumns={1}
          keyExtractor={(item) => item.date.toString()}
        />
      )}
    </Container>
  );
}

const styles = StyleSheet.create({
  banner: {
    backgroundColor: '#F6F6F6',
    height: 70,
    borderRadius: 10,
    width: '90%',
    alignSelf: 'center',
  },
});

 

ListHeaderComponent 속에는 컴포넌트를 삽입해서 

아래와 같은 부분을 정의할 수 있습니다

 

 

ListHeaderComponent
헤더 컴포넌트 정의하기

 

 

onEndReachedThreshold={0}은 제일 하단을 언제부터 감지할 것이냐라는 것입니다

0을 준다면 하단 끝까지 맞닿았을 때 감지하게 됩니다.

이 부분은 조금씩 변경해서 한번 테스트를 해보시길 바랍니다.

그리고 감지될 경우  onEndReached에 정의된 함수를 실행하게 됩니다.

keyExtractor속성은 데이터의 키값에 해당하는 값을 넘겨주시면 됩니다.

 

 

속성설명
속성설명

 

하단이 감지된다면 

onEndReached의 함수가 실행돼서

다음 데이터를 호출하여 무한 스크롤 효과를 적용합니다

 

그리고 그 getNextData는 구글 파이어 베이스의 cloud Storage의 기능을 사용합니다

 

export async function getNextData(nextDate, setNext) {
  try {
    console.log("불러올 다음 date: " + nextDate)
    let data = []
    const db = firebase.firestore();
    const next = db.collection('diary')
      .orderBy('date', 'desc')
      .startAfter(nextDate)
      .limit(5);
    const snapshot = await next.get();
    snapshot.docs.map((doc) => {
      console.log("[페이지네이션 Next]")
      doc.data()
      data.push(doc.data());
    });
    console.log(snapshot.docs.length)
    let last;
    if (snapshot.docs.length !== 0) {
      last = snapshot.docs[snapshot.docs.length - 1];
      setNext(last.data().date)
      return data
    } else {
      return 0
    }

  } catch (err) {
    console.log(err);
    return false;
  }
}

 

 

위의 코드를 본다면 .startAfter은 매개변수의 값의 기준으로 그다음의 정보를 불러옵니다.

그리고 last함수에 마지막 데이터를 저장해서 값을 setNext에 넣어줍니다.

그래서 함수를 다시 호출할 때 next값을 사용하여 계속 정보를 가져오게 됩니다.

 

React Native를 공부하기 위해 책으로 공부할까 아니면

강의를 들을까 하다 귀찮기도 하고 강의를 듣기로 하였습니다

책은 값이 싸기는 하지만 책을 보면서 하면 시간이 많이 걸리고

강의를 보면 강의료가 비싸긴 해도 1~2주에 끝날 수 있으니 선호하는 편입니다

 

그러던 중 스파르타 코딩 클럽을 찾았고

후기가 안 좋은 편이긴 하였으나

처음이라 어떤지 궁금하기도 했고

올해 초 이벤트를 하길래 결제를 했었습니다

이벤트가 아니면 너무 비싼 가격이라 하지 않으려고 했었죠

하지만 코드를 보면 리팩토링 해야 할게 너무나도 많았습니다

처음에는 고치면서 하려다가 새로운 코드를 강의마다 적용해야 해서

엎는 과정에서 시간 소요가 상당했습니다

 

그래서 중간에 포기하고 그냥 포스팅하면서 기능 위주로 보려고 하는데

조금 심한 경우가 많네요

이걸 초보자분들이 본다고 생각하니 조금 아찔하기도 합니다

 

if문에 두 개의 return이 있는 거 하며

onEndReached를 실행할 때마다 next값이 0인데도 계속 조회해오는 이상한 구조입니다

처음부터 setNext에 0을 할당해서 getNextData를 호출하지 않게 해야 하는 것이 더 중요한데 말이지요

 

강사분도 그렇게 경력이 많아 보이지도 않고요

다음에는 정말 좋은 강의를 소개하는 포스팅도 쓰도록 해보아야겠네요

 

아무튼 무한 스크롤 구현은 끝났습니다

다음에 이 앱 개발 플러스 프로젝트를 마치고

전체적으로 리팩토링을 하는 포스팅을 올리도록 하겠습니다

 

아무튼 오늘도 앱에 대한 이해도를 넓히기 위해  공부한 것은 보람이 있었다고 할 수 있겠네요

그럼 모든 분들도 보람 있는 하루가 되셨기를 바랍니다

그럼 다음 포스팅에서 뵙겠습니다

 

파이팅!

 

 

 

 

 

 

 

 

 

728x90
반응형
728x90
반응형

이미지 업로드 기능 구현하기

 

 

앱에서 이미지나 사진을 업로드할 경우 두가지 방법이있습니다

 

첫번째는 사진을 찍어서 업로드를 하는 방법

두번째는 자신의 사진첩에서 불러와 업로드 하는 방법

 

이 두가지를 방법을 구현할 수 있는 기능을 알아보도록 하겠습니다

 

공식문서 사이드바에서

공식문서 & 유용한 툴 목차를 보자

 

Expo-image-picker
이미지 픽커 공식문서

 

 

expo-image-picker 라이브러리는 설치

사진 접근 권한 알림 팝업 기능 구현

launchImageLibraryAsync를 사용해서 사진첩에 접근해서 사진을 불러옵니다

 

 

expo-image-picker 라이브러리는 설치하겠습니다

 

expo install expo-image-picker

 


 

권한 허용 함수 구현하기

 

 

사진을 등록할 경우에

접근권한을 물어보는 것이 좋을 것같습니다 

 

아래와 같이 함수를 구현하여

사진을 업로드 할 경우 권한이 가능한지에 대해

true, false를 반환하여 

값에 따라 다음 절차를 진행 여부를 판단합니다

 

const getPermission = async () => {
    if (Platform.OS !== 'web') { // is web or mobile?
          const {
            status,
          } = await ImagePicker.requestMediaLibraryPermissionsAsync();
          if (status !== 'granted') {
            alert('게시글을 업로드하려면 사진첩 권한이 필요합니다.');
            return false
          }
          return true
    }
};

 

 

위의 코드에서 ImagePicker.requestMediaLibraryPermissionsAsync();

함수를 사용해서 팝업 창이 노출되면서 허용 권한을 설정할 수 있게됩니다

그리고 한번 허용되면 다음부터는 팝업이 노출되지 않을겁니다

 

그럼 권한 허용이 되면

다음 함수를 실행합니다

 


 

 

 

반응형

 

 


 

디바이스 내 사진첩 사진 데이터 불러오기, 찍은 사진 데이터 불러오기

 

 

그럼 아래와 같이 코드를 구현합니다

이때 launchImageLibraryAsync를 사용해서 사진첩에 접근해서 사진을 불러옵니다

그리고 사진을 선택하면 함수의 리턴값으로 이미지 데이터를 받을 수 있습니다

 

또 한, launchCameraAsync 함수를 사용하면

직접 사진을 찍어서 앱 내부로 데이터를 가져올 수 있습니다

 

아래와 같이 함수를 구현합니다

 

 

const pickImage = async () => {
    console.log('이미지 선택');
    let imageData = await ImagePicker.launchImageLibraryAsync({
        mediaTypes: ImagePicker.MediaTypeOptions.All, // 이미지 타입을 지정할 수 있다
        allowsEditing: true, // 사진을 수정허용 여부을 지정한다.
        aspect: [4, 4], // 사진의 비율을 정할 수 있다.
        quality: 1, // 현재 용량을 줄이고 높일 수 있다.
    });
    console.log('이미지 데이터: ', imageData);
};

 

 

사진을 불러올때 여러가지 옵션이 있습니다

용량을 줄이거나 사진비율을 정하거나 수정을 허용여부를 정할수도 있습니다

아래에 더 자세하게 설명해놓았습니다

확인해보세요!~

 

 

 

ImagePickOption

allowsEditing
(optional)
boolean 이미지를 선택한 후 편집할 UI를 표시할지 여부입니다. Android에서는 사용자가 이미지를 자르고 회전할 수 있고 iOS에서는 단순히 이미지를 자를 수 있습니다.
Default: false
allowsMultipleSelection
(optional)
boolean Only for: Web

한 번에 여러 미디어 파일을 선택할 수 있는지 여부입니다.
aspect
(optional)
[number, number] [x, y]사용자가 이미지를 편집할 수 있는 경우( 를 전달하여) 유지할 종횡비를 지정하는 두 개의 항목이 있는 배열입니다 allowsEditing: true. iOS에서는 자르기 사각형이 항상 정사각형이기 때문에 Android에서만 적용할 수 있습니다
base64
(optional)
boolean Base64 형식의 이미지 데이터도 포함할지 여부입니다.
exif
(optional)
boolean 이미지에 대한 EXIF ​​데이터도 포함할지 여부입니다. iOS에서 EXIF ​​데이터는 카메라 케이스에 GPS 태그를 포함하지 않습니다.
mediaTypes
(optional)
MediaTypeOptions 선택할 미디어 유형을 선택합니다.
Default: ImagePicker.MediaTypeOptions.Images
presentationStyle
(optional)
UIImagePickerPresentationStyle Only for: iOS

사진/동영상을 촬영하는 동안 보기를 사용자 지정 하려면 프레젠테이션 스타일 을 선택하세요 
Default: ImagePicker.UIImagePickerPresentationStyle.Automatic
quality
(optional)
number 에서 까지 압축 품질을 지정 0합니다 1. 0작은 크기를 위한 1압축을 의미하고 최대 품질을 위한 압축을 의미합니다.
videoExportPreset
(optional)
VideoExportPreset Only for: 
iOS 11+

선택한 비디오를 압축하는 데 사용할 사전 설정을 지정합니다.
Default: ImagePicker.VideoExportPreset.Passthrough
videoMaxDuration
(optional)
number 비디오 녹화의 최대 지속 시간(초). 제한 을 0비활성화하도록 설정합니다. 기본값은 0(무제한)입니다.
  • iOS 에서 allowsEditing가 로 설정된 true경우 최대 지속 시간은 10분으로 제한됩니다. 이 제한은 0값이 지정되거나 지정되지 않은 경우 자동으로 적용됩니다.
  • Android 에서 이 옵션의 효과는 설치된 카메라 앱의 지원에 따라 다릅니다.
  •  에서 이 옵션은 효과가 없습니다. 제한은 브라우저에 따라 다릅니다.
videoQuality
(optional)
UIImagePickerControllerQualityType Only for: 
iOS

녹화된 비디오의 품질을 지정합니다. 기본값은 장치에 사용할 수 있는 최고 품질입니다.

Default: ImagePicker.UIImagePickerControllerQualityType.High

 

 

속성을 지정하고 함수를 호출하면 아래와 같이 데이터를 받을 수 있습니다

 

 

사진불러오기
이미지 데이터

 

 

이 데이터를 받아서 클라우드에 저장하면 됩니다

그 방법은 클라우드에 맞는 여러방법들이 있을것이니

그에 맞게 기능구현이 필요할 것 같습니다

 

이렇게 expo-image-picker를 구현해보있습니다

그럼 오늘도 이렇게 글을 마치겠습니다

다음 포스팅도 기대해주시고~

 

앞으로 같이 계속 공부해보아요~

 

 

 

 

728x90
반응형
728x90
반응형

AsyncStorage란?

웹에서 로컬 스토리지랑 비슷한 앱 내부에서 저장하는 라이브러리가

바로 그 것입니다

 

이 라이브러리를 사용하게 되면

로그인 후 앱을 꺼지고 나서도

로그인을 유지할 수 있도록 하는 기능입니다

 

 

React Native 사용 설치와 Expo 설치는 아래와 같이 하시길 바랍니다

yarn add @react-native-async-storage/async-storage
expo install @react-native-async-storage/async-storage

 

 

우선 로그인 기능에 

AsyncStorage함수를 사용하여

로그인 후 로컬 스토리지에 저장합니다

 

 

import * as firebase from "firebase";
import "firebase/firestore";
import { Alert } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { confirmAlert } from '../item/alertPopup'

export async function registration(nickName, email, password, navigation) {
  try {
    console.log(nickName, email, password);
    await firebase.auth().createUserWithEmailAndPassword(email, password);
    const currentUser = firebase.auth().currentUser;
    const db = firebase.firestore();
    db.collection('users').doc(currentUser.uid).set({
      email: currentUser.email,
      nickName: nickName,
    });
    Alert.alert('회원가입 성공!');
    await AsyncStorage.setItem('session', email);
    navigation.push('TabNavigator');
  } catch (err) {
    Alert.alert('무슨 문제가 있는 것 같아요! => ', err.message);
  }
}

export async function signIn(email, password, navigation) {
  try {
    await firebase.auth().signInWithEmailAndPassword(email, password);
    await AsyncStorage.setItem('session', email);
    navigation.push('TabNavigator');
  } catch (err) {
    Alert.alert('로그인에 문제가 있습니다! ', err.message);
  }
}

export function logout(navigation) {
  try {
    confirmAlert('로그아웃을 진행하시겠습니까?', async () => {
      const currentUser = firebase.auth().currentUser;
      console.log(currentUser)
      await AsyncStorage.removeItem('session');
      await firebase.auth().signOut();
      navigation.push("SignInPage")
    })
  } catch (err) {
    Alert.alert('로그 아웃에 문제가 있습니다! ', err.message);
  }
}

 

위와 같이 로그인과 로그아웃, 회원 가입할 경우

로컬 스토리지에 저장을 하게 됩니다 

 

아래는 함수의 사용법을 입니다

 

 

 

반응형

 

 

 

로컬 스토리지에서 특정값 가져오기

AsyncStorage.getItem('session', (err, result) => {
  console.log(result);
})

 

 

로컬스토리지에서 특정값 저장하기

AsyncStorage.setItem('session', email, ()=>{
  console.log('저장 완료')
});

 

 

로컬스토리지에서 특정값 삭제하기

AsyncStorage.removeItem('session');

 

 

하지만 이 라이브러리는 

약간의 단점이 존재한다

AsyncStorage는 저장할 당시 

String값의 Key-Value 체인으로 되어있기 때문에

JSON이나 Array와 같은 형식의 데이터를 저장하는데 

JSON.parseJSON.stringifyObject형식으로 변경하여 저장해야 합니다

 

 

AsyncStorage.setItem('session',JSON.stringify({'email': 'https://tantangerine.tistory.com/' }), () => {
  console.log('저장 완료')
});

AsyncStorage.getItem('session', (err, result) => {
  const MbInfo = Json.parse(result);
  console.log('email : ' + MbInfo.email);
});

 

 

위와 같이 데이터를 저장하고 가져와야 합니다

 

조금 불편 하지만 위의 코드를 함수모듈화로 

보다 쉽게 사용할 수 있을 것입니다

 

 


// AsyncStorage getItem 함수
export const getItemFromAsync = (storageName) => {
  let resultData
  AsyncStorage.getItem(storageName , (err, result) => {
    resultData = JSON.parse(result)
  });
  
  return resultData
};

// AsyncStorage setItem 함수 
export const setItemToAsync = (storageName, item) => {
  let isSuccess = false
  AsyncStorage.setItem((storageName, ,JSON.stringify(item)), (error) => {
    if(error){
      return isSuccess 
    }
  });
   return isSuccess
};

 

 

조금 엉성하지만 위와 같이 만들어 보았습니다

앱에서도 로컬 스토리지에 저장할 수 있는 방법을 알아보았습니다

 

 IT 개발자로 당당해지는 그날까지 계속 나아갑시다

대모험은 아직 끝나지 않았으니까요!!

그럼 열공하시고!

 

다음 포스팅은 파이어 베이스의 Cloud Firestore에 대해

데이터 저장 읽기 이미지 저장 등을 알아보겠습니다

 

한걸음 나아갑시다!!

 

 

728x90
반응형
728x90
반응형

Admob(애드몹)이란?

앱에서 구글의 광고를 간편하게 노출할 수 있으며,

그에 따른 수익 현황 및 관리를 도와주는 서비스입니다

 

구글에는 4가지의 광고 모델이 있습니다

 

구글 애드몹 광고 유형

 

 

 

배너

앱 레이아웃의 일부를 차지하는 사각형 광고입니다

 

 

전면

레벨 완료 등의 자연스러운 중단이나 전환시점에 게재되는 전체 페이지 광고 형식입니다

 

 

리워드

광고를 본 사용자에게 리워드를 제공하는 광고 형식입니다

 

 

네이티브 고급 광고

앱의 디자인과 분위기에 어울리게 맞춤설정할 수 있는 광고 형식입니다

 

 

 

 Expo에서도 구글 애드몹 사용이가능합니다

아래와 같이 라이브러리를 추가합니다

 

 

expo install expo-ads-admob

 

 

라이브러리를 추가 완료하면,

아래의 코드를  app.json 파일 하단부에 추가합니다

그러면 사용할 준비

 

"ios": {
      "supportsTablet": true,
      "buildNumber": "1.0.0",
      "bundleIdentifier": "##########",
      "config": {
        "googleMobileAdsAppId": ""
      }
    },
    "android": {
          "package": "##########",
          "versionCode": 1,
          "config": {
            "googleMobileAdsAppId": ""
          }
  },

 

 

 

bundleIdentifier, package는 앱 마켓들과 구글에 앱 이름을 알려주는 부분입니다.

설정은 이렇게 끝을 내고 광고 배너 생성을 알아보자

 

 

구글 광고 애드몹(AdMob) 가로 배너 생성

 

 

광고 4가지 유형에서 선택하면, 

광고 단위 설정 구성화면에서 광고 단위 이름을 지정하고 

광고 단위 만들기 버튼을 클릭해서 광고를 생성한다

 

광고 설정 화면

 

 

아래와 같이 키값이 형성되고

그 키값들은 app.json에 설정하여야 합니다

 

 

광고 생성화면

 

 

 

래의 키값은

app.json에 비워져 있던 androidgoogleMobileAdsAppId에 적용합니다

 

 

 

광고 SDK

 

 

 

아래의 키값은 

AdMobBanner 컴포넌트의 adUnitId 속성에 적용합니다

 

 

 

광고 유닛키

 

 

아래와 같이 코드를 작성하면 제일 하단에 광고가 노출될 수 있습니다

여러 속성들은 사이드바에 Expo 애드몹 공식문서를 참조하세요

 

 

{Platform.OS === 'ios' ? (
                <AdMobBanner
                  bannerSize="fullBanner"
                  servePersonalizedAds={true}
                  adUnitID="ca-app-pub-3271224099084995/4041258226"
                  onDidFailToReceiveAdWithError={bannerError}
                  style={styles.banner}
                />
            ) : (
                <AdMobBanner
                  bannerSize="fullBanner"
                  servePersonalizedAds={true}
                  adUnitID="ca-app-pub-3271224099084995/5120026862"
                  onDidFailToReceiveAdWithError={bannerError}
                  style={styles.banner}
                />
            )}

 

 

AdMobBanner 컴포넌트는 아래와 같이 속성을 가지고 있습니다

 

 

banner 휴대폰 및 태블릿용 표준 배너 320x50
largeBanner 휴대폰 및 태블릿용 대형 배너 320x100
mediumRectangle 휴대폰 및 태블릿용 IAB 중간 직사각형 300x250
fullBanner 태블릿용 IAB 전체 크기 배너 468x60
leaderboard 태블릿용 IAB 리더보드 728x90
smartBannerPortrait 휴대폰 및 태블릿용 스마트 배너(기본값) 화면 너비 x 32
smartBannerLandscape 휴대폰 및 태블릿용 스마트 배너 화면 너비 x 32

 

 

광고 단위 생성은 

전면, 리워드, 네이티브 고급 광고도 위와 같이 생성하여

두 개의 키값을 사용하면 됩니다.

 

 

구글 광고 애드몹(AdMob) 전면 배너 생성

전면 광고를 사용자들에게 아래와 같이 노출하는 광고를 생성합시다

 

전면 광고 노출

 

 

아래의 코드를 작성하면 

꿀팁인 카드 컴포넌트를 클릭하면 전면광고가 뜨고

전면 광고 노출 일정 시간 후 디테일 페이지로 이동하게 됩니다

 

그리고 ios와 안드로이드의 분기를 하여 키값을 따로 설정해줍니다

그리고 로드를 시작할 때 함수와 로드를 끝날때 함수와 광고 시작할때 함수 광고가 끝날대 함수를 설정해서

광고가 끝나거나 시작할때 어떠한 함수를 실행할 수 있습니다

 

가장 중요한 것은 애드몹도 외부 API 이므로 실행 순서를

지키기 위해 async/await 사용해야 한다는 것입니다

 

import React, { useEffect } from 'react';
import {View, Image, Text, StyleSheet,TouchableOpacity,Platform} from 'react-native'
import {
  setTestDeviceIDAsync,
  AdMobBanner,
  AdMobInterstitial,
  PublisherBanner,
  AdMobRewarded
} from 'expo-ads-admob';

export default function Card({content,navigation}){

    useEffect(()=>{
        Platform.OS === 'ios' 
            ? AdMobInterstitial.setAdUnitID("ca-app-pub-5579008343368676/6838730428") 
            : AdMobInterstitial.setAdUnitID("ca-app-pub-5579008343368676/4903859898")

        AdMobInterstitial.addEventListener("interstitialDidLoad", () =>
            console.log("interstitialDidLoad")
        );
        AdMobInterstitial.addEventListener("interstitialDidFailToLoad", () =>
            console.log("interstitialDidFailToLoad")
        );
        AdMobInterstitial.addEventListener("interstitialDidOpen", () =>
            console.log("interstitialDidOpen")
        );
        AdMobInterstitial.addEventListener("interstitialDidClose", () => {
            console.log("interstitialDidClose")
          
        });
    },[])
    const goDetail = async () =>{
      try {
        await AdMobInterstitial.requestAdAsync({ servePersonalizedAds: true});
        await AdMobInterstitial.showAdAsync();
        await navigation.navigate('DetailPage',{idx:content.idx})
      } catch (error) {
        console.log(error)
        await navigation.navigate('DetailPage',{idx:content.idx})
      }
    }

    return(
        <TouchableOpacity style={styles.card} onPress={()=>{goDetail()}}>
            <Image style={styles.cardImage} source={{uri:content.image}}/>
            <View style={styles.cardText}>
                <Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text>
                <Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text>
                <Text style={styles.cardDate}>{content.date}</Text>
            </View>
        </TouchableOpacity>
    )
}

 

 

 

setAdUnitID, requestAdAsync, showAdAsync 등의 함수는 아래와 같이 설명을 확인할 수 있습니다

 

그리고 광고 노출 전 키값을 먼저 세팅하고 함수들을 지정함으로써

광고 상태로 함수를 실행할 수 있습니다

 

그 후 detailPage로 이동하는 함수에 requestAdAsync 함수와 showAdAsync를 사용하여

전면광고를 노출합니다

 

다시 말하지만 비동기가 중요합니다!!

 

그리고 useEffect인 화면 첫 랜더링 시 실행하는 함수들을 나열하는 것 또한 중요합니다!!

 

 

 

이렇게 구글의 애드몹 광고 배너와 전면광고 노출하는 방법을 알아보았습니다

다음에는 시간이 있다면 다른 광고들도 한번 알아보도록 하겠습니다

 

그럼!

 

 

 

 

 

 

 

 

 

 

728x90
반응형
728x90
반응형

탭 네비게이션 활용 및 설정 법은 이전 글 포스팅으로 확인하세요

 

 

2022.07.17 - [Mobile/React Native] - 리액트 네이티브 X EXPO 탭 네비게이터 설정 및 TabNavigator 사용방법을 알아보자

 

리액트 네이티브 X EXPO 탭 네비게이터 설정 및 TabNavigator 사용방법을 알아보자

탭 내비게이터란? 여러 앱들이 아래의 UI를 많이 채택해서 사용하고 있습니다 탭이라는 하단 영역에 직관적인 아이콘을 사용함으로써 페이지 이동을 보다 자유롭게 하게 함입니다 스택 내비게

tantangerine.tistory.com

 

 

 

메인 페이지에는 많은 이미지들이 존재합니다

이처럼 이미지가 많은 페이지라면 이미지가 지연없이 부드럽게 호출할 수 있게

react-native-image-blur-loading 라이브러리를 사용하도록 하겠습니다

 

 

라이브러리를 다음과 같이 추가합니다

 

yarn add react-native-image-blur-loading

 

 


 

 

메인페이지 구성 및 배너카드 구성하기

 

 

mainPage를 아래와 같이 코드를 작성합니다

메인페이지에 Grid 컴포넌트를 사용해서 메인에서 한개의 배너카드를 구현할 수 있습니다

이렇게 로고 배너를 삽입하여 어떠한 정보를 노출할 수 있습니다

CardComponent에 적용하는 것이 아니라

메인에 적용하여 단발적인 배너카드만 적용하게된다

 

 

배너 카드

 

 

 

import React from 'react';
import { StyleSheet, View } from 'react-native';
import { Col, Grid } from 'react-native-easy-grid';
import { Container, Content, Icon, Text } from 'native-base';
import CardComponent from '../components/CardComponent';
import HeaderComponent from '../components/HeaderComponent';

const data = require('../data2.json');
export default function MainPage({ navigation }) {
  return (
    <Container>
      <HeaderComponent />
      <Content>
        <Grid style={styles.banner}>
          <Col size={1} style={{ padding: 20 }}>
            <Icon name="paper-plane" style={{ color: 'deeppink' }} />
          </Col>
          <Col size={6} style={{ padding: 15 }}>
            <Text>이야기 하고 싶은 친구들에게</Text>
            <Text style={{ fontWeight: '700' }}>wegram을 전하세요</Text>
          </Col>
        </Grid>
        <Grid style={{ padding: 20 }}>
          <Text style={{ color: 'grey' }}>FROM THE DIARY</Text>
        </Grid>
        <View style={{ marginTop: -20 }}>
          {data?.diary?.map((content, i) => {
            return (
              <CardComponent
                content={content}
                key={i}
                navigation={navigation}
              />
            );
          })}
        </View>
      </Content>
    </Container>
  );
}

const styles = StyleSheet.create({
  banner: {
    backgroundColor: '#F6F6F6',
    height: 70,
    borderRadius: 10,
    width: '90%',
    alignSelf: 'center',
  },
});

 

구조는 네이티브 베이스를 사용해서 Grid, Col 사용한것을 확인 할수 있습니다.

 

또 한,

CardComponent, HeaderComponent를사용하여 아래와 같이 구현하게됩니다.

 

메인페이지 이미지

 

헤더컴포넌트에 대한 코드는 아래와 같습니다.

 

 

네이티비 베이스의 Header컴포넌트를 사용하여

transparent의 속성을 부여하여 배경색을 제거합니다.

 

여기에서 중요 포인트는 Left, Right를 사용하여 

왼쪽에는 로고와 오른쪽에는 토글이미지의 설정기능할 수 있는 영역을 지정합니다

이것으로 HeaderComponent 구성은 쉽게 끝낼 수 있습니다.

 

 

 

반응형

 

 


 

HeaderComponent  구성하기

 

 

헤더 이미지

 

import React from 'react';
import { StyleSheet, Image, View } from 'react-native';
import { Header, Left, Icon, Right, Text, Button } from 'native-base';

const logo = require('../assets/logo.png');

export default function HeaderComponent() {
  return (
    <Header transparent>
      <Left>
        <Button transparent>
          <Image source={logo} style={styles.logoImage} />
        </Button>
      </Left>
      <Right>
        <Icon name="ellipsis-horizontal" style={{ color: 'deeppink' }} />
      </Right>
    </Header>
  );
}

const styles = StyleSheet.create({
  logoImage: { width: 100, resizeMode: 'contain', marginLeft: 10 },
});

 

 

 

위의 코드는 HeaderComponent 입니다.

 

 


 

CardComponent 구성 및 ImageBlurLoading 구성하기

 

 

CardComponent는 위에 설명했듯이

ImageBlurLoading 컴포넌트를 사용하였습니다

이미지를 부드럽게 호출할 수 있는 라이브러리 입니다

 

ImageBlurLoading 속성에

thumbnailSource는 이미지가 로딩될때 보여지는 이미지를 출력합니다

withIndicator는 이미지로딩시 로딩중이라고 알려주는 기능입니다

source는 이미지 데이터입니다

이때 ImageBlurLoading 컴포넌트는 CardItem에 사용하여 한개의 이미지를 컴포넌트로 생각한다

 

그리고 CarItemCard에서 CarItem을 사용하여 영역을 지정하여

편리하게 이미지를 구현할 수 있습니다

 

 

import React from 'react';
import { StyleSheet, Image, TouchableOpacity } from 'react-native';
import { Col, Row, Grid } from 'react-native-easy-grid';
import { Icon, Text, Card, CardItem } from 'native-base';
const image = require('../assets/background2.png');
const logo = require('../assets/logo.png');
import ImageBlurLoading from 'react-native-image-blur-loading';

export default function CardComponent({ navigation, content }) {
  return (
    <TouchableOpacity
      onPress={() => {
        navigation.navigate('NewDetailPage', { content: content });
      }}
      style={styles.container}
    >
      <Card style={styles.card} transparent>
        <CardItem transparent>
          <ImageBlurLoading
            withIndicator
            thumbnailSource={{ uri: content?.image }}
            source={{ uri: content?.image }}
            style={styles.image}
          />
        </CardItem>
        <CardItem style={{ marginTop: -10 }}>
          <Grid>
            <Col size={9}>
              <Text numberOfLines={1} style={styles.title}>
                {content.title}
              </Text>
              <Text style={[styles.grey, styles.writer]}>{content.author}</Text>
            </Col>
            <Col size={2}>
              <Grid>
                <Col>
                  <Icon name="chatbox-outline" style={styles.grey} />
                </Col>
                <Col>
                  <Icon name="heart-outline" style={styles.grey} />
                </Col>
              </Grid>
            </Col>
          </Grid>
        </CardItem>
      </Card>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  container: { alignItems: 'center', alignSelf: 'center' },
  card: {
    width: '100%',
    alignSelf: 'center',
  },
  image: { height: 200, width: '100%', borderRadius: 10 },
  grey: { color: 'grey' },
  writer: { fontSize: 12, color: 'grey', marginLeft: 10 },
  title: { fontWeight: '700', fontSize: 15, marginLeft: 10 },
});

 


 

 

 

이렇게 메인페이지를 구현해보았습니다

이번에는 CardComponentImageBlurLoadingCarItem을 활용하였습니다

CarItem은 사이드 메뉴의 Expo의 공식문서를 보면서 더욱 활용도를 높여보세요

 

언제나 배우면 배울수록 끝이 없는것같다고 생각이 드네요

화이팅 하시고 힘내세요!!

 

아직 우리의 IT대모험은 끝나지 않았으니까요!!

파이팅!

 

 

 

728x90
반응형
728x90
반응형

 

탭 내비게이터란?

 

여러 앱들이 아래의 UI를 많이 채택해서 사용하고 있습니다

탭이라는 하단 영역에 직관적인 아이콘을 사용함으로써

페이지 이동을 보다 자유롭게 하게 함입니다

 

스택 내비게이터와 비슷하며 두 개를 같이 사용한다고만 알고 계시고 

예문을 보면서 같이 알아보도록 하겠습니다

 

 

 

2022.07.04 - [Mobile/React Native] - React Native_스택 내비게이션 활용 페이지와 컴포넌트 이동

 

React Native_스택 네비게이션 활용 페이지와 컴포넌트 이동

스택 네비게이션이란? 컴포넌트에서 컴포넌트로 이동을 용이하게 해주는 기능이다. 즉 페이지를 이동하는 방법이라고 생각하면된다. 컴포넌트를 이동이라고는 하지만 솔직히 페이지 이동이라

tantangerine.tistory.com

 

 

탭 네비게이터 설정방법

 

 

페이지 구성

 

마이페이지와 그리고 메인 페이지, 팁 페이지, 페이지를 추가할 페이지를 

만들어 보겠습니다

 

 

탭 네비게이터 영역의 아이콘 노출이미지

 

 

 

각각 영역을 선택하게 되면 아래와 같은 페이지가 노출되게 연결하겠습니다

 

 

구현 할 페이지 이미지

 

 

탭 내비게이터 영역에 들어갈 페이지를 컴포넌트로 탭 내비게이터와 연결합니다

 

 

탭 네비게이터 라이브러리 추가

 

아래와 같이 라이브러리를 추가하여 줍니다.

 

yarn add @react-navigation/bottom-tabs

 

 

TabNavigator.js 파일을 생성하고 

아래와 같이 코드 작성을 합니다

 

 

탭 네비게이터 코드 작성

 

import React, { useEffect } from 'react';

import { Platform } from 'react-native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

import TipPage from '../pages/TipPage';
import MainPage from '../pages/MainPage';
import MyPage from '../pages/MyPage';
import AddPage from '../pages/AddPage';
import { Ionicons } from '@expo/vector-icons';

const Tabs = createBottomTabNavigator();

const TabNavigator = ({ navigation, route }) => {
  return (
    <Tabs.Navigator
      screenOptions={({ route }) => ({
        tabBarShowLabel: true,
        tabBarStyle: {
          backgroundColor: '#fff',
          borderTopColor: '#eee',
          height: 40,
          fontSize: 10,
        },
        tabBarIcon: ({ focused }) => {
          let iconName = Platform.OS === 'ios' ? 'ios-' : 'md-';

          if (route.name === 'MainPage' || route.name === 'TipPage') {
            iconName += 'list';
          } else if (route.name === 'AddPage') {
            iconName += 'apps-outline';
          } else if (route.name === 'MyPage') {
            iconName += 'person';
          }
          return (
            <Ionicons
              name={iconName}
              color={focused ? 'hotpink' : 'grey'}
              size={26}
            />
          );
        },
      })}

    >
      <Tabs.Screen name="MyPage" component={MyPage} />
      <Tabs.Screen name="MainPage" component={MainPage} />
      <Tabs.Screen name="TipPage" component={TipPage} />
      <Tabs.Screen name="AddPage" component={AddPage} />
    </Tabs.Navigator>
  );
};

export default TabNavigator;

 

 

위의 코드를 보시면 화면 아래 탭 영역에 추가할 페이지를 컴포넌트 속성에 할당합니다

그러면 아래 탭 영역에는 4개의 아이콘이 노출되는 것을 확인할 수 있습니다

 

 

그리고 위의 아이콘들은 Expo에서 제공하는 아이콘들입니다

 

 

Expo 아이콘 활용하기

라이브러리를 아래와 같이 추가하시면 사용이 가능합니다

 

 

expo install expo-font

 

 

라이브러리를 사용하는데 약간의 규칙이 있습니다

아래의 부분을 보시면

Palatform.os의 함수를 사용하면 ios인지 안드로이드 인지 구분을 할 수 있는 값을 return 합니다

그 값을 활용해서 사용할 아이콘의 이름을 플랫폼별 다른 값을 더해 노출할 수 있습니다 

 

그리고 focused를 통해 클릭할 당시의 색깔을 변경할 수 있습니다

 

 

 

 

반응형

 

 

 

탭 네비게이션의 속성 활용법

 

 

플렛폼별 아이콘 설정법

 

 

또한,

공식문서를 보면 더 많은 아이콘들을 확인할 수 있습니다

그리고 공식 문서는 사이드 메뉴에 라이브러리 공식문서 칸에 등록해놓겠습니다

 

 

전체 방문자 밑에 있으니 클릭해서 보세요

 

 

expo 공식문서 소개

 

 

그리고!

screenOptions에 여러 가지 속성을 부여할 수 있다

경우에 맞게 속성을 부여해 봅시다~

 

  • tabBarActiveTinitColor : 활성화된 항목의 아이콘과 텍스트 색상
  • tabBarActiveBackgroundColor : 활성화된 항목의 배경색
  • tabBarInactiveTintColor : 비활성화된 항목의 아이콘과 텍스트 색상
  • tabBarInactiveBackgroundColor : 비활성화된 항목의 배경색
  • tabBarShowLabel : 항목에서 텍스트의 가시성 설정(default : true)
  • tabBarShowIcon : 항목에서 아이콘의 가시성 설정(default : false)
  • tabBarStyle : 하단 탭 스타일
  • tabBarLabelStyle : 텍스트 스타일
  • tabBarItemStyle : 항목 스타일
  • tabBarLabelPosition : 텍스트 위치
    - beside-icon : 아이콘 우측
    - below-icon : 아이콘 하단
  • tabBarAllowFontScaling : 시스템 폰트 크기에 따라 폰트 크기를 키울지 결정(default : true)
  • tabBarSafeAreaInset : SafeAreaView의 forceInset 덮어쓰는 객체(default: {bottom: 'always', top: 'naver'})
  • tabBarKeyBoardHidesTabBar : 키보드가 나타날 때 하단 탭을 가릴지 결정(default : false)

 

 

 

screenOptions에서 route 값을 활용하고 싶으면

화살표 함수를 이용해서 return으로 통으로 값을 할당할 수 있습니다

그래서 현재 name를 활용해서 플랫폼 별 아이콘을 설정할 수 있습니다

 

 

scrennOption 설정 방법

 

route name 활용

 

 

routefocused 이외에도 여러 속성이 존재합니다

아래와 같이 screenOptions에 있는 속성들을 navigation안에 여러 함수들과

조금 전에 사용한 route를 보실 수 있습니다

 

 

screenOptions 속성

 

 

tabBarIcon에도 여러 가지 속성을 확인하실 수 있습니다

 

tabBarIcon 속성

 

여러 가지를 속성들을 확장연산자를 사용하여 object안에 있는 변수를 바로 사용하는 모습을 볼수 있어요

상황에 맞게 여러가지 속성들을 사용하면 될 것 같습니다

다른 옵션에도 어떠한 속성들이 있는지 확장 연사자를 쓰지 전에 props로 받아서 

console.log()로 확인을 해보시길 바랍니다.

 

 

stackNavigator.js에 상단에 추가해주면 되겠습니다

return의 상단에 하셔야 합니다!!

<Stack.Screen name="TabNavigator" component={TabNavigator} options={{ headerShown: false }}/>

 

 

이것으로 탭 내비게이션의 설정법을 알아보았습니다

다음에는 활용법을 알아보도록 하겠습니다

그런데 너무 길어지지 다음 포스팅에 알아보도록 하겠습니다

 

오늘도 조금 어려운 점이 없지 않았나 하고 생각 드네요

그래도 새로운 것을 공부하는 것은 필요하다고 생각합니다

IT 개발자들은 필수이지요!!

 

자체 플랫폼 서비스를 하는 곳에서는

쓰는 언어나 패턴들이 정형화되어 새로운 공부를 하지 않게 되는데

요즘 개발자가 귀한 상황이니 열심히 공부해서 더 좋은 곳으로 이직하는 것도 좋은 방법이겠네요

 

파이팅 하시고 힘들어도 힘내세요!

아직 대모험은 끝나지 않았으니까요!

파이팅!!

 

728x90
반응형
728x90
반응형

 

앱이나 웹을 만들 때 여러 가지 어려움이 있겠지만 그중에 스타일이 아닐까 합니다

화면을 스타일링은 익숙하지 않은 사람들에게는

시간이 꽤나 걸리는 작업일 것입니다

 

그래서 스타일링을 간편하게 도와주는 NativeBase 라이브러리가 있습니다

 

공식 홈페이지를 들어가면 더 상세한 정보를 알 수 있습니다

https://docs.nativebase.io

 

Getting Started | NativeBase | Universal Components for React and React Native

NativeBase 3.0 lets you build consistently across android, iOS & web. It is inspired by the Styled System and is accessible, highly themeable, and responsive.

docs.nativebase.io

 

한 가지를 같이 살펴보자면

 

위와 같이 여러 FORMS, DATE DISPAY, LAYOUT 등 여러 가지를 지원하고 있습니다

그중 FORMS의 INPUT을 보도록 하겠습니다

 

 

 

속성에 값을 할당하는 것만으로 손쉽게 스타일링을 할 수 있는 장점이 있습니다

시간 절약과 디자인이 조금 힘든 사람이라면 사용하는 것도 용이한 것 같습니다

 

 

 

 

 

 

그리고 아래와 같은 속성 값을 받아 여러 가지 기능도 같이 활용할 수 있습니다

 

 

 

 

그럼 직접 코딩을 한번 해보겠습니다

우선 아래와 같이 설치를 합니다

 

yarn add native-base@2 --save

 

NativeBase의 기능을 알아보자

 

 

앱의 상단 헤더 바 구현이 용이하다

아래와 같이 라이브러리의 컴포넌트를 사용하여 구성해 줍니다

 

import React, { Component } from 'react';
import { Container, Header, Content, Footer, Text } from 'native-base';
export default regiMember = () => {

    return (
      <Container>
        <Header />
        <Content padder>
          <Text>
          </Text>
        </Content>
        <Footer />
      </Container>
    );
 
}

 

 

상단 헤더 노출 이미지

 

위와 같이 헤드가 생성된 것을 확인할 수 있습니다

그러면 해더의 왼쪽, 오른쪽 <Left />, <Right />로

백키와 마이페이지 같은 활성 창을 노출시키는 기능을 구현할 수 있겠죠?

 

 

 

키보드 노출 및 태그에 필요한 액션 기능이 용이하다

 

input 같은 태그에 입력을 할 경우 키보드가 노출되는 기능도 <Content /> 태그로 구현한다면 

간편하게 구현할 수 있습니다

 

키자판 노출

 

 

레이아웃 구성이 직관적이다

 

가로세로 구분을 직관적으로 표현할 수 있습니다

Col, Row의 값으로 구분할 수 있으며, size의 속성으로 범위를 지정할 수 있습니다

 

import React, { Component } from 'react';
import { Container, Header } from 'native-base';
import { Col, Row, Grid } from 'react-native-easy-grid';
export default layout = () => {
    return (
      <Container>
        <Header />
        <Grid>
          <Col
            size={2}
            style={{ backgroundColor: '#635DB7', height: 200 }}
          ></Col>
          <Col
            size={1}
            style={{ backgroundColor: '#00CE9F', height: 200 }}
          ></Col>
        </Grid>
      </Container>
    );
}

 

 

아래와 같이 화면이 노출되고

지정된 영역도 직관적으로 확인이 가능합니다

 

레이아웃 화면

 

그 외에도 여러 가지 태그 속성들이 있습니다

잘 활용한다면 쉽게 스타일링할 수 있을 것 같습니다

 

태그 속성 목록

 

지금까지 nativeBase 라이브러리를 알아보았습니다

이것을 바탕으로 로그인 화면을 만들어 보려고 합니다

그럼 그때 다시 공부하도록 합시다!

 

언제나 그렇듯 코딩 공부는 힘이 들고 어렵네요

그래도 목표가 있으니!!

조금만 같이 힘내세요!!

 

아직 대모험은 끝나지 않았으니!!ㅋㅋ

파이팅!!

 

 

728x90
반응형
728x90
반응형

 

이전 포스팅이였던  스택 네비게이션도 한번 확인 해보세요~

 

2022.07.04 - [Mobile/React Native] - React Native_스택 네비게이션 활용 페이지와 컴포넌트 이동

 

React Native_스택 네비게이션 활용 페이지와 컴포넌트 이동

스택 네비게이션이란? 컴포넌트에서 컴포넌트로 이동을 용이하게 해주는 기능이다. 즉 페이지를 이동하는 방법이라고 생각하면된다. 컴포넌트를 이동이라고는 하지만 솔직히 페이지 이동이라

tantangerine.tistory.com

 

 

앱 공유하기 기능 - Share

 

유튜브나 블로그 글 같은 것을 보다 보면 공유하기 버튼을 클릭해서

앱들 간의 다른 사람들과 공유하는 기능을 보실 수 있었을 것입니다.

 

react-nativeShare함수를 사용하면 간편하게 기능을 구현할 수 있습니다

 

 

import { Share } from "react-native"

 

위와 같이 import를 해서 사용합니다

 

Share.share({ message: '내용' });

 

 

share 함수를 사용하면 우리가 흔히 볼 수 있는 공유 창이 나타나고 내용들이 메세지로 전달됩니다.

 

 

import React from 'react';
import { TouchableOpacity,Share } from 'react-native';


export default function DetailPage({navigation,route}) {	
    const share = () => {
        Share.share({
            message:`${tip.title} \n\n ${tip.desc} \n\n ${tip.image}`,
        });
    }
    
    return (
      <TouchableOpacity style={styles.button} onPress={()=>share()}>
        <Text style={styles.buttonText}>
          공유하기
        </Text>
      </TouchableOpacity>
    )
}

 

TouchableOpactiy 컴포넌트에 onPress속성에 share함수만 넣어서 실행하면됩니다.

 그때 실행할 때 인자값으로 공유할 내용을 같이 전달하면 기능 구현은 끝입니다.

 

 

아래와 같이 공유 기능이 노출됩니다

 

공유하기 버튼클릭시 이미지

 

반응형

 

 

공유 전달된 이미지

 

이미지도 지금은 글자로 들어가지만 

<img> 태그를 사용하면 문자로 보낼 경우 이미지를 노출시킬수도 있습니다

 

 


 

앱 외부링크 이동 기능 - Linking 

 

앱에서 외부링크를 여는 방법은 Expo에 제공해주는 라이브러리를 설치하여 

LinkingopenURL 함수를 사용하여 기능 구현을 합니다

 

import React from 'react';
import { TouchableOpacity,Share } from 'react-native';


export default function DetailPage({navigation,route}) {	
    const link = () => {
        Linking.openURL("https://spartacodingclub.kr")
    }
    
    return (
       <TouchableOpacity style={styles.button} onPress={()=>link()}>
         <Text style={styles.buttonText}>
           외부 링크
         </Text>
       </TouchableOpacity>
    )
}

 

정말 위의 코드만 보면 정말 간단하죠?

 

코드를 작성하면서 저 또한  앱에 대한 기능 공부를 복습하게되었습니다

저도 저만의 앱을 만들려고 앱을 공부하고 있습니다

 

아직까지 모험은 끝나지 않았으니까요!!

오늘도 한 발자국 나아갑시다!!

화이팅!!

 

728x90
반응형
728x90
반응형

스택 네비게이션이란?

컴포넌트에서 컴포넌트로 이동을 용이하게 해주는 기능이다.

즉 페이지를 이동하는 방법이라고 생각하면된다.

 

페이지이동에 대한 과정이다

 

컴포넌트를 이동이라고는 하지만 솔직히 페이지 이동이라고 하는것이 맞는 것 같아요.

하지만 컴포넌트 이동이라고 표현하는 것도 코드 구조를 보면 약간은 이해가 갈거예요.

 

왜 그렇냐면 화면에 노출 시킬 페이지를 import하여 Stack.Screen 속성 component에 할당합니다.

모든 페이지를 그렇게 연결하게되면 페이지이동을 간편하게 할 수 있습니다

 

아래의 코드를 보고 다시 한번 더 확인해보아요.

 

 

스택네비게이션의 활용방법

 

라이브러리 설치

yarn add @react-navigation/stack

 

 

/navigation/StackNavigator.js

폴더를 생성하고 파일을 만들어 코드 작성을 합니다.

 

StackNavigator.js

import React from 'react';
import { createStackNavigator } from '@react-navigation/stack';

import DetailPage from '../pages/DetailPage';
import MainPage from '../pages/MainPage';

const Stack = createStackNavigator();

const StackNavigator = () =>{
    return (
         <Stack.Navigator
            screenOptions={{
                headerStyle: {
                    backgroundColor: "white",
                    borderBottomColor: "white",
                    shadowColor: "white",
                    height:100
                },
                headerTitleAlign:'left',
                headerTintColor: "#000",
                headerBackTitleVisible: false
            }}
            
        >
            <Stack.Screen name="MainPage" component={MainPage}/>
            <Stack.Screen name="DetailPage" component={DetailPage}/>
        </Stack.Navigator>
    )
}

export default StackNavigator;

 

 

createStackNavigator() 함수를 변수에 할당하여 변수로 활용합니다.

 

Stack에 저장된 스택 네비게이션에는 몇가지 태그가 존재한다. 그 중에는 Navigator, Screen있습니다.

 

 

Stack.Navigator

Stack.Navigator는 페이지에 헤더가 되는 부분을 스타일링을 해주는 컴포넌트있습니다.

이 컴포넌트에서는 페이지에서 헤더가 별도로 존재하지않아도 공통으로 관리할 수 있습니다.

배경 색깔, 버튼 색깔, 페이지 타이틀, 타이틀 위치 등등

 

 

Stack.Screen

Stack.Screen은 활용하면 페이지를 할당해서 스택 네비게이션 함수를 사용하여

스택 네비게이션에 관리가 용이하다. 그리고 Stack.Screen에 등록됩니다.

모든 페이지들은 navigationrouter 객체를 넘겨받아 사용할 수 있습니다.

 

navigation.setOptions({ title: '메인 페이지' })

- 해당 페이지의 제목을 설정할 수 있습니다.

 

navigation.navigate("DetailPage")

- Stack.screen에서 등록된 속성 name으로 지정하면 페이지로 이동하는 함수입니다.

 

navigation.navigate("DetailPage", { title: '페이지' })

- 페이지를 이동하면서 두번째 인자값의 객체를 이동된 페이지에서 router로 받을 수 있습니다.

 

 

이러한 기능들이 다 사용하여 페이지를 이동시 데이터를 주고 받을 수 있습니다.

그럼 메인 페이지의 코드와 상세 페이지의 코드를 확인해서 어떻게 사용하는지 확인해 보아요!! 

 

 

MainPage.js

import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, TouchableOpacity, ScrollView} from 'react-native';

const main = 'https://storage.googleapis.com/sparta-image.appspot.com/lecture/main.png'
import data from '../data.json';
import Card from '../components/Card';
import Loading from '../components/Loading';
import { StatusBar } from 'expo-status-bar';
export default function MainPage({navigation,route}) {
  const [state,setState] = useState([])
  const [cateState,setCateState] = useState([])
  const [ready,setReady] = useState(true)

  useEffect(()=>{
    setTimeout(()=>{
        navigation.setOptions({
          title:'메인 페이지'
        })  
        setState(data.tip)
        setCateState(data.tip)
        setReady(false)
    },1000)
 
    
  },[])

  const category = (cate) => {
    if(cate == "전체보기"){
        setCateState(state)
    }else{
        setCateState(state.filter((d)=>{
            return d.category == cate
        }))
    }
}

  let todayWeather = 10 + 17;
  let todayCondition = "흐림"

  return ready 
    ? <Loading/> 
    :  (
        <ScrollView style={styles.container}>
          <StatusBar style="light" />
          <Image style={styles.mainImage} source={{uri:main}}/>
          <View style={styles.cardContainer}>
             {
              cateState.map((content,i)=>{
                return (<Card content={content} key={i} navigation={navigation}/>)
              })
            }
          </View>
        </ScrollView>
       )
}

 

navigation.setOptions({ title:'메인 페이지' })  

 

navigation.setOptions를 사용하여 현재 페이지의 타이틀, 배경색깔등을 변경할 수 있습니다

 

 

반응형

 

<Card navigation={navigation}  />

 

위와 같이 컴포넌트에 navigation을 전달하게되면

해당 컴포넌트 내부에서 navigation을 사용하여 detailPage 화면으로 이동할 수 있습니다.

 

 

Card.js

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

export default function Card({content,navigation}){
    return(
        <TouchableOpacity style={styles.card} onPress={()=>{navigation.navigate('DetailPage',content)}}>
            <Image style={styles.cardImage} source={{uri:content.image}}/>
            <View style={styles.cardText}>
                <Text style={styles.cardTitle} numberOfLines={1}>{content.title}</Text>
                <Text style={styles.cardDesc} numberOfLines={3}>{content.desc}</Text>
                <Text style={styles.cardDate}>{content.date}</Text>
            </View>
        </TouchableOpacity>
    )
}

 

navigation.navigate('DetailPagae', content)

 

인자 값으로 받은 content와, navigation 두개를 활용하여

<TouchableOpacity /> 컴포넌트에서 onPress 속성에 스택네비게이션 함수를 사용하는 모습을 볼 수 있습니다

 

 

그래서 MainPage에서 Card 리스트가 노출되어 클릭을 하는 순간

Card의 이벤트로 DetailPage로 화면이동이 됩니다

 

 

DetailPage.js

import React,{useState,useEffect} from 'react';
import { StyleSheet, Text, View, Image, ScrollView,TouchableOpacity,Alert } from 'react-native';

export default function DetailPage({navigation,route}) {
    const [tip, setTip] = useState({
        "idx":9,
        "category":"재테크",
        "title":"렌탈 서비스 금액 비교해보기",
        "image": "https://storage.googleapis.com/sparta-image.appspot.com/lecture/money1.png",
        "desc":"요즘은 정수기, 공기 청정기, 자동차나 장난감 등 다양한 대여서비스가 활발합니다. 사는 것보다 경제적이라고 생각해 렌탈 서비스를 이용하는 분들이 늘어나고 있는데요. 다만, 이런 렌탈 서비스 이용이 하나둘 늘어나다 보면 그 금액은 겉잡을 수 없이 불어나게 됩니다. 특히, 렌탈 서비스는 빌려주는 물건의 관리비용까지 포함된 것이기에 생각만큼 저렴하지 않습니다. 직접 관리하며 사용할 수 있는 물건이 있는지 살펴보고, 렌탈 서비스 항목에서 제외해보세요. 렌탈 비용과 구매 비용, 관리 비용을 여러모로 비교해보고 고민해보는 것이 좋습니다. ",
        "date":"2020.09.09"
    })
    
    useEffect(()=>{
        console.log(route)
        navigation.setOptions({
            title:route.params.title,
            headerStyle: {
                backgroundColor: '#000',
                shadowColor: "#000",
            },
            headerTintColor: "#fff",
        })
        setTip(route.params)
    },[])

    const popup = () => {
        Alert.alert("팝업!!")
    }
    return ( 
        <ScrollView style={styles.container}>
            <Image style={styles.image} source={{uri:tip.image}}/>
            <View style={styles.textContainer}>
                <Text style={styles.title}>{tip.title}</Text>
                <Text style={styles.desc}>{tip.desc}</Text>
                <TouchableOpacity style={styles.button} onPress={()=>popup()}><Text style={styles.buttonText}>팁 찜하기</Text></TouchableOpacity>
            </View>
        </ScrollView>
    
    )
}

 

Card 컴포넌트에서 두번째 인자값으로 content를 전달했었죠?

 

navigation.navigator 함수로 전달 할 경우

Stack.Screen으로 component를 연결해야지만 router로 받을수 있습니다

 

router.params 안에 객체의 값이 들어 있으니 참고하세요!

 

 

 

지금까지 스택네비게이션을 알아보았습니다.

복잡하지만 차근 차근 구조를 익히다보면 쉽게 하실수 있을거예요

 

마지막으로 간략히 설명하자면,

 

처음 스택네비게이션을 설치 후

파일을 만든다음 Stack.Navigator의 부모태그와 Stack.Screen의 자식태그로 지정하여

코드를 작성해주고 원하는 페이지를 속성으로 묶어 주기만하면 끝이라는 점!

 

그리고

부모태그 자식태그의 파일을 import 해서 사용하기만 하면

된다는 점을 인지하여 주시길바랍니다

 

 

이렇게 오늘도 저도 복습하며 블로그를 이어나가네요

요즘 다시 블로그를 살려볼려고 힘을 내고 있습니다

 

모두들 대모험은 아직 끝나지 않았습니다

화이팅 하시고 

 

다음 포스팅에서 뵐게요~

 

 

이전 포스팅은 밑에서~

2022.06.30 - [모바일/React Native] - [React Native X Expo] View, ScrollView, Text, Button, TouchableOpacity, Image 엘리먼트 & 태그 활용 리액트 네이티브

 

[React Native X Expo] View, ScrollView, Text, Button, TouchableOpacity, Image 엘리먼트 & 태그 활용 리액트 네이티

View, ScrollView, Text, Button, Image 엘리먼트 & 태그 활용 엘리먼트 활용 화면의 영역(레이아웃)을 잡아주는 엘리먼트이다. App.js 상에서 View는 화면 전체 영역을 가진다. 아래와 같이 화면을 분할.

tantangerine.tistory.com

 

728x90
반응형
728x90
반응형

엘리먼트 & 태그에 Style 입히기

 

이전 포스팅에서 만들어보았던 화면들로 스타일을 입혀보자

이전 포스팅을 보고 싶다면 아래를 클릭!!

 

2022.06.30 - [모바일/React Native] - [React Native X Expo] View, ScrollView, Text, Button, TouchableOpacity, Image 엘리먼트 & 태그 활용 리액트 네이티브

 

[React Native X Expo] View, ScrollView, Text, Button, TouchableOpacity, Image 엘리먼트 & 태그 활용 리액트 네이티

View, ScrollView, Text, Button, Image 엘리먼트 & 태그 활용 엘리먼트 활용 화면의 영역(레이아웃)을 잡아주는 엘리먼트이다. App.js 상에서 View는 화면 전체 영역을 가진다. 아래와 같이 화면을 분할.

tantangerine.tistory.com

 

React Native에서 사용하는 styleSheet 활용 문법

 

태그에 스타일을 입히는 방법은 몇 가지가 존재합니다

 

  • 모든 태그에는 공통적인 style 속성이 존재한다 그래서 그 속성에 값을 직접 주는 방법
  • 리액트 네이티브에서 제공하는 StyleSheet 모듈을 임 폴트 해서 사용하는 방법
    • StyleSheet는 모듈로 create 함수를 사용하여 객체로 만들어서 스타일을 정리해두어 사용하게 될 경우 객체로 이름을 부여하여 사용이 가능합니다
import { StyleSheet } from 'react-navite'

const styles = StyleSheet.create({
	container: {
    		backgroundColor: '#77'
    }
})

위와 코드를 작성하게 되면 style속성에 객체로 값을 부여할 수 있게 됩니다

 

<View style={styles.container}>

 

style속성에 우리가 만들어 두었던 styles의 객체로 container를 불러서 사용할 수 있습니다

 


 

자주 사용하는 스타일 속성

 

지금까지는 스타일을 입히는 방법을 알아보았다면

이제는 어떠한 속성들이 있는지를 알아보시죠!

하지만 그 많은 것들을 다 알 필요는 없습니다

 

왜냐하면 모든 사람들이 그것을 다 외우지는 않으니까요

 

그때그때 상황에 맞게 필요할 때마다 속성을 검색해서

사용하는 방법을 익히면 됩니다

그렇다고 막 익히려고 하지 않아도 자연스럽게 채득 할 수 있을 겁니다  

 

import { StyleSheet } from 'react-native';

const styles = StyleSheet.create({
  container: {
    //영역을 잡는 속성입니다. 따로 자세히 다룹니다.
    //flex: 1은 전체 화면을 가져간다는 뜻입니다
    flex: 1,
    //영역의 배경 색을 결정합니다
    backgroundColor: '#fff',
    //아래 두 속성은 영역 안의 컨텐츠들의 배치를 결정합니다. 
    //flex를 자세히 다룰때 같이 자세히 다룹니다
    justifyContent:"center",
    alignContent:"center"
  },
  textContainer: {
    //영역의 바깥 공간 이격을 뜻합니다(하단 이미지 참조)
    margin:10,
    //영역 안의 컨텐츠 이격 공간을 뜻합니다(하단 이미지 참조)
    padding: 10,
    //테두리의 구부러짐을 결정합니다. 지금 보면 조금 둥글죠?
    borderRadius:10,
    //테두리의 두께를 결정합니다
    borderWidth:2,
    //테두리 색을 결정합니다
    borderColor:"#000",
    //테구리 스타일을 결정합니다. 실선은 solid 입니다
    borderStyle:"dotted",

  },
  textStyle: {
    //글자 색을 결정합니다. rgb, 값 이름, 색상코드 모두 가능합니다
    color:"red",
    //글자의 크기를 결정합니다
    fontSize:20,
    //글자의 두께를 결정합니다
    fontWeight:"700",
    //가로기준으로 글자의 위치를 결정합니다
    textAlign:"center"
  }
});

위와 같이 정말 여러 속성들이 있죠?

저도 매일 찾아서 하니깐 너무 신경 쓰지 말고 이런 것이 있구나 하고 다음으로 넘어갑시다!!

 


 

style 속성 중 중요한 Flex 제대로 알기

  • flex
    • 화면을 구성할 경우 정말 중요한 것이 flex라고 할 수 있습니다 
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.containerOne}>

      </View>
      <View style={styles.containerTwo}>

      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex:1
  },
  containerOne: {
    flex:1,
    backgroundColor:"red"
  },
  containerTwo:{
    flex:2,
    backgroundColor:"yellow"
  }
});

 

위와 같이 flex에 숫자를 넣어서 값을 할당할 수 있습니다

그렇게 되면 전체 화면에 대한 비율을 나타나게 됩니다

위에는 flex를 3번을 사용했습니다

하지만 태그 구조상 상위 View태그 하나에 하위 View 태그 2개가 존재합니다

그렇기 때문에 상위 태그의 flex 1은 전체를 나타내는 비율이며

그 안에 하위 2개의 하위 태그가 다시 비율을 지정하게 됩니다

2개의 하위 태그는 각각 1과 2를 flex에 부여하고 있어 

1 + 2를 하여 1/3과 2/3의 비율로 화면이 구성되게 됩니다

 

위의 코드를 구성화면이며 1/3과 2/3의 비율로 화면이 분활되어있음을 확인할 수 있다

 

그럼 한 가지 예를 더 보고 넘어가도록 합시다

 

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

export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.containerOne}>

      </View>
      <View style={styles.containerTwo}>
        <View style={styles.innerOne}>

        </View>
        <View style={styles.innerTwo}>

        </View>

      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex:1
  },
  containerOne: {
    flex:1,
    backgroundColor:"red"
  },
  containerTwo:{
    flex:2,
    backgroundColor:"yellow"
  },
  innerOne: {
    flex:1,
    backgroundColor:"blue"
  },
  innerTwo: {
    flex:4,
    backgroundColor:"orange"
  }
});

 

이 경우는 1개의 상위 view태그에 2개의 하위 태그

그리고 한 개의 하위 태그는 다시 2개로 분할 되어있죠

이 경우는 처음 2개의 하위 태그 flex 1과 2로 분할하여

2/3에 해당하는 영역에서 다시 두개로 나눈값을 1/5, 4/5분할하게 됩니다 

그래서 flex 값이 같더라도 영역의 크기가 달라지게 됩니다

 

위의 코드를 구현한 화면이다

 

 

반응형

  • FlexDirection
    • 자식태그의 영역을 정렬방향을 세로 또는 가로로 지정할 수 있는 속성
    • flexDirection: "row" 가로 방향,  flexDirection: "column" 세로 방향
    • 기본값은 colunm입니다
export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.containerOne}>
      </View>
      
      <View style={styles.containerTwo}>
        <View style={styles.innerOne}>
        </View>
        
        <View style={styles.innerTwo}>
        </View>

      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex:1
  },
  containerOne: {
    flex:1,
    backgroundColor:"red"
  },
  containerTwo:{
    flex:2,
    flexDirection:"row",
    backgroundColor:"yellow"
  },
  innerOne: {
    flex:1,
    backgroundColor:"blue"
  },
  innerTwo: {
    flex:4,
    backgroundColor:"orange"
  }
});

 

 

정렬이 빨강 영역보다 다르다는 것을 알 수 있다

 


 

  • justifyContent
    • justifyContent는 상위 태그에서 지정된 flexDirection의 방향과 어떻게 정렬할것인지 지정하는 속성입니다.
    • flexDirection을 꼭 지정해야 justifyContent를 지정할 수 있는것을 기억하세요
    • 속성에는 flex-start, center, flex-end, space-between, space-around이 있습니다.
    • flex-start는 영역들이 제일 상단에서 부터 정렬됩니다.
    • center는 영역들이 중앙에 모여있는 형태가 된다.
    • flex-end는 제일 하단에서 부터 정렬된다 
    • space-between는 여러 영역들을 처음 중간 끝에 나열하게된다.
    • space-around는 여러 영역들을 처음 중간 끝을 일정한 간격으로 나열하게된다

어떻게 정렬되는지 확인이 가능하다

 

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

export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.containerOne}>

      </View>
      <View style={styles.containerTwo}>
        <View style={styles.innerOne}>
         
        </View>
        <View style={styles.innerTwo}>
          <Text>티스토리 블로그</Text>
        </View>

      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex:1
  },
  containerOne: {
    flex:1,
    backgroundColor:"red"
  },
  containerTwo:{
    flex:2,
    flexDirection:"row",
    backgroundColor:"yellow"
  },
  innerOne: {
    flex:1,
    backgroundColor:"blue"
  },
  innerTwo: {
    flex:4,
    justifyContent:"flex-start",
    backgroundColor:"orange"
  }
});

 

 

왼쪽에 치우쳐진 것을 볼수 잇다

 

부모 태그 영역을 flexDirection이 무엇으로 지정했는지가 중요합니다

 

 


 

  • alignItem
    • alignItem은 flexDirection의 반대로 정렬됩니다
    • flexDirection 값이 coloumn으로 지정 되었다면, 자식 태그에 alignItem의 값을 지정하게 되면 좌우로 정렬 됩니다
    • row으로 지정되었다면, 반대가 된다
    • flex-start, center, flex-end, stretch 속성을 가지고 있습니다

 

이미지를 잘 확인하면서 속성들이 어떻게 표현하는지 확인 합시다

 

 

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

export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.containerOne}>

      </View>
      <View style={styles.containerTwo}>
        <View style={styles.innerOne}>
         
        </View>
        <View style={styles.innerTwo}>
          <View style={styles.content}></View>
        </View>

      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex:1
  },
  containerOne: {
    flex:1,
    backgroundColor:"red"
  },
  containerTwo:{
    flex:2,
    flexDirection:"row",
    backgroundColor:"yellow"
  },
  innerOne: {
    flex:1,
    backgroundColor:"blue"
  },
  innerTwo: {
    flex:4,
    backgroundColor:"orange",
    alignItems:"flex-end"
  },
  content: {
    width:50,
    height:50,
    backgroundColor:"#000"
  }
});

 

 

이미지를 확인해보세요!!

 

 

2개의 포스팅으로 앱 화면 만들어 보았습니다

저도 개발자가 되고 공부를 많이 하고있습니다

이 직업은 항상 공부를 해야 한다는 것이 부담되고 힘들기도 합니다

하지만 공부라고 생각하지마시고 사이드프로젝트를 하면서

자기만의 사이트를 만들어보고, 다른 기능들도 붙여보고,

회사에서 사용한 코드들을 나만의 노트에 정리도 하면서,

흥미를 붙이는 과정이 정말 중요한것 같습니다

그럼 모두 화이팅 하시고!!

 

즐거운 코딩시간이 되었으면 합니다

화이팅!!

 

 

728x90
반응형
728x90
반응형

View, ScrollView, Text, Button, Image 엘리먼트 & 태그 활용 

<View> 엘리먼트 활용

  • 화면의 영역(레이아웃)을 잡아주는 엘리먼트이다.
  • App.js 상에서 View는 화면 전체 영역을 가진다.
  • 아래와 같이 화면을 분할할 수 있다.
import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <View style={styles.subContainerOne}></View>
      <View style={styles.subContainerTwo}></View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  subContainerOne: {
    flex:1,
    backgroundColor:"yellow"
  },
  subContainerTwo: {
    flex:1,
    backgroundColor:"green"
  }
});
  • 각 태그들에는 style이라는 속성을 가지고 있다
  • 속성은 하단에 스타일 코드 객체의 키값을 할당하여 엘리먼트에 스타일을 부여한다

 

View호 화면을 분할하고 영역을 나누려면

스타일 문법(StyleSheet)과 같이 사용해야 한다

 

스타일 문법(StyleSheet)은 다음 포스팅에서 확인하고

View는 화면의 영역을 잡는 엘리먼트라는 것만 알아두자

 

 

아래의 이미지는 위의 코드로 표현한 앱 화면이다 

상위 View엘리먼트 안에 하위 2개의 View 엘리먼트로 인해 2개의 영역이 표현된다.

코드로 표현한 앱화면이다

 


 

<ScrollView> 엘리먼트 활용

  • 앱 화면에 노출되는 영역보다 엘리먼트가 벗어나면 ScrollView 엘리먼트를 사용하면 스크롤이 가능하다
import React from 'react';
import { StyleSheet, Text, View, ScrollView } from 'react-native';

export default function App() {
  return (
    <ScrollView style={styles.container}>
      <View style={styles.textContainer}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </View>
      <View style={styles.textContainer}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </View>
      <View style={styles.textContainer}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </View>
      <View style={styles.textContainer}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </View>
      <View style={styles.textContainer}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </View>
      <View style={styles.textContainer}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </View>
      <View style={styles.textContainer}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </View>
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  textContainer: {
    height:100,
    borderColor:'#000',
    borderWidth:1,
    borderRadius:10,
    margin:10,
  },
  textStyle: {
    textAlign:"center"
  }
});

 

상위 엘리먼트를  View로 구현했다면 마지막 부분이 짤려서 보이질 않는다.

ScrollView를 사용하면 스크롤이 가능해지면서 마지막부분도 보이게된다.

 

위의 코드로 표현된 앱 화면

 


반응형

<Text> 엘리먼트 활용

  • 앱에 글을 표현하려면 꼭 사용해야 할 엘리먼트이다.
  • 방금 전 위에서 배운 ScrollView 엘리먼트 안에 문자를 작성하면 오류가 발생한다.
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
      <Text>문자는 Text 태그 사이에 작성!!</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

 


 

<Button> 엘리먼트 활용

  • Button 태그를 이용해서 손쉽게 버튼을 만들 수 있다
  • Button 태그에는 title, color, onPress 등의 속성을 가지고 있는데, 속성을 잘 활용하면 여러기능을 구현할 수 있다.
import React from 'react';
import { StyleSheet, Text, View, Button, Alert } from 'react-native';

export default function App() {
  const customAlert = () => {
    Alert.alert("JSX 밖에서 함수 구현 가능!")
  }
  return (
    <View style={styles.container}>
      <View style={styles.textContainer}>
        <Text style={styles.textStyle}>아래 버튼을 눌러주세요</Text>
        <Button 
          style={styles.buttonStyle} 
          title="버튼입니다 "
          color="#f194ff" 
          onPress={customAlert}
        />
        <Button 
            style={styles.buttonStyle} 
            title="버튼입니다 "
            color="#FF0000" 
            onPress={() => {customAlert()}}
          />
          </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  textContainer: {
    height:100,
    margin:10,
  },
  textStyle: {
    textAlign:"center"
  },
});

 

위의 코드는 Button 태그에 onPress 속성을 부여하여 앱화면 버튼영역 터치시 얼럿창을 노출하는 기능을 구현한 것이다

함수는 ES6문법인 화살표 함수를 사용해도 된다.

하지만 Button 태그는 자신의 영역을 갖기때문에 스타일을 부여하기가 어려움이 있다.

아래의 코드 처럼 ScrollView에서 카드 형식으로 만든 앱 화면이면 Button 태그를 사용하기 어렵다 그러므로 <TouchableOpacity> 태그를 활용하면 화면에 영향을 주지않고 쉽게 구현할 수 있다.

 


 

<TouchableOpacity> 태그를 활용해서 Button 태그 대체하기 

  • <ScrollView> 상위 태그로 하위태그는 View를 사용하지만 그것을 TouchableOpacity태그로 대체하면 임의의 영역과 디자인에 버튼 기능을 구현하고 싶을경우 주로 사용한다
import React from 'react';
import { StyleSheet, Text, View, ScrollView, TouchableOpacity, Alert } from 'react-native';

export default function App() {
  const customAlert = () => {
    Alert.alert("TouchableOpacity에도 onPress 속성이 있습니다")
  }
  return (
    <ScrollView style={styles.container}>
      <TouchableOpacity style={styles.textContainer} onPress={customAlert}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </TouchableOpacity>
      <TouchableOpacity style={styles.textContainer} onPress={customAlert}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </TouchableOpacity>
      <TouchableOpacity style={styles.textContainer} onPress={customAlert}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </TouchableOpacity>
      <TouchableOpacity style={styles.textContainer} onPress={customAlert}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </TouchableOpacity>
      <TouchableOpacity style={styles.textContainer} onPress={customAlert}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </TouchableOpacity>
      <TouchableOpacity style={styles.textContainer} onPress={customAlert}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </TouchableOpacity>
      <TouchableOpacity style={styles.textContainer} onPress={customAlert}>
        <Text style={styles.textStyle}>영역을 충분히 갖는 텍스트 입니다!</Text>
      </TouchableOpacity>
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  textContainer: {
    height:100,
    borderColor:'#000',
    borderWidth:1,
    borderRadius:10,
    margin:10,
  },
  textStyle: {
    textAlign:"center"
  }
});

 

 

위와 같이 영역에서 버튼처럼 기능구현이 가능하다

 


 

<Image> 태그 활용해서 앱화면에 이미지를 노출하자

  • 내부 폴더 안에있는 이미지를 사용하는 방법이 있다
  • 여러 속성을 사용해서 이미지를 삽입한다
  • source, resizeMode, style등 여러 속성을 활용할 수 있다.
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import favicon from "./assets/favicon.png"

export default function App() {
  return (
    <View style={styles.container}>
      <Image 
        source={favicon}
        resizeMode={"repeat"}
        style={styles.imageStyle}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    justifyContent:"center",
    alignContent:"center"
  },
  imageStyle: {
    width:"100%",
    height:"100%",
    alignItems:"center",
    justifyContent:"center"
  }
});

 

 

resizeMode를 repeat로 부여했다

 

 

  • 외부 이미지 링크를 사용하는 방식도 있다.
  • 위와 다르게 resizeMode에 repeat을 cover로 변경해서 사용하였다 결과를 아래에서 확인해보자.
import React from 'react';
import { StyleSheet, Text, View, Image } from 'react-native';
import favicon from "./assets/favicon.png"

export default function App() {
  return (
    <View style={styles.container}>
      <Image 
        source={{uri:'https://images.unsplash.com/photo-1424819827928-55f0c8497861?fit=crop&w=600&h=600%27'}}
        resizeMode={"cover"}
        style={styles.imageStyle}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    justifyContent:"center",
    alignContent:"center"
  },
  imageStyle: {
    width:"100%",
    height:"100%",
    alignItems:"center",
    justifyContent:"center"
  }
});

 

resizeMode를 cover로 부여했다

 

 

앱 화면을 구현하기위해 기초적인 태그들을 정리해보았다

앞으로 React Native를 활용해서 Expo와 같이 구현한다

 Expo에 대한 장점과 단점은 분명하며 어떤 앱을 구현할때 Expo가 유리할지도 생각해보아야겠다

앞으로 어떤앱이 탄생할지 계속해서 만들어보자

 

728x90
반응형

+ Recent posts

Powered by Tistory, Designed by wallel