카테고리 없음

[iOS/Swift] iOS 프로그래밍 기초 (11/15)

59date 2024. 11. 20. 16:49

iOS 오토 레이아웃(Auto Layout)이란?

 

**iOS 오토 레이아웃(Auto Layout)**은 제약 기반 레이아웃 시스템으로, 화면 크기와 방향이 변하더라도 UI 요소 간의 위치와 크기를 유지하거나 자동으로 조정할 수 있도록 규칙(Constraints)을 설정하는 방식입니다. 이는 다양한 기기와 해상도를 지원하기 위해 만들어졌으며, 다음과 같은 이론적 특징을 가집니다.


1. 제약 조건(Constraints)

오토 레이아웃은 UI 요소 간의 상대적인 위치, 크기, 여백 등 관계를 정의하는 규칙을 기반으로 작동합니다. 제약 조건은 다음과 같은 항목으로 구성됩니다:

  • 위치: 한 요소가 다른 요소나 화면의 특정 위치와의 관계.
  • 크기: 요소의 너비와 높이.
  • 비율: 요소의 크기가 다른 요소나 자체 크기와의 비율.
  • 여백: 요소 간의 거리.

예:

  • "이 버튼은 화면의 왼쪽 가장자리에서 20pt 떨어져 있어야 한다."
  • "이 텍스트 필드의 높이는 버튼의 2배이다."

2. 내재적 콘텐츠 크기(Intrinsic Content Size)

각 UI 요소는 고유의 기본 크기를 가집니다. 이 크기는 요소의 콘텐츠에 의해 결정됩니다.

  • 예: 라벨의 크기는 텍스트 길이에 따라 달라질 수 있습니다.
  • 오토 레이아웃은 이 기본 크기를 참고해 적절한 제약 조건을 설정합니다.

3. 우선순위(Priority)

모든 제약 조건에는 우선순위 값이 부여됩니다(기본값: 1000).
우선순위는 충돌하는 제약 조건 중 어떤 것을 우선적으로 적용할지를 결정합니다. 낮은 우선순위를 가진 제약 조건은 필요할 경우 무시될 수 있습니다.

예:

  • "라벨의 크기는 텍스트에 맞게 조정되지만, 최대 너비는 300pt를 넘을 수 없다."
    • 텍스트 크기 우선순위: 1000
    • 최대 너비 우선순위: 750

4. 상대적 관계

오토 레이아웃은 절대적인 좌표(픽셀 단위)가 아닌 상대적인 관계를 기반으로 작동합니다. 이는 UI 요소가 화면 크기나 방향에 따라 유동적으로 위치를 조정하도록 만듭니다.

예:

  • "버튼은 화면 중앙에 위치하고, 너비는 화면 너비의 50%이다."
  • "이미지는 라벨 아래에 있으며, 라벨과의 거리는 10pt이다."

5. 적응형 레이아웃(Adaptive Layout)

오토 레이아웃은 다양한 화면 크기와 방향(세로/가로)에 따라 UI를 조정합니다. 이를 통해 하나의 레이아웃 설정으로 여러 기기를 지원할 수 있습니다.


핵심 목표

오토 레이아웃의 궁극적인 목적은 반응형 UI(Responsive UI)를 구현하는 것입니다. 이를 통해 개발자는 복잡한 화면 크기와 해상도를 직접 고려하지 않고도 다양한 기기에서 일관된 사용자 경험을 제공할 수 있습니다.

 

 

control을 누르고 연결시키면 outlet을 연결시킬 수 있음.

 

