0Pricing
React Native Academy · 강의

전환 버튼, 스위치 및 체크박스

Switch 컴포넌트로 불리언 환경설정을 받고, 상태를 전환하며 스타일이 지정된 View를 업데이트해 사용자 지정 체크박스를 만듭니다.

전환 버튼, 스위치 및 체크박스은(는) CoddyKit의 무료 React Native Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 React Native Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

The Switch Component

React Native's built-in Switch component renders the platform's native toggle control — a pill-shaped slider on iOS and a Material Design toggle on Android. It is a controlled component: you must manage its state with useState and provide both the value prop (the current boolean) and the onValueChange callback. Switch is ideal for simple on/off preferences like enabling notifications, dark mode, location access, or auto-save — anywhere a binary choice is needed.

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

export default function NotificationsToggle() {
  const [enabled, setEnabled] = useState(true);

  return (
    <View style={styles.row}>
      <Text style={styles.label}>Push Notifications</Text>
      <Switch
        value={enabled}
        onValueChange={setEnabled} // same as (val) => setEnabled(val)
      />
    </View>
  );
}

const styles = StyleSheet.create({
  row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 16, backgroundColor: '#fff', borderRadius: 12 },
  label: { fontSize: 16, color: '#333' },
});

Styling the Switch

The Switch component accepts color props to customize its appearance. trackColor takes an object with false and true keys for the track color in each state. thumbColor sets the knob color (use a function of the current value for dynamic coloring on Android). ios_backgroundColor sets the track color when the switch is off on iOS (since iOS ignores trackColor.false in some versions). These props let you match the switch to your app's brand colors rather than using the default system blue.

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

export default function BrandedSwitch() {
  const [active, setActive] = useState(false);

  return (
    <View style={styles.row}>
      <Text style={styles.label}>Dark Mode</Text>
      <Switch
        value={active}
        onValueChange={setActive}
        trackColor={{ false: '#e0e0e0', true: '#4f86f7' }}
        thumbColor={active ? '#fff' : '#f0f0f0'}
        ios_backgroundColor='#e0e0e0'
      />
    </View>
  );
}

const styles = StyleSheet.create({
  row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 16 },
  label: { fontSize: 16 },
});

A Settings Screen with Multiple Switches

A typical settings screen has many toggle switches. Manage each setting in an object state variable and update individual fields using the spread pattern. Render each setting in a styled row with a Switch on the right. Separate sections with visual dividers or section headers. Pass the current value and an updater function to each row. When the user changes a setting, update state and optionally persist to AsyncStorage for next launch.

import { Switch, View, Text, StyleSheet, ScrollView } from 'react-native';
import { useState } from 'react';

export default function SettingsScreen() {
  const [settings, setSettings] = useState({
    notifications: true,
    darkMode: false,
    autoPlay: true,
    locationAccess: false,
  });

  function toggle(key) {
    setSettings(prev => ({ ...prev, [key]: !prev[key] }));
  }

  const rows = [
    { key: 'notifications', label: 'Push Notifications' },
    { key: 'darkMode', label: 'Dark Mode' },
    { key: 'autoPlay', label: 'Auto-Play Videos' },
    { key: 'locationAccess', label: 'Location Access' },
  ];

  return (
    <ScrollView style={styles.screen}>
      <View style={styles.section}>
        {rows.map(({ key, label }) => (
          <View key={key} style={styles.row}>
            <Text style={styles.label}>{label}</Text>
            <Switch value={settings[key]} onValueChange={() => toggle(key)} trackColor={{ false: '#e0e0e0', true: '#4f86f7' }} />
          </View>
        ))}
      </View>
    </ScrollView>
  );
}

