before
입력값이 많아져 텍스트의 길이가 화면 너비를 넘기면, 그때부터 입력값은 자리가 없으니 ...
로 표시된다. 텍스트가 축약되지 않고 입력값이 계속 표시될 수 있게 스크롤이 넣고 싶어졌다. 우선 강의에서 배운 내용에 따르면 스크롤 뷰의 내용(컨텐트 뷰)이 스크롤 뷰와 너비가 같으면 vertical
, 높이가 같으면 horizontal
스크롤이 생긴다. 그걸 떠올리며 UIScrollView
를 MainViewController
에 추가하고 레이아웃을 적용했다.
class MainViewController: UIViewController {
private lazy var scrollView: UIScrollView = {
let view = UIScrollView()
view.backgroundColor = .black
view.indicatorStyle = .white // 배경이 까마니까 스크롤은 하얗게
return view
}()
private func addSubview() {
// inputLabel을 view에 subview로 지정했던 것을 지우고, scrollView의 subview로 지정
view.addSubview(scrollView)
scrollView.addSubview(inputLabel)
}
private func layout() {
let superView = view.safeAreaLayoutGuide
let offset: CGFloat = 30.0
NSLayoutConstraint.activate([
// 원래 inputLabel이 갖고 있던 제약조건을 그대로 scrollView에 적용
scrollView.leadingAnchor.constraint(equalTo: superView.leadingAnchor, constant: offset),
scrollView.trailingAnchor.constraint(equalTo: superView.trailingAnchor, constant: -offset),
scrollView.topAnchor.constraint(equalTo: superView.topAnchor, constant: 200),
scrollView.heightAnchor.constraint(equalToConstant: 100),
// inputLabel의 상하좌우 및 높이 값을 scrollView에 일치
inputLabel.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor),
inputLabel.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor),
inputLabel.topAnchor.constraint(equalTo: scrollView.topAnchor),
inputLabel.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor),
inputLabel.heightAnchor.constraint(equalTo: scrollView.heightAnchor),
])
}
}
여기까지 하고 실행해보니, 가로(horizontal) 스크롤
이 생겼다. 그런데 두가지 개선해야 할 점이 있었다.
- 오른쪽 정렬이었던
inputLabel
의 텍스트가 갑자기 왼쪽 정렬이 되었다. 다시 오른쪽으로 보내야 한다.- 텍스트가 길어져 스크롤이 생겼을 때, 스크롤이 가장 최근에 입력된 값 쪽(오른쪽)에 위치해야하는데 맨 앞(왼쪽)에 고정되어 있다.
즉, 라벨 텍스트와 스크롤을 둘다 오른쪽으로 보내기
가 미션이다. 어떻게 할 수 있을까?
view hierarchy
를 보면, label의 너비
를 따로 지정하지 않았기 때문에, text의 길이
에 따라 너비를 갖게 된 것을 확인할 수 있다. 그렇기 때문에 label.textAlignment = .right
로 텍스트의 오른쪽 정렬을 지정했어도 소용이 없는 것이다. 저 좁은 공간 안에서 텍스트는 이미 오른쪽에 붙어있을 것이다. 스크롤 뷰 공간 내에서 오른쪽에 붙이려면 어떻게 해야할까? 스크롤 뷰가 가진 속성들을 구경하며 뭘 넣으면 좋을까 고민해본다.
Alignment
라는 단어를 보자마자 이거다 싶다.
A point where the scroll view anchors content that's smaller than the scroll view's frame.
스크롤 뷰가 자신의 프레임보다 작은 컨텐트를 고정시키는(anchors : 닻을 내리는) 포인트.
밑에 디스커션을 읽어보면 좌측상단을 (0, 0)
으로 하는 좌표 값이 default
라고 되어있다.(내 label
이 왼쪽에 붙어있는 이유) 가운데 넣고 싶다면 (0.5, 0.5)
로 하라고 조언하고 있다. 그럼 우측 중앙에 넣고 싶다면?
scrollView.contentAlignmentPoint = CGPoint(x: 1, y: 0.5)
완성.
AI한테 물어봤는데
contentAlignmentPoint
가 UIScrollView
의 프로퍼티가 아니라는 뚱딴지 같은 소리를 하고 textAlignment = .right
이미 했는데 이거나 하라고 한다. 나보고 슬라잇 미스언더스탠딩 이러고 있네 아오 너는 휴즈 미스언더스탠딩을 하고 있어 이 자식아.
한마디 해줬다. 아니 제대로 안알려주면 어떡하냐고 내가 스스로 알아내야 되냐고😑(그렇긴 함) 하여튼 이 자식 때문에 스스로 알아내느라 좀 헤맸다.
다행이 이 부분은 클로드 친구가 조언을 주었다. 일단, scrollView
의 contentSize
속성을 label
과 일치시킨다.
scrollView.contentSize = CGSize(width: inputLabel.intrinsicContentSize.width, height: inputLabel.bounds.height)
// 찾아보니 intrinsicContentSize는 고유 사이즈라고 한다.
그 다음, contentOffset
의 x
값을 컨텐트(라벨) 너비에서 스크롤 뷰 너비를 뺀 값
으로 지정해준다.
scrollView.contentOffset = CGPoint(x: scrollView.contentSize.width - scrollView.bounds.width, y: 0)
풀어서 얘기하자면 텍스트가 길어지느라 화면 밖으로 넘어간 만큼 x
에 offset
을 반대로 주는 것이다.(-
니까?) 솔직히 그렇구나 싶은거지 백퍼 이해는 안된다.
하여튼 저 두 코드를 열심히 작성한 뒤 viewDidLoad
에 호출하면 안되고, viewDidLayoutSubviews
라는 함수를 override
하여 호출해야 한다. 이 부분은 내배캠 동기님의 포스팅을 참고하여 안 것이다. (클로드는 텍스트가 추가되는 시점에 호출하는 예시를 보여주었다.)
override func viewDidLayoutSubviews() {
setScrollView()
}
private func setScrollView() {
// 스크롤 뷰의 content size를 label size와 일치시킴
scrollView.contentSize = CGSize(width: inputLabel.intrinsicContentSize.width, height: inputLabel.bounds.height)
// 스크롤을 우측에 고정
scrollView.contentOffset = CGPoint(x: scrollView.contentSize.width - scrollView.bounds.width, y: 0)
}
after
오른쪽에 잘 붙어있는 스크롤이 적용되었다.
제 블로그가 소개되다니 쑥스럽네요ㅎㅎ
스크롤뷰를 적용하는 과정 재밌게 봤습니다!! 중간에 AI에게 뭐라고 하시는 부분이 인상깊네요ㅎㅎ