DateP

전체적인 앱 구조 설계 (2025 -01-09)

Solo.dev 2025. 1. 9. 03:26

전체적인 앱 구조 설계


앱 설계 아이디어

DateP 앱은 간단하면서 직관적인 구조로 구성됩니다. 아래는 앱의 전체적인 설계 개요입니다.


탭 네비게이션 사용

  • Home 탭: 사용자 입력 (취미, 나이, 데이트 코스 선택 등).
  • Result 탭: 이전에 추천받은 결과를 확인하고 저장할 예정(아직 개발 중).

각 화면의 역할

  1. Home 화면:
    • 데이트 추천을 위한 입력값을 수집하고, 결과를 반환하는 주요 인터페이스.
    • 사용자 입력 필드와 Select 컴포넌트를 활용하여 동적인 UI 제공.
  2. Result 화면:
    • 추천받은 결과의 히스토리를 저장하고 다시 볼 수 있는 기능 제공 예정.

설계 목표

  • 직관적이고 사용하기 쉬운 UI를 제공.
  • Gluestack UI의 컴포넌트를 최대한 활용하여 일관성 있는 디자인 구현.
  • 사용자가 추천 결과를 쉽게 볼 수 있도록 모달을 활용하여 데이터를 표시할 계획.

구현 방법

탭 네비게이션

  • 앱의 주요 화면 전환은 탭 네비게이션을 통해 이루어집니다.
  • expo-router 또는 React-Navigation의 BottomTabNavigator를 사용하여 구현.

추천 결과 표시

  • 현재 Result 화면은 개발 중이며, 추천 결과는 **모달(Modal)**을 활용해 사용자에게 표시할 예정.

탭 구조 코드

import React from 'react';
import { Tabs } from 'expo-router';

export default function Layout() {
  return (
    <Tabs
      screenOptions={{
        tabBarActiveTintColor: '#2D9CDB',
        headerShown: false,
      }}
    >
      {/* Home 화면 */}
      <Tabs.Screen
        name="home"
        options={{
          title: 'Home',
          tabBarIcon: ({ color }) => (
            <IconSymbol size={28} name="house.fill" color={color} />
          ),
        }}
      />
      
      {/* Result 화면 (개발 예정) */}
      <Tabs.Screen
        name="result"
        options={{
          title: 'Result',
          tabBarIcon: ({ color }) => (
            <IconSymbol size={28} name="checkmark.seal.fill" color={color} />
          ),
        }}
      />
    </Tabs>
  );
}

현재 진행 상황

  1. Home 화면 작업
    • 사용자가 입력할 수 있는 Input과 Select 컴포넌트를 배치.
    • 입력값을 기반으로 추천 결과를 생성하는 "추천받기" 버튼 제공.
    • 전체적인 화면의 레이아웃은 Gluestack UI의 Box, Input, Select 컴포넌트로 구성.
  2. Result 화면
    • 아직 구현되지 않았으나, 사용자가 추천받은 결과를 확인할 수 있도록 리스트 형태로 제공할 예정.
  3. 추천 결과 표시
    • 사용자가 추천받은 결과는 **모달(Modal)**을 통해 보여줄 계획.
    • Gluestack UI와 React-Native의 Modal을 활용해 간단하고 시각적으로 깔끔한 UI를 제공할 예정.

코드 스니펫: Home 화면 기초

 
import React from 'react';
import { Box, Heading, Input, InputField, Button, ButtonText } from '@/components/ui';
import CustomSelect from '@/components/CustomSelect';
import { selectOptions } from '@/src/data/optionsData';

