[따라하며 배우는 리액트 네이티브 기초] 섹션 7 - Search 컴포넌트 UI 작성 / 모달 생성 / 화면 가운데 정렬

posinity·2023년 7월 3일
0

1. SearchInput UI 작성하기

SearchInput.js / SearchContent.js 컴포넌트 추가하기

Search.js 파일 코드 추가하기

SafeAreaView 로 항상 감싸주고 스크롤뷰 넣기

import {SafeAreaView, ScrollView} from 'react-native';
import React from 'react';
import SearchInput from '../components/SearchInput';
import SearchContent from '../components/SearchContent';

const Search = () => {
  return (
    <SafeAreaView
      style={{
        width: '100%',
        backgroundColor: 'white',
        position: 'relative',
      }}>
      <ScrollView showsVerticalScrollIndicator={false}>
        <SearchInput />
        <SearchContent />
      </ScrollView>
    </SafeAreaView>
  );
};

export default Search;

SearchInput.js 코드 작성

import {TextInput, View} from 'react-native';
import React from 'react';
import Ionic from 'react-native-vector-icons/Ionicons';

const SearchInput = () => {
  return (
    <View
      style={{
        justifyContent: 'center',
        alignItems: 'center',
        width: '100%',
        paddingVertical: 10,
        position: 'relative',
      }}>
      <Ionic
        name="search"
        style={{
          fontSize: 18,
          opacity: 0.7,
          position: 'absolute',
          zIndex: 1,
          left: 25,
        }}
      />
      <TextInput
        placeholder="search"
        placeholderTextColor="#909090"
        style={{
          width: '94%',
          backgroundColor: '#EBEBEB',
          borderRadius: 10,
          alignItems: 'center',
          justifyContent: 'center',
          fontSize: 15,
          padding: 4,
          paddingLeft: 40,
        }}
      />
    </View>
  );
};

export default SearchInput;

2. SearchContent.js 컴포넌트 작성하기

데이터 추가하기

const searchData = [
    {
      id: 0,
      images: [
        require('../../assets/images/post1.jpeg'),
        require('../../assets/images/post2.jpeg'),
        require('../../assets/images/post3.jpeg'),
        require('../../assets/images/post4.jpeg'),
        require('../../assets/images/post5.jpeg'),
        require('../../assets/images/post6.jpeg'),
      ],
    },
    {
      id: 1,
      images: [
        require('../../assets/images/post7.jpeg'),
        require('../../assets/images/post8.jpeg'),
        require('../../assets/images/post9.jpeg'),
        require('../../assets/images/post10.jpeg'),
        require('../../assets/images/post11.jpeg'),
        require('../../assets/images/post12.jpeg'),
      ],
    },
    {
      id: 2,
      images: [
        require('../../assets/images/post13.jpeg'),
        require('../../assets/images/post14.jpeg'),
        require('../../assets/images/post15.jpeg'),
      ],
    },
  ];

1번 UI 작성

data의 id가 1인 것만 보여주고, id가 1인 데이터의 images를 map으로 돌려 뿌려줌

return (
    <View>
      {searchData.map((data, index) => {
        return (
          <View key={index}>
            {data.id === 0 ? (
              <View
                style={{
                  flexDirection: 'row',
                  flexWrap: 'wrap',
                  justifyContent: 'space-between',
                  width: '100%',
                }}>
                {data.images.map((imageData, imgIndex) => {
                  return (
                    <TouchableOpacity
                      key={imgIndex}
                      style={{
                        paddingBottom: 2,
                        width: '33%',
                      }}>
                      <Image
                        source={imageData}
                        style={{
                          width: '100%',
                          height: 150,
                        }}
                      />
                    </TouchableOpacity>
                  );
                })}
              </View>
            ) : null}
          </View>
        );
      })}
    </View>
  );

2번 UI 작성

{data.id === 1 ? (
              <View
                style={{
                  flexDirection: 'row',
                  justifyContent: 'space-between',
                }}>
                <View
                  style={{
                    flexDirection: 'row',
                    flexWrap: 'wrap',
                    width: '66.5%',
                    justifyContent: 'space-between',
                  }}>
                  {data.images.slice(0, 4).map((imageData, imgIndex) => {
                    return (
                      <TouchableOpacity
                        key={imgIndex}
                        style={{
                          paddingBottom: 2,
                          width: '49.5%',
                        }}>
                        <Image
                          source={imageData}
                          style={{width: '100%', height: 150}}
                        />
                      </TouchableOpacity>
                    );
                  })}
                </View>
                <TouchableOpacity style={{marginLeft: 2, width: '33%'}}>
                  <Image
                    source={data.images[5]}
                    style={{width: '100%', height: 300}}
                  />
                </TouchableOpacity>
              </View>
            ) : null}

3번 UI 작성

