프론트엔드 앱/React-native

[자동완성검색] UI-Kitten Autocomplete 키보드에 따라 옵션창 위치 바꾸기

세리둥절 2021. 12. 18. 19:24
반응형

 

✔️ 필요성

React Native로 개발하다보면 (앱을 개발하다보면) 웹이랑 다르게 신경써야할 부분이 키보드이다. 키보드가 올라오면 화면의 약 1/3을 가리게 되는 데 이 때 어떻게 해야할 지 신경써야한다는 것이다.

 

검색창처럼 검색 결과가 검색창 아래로 내려오는 경우 더 신경이 쓰이는데, 이를 위해 앱을 보면 대체로 검색창은 가장 상단에 위치하는 것이 국룰이다.

 

 

 

✔️ 문제 해결

UI Kitten Autocomplete에서는 이에 대응하기 위해서 옵션창의 위치를 바꿀 수 있다. 검색 결과(옵션)이 나오는 부분이 원래 검색창 아래에 있는데 키보드를 인지하면 위로 바꿔주는 것이다.

 

키보드를 인지하기 위해서 react-native에서 제공하는 Keyboard.addListener를 사용했다.

const [placement, setPlacement] = React.useState('bottom');

  // keyboard 여부에 따라 검색옵션화면 위치 변동
  useEffect(() => {
    Keyboard.addListener('keyboardDidShow', e => {
      setPlacement('top');
    });
    Keyboard.addListener('keyboardDidHide', e => {
      setPlacement('bottom');
    });
    return () => {
      Keyboard.removeAllListeners('keyboardDidShow');
      Keyboard.removeAllListeners('keyboardDidHide');
    };
  }, []);

 

 

✔️ 전체 코드

import React, {useEffect, useRef} from 'react';
import styled from 'styled-components/native';
import {Keyboard} from 'react-native';
import {Autocomplete} from '@ui-kitten/components';
import Icon from 'react-native-vector-icons/Ionicons';
import {SCREEN_WIDTH} from '~/utils/common';

const Pressable = styled.Pressable``;
const IconContainer = styled.View<{pressed: boolean}>`
  opacity: ${({pressed}) => (pressed ? 0.55 : 1)};
`;

interface Props {
  renderItem: (item: any, index: number) => JSX.Element;
  dataset: any[];
  placeholder: string;
}

const AutoCompleteSearch = ({renderItem, dataset, placeholder}: Props) => {
  const ref = useRef<any>(null);
  const [value, setValue] = React.useState('');
  const [data, setData] = React.useState(dataset);
  const [placement, setPlacement] = React.useState('bottom');

  // keyboard 여부에 따라 검색옵션화면 위치 변동
  useEffect(() => {
    Keyboard.addListener('keyboardDidShow', e => {
      setPlacement('top');
    });
    Keyboard.addListener('keyboardDidHide', e => {
      setPlacement('bottom');
    });
    return () => {
      Keyboard.removeAllListeners('keyboardDidShow');
      Keyboard.removeAllListeners('keyboardDidHide');
    };
  }, []);

  // 검색 filter 함수
  const filter = (item: any, query: string) => item.title.includes(query);

  // 클릭했을 때 선택 이벤트
  const onSelect = (index: number) => {
    setValue(data[index].title);
  };

  // 검색창에 타이핑할 때 이벤트
  const onChangeText = (query: string) => {
    setValue(query);
    setData(dataset.filter(item => filter(item, query)));
  };

  return (
    <Autocomplete
      ref={ref}
      size={'medium'}
      style={{width: SCREEN_WIDTH * 0.7}}
      placeholder={placeholder}
      value={value}
      placement={placement}
      accessoryRight={
        <Pressable onPress={() => ref.current.show()}>
          {({pressed}) => (
            <IconContainer pressed={pressed}>
              <Icon name="ios-caret-down-outline" size={20} />
            </IconContainer>
          )}
        </Pressable>
      }
      onChangeText={onChangeText}
      onSelect={onSelect}>
      {data.map(renderItem)}
    </Autocomplete>
  );
};

export default AutoCompleteSearch;

반응형