React Native Toggle Button 만들기

Ollin·2024년 9월 7일

React Native

목록 보기
2/10

1. ToggleButton 컴포넌트 설명

  • initialState 초기 상태 값을 받아 애니메이션을 통해 토글 버튼의 상태를 UI에 반영
  • onToggle이라는 함수를 받아 상태가 바뀔 때마다 부모 컴포넌트에 전달
  • loading 상태에서는 버튼이 비활성화되어 사용자의 추가 입력을 막는 역할

2. 애니메이션 처리

  • React Native의 Animated 모듈을 사용하여 토글의 배경색과 아이콘의 이동을 부드럽게 전환
  • useRef로 애니메이션 값을 관리
  • Animated.timing을 통해 상태 변화에 따른 애니메이션을 적용

전체 코드

import React, {useState, useRef, useEffect} from 'react';
import {StyleSheet, TouchableOpacity, Animated} from 'react-native';
import {ToggleProps} from 'types/Common'; // 타입 정의 import

// ToggleButton 컴포넌트 정의
const ToggleButton: React.FC<ToggleProps> = ({
  initialState, // 초기 상태 값
  onToggle,     // 상태 변경 시 호출되는 함수
  loading = false, // 로딩 중일 때 버튼을 비활성화하기 위한 flag
}) => {
  // 상태 관리를 위한 useState, 초기값으로 initialState를 사용
  const [isOn, setIsOn] = useState(initialState);
  
  // 애니메이션 값을 저장하는 useRef
  const animatedValue = useRef(new Animated.Value(isOn ? 1 : 0)).current;

  // 상태 변경 시 애니메이션 적용
  useEffect(() => {
    Animated.timing(animatedValue, {
      toValue: isOn ? 1 : 0, // 상태에 따라 애니메이션 목표값 설정
      duration: 400, // 애니메이션 지속 시간 (400ms)
      useNativeDriver: true, // 성능 향상을 위한 Native Driver 사용
    }).start(); // 애니메이션 시작
  }, [isOn, animatedValue]);

  // 버튼이 눌렸을 때 실행되는 함수
  const handleToggle = () => {
    if (!loading) { // 로딩 중이 아닐 때만 작동
      const newState = !isOn; // 현재 상태를 반전
      setIsOn(newState); // 상태 업데이트
      onToggle(newState); // 부모 컴포넌트에 상태 변경 알림
    }
  };

  // 아이콘이 이동할 위치 애니메이션 설정 (X축 이동)
  const iconTranslateX = animatedValue.interpolate({
    inputRange: [0, 1],
    outputRange: [-2, 13], // 상태에 따라 X축 위치 변경
  });

  // 배경색 애니메이션 설정 (회색 -> 빨간색)
  const bgColor = animatedValue.interpolate({
    inputRange: [0, 1],
    outputRange: ['#AAA', '#ED423F'], // 상태에 따라 배경색 변경
  });

  return (
    // Animated.View로 배경색 애니메이션 적용
    <Animated.View style={[styles.toggleWrapper, {backgroundColor: bgColor}]}>
      <TouchableOpacity
        activeOpacity={0.8} // 버튼을 눌렀을 때 투명도 효과
        onPress={handleToggle} // 버튼 클릭 시 실행되는 함수
        disabled={loading} // 로딩 중일 때는 비활성화
      >
        {/* 아이콘 애니메이션 */}
        <Animated.View
          style={[styles.icon, {transform: [{translateX: iconTranslateX}]}]}
        />
      </TouchableOpacity>
    </Animated.View>
  );
};

// 스타일 정의
const styles = StyleSheet.create({
  toggleWrapper: {
    borderRadius: 20, // 버튼의 테두리 둥글게
    padding: 5, // 내부 여백
    width: 40,  // 버튼의 너비
    height: 24, // 버튼의 높이
    justifyContent: 'center', // 아이콘을 수직 가운데로 정렬
  },
  icon: {
    width: 19,  // 아이콘의 너비
    height: 19, // 아이콘의 높이
    backgroundColor: '#FFF', // 아이콘의 배경색
    borderRadius: 30, // 아이콘을 둥글게 만듦
  },
});

export default ToggleButton;

3. 핸들링 로직

  • handleToggle 함수에서는 로딩 상태가 아닐 때만 상태를 반전
    onToggle 함수는 부모 컴포넌트로 상태 변경을 전달하는 역할
  • 로딩 중일 때는 버튼을 비활성화하여 사용자의 추가 액션을 방지


4. 스타일링

  • 토글 버튼의 크기와 아이콘의 크기를 적절하게 설정하여 재사용이 용이하도록 구성
  • 배경색과 아이콘의 위치는 애니메이션으로 부드럽게 전환되도록 설정

사용 예시


import ToggleButton from 'components/common/ToggleButton';
import React, {useState} from 'react';
import {View} from 'react-native';

const ToggleButtonTest = () => {
  const [isOn, setIsOn] = useState(true);

  const handleToggle = () => {
    setIsOn(!isOn); // 상태 반전
  };

  return (
    <View>
      {/* ToggleButton 사용, 상태와 상태 변경 함수 전달 */}
      <ToggleButton initialState={isOn} onToggle={handleToggle} />
    </View>
  );
};

export default ToggleButtonTest;
optiondescriptiontyperequireddefault
initialState초기 상태 값booleantrue
onToggle토글 시 동작하는 메소드functiontrue
loadingapi 호출 시 로딩 상태booleanfalsetrue

결과 화면

애니메이션과 함께 동작하는 토글 버튼을 사용한 화면입니다:


위 컴포넌트를 사용하면 React Native에서 커스텀 토글 버튼을 쉽게 구현할 수 있습니다. 애니메이션 효과와 로딩 상태 처리 기능을 통해 UX를 향상시킬 수 있으며, 다양한 프로젝트에 재사용 가능합니다.

좋은 라이브러리도 많이 있지만 아직 모르는 게 너무 많고 일단 뭐든 해보는 게 중요하다고 생각했기 때문에 직접 만들었고 어렵지 않게 구현할 수 있었다. 또 만들어보면서 많이 배울 수 있었기 때문에 좋은 경험이었던 것 같다.

0개의 댓글