{data.id === 2 ? (
              <View
                style={{
                  flexDirection: 'row',
                  justifyContent: 'space-between',
                }}>
                <TouchableOpacity style={{paddingRight: 2, width: '66.5%'}}>
                  <Image
                    source={data.images[2]}
                    style={{width: '100%', height: 300}}
                  />
                </TouchableOpacity>
                <View
                  style={{
                    flexDirection: 'row',
                    flexWrap: 'wrap',
                    width: '33%',
                    justifyContent: 'space-between',
                  }}>
                  {data.images.slice(0, 2).map((imageData, imgIndex) => {
                    return (
                      <TouchableOpacity
                        key={imgIndex}
                        style={{
                          paddingBottom: 2,
                          width: '100%',
                        }}>
                        <Image
                          source={imageData}
                          style={{width: '100%', height: 150}}
                        />
                      </TouchableOpacity>
                    );
                  })}
                </View>
              </View>
            ) : null}

3. 모달 생성

search 컴포넌트에서 클릭한 이미지 데이터 보관

import {SafeAreaView, ScrollView} from 'react-native';
import React, {useState} from 'react';
import SearchInput from '../components/SearchInput';
import SearchContent from '../components/SearchContent';

const Search = () => {
  const [image, setImage] = useState(null);

  const getData = data => {
    setImage(data);
  };
  return (
    <SafeAreaView
      style={{
        width: '100%',
        backgroundColor: 'white',
        position: 'relative',
      }}>
      <ScrollView showsVerticalScrollIndicator={false}>
        <SearchInput />
        <SearchContent getData={getData} /> //getData 함수 내려줌
      </ScrollView>
    </SafeAreaView>
  );
};

export default Search;

내려준 함수 TouchableOpacity에 넣기

imageData를 state에 넣어주고 떼면 null로 변화

<TouchableOpacity
   onPressIn={() => getData(imageData)}
   onPressOut={() => getData(null)}
>
// 이런식으로 특정 이미지를 넣어주는 경우도 있음. 찾아서 넣기!
onPressIn={() => getData(data.images[2])}

모달창 ui 만들기

{image ? (
        <View
          style={{
            position: 'absolute',
            zIndex: 1,
            width: '100%',
            height: '100%',
            backgroundColor: 'rgba(52, 52, 52, 0.8)',
          }}>
          <StatusBar backgroundColor="#525252" barStyle="dark-content" />
          <View
            style={{
              position: 'absolute',
              backgroundColor: 'white',
              width: '90%',
              height: 465,
              borderRadius: 15,
              zIndex: 1,
            }}>
            <View
              style={{
                flexDirection: 'row',
                alignItems: 'center',
                paddingVertical: 10,
                paddingHorizontal: 15,
              }}>
              <Image
                source={image}
                style={{width: 30, height: 30, borderRadius: 100}}
              />
              <View style={{paddingLeft: 8}}>
                <Text style={{fontSize: 12, fontWeight: '600'}}>
                  친구 아이디
                </Text>
              </View>
            </View>
            <Image source={image} style={{width: '100%', height: '80%'}} />
            <View
              style={{
                justifyContent: 'space-around',
                width: '100%',
                flexDirection: 'row',
                alignItems: 'center',
                padding: 8,
              }}>
              <Ionic name="ios-heart-outline" style={{fontSize: 26}} />
              <Ionic name="ios-person-circle-outline" style={{fontSize: 26}} />
              <Feather name="navigation" style={{fontSize: 26}} />
            </View>
          </View>
        </View>
      ) : null}

모달창 화면의 정가운데로 보내기

나는 해보니까 정가운데로 가지 않았다.
기기별로 차이가 있는 것 같다.
다른방법을 찾아서 하는게 좋을듯

const windowWidth = Dimensions.get('window').width;
const windowHeight = Dimensions.get('window').height;
  
...

<View
            style={{
              position: 'absolute',
              top: windowHeight / 6,
              left: windowWidth / 18,
              backgroundColor: 'white',
              width: '90%',
              height: 465,
              borderRadius: 15,
              zIndex: 1,
            }}>

내가 시도한 방법

flex 속성을 이용한다
검정 영역에

flex: 1
justifyContent: 'center'
alignItems: 'center'

추가

{image ? (
        <View
          style={{
            position: 'absolute',
            zIndex: 1,
            width: '100%',
            height: '100%',
            backgroundColor: 'rgba(52, 52, 52, 0.8)',
            top: Platform.OS === 'ios' ? statusBarHeight : 0,
            flex: 1,
            justifyContent: 'center',
            alignItems: 'center',
          }}>
  
...

// 모달 영역 style에 position을 없애줌
<View
            style={{
              backgroundColor: 'white',
              width: '90%',
              height: 465,
              borderRadius: 15,
              zIndex: 1,
            }}>

react-native-status-bar 사용하기

ios에서는 검은 부분이 위로 올라가있음.
status-bar 부분 아래로 내릴 수 있게 모듈 설치
https://github.com/ovr/react-native-status-bar-height

npm install --save react-native-status-bar-height

/// 상단 import
import {getStatusBarHeight} from 'react-native-status-bar-height';

...

const statusBarHeight = getStatusBarHeight();

...

/// 검정 영역 부분에 놔두기
{image ? (
        <View
          style={{
            position: 'absolute',
            zIndex: 1,
            width: '100%',
            height: '100%',
            backgroundColor: 'rgba(52, 52, 52, 0.8)',
            top: Platform.OS === 'ios' ? statusBarHeight : 0,
          }}>
profile
문제를 해결하고 가치를 제공합니다

0개의 댓글