ZigZag 클론 코딩을 하면서 상단 탭바 구현이 필요했습니다.

상단 탭바는 직접 구현할 수도 있고, 혹은 다양한 라이브러리를 활용해 구현할 수 있습니다.

 


아래 영상은 상단 탭바 - 탭맨 라이브러리 활용커스텀최종 결과물입니다.

탭맨 전체 코드 최하단에 있으니 확인하시기 바랍니다.

 

탭맨 라이브러리 커스텀 결과물.

 


 

우선 대표적인 상단 탭바 라이브러리 일부를 소개드리겠습니다.

 

상단탭바 라이브러리 모음

TabMan : https://github.com/uias/Tabman

 

GitHub - uias/Tabman: ™️ A powerful paging view controller with interactive indicator bars

™️ A powerful paging view controller with interactive indicator bars - GitHub - uias/Tabman: ™️ A powerful paging view controller with interactive indicator bars

github.com

 

PagingKit : https://github.com/kazuhiro4949/PagingKit | https://www.youtube.com/watch?v=RtneD_6FrNM

 

XLPagerTabStrip : https://github.com/xmartlabs/XLPagerTabStrip

 




커스텀하는 방법을 말씀드리기 전에, 우선 기본적인 설치방법부터 말씀드리겠습니다.


1. 코코아팟을 통해 라이브러리를 설치합니다.

pod 'Tabman', '~> 2.11'

코코아팟을 통해 설치하는 방법을 모르신다면 여기를 참고하시기 바랍니다.


2. 사용할 ViewController에 아래 내용을 import 해줍니다.

import Tabman
import Pageboy

import에 안 뜨신다면, 커맨드 + B를 눌러 빌드한 뒤 진행하면 됩니다.

 

3. UIViewController 대신 TabmanViewController  상속받도록 수정합니다.

 

TabmanViewController 상속.

(전 이름을 수정해서 ViewController가 아닌 HomeViewController입니다.)

 


4. 하단에 Extension추가합니다.

각 case에 맞게 탭 Title을 설정해주면 됩니다.

 

extension HomeViewController: PageboyViewControllerDataSource, TMBarDataSource {
    
    func barItem(for bar: TMBar, at index: Int) -> TMBarItemable {
//        let item = TMBarItem(title: "")
//        item.title = "Page \(index)"
//        item.image = UIImage(named: "image.png")
//
//        return item
        
        // MARK: - Tab 안 글씨들
        switch index {
        case 0:
            return TMBarItem(title: "홈")
        case 1:
            return TMBarItem(title: "Brand")
        case 2:
            return TMBarItem(title: "베스트")
        case 3:
            return TMBarItem(title: "세일")
        default:
            let title = "Page \(index)"
            return TMBarItem(title: title)
        }

    }
    
    func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int {
        return viewControllers.count
    }
    
    func viewController(for pageboyViewController: PageboyViewController, at index: PageboyViewController.PageIndex) -> UIViewController? {
        return viewControllers[index]
    }
    
    func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? {
        return nil
    }
    
    
}

 

 


 

이렇게 하고 실행하면 상단 탭바가 작동은 잘 됩니다.

(만약 작동이 잘 되지 않으셔도 괜찮으니 우선 넘어가세요. 최하단에 전체 코드를 올려놓았습니다.)

 

하지만 이렇게 예제만 했을 땐 2가지 문제가 있었습니다.

 

아래 이미지를 보시면,

1. 예제는 왼쪽으로 쏠려 있습니다. 즉, 사진처럼 균등하게 분배되지 않았습니다.

2. (화면 최상단이 아닌) 제가 원하는 곳에 상단 탭바를 넣을 수 없었습니다. 

 

상단탭바의 원하는 모습.

 

기본 예제는

https://gonslab.tistory.com/17https://velog.io/@iammiori/iOS-opensource-tabman 를 참고했습니다.

 


 

원하던 대로 커스텀하는 방법


 

문제 1번 해결 방법

: 각 버튼을 화면에 딱 맞게 설정하는 방법.

 

위에 참고 링크들에선, 원하던 이미지처럼 화면에 딱 맞게 설정하는 방법이 안 나와 있었습니다.

다행히 공식문서에서 내용을 찾아 해결했습니다!

 

bar.layout.contentMode = .fit 을 하면 됩니다!

bar.layout.alignment = .centerDistributed // .center시 선택된 탭이 가운데로 오게 됨.
bar.layout.contentMode = .fit
// bar.layout.interButtonSpacing = 35 // 버튼 사이 간격 (화면 보면서 필요시 조절)

 

아래는 탭맨 공식 문서 중 일부입니다.

주석 부분에 각 옵션에 대한 상세한 설명이 나와 있습니다.

 

탭맨 공식 문서 중 일부.

 

 


 

문제 2번 해결 방법

: 내가 원하는 곳에 Bar를 위치시키는 방법.

 

문제 2번을 해결하는 게 어려웠습니다. 이 글을 쓰게 된 이유이기도 합니다. 저와 같은 힘듦을 겪으실 분들을 위해...

 

addBar함수 중, .custom을 통해 가능합니다.

(Bar를 넣을 UIView를 미리 만들어 놓고, UIView의 이름(여기선 tempView)을 넣어주면 됩니다.)

 

// Add to view
addBar(bar, dataSource: self, at: .custom(view: tempView, layout: nil)) // .custom을 통해 원하는 뷰에 삽입함. BarLocation -  https://github.com/uias/Tabman/blob/main/Sources/Tabman/TabmanViewController.swift#L27-L32

 

