[UIKit] Basics Of UIKit!

Do Gyung Kim (Bryan)·2023년 11월 17일
0

기본 개념


Apple Document Explaination

UIKit provides a variety of features for building apps, including components you can use to construct the core infrastructure of your iOS, iPadOS, or tvOS apps. The framework provides the window and view architecture for implementing your UI, the event-handling infrastructure for delivering Multi-Touch and other types of input to your app, and the main run loop for managing interactions between the user, the system, and your app.

  • 쉽게 말해 Apple이 제공하는 iOS, iPadOS, tvOS 앱을 만들수 있는 공식 프레임 워크이다.

StoryBoard

Storyboard는 iOS 애플리케이션의 UI의 흐름을 시각적으로 표현한 것으로 화면의 내용과 화면과 화면 간의 연결을 보여준다
그리고 storyboard는 viewController와 view로 이루어진 scene의 집합으로 이루어져 있습니다.
Scene들은 두 개의 viewcontroller의 전환을 나타내는 segue 객체로 연결되어 있습니다.

InterfaceBuilder

Xcode는 storyboard를 위한 visual editor를 제공합니다. 이 에디터를 InterfaceBulider라고 합니다.
그리고 우리는 이 에디터를 이용해서 storyboard를 편집하면서 scene에 button, view 등을 배치하고 viewcontroller 간의 데이터 전송을 관리할 수 있습니다.

Storyboard = 다수의 scene과 seque를 통해 UI의 흐름을 보여주는 것

InterfaceBuilder = 코드를 이용하지 않는 StoryBoard 에디터

Meta-Data

  • 시스템에 대한 정보를 담은 데이터
  • 애플리케이션에 Info.plist 가 같이 번들되어(합쳐져서) 본 파일에 적힌 정보를 가져와 출력하게 된다.
  • 메타 데이터는 앱이 특정한 하드웨어를 사용할때 허락을 구하거나 특정 상황에서 어떤 메시지를 보낼 지에 대한 부분을 담당한다. 민감한 정보를 다루어야 할 때에도 사용될 수 있다.
  • 예를 들어 카메라 디바이스, 위치 정보, 알람 기능을 사용하는데에는 개인정보가 들어가며 하드웨어를 사용하게 된다.

2 Required Resources

  • App icon
  • Launch Screen Stroyboard

요 두개는 UIKit를 사용하는 프로젝트에는 들어있어야한다


코드 구조(MVC)

  • UIKit apps is based on the Model-View-Controller (MVC) design pattern

  • Model : objects manage the app’s data and business logic.

  • View : objects provide the visual representation of your data.

  • Controller : objects act as a bridge between your model and view objects, moving data between them at appropriate times.

  • UIKit 및 Foundation 프레임워크는 앱의 모델 객체를 정의하는 데 사용하는 기본 유형을 많이 제공합니다. UIKit은 디스크 기반 파일에 속하는 데이터 구조를 구성하는 UIDocument 객체를 제공합니다.

  • Foundation 프레임워크는 문자열, 숫자, 배열 및 기타 데이터 유형을 나타내는 기본 객체를 정의합니다. Swift 표준 라이브러리는 Foundation 프레임워크에서 사용할 수 있는 많은 유형을 제공합니다.

  • UIKit은 앱의 컨트롤러 및 뷰 레이어에서 대부분의 객체를 제공합니다. 특히, UIKit은 UIView 클래스를 정의하며, 일반적으로 콘텐츠를 화면에 표시하는 역할을 맡습니다. (Metal 및 기타 시스템 프레임워크를 사용하여 직접 화면에 콘텐츠를 렌더링할 수도 있습니다.)

  • UIApplication 객체는 앱의 주요 이벤트 루프를 실행하고 앱의 전반적인 수명 주기를 관리합니다.


Auto-Layout

  • Auto Layout은 뷰계층에 존재하는 뷰의 위치나 크기를 설정된 제약에 따라 동적으로 계산 해준다

