[UMC] 2주차 : 오토 레이아웃 & 버튼 & 화면전환
IOS 2주차 정리
iOS 2주차 워크북 : 오토 레이아웃&버튼
📝 학습 목표
- Frame 기반 레이아웃과 AutoLayout의 차이점에 대해 이해한다.
- Autolayout의 주요 속성에 대해 이해한다.
- Autolayout으로 비율코딩을 하는 방법에 대해 이해한다.
✍🏻 수업 내용 정리
피드백
오늘은 이전 미션과 자료조사에서 겹치는 내용이 많아 한꺼번에 피드백을 해주셨다.
잠깐 복습 타임, 저번 시간에 했던 내용이다.
프로젝트의 기본 구성은 이렇게 되어있다.
오토 레이아웃
아이폰은 나온지 꽤 된 핸드폰이다. 오랜 시간 동안 발전해온 만큼, 디바이스 크기는 세대별로 천차만별이다.
개발자 관점에서 볼 땐, 모델 별 디바이스 크기가 달라도 유저에게 동일한 화면을 보여줘야 할 의무가 있다.
그래서 화면 구성을 디바이스 크기에 맞게 대응해주는 것이 바로 ‘오토 레이아웃’이다.
Q. 디바이스 세대가 흘러가면서 일어난 가장 큰 변화는 무엇이라고 생각하는가?
카메라??
Ans. 정답은 바로 10주년 기념으로 나온, 아이폰x에 나온다
아이폰 x에서 일어난 가장 큰 변화는 바로 새로 생긴 노치 영역과 사라진 홈버튼이었다.
이 노치영역과 홈버튼이 사라지자 기존의 홈버튼이 있고 노치가 없는 모델들과의 화면 모양이 달라지게 되면서
Safe Area 라는 개념이 떠올랐다.
Safe Area
safe area란, 필수적으로 노출되어야 하는 것을 보장하는 영역이다
이 부분은 절대로 건들지 마! 라고 선언되는 영역이다.
예를 들어 세상에는 엄청나게 다양한 television 모델이 있는데
각각의 화면 비율, 크기가 전부 다른 상황에서 잘리지 않은 화면을 보여주려면
이 safe area 영역에서 화면을 보여주면 된다.
🎯 핵심 키워드
-
safeArea
iOS 11이 나오기 전,
즉 Safe Area가 등장하기 전엔 Top / Bottom Layout Guide라는 것이 존재했다.
이 Top/Bottom Layout Guide는 Status Bar, Navigation Bar, Tabbar 등에 의해서
View가 가려지지 않기 위해서 제공 되던 시스템적인 마진이었다.
이때는 Top, Bottom의 View가 가려지는 것만 신경쓰면 됐고,
Landscape 모드일 떄도 문제가 되지 않았다.
회전 했을 시, 상단바는 사라지지만 다른 내비게이션 바가 있더라도
오로지 Top, Bottom만 신경쓰면 됐다.
하지만 iOS 11이 등장하면서 검은탈모머리, 노치가 생겨버렸다.
노치에 View가 가려지는 건 어쩔텐가
검은탈모머리 때문에 Landscape일 때 Leading / Trailing에 대한 마진도 필요하게 되었다.
Top, Bottom 뿐만 아니라, Leading, Trailing도 시스템 마진이 필요해졌기 때문에,
기존에 쓰이던 Top / Bottom Layout Guide가 Deprecate 되고
Top, Bottom, Leading, Trailing 시스템 마진을 모두 가지는 Safe Area가 등장하게 됐다.
즉, 시스템에 의해 가려질 수 있는 부분의 마진을 자체적으로 가지는 것이 Safe Area
-
AutoLayout
오토 레이아웃(Auto Layout)이란,
제약 조건(Constraints)에 따라 뷰 계층 구조에 있는 모든 뷰의 크기와 위치를 동적으로 지정하는 것이다
다양한 기기가 존재하고, 그에 따른 기능도 다양하고, 다양한 국가가 애플에 기기를 사용하기 때문에 이를 동적으로 응답하는 사용자 인터페이스를 만들기 위해 필요하다
-
Inspector
inspector영역: 프로젝트 네비게이터에서 선택한 개체 또는 전체 프로젝트에 대한 정보를 보고 편집할 수 있다. 인스펙터 영역을 열기 위해서는 메인창의 툴바에서 오른쪽 버튼을 클릭하면 된다.
-
Constraint
제약은 오토 레이아웃에서 핵심적인 내용이다.
Constraint는 NSLayoutConstraint 클래스로 구현되어있다
# NSLayoutConstraint
The relationship between two user interface objects that must be satisfied by the constraint-based layout system.
## Declaration
iOS, iPadOS, Mac Catalyst, tvOS
@MainActor class NSLayoutConstraint :NSObject
macOS
class NSLayoutConstraint :NSObject
-
IBOutlet & IBAction
이 둘의 역할은 StoryBoard와의 연결고리를 담당한다. 변수나 함수를 정의할 때 앞에 @IBAction 또는 @IBOutlet 키워드를 통해 StoryBoard에서 버튼이나 레이블같은 컴포넌트와 연결이 가능하다.
IBAction은 Event가 일어난 경우 호출되는 Action을 정의해둔 것이고, IBOutlet은 값에 접근하기위한 변수라고 보면 편할 것 같다.
일단, Action과 Outlet은 어느정도 의미가 짐작이 된다. 말 그대로 Action은 입력이 들어왔을때 어떤 행동을 할 지를 나타내고 Outlet은 데이터를 가져오는 것이다. 앞에 있는 IB는 Interface Builder의 약자이다. 즉 IBAction은 Interface Builder를 통해 받아온 정보로 Action을 수행하겠다는 의미.
@는 컴파일러에게 어떤 속성을 가지고있다고 전하는 역할을 하는 예약어이다. 컴파일러에게 @가 붙은 명령어에 대해 어떤 attribute가 부여되었음을 말한다. 아래의 예시처럼 속성이 부여된다.
@IBAction // Interface Builder와 연결된 Action이다.
@UIApplicationMain // App의 Main이 여기에 있다.
📢 2주차 수업 후기
- 2주차 수업을 듣고 서로 느낀 점을 이야기해주세요!
- 핵심 키워드에 대해 완벽하게 이해했는지? 혹시 이해가 안 되는 부분은 뭐였는지? 서로 이야기해주세요!
⚠️ 스터디간 주의사항
- 과제 피드백 기반 진행입니다 - 한명씩 본인의 과제를 발표하는 시간 그리고 해온 과제에 대한 피드백을 하는 시간(ex: 전 이렇게 생각해서 이런 부분 다르게 해왔는데 저것도 괜찮은 것 같아요!)이 무조건 기반이 되어야 합니다!
- 부가적으로 워크북에서 제공되는 키워드 혹은 강의에서 들은 디테일적인 부분에서 더 토의해봐도 좋을 것 같습니다
✅ 실습 체크리스트
- Frame 기반 레이아웃과 Autolayout으로 레이아웃을 짜는 방법의 차이점을 이해했나요?
Frame 베이스는 코드로 레이아웃을 하나하나 따는 것이다.
일반적으로 각 view frame을 programmatically하게 설정해 사용자 인터페이스에 배치하는 거고
frame에는 super view의 좌표와 view의 origin, 높이, 너비를 정의한다.
- frame에는 super view의 좌표와 view의 origin, 높이, 너비를 정의= 위의 그림에서 보이듯 super view에서 해당 view의 위치, 원점, 높이 너비를 지정해줘야 한다.
**let** myView: UIImageView **=** .init(frame: .init(x: 30, y: 80, width: 350, height: 200))
이렇게….(딱 봐도 개힘들어 보임)
이게 우리가 흔히 아는 오토레이아웃에서 contraint 지정 방법
-
Autolayout에서 constraint의 의미와 constraint를 주어 뷰를 배치하는 방법에 대해 이해했나요?
완료
- Autolayout에서 equal width, equal height에 대해 이해하고 직접 실습해보았나요?
이 세가지 component에 equal width equal height 적용
- Autolayout에서 Align center X, Y에 대해 이해하고 직접 실습해보았나요?
각 컴포넌트 x축 정렬, 마지막 바닥에 있는 세 컴포넌트(문의하기 등) y축 정렬
- 위 사항을 종합하여 Autolayout으로 뷰를 간단하게 배치해보시고, iPhone8 과 iPhone13 Pro Max 시뮬레이터로 돌렸을 때 뷰가 비율에 알맞게 배치되었나요?
아이폰 8과 12(13과 동일 사이즈) 확인
- Standard Mission
- 실제 앱을 하나 정해서, 특정 화면 구성해보기 ✅ 다양한 Auto Layout을 활용해보기 ✅ Safe Area 지키기 ✅ 모든 디바이스 크기에 대응하기
저번주와 같게 하는 건 재미없을 것 같아서
이번에는 에브리타임 인트로를 구현하기로 했다.
(이 재미없을 것 같다는 생각이 화근이었다)
각 컴포넌트를 대략 배치하고
오늘 세미나에서 다룬 오토 레이아웃을 이용해 크기를 맞춰주었다.
그러자 발생한 예상치 못한 문제
문제1
there is no scene delegate set. a scene delegate class must be specified to use a main storyboard file.
:이런 오류메세지가 뜨면서 아예 앱이 검은 화면이 되어버린다.
혹시 시뮬 문제인가(현실부정) 싶어서 시뮬도 초기화 해봤지만 소용 없었다.
AppDelegate에 window 객체도 추가해보았으나(13관련 이슈) 역시나 실패
뭐여…뭐가 문제여
결국 xcode 파일을 새로 생성해 전부 옮겼더니 해결되었다.
문제2
로그인 버튼의 radius는 적용이 되는 반면, 아이디 textField와 비밀번호 textField의 radius가 적용이 안되는 문제 발생
장시간의 구글링 결과 알아낸, 어느 외쿡 사이트에서 얻은 해결 방법!
바로 텍스트 필드의 **clipsToBounds를 true로 설정해주는것!!**
(널 알아내려고 별의 별 사이트를 다 뒤졌다)
그럼 clipsToBounds가 무엇인가 하니
clipsToBounds
A Boolean value that determines whether subviews are confined to the bounds of the view.
iOS 2.0+iPadOS 2.0+Mac Catalyst 13.0+tvOS 9.0+
Declaration
var clipsToBounds: [Bool](https://developer.apple.com/documentation/swift/bool) { get set }
Discussion
Setting this value to true
causes subviews to be clipped to the bounds of the view. If set to false
, subviews whose frames extend beyond the visible bounds of the view aren’t clipped.
The default value is false
. Some subclasses of UIView
, like [UIScrollView](https://developer.apple.com/documentation/uikit/uiscrollview)
, override the default value to true
.
애플 공식문서를 보면, 서브뷰가 뷰의 테두리로 제한되냐 안되냐를 결정하는 거라고 한다.
쉽게 말하자면
텍스트 필드 경우에는 안에 placeholder를 위치했을 때
서브뷰 개념의 text의 테두리 때문에 아무리 cornerRadius를 적용해도 글자가 잘릴까 봐 적용하지 못하고 있던 거였고, 이 clipsToBounds를 true로 설정하면 그냥 텍스트를 무시하고 잘라버려서, cornerRadius가 적용됐던 것이다!!
😃😃결국 성공!!
그리고 아래가 실제 우리가 쓰는 앱 화면
똑같죠…?
- Challenge Mission
- 버튼 터치를 통해 다른 화면(다른 스토리보드와 ViewController)으로 화면 전환하기(Present, Navigation)
iOS에서 화면을 전환하는 방식은 크게 두 가지가 있다.
소스코드를 통해 전환하는 방식
storyboard를 통해 전환하는 방식
😃 화면 전환 방법(concrete)
- view Controller의 View 위에 다른 View를 가져와 바꿔치기
- View Controller에서 다른 View Controller를 호출하여 전환하기
- Navigation Controller를 사용하여 화면 전환하기
- 화면 전환용 객체 세그웨이를 사용하여 화면 전환하기
위에 중 1번, 뷰 컨트롤러의 뷰 위에 다른 뷰를 가져와 바꿔치기는 메모리 누수 위험 때문에 되도록 사용하지 말아야 한다.
😇 View Controller에서 다른 View Controller를 호출하여 전환하기
Declaration
func present(
_ viewControllerToPresent: [UIViewController](https://developer.apple.com/documentation/uikit/uiviewcontroller),
animated flag: [Bool](https://developer.apple.com/documentation/swift/bool),
completion: (() -> [Void](https://developer.apple.com/documentation/swift/void))? = nil
)
**Parameters**
viewControllerToPresent
The view controller to display over the current view controller’s content.
flag
Pass true
to animate the presentation; otherwise, pass false
.
completion
The block to execute after the presentation finishes. This block has no return value and takes no parameters. You may specify nil
for this parameter.
**Declaration**
func dismiss(
animated flag: [Bool](https://developer.apple.com/documentation/swift/bool),
completion: (() -> [Void](https://developer.apple.com/documentation/swift/void))? = nil
)
**Parametersflag
Pass true
to animate the transition.completion
The block to execute after the view controller is dismissed. This block has no return value and takes no parameters. You may specify nil
for this parameter.
현재 컨트롤러에서 이동할 위치의 컨트롤러를 직접 호출해서 화면을 전환하는 방식.
직접 호출(표시)한다는 의미에서 presentation 방식이라 부른다.
기존 viewController위에 새로운 viewController를 덮는 방식
present() 메소드에 이동할 화면의 뷰 컨트롤러를 넘겨주면 이전 화면에서 이동할 화면의 뷰 컨트롤러가 표시된다.
present 메소드의 첫 번째 파라미터엔 이동할 화면의 뷰 컨트롤러 인스턴스를 넘겨주면 되고
두번째 파라미터엔 애니메이션 효과를 줄 건지 안 줄건지 Bool 값으로
마지막 completion엔 클로저를 전달받고 있는데
이 클로저에 코드를 쓰면, 화면 전환이 완료되는 시점에 맞춰 completion 클로저가 호출되게 된다.
화면 전환 방식은 비동기 방식으로 처리되기 때문에 화면 전환이 완료된 이후에 코드로 처리해야할 로직이 있다면 여기에 쓰면 된다.
그리고 present 되었던 화면에서 이전화면으로 돌아가게 해주는 메소드가 있다.
바로 dismiss 메소드!
이 메소드는 이전 화면으로 돌아가는 기능이라 뷰 컨트롤러의 인스턴스를 인자로 받지 않는다.
dismiss 메소드의 첫번째 파라미터는 애니메이션 적용 여부
두 번째는 completion 클로저이다. (마찬가지로 화면 전환 후 동작)
😌 Navigation Controller를 사용해 화면 전환하기
Declaration
func pushViewController(
_ viewController: [UIViewController](https://developer.apple.com/documentation/uikit/uiviewcontroller),
animated: [Bool](https://developer.apple.com/documentation/swift/bool)
)
**ParametersviewController
The view controller to push onto the stack. This object cannot be a tab bar controller. If the view controller is already on the navigation stack, this method throws an exception. animated
Specify true
to animate the transition or false
if you do not want the transition to be animated. You might specify false
if you are setting up the navigation controller at launch time.
Declaration
func popViewController(animated: [Bool](https://developer.apple.com/documentation/swift/bool)) -> [UIViewController](https://developer.apple.com/documentation/uikit/uiviewcontroller)?
**Parametersanimated
Set this value to true
to animate the transition. Pass false
if you are setting up a navigation controller before its view is displayed.
Return Value
The view controller that was popped from the stack.
네비게이션 컨트롤러는 계층적인 성격을 띈 컨텐츠 구조를 관리하기 위한 컨트롤러
그래서 네비게이션 컨트롤러는 뷰 컨트롤러의 전환을 직접 컨트롤하고
앱의 네비게이션 정보를 표시하는 역할을 할 뿐만 아니라
네비게이션 스택으로 자식 뷰 컨트롤러들을 관리한다.
네비게이션 스택은 우리가 아는 그 스택이다. 선입후출 방식으로 나중에 들어온 화면이 제일 먼저 나간다.
그래서 pushViewController 메소드를 통해 네비게이션 스택에 화면을 추가하고
PopViewController 메소드를 사용해 네비게이션 스택에서 화면을 제거한다.
pushViewController메소드의 첫번째 파라미터는 이동할 화면의 인스턴스, 두 번째 파라미터는 전환시 애니메이션 유무 표시이다.
popViewController메소드의 첫번째 파라미터는 이전 화면으로 이동할 때 애니메이션을 사용할지 여부이다.
🧐 화면 전환용 객체 세그웨이를 사용해 화면 전환하기
Segueway는 두 개의 뷰 컨트롤러 사이에 연결된 화면 전환 객체를 말한다.
스토리보드를 통해 출발지와 도착지를 직접 지정하는 것을 segueway 방식이라고 한다.
코드를 사용하지 않고 스토리보드만으로 화면 전환을 구현할 수 있는 것이 특징!!
segueway의 종류에는 Action Segueway와 Manual Segueway가 있다.
출발점이 ViewController 자체인 경우를 Manual Segueway라고 하고,
출발점이 버튼, 셀 등이면 Action Segueway, trigger Segueway라고 나누어 부른다.
액션 세그웨이는 버튼 터치와 같은 트리거 이벤트가 세그웨이 실행으로 바로 연결된다.
그래서 소스코드를 추가하지 않아도 화면 전환을 바로 구현할 수 있다.
메뉴얼 세그웨이는 적절한 시점에 perform segue라는 메소드를 호출하며 세그웨이가 실행되어 화면전환이 실행된다.
📸 Action Segueway 종류
Show : 가장 일반적인 세그웨이, 네비게이션 컨트롤러를 사용하게 되면 화면 전환 시 뷰컨트롤러가 네비게이션 스택에 쌓인다. 만약 사용 안하면 네비게이션 컨트롤러 present
Show Detail: split 뷰에서 사용하는 세그웨이 (아이패드에서 특이한 구조로 나타남 ex: 아이패드 메세지 화면)
Present Modally:이전 뷰 컨트롤러를 덮으면서 새로운 화면 나타남(프레젠테이션 방식으로 화면이 전환)
Present As Popover: 아이패드에서 사용, 팝업창을 띄울 때 사용(아이폰 사용x)
Custom:세그웨이를 사용자가 원하는 방식으로 커스텀 할 때 사용
💿💿💿💿완성화면
댓글남기기