본문 바로가기

이상/iOS

[iOS] UIScrollView(Vertical) 만들기

반응형

+21.05.20
비교적 조회수가 높아서 다시보니
Horizontal과 Vertical을 반대로 작성했네요.
무슨 생각으로 글을 작성했는지...
죄송합니다.
본의아니게 어그로를 끌었네요.
Horizontal ScrollView는 조만간
새로 작성하겠습니다.

+21.06.01

-> [iOS] UIScrollView(Horizontal) 만들기 (+SnapKit 사용법)

———————————————

 

UIScrollView는 이름 그대로 Scroll 기능이 있는 View다.

 

스마트폰과 PC의 가장 큰 차이점은 화면의 크기다.

 

갤럭시 노트나 아이폰 플러스, 플러스 프로와 같이 화면이 큰 스마트폰들도 있지만

 

이 기종들도 PC의 모니터에 비하면 화면이 너무나 작다.

 

때문에 UIScrollView는 생각보다 많이 사용되므로 알아두는게 좋다.

 

이번에는 이전 글에서 만들었던 CustomView와 UIScrollView를 이용하여

 

아래와 같이 Instagram의 메인화면을 만들어보자.

 

참고로 다른 방식들도 많으며 이건 내가 가장 간단하고 편하다고 생각하는 방식이다.

 

Testagram

 

처음 UIScrollView를 사용했을 때를 생각해보면,

 

UIScrollView를 추가하면 하위에 Content Layout Guide와 Frame Layout Guide가 있어서 이게 뭔가 싶었고

 

내부에 들어갈 View를 추가하고 Constraints를 이리저리 지정해도 error가 없어지지 않아서 짜증이 많이 났었다.

 

그래도 포인트만 알아두면 그렇게 어려운 것도 아니니 중요한 포인트만 알아두자.

 

 

 

1. UIScrollView 추가

우선 UIViewController에 ScrollView를 추가해서 영역을 지정해준다.

 

UIScrollView 추가

UIScrollView의 포인트는 Content Layout Guide와 Frame Layout Guide, 그리고 Error이다.

 

원래 가장 스트레스를 많이 받았던 기억이 그만큼 오래 남기 때문에 나에겐 이 두가지가 포인트다.

 

 

 

1) Content Layout Guide, Frame Layout Guide

 

글자 그대로 생각하면 쉽다.

 

Frame Layout Guide는 ScrollView의 Frame에 해당하는 영역

 

즉, 스마트폰의 화면을 바라봤을 때 ScrollView가 보여질 영역이다.

 

Content Layout Guide는 ScrollView에 들어갈 Content 전체영역이다.

 

Frame Layout Guide 영역

 

Content Layout Guide 영역

 

이제 Constraint를 어떻게 지정해야할지 생각해보자.

 

Vertical 방향으로 Scroll하려면 Horizontal 방향으로는 움직여선 안 된다.

 

때문에 Content의 width값은 화면의 width값보다 같거나 작아야 한다.

 

 

 

이와 반대로 height는 화면 아래의 보이지않는 부분을 넘어야하기 때문에

 

Content의 height값이 화면의 height값보다 커야할 것이다.

 

같거나 크다가 아니라 커야할 것이다다.

 

아주 정확하게 말하면 작을 수도 있고, 같을 수도 있고, 클 수도 있다.

 

Content로 보여줄 크기가 커서 Scroll 해야할 수도 있지만

 

그와 반대로, 특정한 여러 이유로 Content 크기가 작아 Scroll할 필요가 없을 수도 있기 때문이다.

 

때문에 height값은 동적으로(dynamic하게) 지정해줘야한다.

(이 글은 Vertical ScrollView를 다루고 있기 때문에 그런 것이고,

Horizontal ScrollView는 width값을 동적으로 지정해줘야하며

Horizontal, Vertical 모두 Scroll을 허용하려면 width, height 값 모두 동적으로 지정해줘야 한다.)

 

정리해보면 ScrollView에 들어갈 Content의 width는 같거나 작게, height는 동적으로 지정해야한다.

 

 

2. Constraints 추가

우리는 instagram과 같이 Vertical ScrollView에, 게시물이 될 CustomView를 반복해서 보여줄 것이므로

 

ScrollView의 Content로 VerticalStackView를 추가한다.

 