Ex) 만약 버튼과 이미지 뷰가 있고, 버튼은 이미지 뷰를 기준으로 가운데 정렬과 8px 아래 위치하는 제약을 설정 했을 때, 이미지의 크기나 위치가 변경 되었을 때 버튼의 위치도 자동으로 매치해주는 것!

  • 이러한 제약을 기반한 디자인 접근은 사용자 UI를, 어떠한 변경(외부, 내부)에도 동적으로 반응 할 수 있게 해준다.

External Change(외부 변경)

External changes occur when the size or shape of your superview changes. With each change, you must update the layout of your view hierarchy to best use the available space.

  • The user resizes the window (OS X).
  • The user enters or leaves Split View on an iPad (iOS).
  • The device rotates (iOS).
  • The active call and audio recording bars appear or disappear (iOS).
  • You want to support different size classes.
  • You want to support different screen sizes.

Internal Change(내부 변경)

Internal changes occur when the size of the views or controls in your user interface change.

  • The content displayed by the app changes.
  • The app supports internationalization.
  • The app supports Dynamic Type (iOS).

Internationalization

여러 언어나 지역을 지원하는 앱의 경우, 아래의 차이를 고려해야한다.

  1. 언어마다 글자의 간격이나 크기가 다르기에, 텍스트의 크기가 Label의 크기가 변경될 수 있다.
  2. 날짜와 숫자의 형식이 나라와 지역에 따라 변할 수 있다.
  3. 글자의 방향에 따라 레이아웃 전체를 바꿔야 할 수 있다.

Frame-based vs Auto-Layout

유저 인터페이스를 배치하는 세가지 메인 접근 방법이 있다.

  1. Programmatically
  2. Autoresizing masks to automate some response to external change
  3. Auto-Layout

Frame-based

  • 보통의 앱은 아래와 같이 뷰 계층에 존재하는 각각의 뷰의 위치와 크기를 일일이 정해주는 방식으로 개발을 해왔다.
  • Programatical 하게 뷰를 정의 하게 되면, 자유도가 보장되지만, 변경에 대해 일일이 정의해야하는 번거러움이 있다
  • ****Autoresizing mask****를 사용하면 이 번거로움을 줄일 수 있지만, 간단한 변경에만 대응이 가능하다.
  • 또한, 내적변경에 대한 변경은 지원하지 않는다.

Auto Layout

  • Auto Layout은 UI를 제약조건에 따라 정의한다.
  • **제약조건은** 보통 뷰와 뷰의 관계를 표상한다
  • 이 제약조건에 따라 위치와 크기를 자동적으로 변경에 대한 뷰를 그려준다.

Layout Margins

Not recommended on iOS 11 or later use **directionalLayoutMargins**

The default spacing to use when laying out content in the view.

  • 뷰의 레이아웃을 잡을 때 사용하는 디폴트 간격 값.
  • 뷰 바깥의 콘텐츠와 겹치는 일을 방지해줌.
  • Layout margin 은 각각의 모서리에 해당하는 inset 값으로 구성되어 있음.
  • 값이 커질수록 View 표시되는 데이터 영역이 줄어든다고 생각하면 편함!
  • 총 4개 ( top, bottom, leading, trailing ) 의 inset 값을 가지고 있음.
//선언
UIEdgeInsets(top:10,bottom:10,left:10,right:10)
//할당
view.layoutMargins = UIEdgeInsets(top:10,bottom:10,left:10,right:10)

//directionalLayoutMargins 선언
//leading trailing keyword 사용, 오른쪽부터 읽는 언어권을 위해
view.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 0, leading: 64, bottom: 0, trailing: 0)

AutoLayout Attributes

위치 속성

Top / Bottom / Leading / Trailing

뷰 직사각형의 상하좌우 테두리를 뜻한다. 직관적이어서 별로 설명할 게 없다.