Outlets 세 개 Actions 하나

 

 

 

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var txtHeight: UITextField!
    @IBOutlet weak var txtWeight: UITextField!
    @IBOutlet weak var lblResult: UILabel!
    @IBAction func calcBmi(_ sender: UIButton) {
        let weight = Double(txtWeight.text!)!
        let height = Double(txtHeight.text!)!
        let bmi = weight / (height*height*0.0001) // kg/m*m
        let shortenedBmi = String(format: "%.1f", bmi)
        var body = ""
        if bmi >= 40 {
            body = "3단계 비만"
        } else if bmi >= 30 && bmi < 40 {
            body = "2단계 비만"
        } else if bmi >= 25 && bmi < 30 {
            body = "1단계 비만"
        } else if bmi >= 18.5 && bmi < 25 {
            body = "정상"
        } else {
            body = "저체중"
        }
        print("BMI:\(shortenedBmi), 판정:\(body)")
        lblResult.text = "BMI:\(shortenedBmi), 판정:\(body)"
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    
}

위 소스는 둘 다 값을 입력하지 않으면 다운 된다.

 

 

//
//  ViewController.swift
//  BMI_ljh
//
//  Created by LimJongHoon on 11/13/24.
//

import UIKit

class ViewController: UIViewController {
    
    // 키 입력 필드를 연결하는 아웃렛
    @IBOutlet weak var txtHeight: UITextField!
    
    // 몸무게 입력 필드를 연결하는 아웃렛
    @IBOutlet weak var txtWeight: UITextField!
    
    // BMI 계산 결과를 출력할 라벨
    @IBOutlet weak var lblResult: UILabel!
    
    // BMI 계산 버튼을 누르면 실행되는 함수
    @IBAction func calcBmi(_ sender: UIButton) {
        // 입력값 검증 (키와 몸무게가 비어있거나 유효하지 않을 경우 처리)
        guard let heightText = txtHeight.text, !heightText.isEmpty,  // 키 텍스트가 비어있는지 확인
              let weightText = txtWeight.text, !weightText.isEmpty,  // 몸무게 텍스트가 비어있는지 확인
              let height = Double(heightText),                      // 키를 Double로 변환
              let weight = Double(weightText),                      // 몸무게를 Double로 변환
              height > 0, weight > 0 else {                         // 키와 몸무게가 0보다 큰지 확인
            lblResult.textColor = .red                               // 에러 메시지를 빨간색으로 표시
            lblResult.text = "⚠️ 키와 체중을 올바르게 입력하세요!"      // 에러 메시지 출력
            return                                                   // 잘못된 경우 함수 종료
        }
        
        // BMI 계산 (체중 / (키 * 키) * 10,000) kg/m² 단위
        let bmi = weight / (height * height * 0.0001)
        
        // BMI 값을 소수점 1자리로 포맷팅
        let shortenedBmi = String(format: "%.1f", bmi)
        
        // BMI 판정 및 관련 스타일 정의
        var body = ""              // 판정 결과 문자열
        var color: UIColor = .black // 라벨 색상
        var emoji = ""             // 이모지 추가
        
        // BMI에 따라 판정 및 스타일 결정
        switch bmi {
        case ..<18.5:
            body = "저체중"
            color = .blue          // 저체중일 때 파란색
            emoji = "🥶"           // 저체중 이모지
        case 18.5..<25:
            body = "정상"
            color = .green         // 정상일 때 초록색
            emoji = "😊"           // 정상 이모지
        case 25..<30:
            body = "1단계 비만"
            color = .orange        // 1단계 비만일 때 주황색
            emoji = "😐"           // 1단계 비만 이모지
        case 30..<40:
            body = "2단계 비만"
            color = .red           // 2단계 비만일 때 빨간색
            emoji = "😟"           // 2단계 비만 이모지
        default:
            body = "3단계 비만"
            color = .darkGray      // 3단계 비만일 때 어두운 회색
            emoji = "😱"           // 3단계 비만 이모지
        }
        
        // 결과 라벨에 BMI 결과와 판정을 출력
        lblResult.textColor = color                                  // 판정에 따라 텍스트 색상 변경
        lblResult.text = "\(emoji) BMI: \(shortenedBmi), 판정: \(body)" // 결과 출력
        
        // 애니메이션 효과 (라벨 크기를 줄였다가 다시 키우기)
        lblResult.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) // 라벨 크기를 80%로 축소
        UIView.animate(withDuration: 0.5,                            // 애니메이션 지속 시간 0.5초
                       delay: 0,                                    // 지연 시간 없음
                       usingSpringWithDamping: 0.5,                 // 스프링 효과
                       initialSpringVelocity: 1.0,                  // 초기 속도
                       options: .curveEaseInOut,                    // 부드러운 시작과 끝
                       animations: {
            self.lblResult.transform = .identity                    // 원래 크기로 복구
        })
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // 키와 몸무게 입력 필드 스타일 설정
        configureTextField(txtHeight)
        configureTextField(txtWeight)
        
