어디까지나 개발자지만, 기본적으로 피그마를 다룰 줄 알면 더 좋을 것 같아서 이번 기회에 다뤄보았다. 다뤄보는 김에 기록하기.

 

 

기본적인 프레임은 아이폰 11 Pro (375) / Android (360) 을 잡아두고 진행하되, 메인으로 한 os를 잡고 가는 것이 수월하다.동시에 2개를 구현하는 것도 좋지만,, 일이 2배니까! 디자인적 측면에서는 아이폰이 홍보 이미지를 만들 때 더 예뼈보여서 선호한다고는 하던데, 나는 일단 안드로이드를 기반으로 작업하려고 한다.

 

폰트 사이즈는 기본 사이즈를 14정도, 조금 큰 요소를 16정도로 잡는다. 10씩 값을 이동할 때 shift 키 누르면 수월. 

 

한 요소를 component로 만들어줄 때는 ctrl+shift+k로 묶어줄 수 있다. 

 

프로토타입 기능을 사용해서 실제로 어떻게 서비스되는지 동적으로도 보여줄 수 있음.

 

auto layout 기능도 잘 쓰면 유용할 듯 함 :)

 

inspect 란에서 개발 환경을 살펴볼 수 있음. 이미지 추출 역시 Export를 사용하면 됨.

 

협업시에는 comment 기능을 통해 이슈를 바로바로 기록해둘 수도 있음!

 

탭 내에서 페이지 이동이 필요한 경우 스택 네이게이션을 통해 페이지를 이동해주면 된다.

 

하단 버튼(탭)을 통해 화면을 전환하는 것을 구현하려고 봤더니 라이브러리가 필수였다. 

https://www.npmjs.com/package/@react-navigation/bottom-tabs

 

@react-navigation/bottom-tabs

Bottom tab navigator following iOS design guidelines. Latest version: 6.3.2, last published: a month ago. Start using @react-navigation/bottom-tabs in your project by running `npm i @react-navigation/bottom-tabs`. There are 210 other projects in the npm re

www.npmjs.com

 

npm i @react-navigation/bottom-tabs

 