const styles = StyleSheet.create({
  screen: { flex: 1, backgroundColor: '#f5f5f5' },
  section: { margin: 16, backgroundColor: '#fff', borderRadius: 12, overflow: 'hidden' },
  row: { flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', paddingHorizontal: 16, paddingVertical: 14, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: '#eee' },
  label: { fontSize: 16, color: '#333' },
});

Building a Custom Checkbox

React Native does not include a built-in checkbox. Build a custom one by managing a boolean state and toggling it on press. Render a square View with a border; when checked, fill it with the brand color and show a checkmark. Use TouchableOpacity or Pressable to detect the tap. This pattern is flexible — you can match any design system's checkbox style, add animations, or support indeterminate state (a minus sign for partially selected parent checkboxes in a tree).

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

export default function Checkbox({ label, value, onChange }) {
  return (
    <TouchableOpacity
      style={styles.row}
      onPress={() => onChange(!value)}
      activeOpacity={0.8}
      accessibilityRole='checkbox'
      accessibilityState={{ checked: value }}
    >
      <View style={[styles.box, value && styles.checked]}>
        {value && <Text style={styles.check}>✓</Text>}
      </View>
      <Text style={styles.label}>{label}</Text>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  row: { flexDirection: 'row', alignItems: 'center', gap: 12, paddingVertical: 8 },
  box: { width: 24, height: 24, borderRadius: 6, borderWidth: 2, borderColor: '#ccc', alignItems: 'center', justifyContent: 'center', backgroundColor: '#fff' },
  checked: { backgroundColor: '#4f86f7', borderColor: '#4f86f7' },
  check: { color: '#fff', fontSize: 14, fontWeight: 'bold' },
  label: { fontSize: 16, color: '#333' },
});

Checkbox Group State Management

For a group of checkboxes where users can select multiple options — like choosing notification types or filtering a product list — manage the selections as a Set or array of selected IDs in the parent component. Pass each checkbox its checked state (based on whether its ID is in the selections) and a toggle callback. The toggle callback adds or removes the item's ID from the selections array. This pattern scales to any number of checkboxes without duplicating state logic.

import { View, Text } from 'react-native';
import { useState } from 'react';
import Checkbox from './Checkbox';

const OPTIONS = [
  { id: 'promotions', label: 'Promotions and deals' },
  { id: 'news', label: 'App news and updates' },
  { id: 'messages', label: 'New messages' },
  { id: 'reminders', label: 'Reminders' },
];

export default function NotificationPrefs() {
  const [selected, setSelected] = useState(new Set(['messages']));

  function toggle(id) {
    setSelected(prev => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  }

  return (
    <View style={{ padding: 16 }}>
      <Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 12 }}>Notify me about:</Text>
      {OPTIONS.map(opt => (
        <Checkbox
          key={opt.id}
          label={opt.label}
          value={selected.has(opt.id)}
          onChange={() => toggle(opt.id)}
        />
      ))}
      <Text style={{ marginTop: 16, color: '#666' }}>{selected.size} selected</Text>
    </View>
  );
}

Radio Button Group Pattern