        // 결과 라벨 스타일 설정
        configureResultLabel(lblResult)
    }
    
    // 텍스트 필드의 스타일을 설정하는 함수
    func configureTextField(_ textField: UITextField) {
        textField.layer.borderColor = UIColor.gray.cgColor          // 테두리 색상: 회색
        textField.layer.borderWidth = 2.0                          // 테두리 두께: 2.0
        textField.layer.cornerRadius = 5.0                         // 모서리를 둥글게: 반경 5.0
        textField.layer.masksToBounds = true                       // 텍스트 필드의 내용을 잘리지 않도록
    }
    
    // 결과 라벨의 스타일을 설정하는 함수
    func configureResultLabel(_ label: UILabel) {
        label.layer.cornerRadius = 10.0                            // 모서리를 둥글게: 반경 10.0
        label.layer.masksToBounds = true                           // 라벨의 내용을 잘리지 않도록
    }
}

 

 

Tab Bar

 

 

 

**iOS Tab Bar Height (탭 바 높이)**에 대해 간단히 요약하면, iOS의 **탭 바(Tab Bar)**는 화면 하단에 위치하며, 앱 내에서 다양한 뷰(탭)를 전환할 수 있도록 도와주는 탐색 컨트롤러입니다. Tab Bar의 높이는 애플의 Human Interface Guidelines(HIG)에 따라 고정된 값 또는 디바이스의 상태에 따라 자동으로 결정됩니다.


탭 바의 기본 높이

  1. 표준 높이:
    • 일반적으로 탭 바의 기본 높이는 49pt입니다.
    • 모든 iPhone과 iPad에서 동일한 높이를 사용합니다.
  2. 안전 영역(Safe Area):
    • iPhone X 이상(노치 디바이스)의 경우, 홈 인디케이터(Home Indicator)를 고려하여 **추가 여백(34pt)**이 포함됩니다.
    • 이로 인해 탭 바의 총 높이는 **83pt (49pt + 34pt)**가 됩니다.

HIG 권장사항

  • Apple은 탭 바의 사용자 경험을 일관되게 유지하기 위해 개발자가 탭 바의 높이를 수정하지 않도록 권장합니다.
  • 탭 바의 콘텐츠와 아이템은 Apple의 시스템 기본 디자인 규칙을 따릅니다.

탭 바 높이 계산 방법 (코드로 확인)

탭 바의 높이를 확인하려면 아래와 같이 코드를 사용할 수 있습니다:

if let tabBarHeight = self.tabBarController?.tabBar.frame.height {
    print("탭 바 높이: \(tabBarHeight)pt")
}

예상 출력:

  • 일반 iPhone: 49.0pt
  • iPhone X 이상: 83.0pt

탭 바 디자인 가이드

  1. 아이콘 및 텍스트 크기:
    • 탭 바의 아이콘은 최대 75px(높이), 텍스트는 기본 12pt 폰트 사용.
  2. 컬러 및 스타일:
    • Apple은 사용자가 탭 바의 배경색, 아이템 색상, 선택된 색상 등을 커스터마이즈할 수 있도록 허용.
  3. 탭 바 아이템 제한:
    • 5개 이하의 아이템을 권장.
    • 5개를 초과하면 "더보기" 탭으로 자동 생성.

탭 바 커스터마이징

