ํ์ด์ง์ ํ ์ ์๋ ํญ์ ๊ตฌํํ ๋, ๊ธฐ์กด์์๋ ํญ๋งจ(Tabman) ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด ์์ฝ๊ฒ ๊ตฌํํ์๋ค.
๊ทธ๋ฌ๋ ์ค๋ก์ง ์ ํ / ๋ฏธ์ ํ ์ ์๊น๋ง ์ง์ ํ ์ ์๋ ๊ฒ์ ์์๊ณ ,
์ด๋ ๋์์ด๋๋์ ์๊ตฌ์ฌํญ๊ณผ๋ ๋ง์ง ์๊ธฐ์... ์ง์ CollectionView๋ก ์์ ์ ํด๋ณด๊ธฐ๋ก ํ๋ค.
๋์์ด๋๋ ์๊ตฌ์ฌํญ
'์ฌ์น'์ '๊ฐ์น' ํด๋ฆญ ์ ๊ธ์จ์ Indicator๋ฐ ์์ ๋ณ๊ฒฝ
๊ทธ๋ฌ๋ ๊ธฐ์กด์ Tabman ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์๋ ์์ ๊ตฌ๋ถ์ ๋ชปํ๊ณ , ๋ฐ ๊ธธ์ด๋ ์กฐ์ ํ ์ ์๋ค๋ ์ด์๊ฐ ์๋ค.
๋จผ์ ๊ตฌ์กฐ๋ถํฐ ์ดํด๋ณด์.
์๋จ ํญ์ CollectionView, ๊ทธ ๋ฐ์ Indicator๋ฐ๋ UIView, ๊ทธ ์๋์ ํ์ด์ง๋๋ ํ์ด์ง๋ค์ CollectionView๋ก ๊ตฌํํ์๋ค.
์ฝ๋
1. ์๋จํญ์ ๊ตฌ์ฑํ๋ CustomMenuBar ํด๋์ค
CollectionView์ Indicator UIView๊ฐ ๊ฐ์ด ์ ์๋์ด์๋ค.
์๋จ ํญ์ customTabBarCollectionView๋ก ์ ์
๋ฐ๋ฅผ IndicatorView๋ก ์ ์.
class CustomMenuBar: UIView {
weak var delegate: CustomMenuBarDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = .white
setupCustomTabBar()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var customTabBarCollectionView: UICollectionView = {
let collectionViewLayout = UICollectionViewFlowLayout()
collectionViewLayout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 0, height: 0), collectionViewLayout: collectionViewLayout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .white
return collectionView
}()
// ํญ ๋ฐ
var indicatorView = UIView().then{
$0.translatesAutoresizingMaskIntoConstraints = false
$0.backgroundColor = .clear
}
var indicatorLineView = UIView().then{
$0.backgroundColor = .zatchPurple
}
//MARK: Properties
var indicatorViewLeadingConstraint:NSLayoutConstraint!
var indicatorViewWidthConstraint: NSLayoutConstraint!
//MARK: Setup Views
func setupCollectionView(){
customTabBarCollectionView.then{
$0.delegate = self
$0.dataSource = self
$0.showsHorizontalScrollIndicator = false
$0.register(CustomCell.self, forCellWithReuseIdentifier: CustomCell.reusableIdentifier)
$0.isScrollEnabled = false
}
let indexPath = IndexPath(item: 0, section: 0)
customTabBarCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: [])
}
func setupCustomTabBar(){
setupCollectionView()
self.addSubview(customTabBarCollectionView)
customTabBarCollectionView.snp.makeConstraints { make in
make.leading.trailing.top.equalTo(self)
make.height.equalTo(54)
}
self.addSubview(indicatorView)
indicatorViewWidthConstraint = indicatorView.widthAnchor.constraint(equalToConstant: self.frame.width / 2)
indicatorViewWidthConstraint.isActive = true
indicatorView.heightAnchor.constraint(equalToConstant: 1.5).isActive = true
indicatorViewLeadingConstraint = indicatorView.leadingAnchor.constraint(equalTo: self.leadingAnchor)
indicatorViewLeadingConstraint.isActive = true
indicatorView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
indicatorView.addSubview(indicatorLineView)
indicatorLineView.snp.makeConstraints { make in
make.centerX.equalToSuperview()
make.height.equalTo(1.5)
make.width.equalTo(50)
}
}
}
CustomMenuBarํด๋์ค์์ CollectionView๋ฅผ ์ผ์ผ๋, delegate๋ ํด์ค๋ค.
์ฒซ๋ฒ์งธ ์ ์ '์ฌ์น', ๋๋ฒ์งธ ์ ์ '๊ฐ์น'๋ก ์ ์ธ.
//MARK:- UICollectionViewDelegate, DataSource
extension CustomMenuBar: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCell.reusableIdentifier, for: indexPath) as! CustomCell
cell.index = indexPath.row
if indexPath.row == 0 {
cell.label.text = "์ฌ์น"
}
else {
cell.label.text = "๊ฐ์น"
}
return cell
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 2
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.frame.width / 2 , height: 54)
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
delegate?.customMenuBar(scrollTo: indexPath.row)
if indexPath.row == 0 {indicatorLineView.backgroundColor = .zatchPurple}
else {indicatorLineView.backgroundColor = .zatchDeepYellow}
}
func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? CustomCell else {return}
cell.label.textColor = .black20
}
}
//MARK:- UICollectionViewDelegateFlowLayout
extension CustomMenuBar: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
๊ทธ๋ ๋ค๋ฉด, ์๋จ ํญ์ ์ฐ์ธ CollectionView์ ๋ ์ ์ํด์ค์ผํ ๊ฒ์ด๋ค.
CustomCell ํด๋์ค - ๋๋ ์ ํ์ง์ ๋ฐ๋ผ์ ์์ ๊ตฌ๋ถ์ ํด์ฃผ์๋๋ฐ, ๊ฐ์ธ์ ๋ฐ๋ผ ๊ตฌ๋ถ ์ํด์ค๋ ๋๋ค.
class CustomCell: UICollectionViewCell {
static let reusableIdentifier = "CustomCell"
var label = UILabel().then{
$0.text = "Tab"
$0.textAlignment = .center
$0.font = UIFont.pretendard(size: 14, family: .Bold)
$0.textColor = .zatchPurple
$0.translatesAutoresizingMaskIntoConstraints = false
}
var index: Int!
override var isSelected: Bool {
didSet{
print("Changed")
if index == 0 {self.label.textColor = isSelected ? .zatchPurple : .black20}
else if index == 1 {self.label.textColor = isSelected ? .zatchDeepYellow : .black20}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(label)
label.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
2. CustomMenuBarDelegate
ํด๋ฆญ ์ ํ๋ฉด์ ์ํ๋ ์ธ๋ฑ์ค๋ก ์คํฌ๋กคํด์ค ์ ์๋ ํจ์๋ฅผ ์ ์ํด์ค๋ค.
protocol CustomMenuBarDelegate: class {
func customMenuBar(scrollTo index: Int)
}
func customMenuBar(scrollTo index: Int) {
let indexPath = IndexPath(row: index, section: 0)
self.pageCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true)
}
3. ๋ฉ์ธ ๋ทฐ์ปจํธ๋กค๋ฌ๋ก ๋์๊ฐ๋ณด์.
์๋จํญ์ ํด๋ฆญ์ ๋ฐ๋ผ ํ์ด์ง๋๋ pageCollectionView๋ฅผ ์ ์ธ.
๊ทธ ์๋์๋ค๊ฐ CustomMenuBar ๊ฐ์ฒด๋ ์ด์ง์ฟต ์ ์ธํด์ค๋ค.
var pageCollectionView: UICollectionView = {
let collectionViewLayout = UICollectionViewFlowLayout()
collectionViewLayout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: 100, height: 100), collectionViewLayout: collectionViewLayout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
var customMenuBar = CustomMenuBar()
SetUp ํด์ค๋ค.
//MARK: Setup view
func setupCustomTabBar(){
self.view.addSubview(customMenuBar)
customMenuBar.then{
$0.delegate = self
$0.translatesAutoresizingMaskIntoConstraints = false
$0.indicatorViewWidthConstraint.constant = self.view.frame.width / 2
}
customMenuBar.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview()
make.top.equalTo(self.view.safeAreaLayoutGuide.snp.top)
make.height.equalTo(50)
}
}
func setupPageCollectionView(){
pageCollectionView.then{
$0.delegate = self
$0.dataSource = self
$0.backgroundColor = .gray
$0.showsHorizontalScrollIndicator = false
$0.isPagingEnabled = true
$0.register(PageCell.self, forCellWithReuseIdentifier: PageCell.reusableIdentifier)
}
self.view.addSubview(pageCollectionView)
pageCollectionView.snp.makeConstraints { make in
make.leading.trailing.equalToSuperview()
make.bottom.equalTo(self.view.safeAreaLayoutGuide.snp.bottom)
make.top.equalTo(self.customMenuBar.snp.bottom)
}
}
CollectionView๋ฅผ ์จ์คฌ์ผ๋ delegate๋ ํด์ผํ ๊ฒ์ด๋ค.
extension TempViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: pageCollectionView.frame.width, height: pageCollectionView.frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
PageCell - ํ์ด์ง๋๋ ํ์ด์ง ์ ๋ค๋ ์ ์ํด์ค๋ค.
class PageCell: UICollectionViewCell {
static let reusableIdentifier = "PageCell"
var label = UILabel().then{
$0.textColor = .black
$0.textAlignment = .center
$0.font = UIFont.systemFont(ofSize: 30, weight: .bold)
$0.translatesAutoresizingMaskIntoConstraints = false
}
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(label)
self.backgroundColor = .systemGray6
label.centerXAnchor.constraint(equalTo: self.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
๋. ์ง์ง ์ฝ๋๊ฐ ์ฐธ ๊ธธ๋ค.
์ด์ฐ์ ์ฐ ์ฑ๊ณต์ ํ์ง๋ง ... ๋๋๋ก์ด๋ฉด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฐ๊ณ ์ถ๋ค.
'๐ iOS' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์ด๋ฏธ์ง ๋ง์คํนํ๊ธฐ - UIImage Mask (0) | 2022.11.07 |
---|---|
Realm ์ฌ์ฉํ๊ธฐ (0) | 2022.11.02 |
FSCalender ์์ ์ด๋ฒคํธ ๋๊ทธ๋ผ๋ฏธ ํฌ๊ธฐ ์ปค์คํ (0) | 2022.10.04 |
Share Extension (0) | 2022.10.03 |
์ฑ์ ๋ผ์ดํธ๋ชจ๋๋ง ์ง์ํ๊ฒ ๋ง๋ ๋ค. (0) | 2022.10.03 |