A radio button group lets users pick exactly one option from a set. React Native has no built-in radio button, so implement it as a single-selection variant of the checkbox group. The state is a single value (the selected option's ID) instead of a Set. Each option renders as a circular checkbox: when selected, the circle fills with the brand color. Pressing an option sets the state to that option's ID, automatically deselecting all others. Include accessibilityRole='radio' and accessibilityState={{ checked }} for screen reader support.

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

const PLANS = ['Free', 'Pro', 'Enterprise'];

export default function PlanSelector() {
  const [selected, setSelected] = useState('Free');

  return (
    <View style={{ padding: 16, gap: 8 }}>
      <Text style={{ fontSize: 18, fontWeight: 'bold', marginBottom: 8 }}>Choose a plan</Text>
      {PLANS.map(plan => (
        <TouchableOpacity
          key={plan}
          style={styles.option}
          onPress={() => setSelected(plan)}
          accessibilityRole='radio'
          accessibilityState={{ checked: selected === plan }}
        >
          <View style={[styles.radio, selected === plan && styles.radioSelected]}>
            {selected === plan && <View style={styles.dot} />}
          </View>
          <Text style={styles.planLabel}>{plan}</Text>
        </TouchableOpacity>
      ))}
    </View>
  );
}

const styles = StyleSheet.create({
  option: { flexDirection: 'row', alignItems: 'center', gap: 12, padding: 14, backgroundColor: '#fff', borderRadius: 10, borderWidth: 1.5, borderColor: '#eee' },
  radio: { width: 22, height: 22, borderRadius: 11, borderWidth: 2, borderColor: '#ccc', alignItems: 'center', justifyContent: 'center' },
  radioSelected: { borderColor: '#4f86f7' },
  dot: { width: 10, height: 10, borderRadius: 5, backgroundColor: '#4f86f7' },
  planLabel: { fontSize: 16, color: '#333', fontWeight: '500' },
});

Animated Toggle Component

Build a custom animated toggle that slides a knob using Animated.Value. Start with a value of 0 (off) or 1 (on) and animate it with Animated.timing when the user taps. Use interpolate to map the animated value (0→1) to a horizontal translation (0→knobTravel) for the knob position, and to a color change for the track. This creates a smooth, branded switch that matches your app's design system exactly — without the platform inconsistencies of the built-in Switch component.

import { Animated, TouchableOpacity, StyleSheet } from 'react-native';
import { useRef, useState } from 'react';

export default function AnimatedToggle({ value, onChange }) {
  const anim = useRef(new Animated.Value(value ? 1 : 0)).current;

  function toggle() {
    const next = !value;
    Animated.timing(anim, { toValue: next ? 1 : 0, duration: 180, useNativeDriver: false }).start();
    onChange(next);
  }

  const trackColor = anim.interpolate({ inputRange: [0, 1], outputRange: ['#e0e0e0', '#4f86f7'] });
  const knobX = anim.interpolate({ inputRange: [0, 1], outputRange: [2, 22] });

  return (
    <TouchableOpacity onPress={toggle} activeOpacity={1}>
      <Animated.View style={[styles.track, { backgroundColor: trackColor }]}>
        <Animated.View style={[styles.knob, { transform: [{ translateX: knobX }] }]} />
      </Animated.View>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  track: { width: 52, height: 30, borderRadius: 15, justifyContent: 'center' },
  knob: { width: 26, height: 26, borderRadius: 13, backgroundColor: '#fff', shadowColor: '#000', shadowOffset: { width: 0, height: 1 }, shadowOpacity: 0.25, shadowRadius: 2, elevation: 2 },
});

Slider for Range Values

For numeric range selection (volume, brightness, price range), use a slider. The community package @react-native-community/slider provides a cross-platform slider component. Set minimumValue, maximumValue, and step. The onValueChange callback fires as the user drags, and onSlidingComplete fires when they release. Style the filled track with minimumTrackTintColor and the empty track with maximumTrackTintColor. Display the current value in a Text label above or beside the slider.

import Slider from '@react-native-community/slider';
// npx expo install @react-native-community/slider
import { View, Text, StyleSheet } from 'react-native';
import { useState } from 'react';

export default function VolumeControl() {
  const [volume, setVolume] = useState(50);

  return (
    <View style={styles.container}>
      <Text style={styles.label}>Volume: {Math.round(volume)}%</Text>
      <Slider
        minimumValue={0}
        maximumValue={100}
        step={1}
        value={volume}
        onValueChange={setVolume}
        minimumTrackTintColor='#4f86f7'
        maximumTrackTintColor='#ddd'
        thumbTintColor='#4f86f7'
        style={styles.slider}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: { padding: 24 },
  label: { fontSize: 18, fontWeight: '600', marginBottom: 8 },
  slider: { width: '100%', height: 40 },
});

Accessibility for Toggles

Make toggles and switches accessible to screen reader users. The built-in Switch is fully accessible out of the box — VoiceOver reads its label and current state. For custom checkboxes and radio buttons, set accessibilityRole ('checkbox' or 'radio') and accessibilityState={{ checked: value }}. For the toggle row, use accessible={true} and accessibilityLabel on the wrapping touchable so the entire row (including the label) is announced as one actionable item. Test with VoiceOver (iOS) or TalkBack (Android) before shipping.

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

export default function AccessibleSettingRow({ label, value, onChange, description }) {
  return (
    // The whole row is accessible: tapping anywhere toggles
    <View
      accessible
      accessibilityLabel={label}
      accessibilityHint={description}
      accessibilityRole='switch'
      accessibilityState={{ checked: value }}
      style={{ flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center', padding: 16 }}
    >
      <View style={{ flex: 1 }}>
        <Text style={{ fontSize: 16, color: '#333' }}>{label}</Text>
        {description && <Text style={{ fontSize: 13, color: '#999' }}>{description}</Text>}
      </View>
      <Switch
        value={value}
        onValueChange={onChange}
        importantForAccessibility='no-hide-descendants' // prevent double announcement
      />
    </View>
  );
}

Select All / None Pattern

When working with multiple checkboxes, adding a Select All toggle improves usability. Track the selections in a Set. The Select All checkbox has three states: checked (all selected), unchecked (none selected), and indeterminate (some selected). In React Native, represent the indeterminate visual state as a dash icon instead of a checkmark. When the user taps Select All, either add all item IDs to the Set (if not all are selected) or clear the Set (if all are selected). This pattern is common in email clients and file managers for bulk actions.

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

const ITEMS = ['Alpha', 'Beta', 'Gamma', 'Delta'];

export default function SelectAll() {
  const [selected, setSelected] = useState(new Set());

  const allSelected = selected.size === ITEMS.length;
  const someSelected = selected.size > 0 && !allSelected;

  function toggleAll() {
    setSelected(allSelected ? new Set() : new Set(ITEMS));
  }

  function toggleItem(item) {
    setSelected(prev => {
      const next = new Set(prev);
      next.has(item) ? next.delete(item) : next.add(item);
      return next;
    });
  }

  return (
    <View style={{ padding: 16 }}>
      <TouchableOpacity style={styles.header} onPress={toggleAll}>
        <View style={[styles.box, (allSelected || someSelected) && styles.checked]}>
          <Text style={styles.check}>{someSelected ? '−' : allSelected ? '✓' : ''}</Text>
        </View>
        <Text style={{ fontWeight: 'bold', fontSize: 16 }}>Select All</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  header: { flexDirection: 'row', alignItems: 'center', gap: 12, paddingVertical: 12 },
  box: { width: 24, height: 24, borderRadius: 6, borderWidth: 2, borderColor: '#ccc', alignItems: 'center', justifyContent: 'center' },
  checked: { backgroundColor: '#4f86f7', borderColor: '#4f86f7' },
  check: { color: '#fff', fontWeight: 'bold', fontSize: 14 },
});

Persisting Toggle State to AsyncStorage

User preferences captured by toggles and switches should persist across app restarts. Save each preference to AsyncStorage whenever it changes, and restore all preferences from AsyncStorage when the settings screen mounts. Use a useEffect with no dependencies to load saved preferences on mount, and a separate useEffect with the settings object as a dependency to save whenever settings change. Wrap the read in a try/catch to handle AsyncStorage errors gracefully — if reading fails, the app uses default values silently.

import AsyncStorage from '@react-native-async-storage/async-storage';
import { useState, useEffect } from 'react';

const SETTINGS_KEY = '@user_settings';

const DEFAULT_SETTINGS = {
  notifications: true,
  darkMode: false,
  autoPlay: true,
};

export function usePersistedSettings() {
  const [settings, setSettings] = useState(DEFAULT_SETTINGS);

  // Load on mount
  useEffect(() => {
    AsyncStorage.getItem(SETTINGS_KEY)
      .then(stored => {
        if (stored) setSettings(JSON.parse(stored));
      })
      .catch(() => {}); // use defaults on error
  }, []);

  // Persist whenever settings change
  useEffect(() => {
    AsyncStorage.setItem(SETTINGS_KEY, JSON.stringify(settings));
  }, [settings]);

  function toggle(key) {
    setSettings(prev => ({ ...prev, [key]: !prev[key] }));
  }

  return { settings, toggle };
}

Quick Check

Test your understanding of React Native Mobile Development concepts from this lesson.

Lesson Recap

In this lesson you learned: Switch is the built-in binary toggle controlled by value and onValueChange props, custom checkboxes use boolean state and a square View that conditionally shows a checkmark, and radio groups manage a single selected-ID string to enforce mutual exclusion. Next up we build a complete login form combining TextInput, switches, and validation.

자주 묻는 질문

“전환 버튼, 스위치 및 체크박스” 강의는 무료인가요?

네 — “전환 버튼, 스위치 및 체크박스” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 React Native Academy 강의 전체를 잠금 해제할 수 있습니다. React Native Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“전환 버튼, 스위치 및 체크박스”에서 뭘 배우나요?

Switch 컴포넌트로 불리언 환경설정을 받고, 상태를 전환하며 스타일이 지정된 View를 업데이트해 사용자 지정 체크박스를 만듭니다. 브라우저에서 직접 실행하는 실습 코드로 React Native Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

React Native Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 React Native Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“전환 버튼, 스위치 및 체크박스” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 React Native Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 React Native Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. TextInput 기초와 키보드 유형
  2. TouchableOpacity와 Pressable로 탭 처리하기
  3. 전환 버튼, 스위치 및 체크박스
  4. 간단한 로그인 양식 만들기
← React Native Academy(으)로 돌아가기