위 명령어를 통해 설치해주고 추가로 필요한 요소들을 공식문서를 보면서 함께 설치해주었다. 공식문서는 여기(https://reactnavigation.org/docs/getting-started)

 

https://reactnavigation.org/docs/getting-started/

 

reactnavigation.org

npm install @react-navigation/native
npm install react-native-screens react-native-safe-area-context

 

기본적으로 하단에 탭을 생성하려면 다음과 같이 컴포넌트를 생성해주면 된다. (코드는 공식문서 예제)

import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';

const Tab = createBottomTabNavigator();

function MyTabs() {
  return (
    <Tab.Navigator>
      <Tab.Screen name="Home" component={HomeScreen} />
      <Tab.Screen name="Settings" component={SettingsScreen} />
    </Tab.Navigator>
  );
}

 

나는 App.js에서 Tab 만드는 것까지 해주었다. 

import {createBottomTabNavigator} from '@react-navigation/bottom-tabs';
import React from 'react';
import AlarmPage from './pages/screens/AlarmPage';
import Home from './pages/screens/Home';
import {NavigationContainer} from '@react-navigation/native';

const Tab = createBottomTabNavigator();

export default function App() {
  return (
    <NavigationContainer>
      <Tab.Navigator>
        <Tab.Screen name="Home" component={Home} />
        <Tab.Screen name="Alarms" component={AlarmPage} />
      </Tab.Navigator>
    </NavigationContainer>
  );
}

 

이렇게 해줬더니 상단에 탭 이름이 표시되어 옵션을 추가로 주었다.

 

공식문서의 이 부분(https://reactnavigation.org/docs/bottom-tab-navigator/#header-related-options)을 참고했다.

<Tab.Screen
          name="Home"
          component={Home}
          options={{headerShown: false}}
/>

 

이 옵션과 함께 알람이 몇개 왔는지 배지로 보여줄 수 있는 옵션 역시 임시 값(5)를 주어 추가했다.

        <Tab.Screen
          name="Alarms"
          component={AlarmPage}
          options={{headerShown: false, tabBarBadge: 5}}
        />

 

Native의 고유한 규칙들

  • div 대신 View 사용
  • 모든 텍스트는 Text 컴포넌트 안에 넣어주기 (그러려면 react-native 라이브러리에서 import를 해줘야 한다)
  • 모든 CSS 속성을 RN에서 다 쓸 수는 없지만 98%정도는 쓸 수 있다.
  • 자동완성 기능을 이용하기 위해 StyleSheet.create기능을 사용하여 스타일 object를 만들어 직접 style 속성으로 넘겨줄 수 있다. 
  • 브라우저가 아니기 때문에, Status-bar와 같은 일부 컴포넌트는 무조건 화면에 렌더링되는 것이 아니라, 운영체제와 통신하기 위한 컴포넌트로 존재한다! (무조건 return해준다고 화면에 다 차례대로 표시되는 것은 아니다. 브라우저랑 다른 것을 명심하자)

 

React Native Package들

과거에 React Native에서 제공했던 컴포넌트, API들이 현재는 제공되지 않는 경우가 많다. 버그도 많고 모든 컴포넌트를 제공하는 것이 어렵다고 판단되어 지원범위를 줄였고 현재 공식 문서를 보면 core component의 개수가 그렇게 많지 않다.  

 

Component와 API의 차이

  • Component : 화면에 렌더링할 요소 (return 태그 안에 넣을 것)
  • API : JS 코드. 운영체제와 소통하는 요소들

 

Third Party Package

RN 팀에서 공식적으로 지원하지 않는 기능들은 이제 유저들이 개발한 Community에서 직접 가져와 사용해야 한다. 유지보수를 유저에게 맡겨야 한다는 단점이 있기에, Expo 팀에서 개발해둔 많은 컴포넌트를 Expo SDK에서 가져다 쓸 수도 있다.

 

 

Layout System

기본적으로 모든  View 컴포넌트는 웹에서 사용하던 flexbox방식을 따른다. grid나 block 방식은 없다. flexbox 방식을 기본적으로 따르고, 디폴트 flex-direction은 column이다. (웹은 row였다)

그리고, 대부분의 경우 너비, 높이에 기반하여 레이아웃을 구성하지 않는다. 반응형 디자인을 고려할 때, width, height 속성은 레이아웃을 잡을 때 쓰지 않는다. RN 방식으로는, flex size를 줘서  지정한다. (비율 시스템)

 

부모에게 flex 값을 주고, 자식에게 얼마만큼의 비율을 차지할 것인지 알려주면 된다. (style 속성)

 

ScrollView

브라우저와 다르게 앱은 컴포넌트가 많다고 자동 스크롤이 되지 않는다. 스크롤이 되도록 하는 View를 RN에서 제공하는데 바로 ScrollView다. (https://reactnative.dev/docs/scrollview

공식 문서를 정말 열심히 뜯어보면서 사용하면 된다. 일단 flex:1은 필요가 없다. 얘는 화면 전체를 먹어야 하니까. 친절하게 나와있는 공식문서 설명을 보면서 따라가보자. 많이 사용할법한 속성으로는 하나하나의 요소를 page단위로 만드는 pagingEnable도 있고, style 속성이 먹지 않기 때문에 스크롤뷰에서만 가능한 contentContainerStyle prop이 있을 것이다. 그리고 현재 기기의 가로 크기를 받아오려면 Dimensions과 관련된 API를 사용하면 된다.

 

Touchable

버튼이 눌렸음을 가시적으로 보여줄 수 있도록 유저가 터치했을 때 피드백을 주는 요소들이 몇가지 있다.

  • TouchableOpacity : 클릭했을 때 약간 투명해짐
  • TouchableHighlight : 클릭했을 때 배경색을 변경
  • TouchableWithoutFeedback : 클릭한 여부만 받아오고 UI의 변화는 없음

이 중 버튼에 관련된 부분은 투명도를 건드리는 컴포넌트로 감싸주는 것이 대부분이다. 공식 문서를 살펴보면 이 컴포넌트보다 더 나은 요소를 pressable로 소개하는데 조금 더 세분화된 속성을 제공한다. 가령 hitSlope 옵션을 사용하여 더 넓은 영역까지 클릭이 되도록 설정해줄 수도 있다. (기존 웹에서는 버튼에 padding을 넣어서 해결했듯이)

크게 2가지 방법으로 나뉘는데, 자세한 설치 방법은 공식 문서를 보면 친절하게 설명되어있다. 

 

원래는 expo 써서 간단하게 개발해보려 했으나, 실제로 배포하는 수준까지 앱을 개발하려고 하기 때문에 안드로이드 스튜디오를 설치하는 정석 방법으로 했다.

 

https://reactnative.dev/docs/environment-setup

 

Setting up the development environment · React Native

This page will help you install and build your first React Native app.

reactnative.dev

 

1. Node, JDK

Chocolatey를 설치하여 보다 쉽게 패키지를 다운받을 수 있게 설정하자. powershell을 관리자 권한으로 켜서 다음의 코드를 실행하여 필요한 Node와 JDK를 설치하자.

choco install -y nodejs-lts openjdk11

 

2. 안드로이드 개발 환경 셋팅

안드로이드 스튜디오를 설치하여 (https://developer.android.com/studio/index.html) 자세한 부분은 공식문서 그대로 따라갔다.

  • Android SDK
  • Android SDK Platform
  • Android Virtual Device

이 3가지를 기본적으로 체크해준 뒤 설치했다.

 

3. Android SDK 설치

안드로이드 스튜디오는 가장 최신ㄴ 버전의 SDK를 기본으로 사용하나, React Native App은 Android 12 SDK버전을 필요로 한다. (현재 글 작성 날짜 기준 2022.8.2) 따라서 SDK manager를 켜서 추가로 설정해주자.

SDK Platform 탭에서 Android 12를 누른 뒤 Show Package Details를 체크하여 다음의 항목을 추가로 설치하자.

  • Android SDK Platform 31
  • Intel x86 Atom_64 System Image or Google APIs Intel x86 Atom System Image

나는 Intel을 깔다가 에러가 나서 뒤의 Google API로 깔았다. 

 

SDK Tools 탭에서 역시 Show Package Details를 체크해준 뒤 Android SDK Build-Tools 항목에서 31.0.0을 체크한다. 모두 체크하였다면 Apply 버튼을 클릭하여 설치해주면 된다.

 

환경변수 설정

다음과 같이 환경변수를 잡아주었다.

환경변수 설정

그리고 Path에 체크된 주소를 추가했다.

가장 마지막 platform-tools 주소를 추가했다.

 

이제 기본적인 설치는 다 완료됬다!

 

npx react-native init AwesomeProject

 

리액트 프로젝트를 시작할 때처럼, 원하는 폴더명으로 리액트 네이티브 프로젝트를 시작하는 코드는 다음과 같다. 이제 이 프로젝트 안에서 물고뜯고 해보자. 

 

 

CLI를 사용하거나 Ignite를 사용하거나 Create-React-Native-App을 사용하는 여러 가지 방법이 있다.

ignite는 개발자가 공통적으로 많이 사용하는 요소들을 미리 다 셋팅해주는 간편한 기능이다. 이 방법을 통해 설치하면 package.json에 엄청 많은 코드가 추가되어있을 뿐만 아니라 기본 폴더들이 생성되어 있는걸 볼 수 있다.

긔록 CRNA는 create-react-app에서 영감을 받아 만들어진 요소로, 기본적인 설정을 대신해주지는 않지만 Expo SDK를 사용가능하게 해주는 강력한 기능이다!

 

아직 리액트 네이티브의 리액트까지만 감이 있는 나는 CLI를 써서 시작했다...ㅎㅎ

https://school.programmers.co.kr/learn/courses/30/lessons/42890

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

접근

유일성을 만족하기 위해 set 자료형을 사용했다. 키의 최대 길이가 8개로, 가능한 키 조합을 모두 구해 각 경우별로 set 자료형으로 변환해도 길이가 변하지 않는 것을 체크했다.

2차원 배열은 set연산을 적용하기가 골치 아파 중간에 한번 tuple 자료형으로 변환해주었다. 

 

유일성을 만족하는 모든 경우의 수를 ck_list 배열에 저장한 뒤, ck_list 배열을 돌면서 최소성을 만족하는지 체크했다.

 

최소성을 만족하는지 체크하기 위해 실제로 최소성을 만족하는 후보키 배열 ck를 만들었다. 모든 후보키에 대해 합집합을 수행해 키가 최소성을 만족하는 경우를 체크했다. (단순히 합집합 한번만 했더니 [(0), (1,2)]과 [1,2,3] 경우를 계산하는 과정에서 0, (1,2,3) 이 조건을 만족하는 것으로 되서 cnt 변수를 통해 모든 후보키에 대해서 고려하도록 수정했다.)

 

한시간정도 걸린 문제였다. 은근 어려워..! 

 

코드

from itertools import combinations

def solution(relation):
    answer = 0
    
    column_list = [i for i in range(len(relation[0]))]

    # 모든 후보키가 될 수 있는 경우의 수(컬럼 인덱스 배열)
    cases = []
    for i in range(1, len(column_list)+1):
        cases.append(list(combinations(column_list, i)))
        
    ck_list = [] 
    for case_list in cases:
        for case in case_list:
            all_senario = []
            for row in range(len(relation)):
                arr = [relation[row][c] for c in case]
                all_senario.append(tuple(arr))
            # print(all_senario)
            
            if len(all_senario) == len(list(set(all_senario))):
                ck_list.append(case)
        
    # print(ck_list)
    
    ck = []
    for key in ck_list:
        if len(ck) == 0:
            ck.append(key)
            continue
        cnt = 0
        for k in ck:
            if set(key) != set(k) | set(key):
                cnt += 1
        
        if cnt == len(ck):
            ck.append(key)
            
    answer = len(ck)        
    return answer

 

 

 

효율성은 없네 경우의 수를 모두 고려해야되서 그런가?

+ Recent posts