다만, Leading은 'Text가 시작하는 부분'이라는 뜻이다.

보통은 왼쪽을 뜻하는 경우가 많다.

하지만 오른쪽에서부터 왼쪽으로 시작하는 언어도 있으므로,

그런 언어를 나타내는 뷰에서는 오른쪽이 Leading이다.

  • 상수로 설정 불가능하고, 다른 뷰와의 관계로 설명해야한다.
A의 Top = (0 * NotAnAttribute) + 200 ❌
A의 Top = (1.0 * B의 Top) + 20

Center X / Center Y

가로, 세로 중심축을 뜻한다.

크기 속성

Height, Width

Top과 Bottom 사이의 높이, Leading과 Trailing 사이의 너비를 말한다.

  • 이 속성들은 상수로 설정 가능하다

Extras

  • 크기 속성과 위치 속성은 같이 못쓴다
A의 Top = B의 Height + 100 ❌
B의 Center X = A의 Width - 200
  • 오토레이아웃 엔진은 4가지 값을 원한다. → 위치 속성 4개
  • 크기가 지정되어있는 View에 위치 속성은 없고 Center X , Y 값만 존재하면 에러가 뜬다. → 위치는 알지만 크기는 알 수 없다.
    • 근데 Center X,Y 값을 알고 있는 상태에서 Top 과 Leading의 속성만 추가해도 알아서 Bottom과 Trailing에 대한 값을 계산한다.
💡 UIKit 은 root view 가 지켜야하는 **최소한의 layout margins 값을 강제한다**

Safe Area

💡 **시스템에 의해 가려질 수 있는 부분의 마진을 자체적으로 가지는 것**
  • Safe Area는 iPhone X의 노치가 생기면서 변화된 화면 비율에 의해 만들어졌다.
  • 이전까지는 직사각형의 형태의 화면에서 화면이 표시되어서 폰을 옆으로 돌려도 상관이 없었다.

→ 그렇기에 Top bottom의 최소 마진 값만 지키면 되었다.

  • 노치와 + 네비게이션 바가 앱의 화면을 가리는걸 방지하기위한 Safe Area가 생겼다.

참조 블로그

Constraints

제약조건 설정하기

  • Storyboard에서 제약조건을 설정하는 방법이다.

코드로 제약조건 설정하기

  • 코드로 제약조건을 적용시키기 위해서는 반드시  some_View.translatesAutoresizingMaskIntoConstraints = false를 설정해주어야 합니다.
  • 또한, SuperView에 붙여준 뒤에 설정해야한다
class ViewController:UIViewController {
    let myButton = UIButton() // 버튼을 하나 생성

    override func viewDidLoad(){
        super.viewDidLoad()
        
        myButton.setTitle("This is Button", for: .normal) // 버튼 이름 설정
        myButton.setTitleColor(.white, for: .normal) // 버튼 이름 색 지정
        myButton.backgroundColor = .darkGray // 버튼 색 지정
        self.view.addSubview(myButton)// view에 붙여주기
        
        myButton.translatesAutoresizingMaskIntoConstraints = false
				//제약조건 설정
				myButton.centerXAnchor.constraint(equalTo:view.centerXAnchor)
            .isActive = true // ---- 1
        myButton.centerYAnchor.constraint(equalTo:view.centerYAnchor)
            .isActive = true // ---- 2
        myButton.heightAnchor.constraint(equalToConstant: 200)
            .isActive = true // ---- 3
        myButton.widthAnchor.constraint(equalToConstant: 200)
            .isActive = true // ---- 4
    }
}

❗코드로 제약조건을 설정할 때에는 equalTo 가 중요하다. 기준 고정점!

  • 이제 Label을 하나 추가해서 Button 아래에 위치하게 해보자
class ViewController:UIViewController {
    let myButton = UIButton() // 버튼을 하나 생성
		let myLabel = UILabel() // Label 생성