탭 바의 스타일과 동작은 UITabBarControllerUITabBar 클래스를 사용해 변경할 수 있습니다.

예제: 탭 바 배경 및 아이템 색상 변경

 
tabBarController?.tabBar.barTintColor = .white // 배경색
tabBarController?.tabBar.tintColor = .blue    // 선택된 아이템 색상
tabBarController?.tabBar.unselectedItemTintColor = .gray // 선택되지 않은 아이템 색상

탭 바 높이 관련 개발 팁

  • 자동 높이 조정: iOS가 디바이스 유형에 따라 탭 바 높이를 자동으로 설정하므로, 수동으로 높이를 변경하지 않는 것이 가장 안전합니다.
  • Safe Area 고려: 탭 바의 콘텐츠를 배치할 때는 반드시 Safe Area를 고려해 콘텐츠가 잘리지 않도록 해야 합니다.

정리

  • 기본 높이: 49pt
  • 노치 디바이스(iPhone X 이상): 83pt (49pt + 34pt)
  • Apple 권장사항: 탭 바 높이는 수정하지 말고, 기본 동작과 스타일 가이드를 따를 것.

탭 바는 iOS 앱 탐색의 핵심 요소이므로 Apple의 HIG를 따르는 것이 가장 중요합니다. 😊

 

 

 

 

**Manual Segue(메뉴얼 세그웨이)**와 **Relationship Segue(릴레이션쉽 세그웨이)**의 차이점

 

Manual Segue(메뉴얼 세그웨이)

  1. 사용 목적: 특정 사용자 동작(예: 버튼 클릭)에서 화면 전환을 수행할 때 사용.
  2. 작동 방식:
    • 코드(performSegue) 또는 UI 요소(버튼, 제스처 등)와 연결하여 명시적으로 호출.
  3. 실행 시점: 버튼 클릭이나 특정 이벤트가 발생했을 때 실행.
  4. 필요한 설정:
    • 스토리보드에서 Segue를 생성하고 Identifier를 지정해야 코드에서 호출 가능.
  5. Identifier 필요 여부: 필요함. (코드 호출 시 Identifier로 Segue를 식별.)
  6. 예제 사용 사례:
    • 버튼 클릭 시 다음 화면으로 이동.
    • 특정 조건에 따라 화면 전환을 동적으로 제어.
  7. 코드 호출 여부: performSegue(withIdentifier:sender:)로 호출 가능.
  8. 기능적 특징: 사용자 동작 기반으로 동적으로 화면 전환 가능.

Relationship Segue(릴레이션쉽 세그웨이)

  1. 사용 목적: 화면 간의 구조적 관계(예: 컨테이너 뷰 컨트롤러)를 정의할 때 사용.
  2. 작동 방식:
    • 스토리보드에서 두 뷰 컨트롤러 간의 관계를 설정하여 자동으로 전환.
  3. 실행 시점: 앱 실행 시 초기화되거나 컨테이너 뷰 컨트롤러에 의해 자동 실행.
  4. 필요한 설정:
    • UINavigationController 또는 UITabBarController와 같은 컨테이너 뷰 컨트롤러와 연결.
  5. Identifier 필요 여부: 필요하지 않음. (자동으로 처리되기 때문.)
  6. 예제 사용 사례:
    • UINavigationController로 화면 계층 구조를 정의.
    • UITabBarController의 탭 간 화면 전환.
  7. 코드 호출 여부: 코드 호출 없이 자동 작동.
  8. 기능적 특징: 앱 내의 화면 구조를 고정적으로 정의.

 

 

 

요약

  • Manual Segue는 사용자의 특정 동작에 따라 명시적으로 화면 전환을 수행하는 데 사용됩니다. 주로 버튼 클릭이나 제스처에 반응하여 코드로 제어할 수 있습니다.
  • Relationship Segue는 UINavigationController나 UITabBarController 같은 컨테이너 뷰 컨트롤러에서 화면 간의 관계를 정의하고, 앱 구조를 고정적으로 설정할 때 사용됩니다.