[따라하며 배우는 리액트 네이티브 기초] 섹션 6 - Animated / useState / postUI 생성

posinity·2023년 7월 3일
0
post-thumbnail

1. Animated 라이브러리

공식 문서 확인하기
애니메이트 라이브러리는 애니메이션을 쉽게 만들고 유지하기 위해 만들어짐
interpolation이 사용됌

interpolation

중간지점에서 함수를 추정하는 수단을 제공함

이용 방법

  1. Animated.Value를 만듦
  2. 애니메이션 구성 요소의 하나 이상의 스타일 속성에 연결함
  3. Animated.timing()을 사용하여 애니메이션을 통해 업데이트를 구동

Animated value 생성

useRef 사용하여 변경 가능한 ref 객체 반환

const progress = useRef(new Animated.Value(0)).current;

Animated value와 스타일 속성 연결하기

Animated value가 0에서 5로 바뀔 때, 다른 출력 범위는 0%~100%로 맵핑해준다.
이 interpolate 함수를 애니메이션 주고 싶은 부분에 연결(width)

const progressAnimation = progress.interpolate({
    inputRange: [0, 5],
    outputRange: ['0%', '100%'],
  });
  
  ...
  
<Animated.View
          style={{
            height: '100%',
            backgroundColor: 'white',
            width: progressAnimation,
          }}></Animated.View>

Animated.timing()을 이용해 Animated value를 업데이트한다

네이티브 드라이버를 사용하여 애니메이션을 시작하기 전에 애니메이션에 대한 모든 것을 네이티브로 전송하여, 네이티브코드가 모든 프레임에서 브리지를 거치지 않고 UI스레드에서 애니메이션을 수행할 수 있도록 한다. 애니메이션이 시작되면 애니메이션에 영향을 주지 않고 js 스레드르 차단할 수 있다.

애니메이션 구성에서 useNativeDriver: true를 지정하여 기본 드라이버를 사용할 수 있다.

useNativeDriver: true로 변경하면 오류 발생

useEffect(() => {
    Animated.timing(progress, {
      toValue: 5,
      duration: 5000,
      useNativeDriver: false,
    }).start();
  }, []);

5초 후 homescreen으로 돌아가기

useEffect(() => {
    let timer = setTimeout(() => {
      navigation.goBack();
    }, 5000);

    return () => {
      clearTimeout(timer);
    };
  }, []);

status bar 부분과 겹칠 때는 아래 라이브러리 설치하여 해결

https://github.com/ovr/react-native-status-bar-height

2. posts UI 생성하기

Posts.js, PostItem.js 컴포넌트 생성

Home 컴포넌트 안에 posts 컴포넌트 넣기

import Posts from '../components/Posts';

...

<ScrollView>
  <Stories />
  <Posts />
</ScrollView>

posts.js에 data 입력

const postInfo = [
    {
      postTitle: 'John',
      postPersonImage: require('../../assets/images/userProfile.jpeg'),
      postImage: require('../../assets/images/post1.jpeg'),
      likes: 765,
      isLiked: false,
    },
    {
      postTitle: 'Tonny',
      postPersonImage: require('../../assets/images/profile5.jpeg'),
      postImage: require('../../assets/images/post2.jpeg'),
      likes: 345,
      isLiked: false,
    },
    {
      postTitle: 'Tom',
      postPersonImage: require('../../assets/images/profile4.jpeg'),
      postImage: require('../../assets/images/post3.jpeg'),
      likes: 253,
      isLiked: false,
    },
    {
      postTitle: 'React',
      postPersonImage: require('../../assets/images/profile3.jpeg'),
      postImage: require('../../assets/images/post4.jpeg'),
      likes: 623,
      isLiked: false,
    },
  ];

posts.js에 postInfo map 돌리기

import PostItem from './PostItem';

...

<View>
      {postInfo.map((data, index) => {
        return <PostItem data={data} key={index} />;
      })}
</View>

postitem.js에 기본 ui 만들기