    override func viewDidLoad(){
        super.viewDidLoad()
        
        myButton.setTitle("This is Button", for: .normal) // 버튼 이름 설정
        myButton.setTitleColor(.white, for: .normal) // 버튼 이름 색 지정
        myButton.backgroundColor = .darkGray // 버튼 색 지정
        self.view.addSubview(myButton)// view에 붙여주기
        
        myButton.translatesAutoresizingMaskIntoConstraints = false
				//제약조건 설정
				myButton.centerXAnchor.constraint(equalTo:view.centerXAnchor)
            .isActive = true // ---- 1
        myButton.centerYAnchor.constraint(equalTo:view.centerYAnchor)
            .isActive = true // ---- 2
        myButton.heightAnchor.constraint(equalToConstant: 200)
            .isActive = true // ---- 3
        myButton.widthAnchor.constraint(equalToConstant: 200)
            .isActive = true // ---- 4
				//제약조건 활성화
				myLabel.translatesAutoresizingMaskIntoConstraints = false
				//제약조건 설정
				myLabel.centerXAnchor.constraint(equalTo:myButton.bottomAnchor
            ,constant: 30)
            .isActive = true // ---- 1
        myLabel.centerYAnchor.constraint(equalTo:view.leftAnchor
            , constant: 40)
            .isActive = true // ---- 2
        myLabel.heightAnchor.constraint(equalTo: view.rightAnchor
            , constant: -40)
            .isActive = true // ---- 3
    }
}
  1. myLabel을 myButton의 밑 변을 기준으로 30만큼 아래로 위치시키는 코드입니다. 즉 myButton의 30만큼 아래에 myLabel을 위치시키는 코드입니다.
  2. myLabel을 superview의 왼쪽 변을 기준으로 40 만큼 떨어뜨려 놓는 코드입니다.
  3. myLabel을 superview의 오른쪽 변을 기준으로 –40 만큼 떨어뜨려 놓는 코드입니다. 여기서 –40인 이유는 x좌표의 양의 방향은 오른쪽이기 때문에 오른쪽에서 40만큼 왼쪽으로 떨어뜨려놓기 위해서는 –40을 사용해야합니다.

<참조>


콘텐츠가 있는 뷰와 없는 뷰

  • UIView나 UIStackView 같은 뷰는 개발자가 컨텐츠를 넣기 전까지는 빈 뷰이다.
  • 옆에 LABEL ,SWITCH, DATE Picker 같은 뷰는 컨텐츠가 포함되어 있는 뷰이다.
  • 이러한 Labe, Switch 같은 컨텐츠가 포함된 뷰들의 크기를 고유컨텐츠크기 라고 한다.

컨텐츠 포함 여부

  • UIView, UIStackView: 아예 없음.
  • UITextview: 보통은 있고, 스크롤 가능하게 설정하면 없음.
  • UIImageview: 이미지가 로드되면 있음.
  • UISlider: '세로(Y축)' 사이즈만 없음.
  • 그 외: 있음.

고유 컨텐츠 크기 (Intrinsic Content Size)

  • 고유 콘텐츠가 포함된 UI들은 사이즈에 맞춰서 조건이 자동으로 만들어진다.
  • 안에 들어가 있는 고유 콘텐츠(폰트 크기, 텍스트의 양, 아이콘, 이미지 등)의 크기에 맞게 조건을 설정한다.개발자가 따로 크기를 지정해주지 않아도 된다. 그래서 모든 조건을 설정해주지 않아도 에러가 뜨지 않는다.

콘텐츠 허깅과 컴프레션 저항

허깅

고유 사이즈 이상으로 '늘어나지 않으려고 하는' 조건.

(줄어드는 것은 아님)

컴프레션

고유 사이즈 이하로 '줄어들지 않으려고 하는' 조건.

(늘어나는 것은 아님)

0개의 댓글