본문 바로가기
카테고리 없음

스토리 보드 없이 컬렉션 뷰 구현하기 - UICollectionView without Story board with Swift 4

by 틴디 2020. 2. 16.
728x90
반응형

* 틀린 곳이 있다면 지적 언제나 환영입니다.

참고한 유튜브 동영상입니다. 스위프트가 완전히 처음이라 강의를 듣지 않고 구현하는데 한계가 많았습니다. 저는 아직까지는 스토리보드라는 걸 사용해 보지 않았고 코드로 구현하고 싶어서,, 아래 동영상이 큰 도움이 되었습니다. 

 

 

최종 구현 모습입니다. 더 고치고 수정할 부분이 많은데 우선 알게된 점 정리할까 싶어 글을 적습니다. 

UICollectionViewController는 뷰 컨트롤러이고 스토리보드를 이용해서 만들거나 nib파일을 할당할 수도 있습니다. 스토리보드를 사용하지 않고 코드를 통해 구현해 보고자 합니다. 컬렉션 뷰 컨트롤러를 생성하면 이 뷰 컨트롤러에 의해 관리되는 collection View 객체가 생성됩니다. collectionView 프로퍼티를 통해 접근할 수 있어요.

여기에 델리게이션과 데이터 소스를 할당해 주어야 합니다. 특히 직접 커스터마이징 한 CollectionViewController는 몇 가지 메소드를 꼭 작성해 주어야 합니다. 왜냐하면 저 뷰 컨트롤러에 들어갈 각각의 내용물의 위치나 내용이 지정이 안된다면 화면에 보여지지 않습니다. 직접 지정하지 않는한 초기화 해주었다 해서 위치를 가지지 않습니다.

 


우선 로드될때 스토리 보드로 연결되지 않도록 왼쪽 네비게이터를 누른 뒤 아래 보이는 Main Interface 부분을 삭제해 줍니다. 그러면 이제 AppDelegate를 타게 됩니다. 

그렇기 때문에 AppDelegate에서 Window를 만들고 윈도우에 메인 뷰 컨트롤러를 구현해 주어야 합니다. 아래 코드를 작성합니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class AppDelegate: UIResponder, UIApplicationDelegate {
 
    var window: UIWindow?
 
 
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        
window = UIWindow(frame: UIScreen.main.bounds)
        window?.makeKeyAndVisible()
        
        let layout = UICollectionViewFlowLayout()
        let vc = ViewController(collectionViewLayout: layout)
        window?.rootViewController = UINavigationController(rootViewController: vc)
        
        return true
   }
cs
 
 
 

스위프트 프로젝트를 생성하면 처음에 생성되어 있는 ViewController을 메인 뷰 컨트롤러로 지정해 줍니다. 컬렉션 뷰 내에 있는 셀에 대해 다양한 지정을 위해 UICollectionViewFlowLayout을 지정해 줍니다. 

 

컬렉션 뷰에는 셀이 필요하고 그 셀을 ReuseIdentifier을 이용하여 지정해 주어야 합니다. 우선 셀을 만들겠습니다. ViewController.swift에서 맨 아래에 UICollectionViewCell을 상속받는 새로운 클래스를 하나더 추가해 줍니다. 

1
2
3
4
5
6
7
class CollectionViewCell: UICollectionViewCell {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
}
cs

 

슈퍼 클래스에서 초기화 할 내용이 있기 때문에 초기화에서는 슈퍼 클래스의 초기화도 해주어야 합니다. 

이제 클래스 내부에서 init 메소드 바로 아래에 setup 함수를 작성해 줍니다. 

셀의 배경화면은 하얀색으로 지정해 주었고 각 셀에 뷰를 서브 뷰로 넣어 줍니다. 서브 뷰의 이름은 imageView로 지정하고 fram을 이용해서 위치를 지정해 주어야 합니다. 그렇지 않으면 내부에서 자신의 위치가 없기 때문에 로드 하면 화면에 표시되지 않습니다. 

 

1
2
3
4
5
6
7
    func setup() {
       self.backgroundColor = .white
        addSubview(imageView)
    
        imageView.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height/2)
        
    }
cs
 

이제 이미지 뷰를 만들어 주도록 하겠습니다. UIImgaeView를 상속받습니다. 배경화면 색은 초록색으로 지정해 주겠습니다. 

1
2
3
4
5
6
7
    let imageView: UIImageView = {
        let iv = UIImageView()
        iv.contentMode = .scaleAspectFit
        iv.backgroundColor = .green
        return iv
    }()
cs

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class CollectionViewCell: UICollectionViewCell {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
    }
    
    func setup() {
        self.backgroundColor = .white
        addSubview(imageView)
    
        imageView.frame = CGRect(x: 0, y: 0, width: contentView.frame.width, height: contentView.frame.height/2)
        
    }
 
    let imageView: UIImageView = {
        let iv = UIImageView()
        iv.contentMode = .scaleAspectFit
        iv.backgroundColor = .green
        return iv
    }()
    
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
}
cs

아래에 required init은 경고 창에서 fix 하시면 자동으로 생성됩니다. 이제 뷰 컨트롤러 클래스 작성을 마무리 하겠습니다. 

메소드는 셀을 지정해 주는 메소드, 위치 지정, 하나의 섹션에 몇개의 셀이 들어가는지 지정해 주는 메소드 등이 필요 합니다. 초기화에는 배경화면 색과 네비게이션, 그리고 셀의 재상용 식별자를 등록해 줍니다.

전체 코드 모습입니다. 우선 클래스에서 cellId 변수에 원하는 재사용 식별자를 적어줍니다. 보통 셀 클래스 명으로 하면 좋은거 같습니다. 

셀은 viewDidLoad에서 재사용 식별자를 통해 셀 클래스를 지정해 줍니다. 

 

- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section;

이 메소드는 require, 즉 필수로 구현해야 하는 메소드 입니다. 하나의 섹션에 몇 개의 셀이 들어갈 것인지를 지정해 주는 것인데 한 개만 해서 단일셀로 만들 수도 있고 데이터 갯수만큼 지정해 줄수도 있습니다.

 

- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath;

이 메소드 또한 데이터소스에서 필수로 구현하라고 명시되어 있는 메소드 입니다. 각 셀에 재사용 셀을 지정해 주면 되는데 위에서 작성한 식별자를 통해 쉽게 등록해 줍니다. 각각의 셀에 CollectionViewCell 클래스에서 명시한 셀이 생성됩니다.

 

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath;

다음은 FlowLayout에서 optional, 즉 작성해도 되고 안해도 되는 메소드로 지정되어 있습니다. 하지만 이를 잘 명시하지 않으면 코드 상으로 작성하는 콜렉션 뷰에서 셀 내용이 화면에 제대로 위치하지 않을 수도 있습니다. 

원하는 대로 위치하기 위해서 각 셀의 넓이와 높이를 지정해 줍니다. 

 

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section;

이 또한 옵셔널입니다. 위 메소드는 각 셀에 대한 높이와 넓이였다면 이 메소드는 하나의 섹션의 위치를 지정합니다. 음..   하나의 섹션에 들어있는 셀들 전체를 하나의 뭉텅이로 보고 그 뭉텅이의 상위 뷰에서 위치, 마진을 정합니다. 

 

실행하면 위와 같이 나옵니다. 

위 유튜브를 보면 유튜버가 직접 설명해주면서 같이 코드를 작성합니다. 꼭 들어가서 참고해 보시고 도움이 되었으면 좋겠네요

728x90
반응형

댓글