아래는 탭맨 공식 문서 중 일부입니다.

주석 부분에 각 옵션에 대한 상세한 설명이 나와 있습니다.

 

 

BarLocation 관련 탭맨 공식 문서 중 일부.

 

탭맨 BarLocation 관련 공식문서 링크입니다.

https://github.com/uias/Tabman/blob/main/Sources/Tabman/TabmanViewController.swift#L27-L32

 

GitHub - uias/Tabman: ™️ A powerful paging view controller with interactive indicator bars

™️ A powerful paging view controller with interactive indicator bars - GitHub - uias/Tabman: ™️ A powerful paging view controller with interactive indicator bars

github.com

 


 

지금까지 탭맨 기본 예제 & 커스텀하는 방법에 대해서 알아봤습니다.

 

저는 위에 설명드린 2가지 방법을 통해, 상단 탭바를 원하던 대로 커스텀했습니다.

 

아래는 결과 화면에 대한 전체 코드입니다.

도움이 되셨다면 좋겠습니다!

 

 

import UIKit
import Tabman
import Pageboy

class HomeViewController: TabmanViewController {

    // 상단 탭바 라이브러리 - TabMan 사용
    private var viewControllers: Array<UIViewController> = []
    @IBOutlet weak var tempView: UIView! // 상단 탭바 들어갈 자리
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let homeHomeVC = UIStoryboard.init(name: "MainPageStoryboard", bundle: nil).instantiateViewController(withIdentifier: "HomeHomeVC") as! HomeHomeViewController
        let brandVC = UIStoryboard.init(name: "MainPageStoryboard", bundle: nil).instantiateViewController(withIdentifier: "BrandVC") as! BrandViewController
        let bestVC = UIStoryboard.init(name: "MainPageStoryboard", bundle: nil).instantiateViewController(withIdentifier: "BestVC") as! BestViewController
        let saleVC = UIStoryboard.init(name: "MainPageStoryboard", bundle: nil).instantiateViewController(withIdentifier: "SaleVC") as! SaleViewController
            
        viewControllers.append(homeHomeVC)
        viewControllers.append(brandVC)
        viewControllers.append(bestVC)
        viewControllers.append(saleVC)
        
        self.dataSource = self

        // Create bar
        let bar = TMBar.ButtonBar()
//        let bar = TMBar.TabBar()
        bar.backgroundView.style = .blur(style: .regular)
        bar.layout.contentInset = UIEdgeInsets(top: 0.0, left: 0.0, bottom: 0.0, right: 0.0)
        bar.buttons.customize { (button) in
            button.tintColor = .mainGray // 선택 안되어 있을 때
            button.selectedTintColor = .black // 선택 되어 있을 때
        }
        // 인디케이터 조정
        bar.indicator.weight = .light
        bar.indicator.tintColor = .black
        bar.indicator.overscrollBehavior = .compress
        bar.layout.alignment = .centerDistributed
        bar.layout.contentMode = .fit
        bar.layout.interButtonSpacing = 35 // 버튼 사이 간격
    
        bar.layout.transitionStyle = .snap // Customize

        // Add to view
        addBar(bar, dataSource: self, at: .custom(view: tempView, layout: nil)) // .custom을 통해 원하는 뷰에 삽입함. BarLocation -  https://github.com/uias/Tabman/blob/main/Sources/Tabman/TabmanViewController.swift#L27-L32
        
    }
}


extension HomeViewController: PageboyViewControllerDataSource, TMBarDataSource {
    
    func barItem(for bar: TMBar, at index: Int) -> TMBarItemable {
//        let item = TMBarItem(title: "")
//        item.title = "Page \(index)"
//        item.image = UIImage(named: "image.png")
//
//        return item
        
        // MARK: - Tab 안 글씨들
        switch index {
        case 0:
            return TMBarItem(title: "홈")
        case 1:
            return TMBarItem(title: "Brand")
        case 2:
            return TMBarItem(title: "베스트")
        case 3:
            return TMBarItem(title: "세일")
        default:
            let title = "Page \(index)"
            return TMBarItem(title: title)
        }

    }
    
    func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int {
        return viewControllers.count
    }
    
    func viewController(for pageboyViewController: PageboyViewController, at index: PageboyViewController.PageIndex) -> UIViewController? {
        return viewControllers[index]
    }
    
    func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? {
        return nil
    }
    
    
}

22.01.11 추가

func defaultPage(...) 함수에서 return nil로 해도 되지만, return .at(index: )를 써도 됩니다.

func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? {
        //return nil
        return .at(index: 0) // https://github.com/uias/Tabman/issues/259
}

22.02.24 추가

이해를 돕기 위해 스토리보드 화면을 캡처 및 편집해서 올립니다.

상세한 내용은 댓글창을 참고해주세요.

 

댓글 질문 : [홈, 브랜드, 베스트, 세일] 탭을 터치할때마다 내용을 바꾸고 싶은데, 현재는 배열에 추가한 뷰컨이 통째로 전환되고 있습니다. 어떻게 해결해야 하나요?

답변 : 뷰 컨트롤러를 "백그라운드가 될 뷰컨 - HomeViewController" 까지 총 5개 만드시고,
"백그라운드가 될 뷰컨 - HomeViewController" 에다가 본문의 코드를 추가하시면 됩니다.

 

이해를 돕기 위한 스토리보드 화면.

 

 

반응형