borderBottomWidth를 0.1로 하니까 렌더링 화면에 보이지 않아
borderBottomWidth를 0.3으로 변경

import {StyleSheet, Text, View, Image} from 'react-native';
import React from 'react';
import Feather from 'react-native-vector-icons/Feather';

const PostItem = ({data}) => {
  return (
    <View
      style={{
        paddingBottom: 10,
        borderBottomColor: 'gray',
        borderBottomWidth: 0.3,
      }}>
      <View
        style={{
          flexDirection: 'row',
          alignItems: 'center',
          justifyContent: 'space-between',
          padding: 15,
        }}>
        <View
          style={{
            flexDirection: 'row',
            alignItems: 'center',
          }}>
          <Image
            source={data.postPersonImage}
            style={{width: 40, height: 40, borderRadius: 100}}
          />
          <View style={{paddingLeft: 5}}>
            <Text style={{fontSize: 15, fontWeight: 'bold'}}>
              {data.postTitle}
            </Text>
          </View>
        </View>
        <Feather name="more-vertical" style={{fontSize: 20}} />
      </View>
    </View>
  );
};

export default PostItem;

const styles = StyleSheet.create({});

postImage 넣기

...

        <Feather name="more-vertical" style={{fontSize: 20}} />
      </View>
/// 이 부분 추가
      <View>
        <Image source={data.postImage} style={{width: '100%', height: 400}} />
      </View>
/// 이 부분 추가
    </View>
  );
};

좋아요를 useState로 관리하기

import React, {useState} from 'react';

...

const PostItem = ({data}) => {
  const [like, setLike] = useState(data.isLiked); //isLiked가 기본값이 되게

사진 아래 버튼 ui 만들기

      <View>
        <Image source={data.postImage} style={{width: '100%', height: 400}} />
      </View>
/// 시작
      <View
        style={{
          flexDirection: 'row',
          justifyContent: 'space-between',
          alignItems: 'center',
          paddingHorizontal: 12,
          paddingVertical: 15,
        }}>
        <View
          style={{
            flexDirection: 'row',
            alignItems: 'center',
          }}>
          <TouchableOpacity onPress={() => setLike(!like)}>
            <AntDesign
              name={like ? 'heart' : 'hearto'}
              style={{
                paddingRight: 10,
                fontSize: 20,
                color: like ? 'red' : 'black',
              }}
            />
          </TouchableOpacity>
          <TouchableOpacity>
            <Ionic
              name="ios-chatbubble-outline"
              style={{
                paddingRight: 10,
                fontSize: 20,
              }}
            />
          </TouchableOpacity>
          <TouchableOpacity>
            <Feather name="navigation" style={{fontSize: 20}} />
          </TouchableOpacity>
        </View>
        <Feather name="bookmark" style={{fontSize: 20}} />
/// 끝
      </View>
    </View>
  );
};

좋아요 및 댓글 ui 만들기

<View style={{paddingHorizontal: 15}}>
        <Text>좋아요 {like ? data.likes + 1 : data.likes}</Text>
        <Text
          style={{
            fontWeight: '700',
            fontSize: 14,
            paddingVertical: 2,
          }}>
          게시글 설명글입니다.
        </Text>
        <Text
          style={{
            opacity: 0.4,
            paddingVertical: 2,
            marginTop: 5,
            marginBottom: 5,
          }}>
          댓글 모두 보기
        </Text>
        <View style={{flexDirection: 'row', justifyContent: 'space-between'}}>
          <View style={{flexDirection: 'row', alignItems: 'center'}}>
            <Image
              source={data.postPersonImage}
              style={{
                width: 25,
                height: 25,
                borderRadius: 100,
                backgroundColor: 'orange',
                marginRight: 10,
              }}
            />
            <TextInput placeholder="댓글 달기..." style={{opacity: 0.5}} />
          </View>
          <View style={{flexDirection: 'row', alignItems: 'center'}}>
            <Text style={{color: '#0095F6'}}>게시</Text>
          </View>
        </View>
      </View>

profile
문제를 해결하고 가치를 제공합니다

0개의 댓글