그리고 StackView의 width를 Frame Layout Guide width Equal로 설정한다.

 

Frame Layout Guide의 Width와 Equal

 

다음으로 Content Layout Guide leading, top, trailing, bottom을 맞춰준다.

 

 

Content Layout Guide의 Leading, Top, Trailing, Bottom과 Equal

 

이제 ScrollView의 Constraint 지정은 끝이다.

 

그런데 Storyboard에서 에러가 있다고 한다. 살펴보자.

(참고로 여기까지만 해줘도 된다.

이후 내용은 저 빨간 에러표시의 찝찝함을 해소하기 위한 내용이다.)

 

 

 

3. 에러 수정

 

Need constraints for: Y position or height

 

Need constraints for: Y position or height

ScrollView의 Y 기준 또는 높이에 대한 constraints가 필요하다.

 

우리가 추가한 StackView의 Constraint 중에 X 기준 또는 너비에 대한 constraint는

 

ScrollView의 Frame Layout Guide의 width와 Equal로 설정했기 때문에 더 이상 추가할 게 없다.

 

하지만 Vertical StackView 또한 정해진 height값이 없기 때문에 이런 에러가 발생하는 것이다.

 

만약 StackView가 아닌 height가 정해져있는 View를 추가하면 어떻게 될까?

 

 

UIScrollView에 배치된 높이가 900인 View

 

이렇게 height가 지정된 View일 때는 에러가 발생하지 않는다.

 

여기서 StackView는 내부에 View를 추가하지 않으면 height가 정해지지 않는데 어떻게 해야하지? 이런 궁금증이 생긴다.

 

StackView가 height값을 가지끔 하려고하면 특정한 View를 addArrangeSubview() 해줘야한다.

 

그럼 그냥 해주자.

 

StackView가 Height를 갖게 되는 듯한 효과

 

StackView에 height = 900인 View를 추가하니 에러가 사라졌다.

 

이제 ScrollView 위에 HeaderView를 추가해주고

 

StackView의 Attributes Inspector의 값을 변경해주자.

 

각 게시물은 같은 간격으로 추가돼야하므로 Distribution을 Equal Spacing으로 선택하고 Spacing은 10으로 입력한다.

 

StackView의 Attributes Inspector 설정

 

소스에 StackView을 IBOutlet으로 연결한 후 StackView에 CustomView를 5개 추가하고 실행해보자.

1
2
3
4
5
6
7
8
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        for _ in 0..<5 {
            let customView = CustomView()
            self.stackView.addArrangedSubview(customView)
        }
    }
cs

 

보라색View 아래에 추가된 CustomView들

 

CustomView들이 StackView의 height값 지정을 위해 추가했던 보라색View의 아래에 추가되었으므로

 

보라색View를 지워주자.

 

StackView의 모든 subview들을 없애는 함수를 만들어 CustomView를 추가하기 전에 호출한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
    override func viewDidLoad() {
        super.viewDidLoad()
        self.removeAllSubViews()
        for _ in 0..<5 {
            let customView = CustomView()
            self.stackView.addArrangedSubview(customView)
        }
    }
    
    func removeAllSubViews(){
        for subview in self.stackView.arrangedSubviews {
            subview.removeFromSuperview()
        }
    }
cs

 

완성된 Testagram

 

완성이다.

 

 

 

참고로 보라색View를 없앨 때 stackView.removeArrangedSubview()로 지우지 않은 이유는

 

removeArrangedSubview()는 나중에 View를 다시 추가할 때,

 

같은 View를 새로 생성하지 않도록 하기 위해 메모리에 그대로 남겨둔다.

 

때문에 StackView에서 removeArrangedSubview() 다음에 새로운 View를 추가하게 되면

 

지워지지 않은 보라색View가 추가된 CustomView 뒤에 여전히 남아있게 된다.

 

 

메모리에 남아있는 보라색View

 

끝이다.

 

반응형

'이상 > iOS' 카테고리의 다른 글

[iOS] 엔터프라이즈 배포  (0) 2020.07.06
[iOS] CheckBox 만들기 with Delegate  (0) 2020.07.06
[iOS] CustomView 사용하기  (0) 2020.06.16
[iOS] CustomView 만들기  (0) 2020.06.16
[iOS] 화면이 깨진다? 원인을 파악해보자  (0) 2020.06.15