export default function HomeScreen() {
  const [select1, setSelect1] = React.useState('');
  const [select1Sub, setSelect1Sub] = React.useState('');

  return (
    <Box className="flex-1 p-4 bg-gray-50">
      <Heading className="text-center mb-4" size="lg">
        데이트 플랜 추천
      </Heading>

      {/* 메뉴 선택 */}
      <CustomSelect
        options={selectOptions.menu}
        placeholder="메뉴 선택"
        selectedValue={select1}
        onValueChange={(value) => {
          setSelect1(value);
          setSelect1Sub('');
        }}
      />
      {select1 && (
        <CustomSelect
          options={selectOptions[select1]}
          placeholder="세부 옵션 선택"
          selectedValue={select1Sub}
          onValueChange={setSelect1Sub}
        />
      )}

      {/* 추천받기 버튼 */}
      <Button className="mt-4 bg-blue-500">
        <ButtonText className="text-white">추천받기</ButtonText>
      </Button>
    </Box>
  );
}

Gluestack UI 컴포넌트 분리 작업

Home 화면에서 Gluestack UI의 Select 컴포넌트를 반복적으로 호출하면서 코드가 길어지는 문제를 해결하기 위해, CustomSelect.tsx라는 별도 컴포넌트를 생성하여 사용했습니다. 이를 통해 재사용 가능하고 간결한 코드를 유지할 수 있습니다.


CustomSelect.tsx 코드

import React from 'react';
import {
  Select,
  SelectTrigger,
  SelectInput,
  SelectIcon,
  SelectPortal,
  SelectBackdrop,
  SelectContent,
  SelectItem,
  SelectDragIndicator,
  SelectDragIndicatorWrapper,
} from '@/components/ui/select';
import { ChevronDownIcon } from './ui/icon';
import { ScrollView, StyleSheet } from 'react-native';

type CustomSelectProps = {
  options: { label: string; value: string }[];
  placeholder: string;
  onValueChange: (value: string) => void;
  selectedValue: string;
};

export default function CustomSelect({
  options,
  placeholder,
  onValueChange,
  selectedValue,
}: CustomSelectProps) {
  return (
    <Select onValueChange={onValueChange} selectedValue={selectedValue}>
      <SelectTrigger
        variant="outline"
        size="xl"
        style={{
          width: '100%',
          paddingHorizontal: 10,
          alignItems: 'center',
        }}
      >
        <SelectInput
          placeholder={placeholder}
          style={{
            textAlign: 'left',
            width: '85%',
            paddingRight: 10,
            fontSize: 14,
            overflow: 'hidden',
            textOverflow: 'ellipsis',
          }}
        />
        <SelectIcon
          as={ChevronDownIcon}
          style={{
            position: 'absolute',
            right: 10,
          }}
        />
      </SelectTrigger>
      <SelectPortal>
        <SelectBackdrop />
        <SelectContent style={styles.selectContent}>
          <ScrollView
            style={styles.scrollContainer}
            contentContainerStyle={styles.scrollContent}
          >
            <SelectDragIndicatorWrapper>
              <SelectDragIndicator />
            </SelectDragIndicatorWrapper>
            {options.map((option) => (
              <SelectItem
                key={option.value}
                label={option.label}
                value={option.value}
                style={styles.selectItem}
              />
            ))}
          </ScrollView>
        </SelectContent>
      </SelectPortal>
    </Select>
  );
}

const styles = StyleSheet.create({
  selectContent: {
    width: '100%',
    alignSelf: 'center',
    borderRadius: 8,
    backgroundColor: '#fff',
  },
  scrollContainer: {
    width: '100%',
    maxHeight: 400,
  },
  scrollContent: {
    flexGrow: 1,
  },
  selectItem: {
    paddingVertical: 10,
    borderBottomWidth: 1,
    borderBottomColor: '#ccc',
  },
});

 


결과물

  • 앱이 탭 네비게이션을 통해 Home 화면을 중심으로 동작.
  • CustomSelect.tsx로 Select 컴포넌트를 모듈화하여 코드 재사용성을 높임.
  • 현재 Result 화면은 개발 중이며, 추천 결과는 **모달(Modal)**을 통해 사용자에게 표시할 예정.

주요 내용 요약

  • 앱 구조 설계: Gluestack UI와 React-Navigation을 활용하여 Home 화면 구성.
  • 코드 재사용성 개선: CustomSelect.tsx로 Select 컴포넌트를 분리하여 코드 간결화.
  • 추천 결과는 모달로 표시하여 사용자 경험을 개선할 예정.