Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions Handy/Handy-Storybook/Component/NavigationViewController.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
//
// NavigationViewController.swift
// Handy-Storybook
//
// Created by 서준영 on 11/13/24.
//

import UIKit
import Handy
import SnapKit

class NavigationViewController: HandyNavigation {

let page1: UIViewController = {
let viewController = UIViewController()
viewController.view.backgroundColor = HandySemantic.bgStatusPositive
viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled)
return viewController
}()

let page2: UIViewController = {
let viewController = UIViewController()
viewController.view.backgroundColor = HandySemantic.bgBasicBlack
viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled)
return viewController
}()

let page3: UIViewController = {
let viewController = UIViewController()
viewController.view.backgroundColor = HandySemantic.bgStatusNegative
viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled)
return viewController
}()

let page4: UIViewController = {
let viewController = UIViewController()
viewController.view.backgroundColor = HandySemantic.bgBasicDefault
viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled)
return viewController
}()

let page5: UIViewController = {
let viewController = UIViewController()
viewController.view.backgroundColor = HandySemantic.iconBasicSecondary
viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled)
return viewController
}()

override func viewDidLoad() {
super.viewDidLoad()
centerItem = false
setViewControllers([page1, page2, page3, page4, page5], animated: false)
}
}
2 changes: 1 addition & 1 deletion Handy/Handy-Storybook/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(frame: UIScreen.main.bounds)
window?.windowScene = windowScene
window?.rootViewController = CheckBoxViewController()
window?.rootViewController = NavigationViewController()
window?.makeKeyAndVisible()
}

Expand Down
37 changes: 26 additions & 11 deletions Handy/Handy.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
A5A12A7F2C57A92000996916 /* HandySematic.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5D02AFC2C46C5A70056CE7B /* HandySematic.swift */; };
A5A12A812C57A93C00996916 /* HandyPrimitive.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5D02AFF2C480A180056CE7B /* HandyPrimitive.swift */; };
A5A12A822C57A93F00996916 /* HandyBasicColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5669A3E2C443E7300DABC21 /* HandyBasicColor.swift */; };
A5C208A32CDCCD75005F20A1 /* HandyNavigation.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C208A22CDCCD75005F20A1 /* HandyNavigation.swift */; };
A5C208C62CE3BCE1005F20A1 /* NavigationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5C208C52CE3BCE1005F20A1 /* NavigationViewController.swift */; };
A5F6D36B2C96F32D00FB961F /* HandyDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5F6D36A2C96F32D00FB961F /* HandyDivider.swift */; };
A5F6D36D2C97099C00FB961F /* DividerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5F6D36C2C97099C00FB961F /* DividerViewController.swift */; };
E51FBF9B2C5399A00097B0DA /* CheckBoxViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E51FBF9A2C5399A00097B0DA /* CheckBoxViewController.swift */; };
Expand All @@ -49,9 +51,6 @@
E5650D432C4D326D002790CC /* HandyCheckBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5650D422C4D326D002790CC /* HandyCheckBox.swift */; };
E5650D452C4E366F002790CC /* HandyIcon.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E5650D442C4E366F002790CC /* HandyIcon.xcassets */; };
E5650D472C512B07002790CC /* HandyIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5650D462C512B07002790CC /* HandyIcon.swift */; };
E5650D432C4D326D002790CC /* HandyCheckBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5650D422C4D326D002790CC /* HandyCheckBox.swift */; };
E5650D452C4E366F002790CC /* HandyIcon.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E5650D442C4E366F002790CC /* HandyIcon.xcassets */; };
E5650D472C512B07002790CC /* HandyIcon.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5650D462C512B07002790CC /* HandyIcon.swift */; };
E5669A3F2C443E7300DABC21 /* HandyBasicColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5669A3E2C443E7300DABC21 /* HandyBasicColor.swift */; };
E5D02AFD2C46C5A70056CE7B /* HandySematic.swift in Sources */ = {isa = PBXBuildFile; fileRef = E5D02AFC2C46C5A70056CE7B /* HandySematic.swift */; };
E5D02AFE2C46C9980056CE7B /* HandyBasicColor.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E5669A422C443FE500DABC21 /* HandyBasicColor.xcassets */; };
Expand Down Expand Up @@ -112,6 +111,8 @@
2D41E8152C5A21B50043161D /* HandyFab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyFab.swift; sourceTree = "<group>"; };
A56B3DE12C4E51D300C3610A /* HandyChip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyChip.swift; sourceTree = "<group>"; };
A5A12A7C2C57A6C200996916 /* ChipViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChipViewController.swift; sourceTree = "<group>"; };
A5C208A22CDCCD75005F20A1 /* HandyNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyNavigation.swift; sourceTree = "<group>"; };
A5C208C52CE3BCE1005F20A1 /* NavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewController.swift; sourceTree = "<group>"; };
A5F6D36A2C96F32D00FB961F /* HandyDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyDivider.swift; sourceTree = "<group>"; };
A5F6D36C2C97099C00FB961F /* DividerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DividerViewController.swift; sourceTree = "<group>"; };
E51FBF9A2C5399A00097B0DA /* CheckBoxViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxViewController.swift; sourceTree = "<group>"; };
Expand All @@ -120,9 +121,6 @@
E5650D422C4D326D002790CC /* HandyCheckBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyCheckBox.swift; sourceTree = "<group>"; };
E5650D442C4E366F002790CC /* HandyIcon.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HandyIcon.xcassets; sourceTree = "<group>"; };
E5650D462C512B07002790CC /* HandyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyIcon.swift; sourceTree = "<group>"; };
E5650D422C4D326D002790CC /* HandyCheckBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyCheckBox.swift; sourceTree = "<group>"; };
E5650D442C4E366F002790CC /* HandyIcon.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HandyIcon.xcassets; sourceTree = "<group>"; };
E5650D462C512B07002790CC /* HandyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyIcon.swift; sourceTree = "<group>"; };
E5669A3E2C443E7300DABC21 /* HandyBasicColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyBasicColor.swift; sourceTree = "<group>"; };
E5669A422C443FE500DABC21 /* HandyBasicColor.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HandyBasicColor.xcassets; sourceTree = "<group>"; };
E5D02AFC2C46C5A70056CE7B /* HandySematic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandySematic.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -152,6 +150,7 @@
025776332C4EA98C00272EC6 /* Handy-Storybook */ = {
isa = PBXGroup;
children = (
A5C208C22CE3BC53005F20A1 /* Component */,
025776482C4EB0E700272EC6 /* Atom */,
025776572C4EB7C700272EC6 /* Font */,
0257765A2C4EB9B800272EC6 /* Storybook */,
Expand Down Expand Up @@ -229,7 +228,6 @@
2D41E8152C5A21B50043161D /* HandyFab.swift */,
A56B3DE12C4E51D300C3610A /* HandyChip.swift */,
A5F6D36A2C96F32D00FB961F /* HandyDivider.swift */,
E5650D422C4D326D002790CC /* HandyCheckBox.swift */,
E51FBF9F2C54CB260097B0DA /* HandyRadioButton.swift */,
E5650D422C4D326D002790CC /* HandyCheckBox.swift */,
);
Expand Down Expand Up @@ -268,6 +266,7 @@
02BDB7F92C3E962D0050FB67 /* Source */ = {
isa = PBXGroup;
children = (
A5C208A12CDCCD4E005F20A1 /* Component */,
02ED76482C577998001569F1 /* Extension */,
029C446B2C468F8E00331F61 /* Font */,
029E47FE2C49FD2E00D2F3B7 /* Atom */,
Expand All @@ -283,8 +282,6 @@
E5669A3E2C443E7300DABC21 /* HandyBasicColor.swift */,
E5D02AFF2C480A180056CE7B /* HandyPrimitive.swift */,
E5D02AFC2C46C5A70056CE7B /* HandySematic.swift */,
E5D02AFF2C480A180056CE7B /* HandyPrimitiveColor.swift */,
E5D02AFC2C46C5A70056CE7B /* HandySematicColor.swift */,
029E47FF2C49FD4000D2F3B7 /* HandyTypography.swift */,
E5650D462C512B07002790CC /* HandyIcon.swift */,
E5650D412C4D30B9002790CC /* Asset */,
Expand All @@ -310,6 +307,22 @@
path = Extension;
sourceTree = "<group>";
};
A5C208A12CDCCD4E005F20A1 /* Component */ = {
isa = PBXGroup;
children = (
A5C208A22CDCCD75005F20A1 /* HandyNavigation.swift */,
);
path = Component;
sourceTree = "<group>";
};
A5C208C22CE3BC53005F20A1 /* Component */ = {
isa = PBXGroup;
children = (
A5C208C52CE3BCE1005F20A1 /* NavigationViewController.swift */,
);
path = Component;
sourceTree = "<group>";
};
E5650D412C4D30B9002790CC /* Asset */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -455,6 +468,7 @@
2D41E8142C5A21930043161D /* FabViewController.swift in Sources */,
A5A12A812C57A93C00996916 /* HandyPrimitive.swift in Sources */,
A5A12A822C57A93F00996916 /* HandyBasicColor.swift in Sources */,
A5C208C62CE3BCE1005F20A1 /* NavigationViewController.swift in Sources */,
A5A12A7E2C57A6D900996916 /* ChipViewController.swift in Sources */,
A5A12A7F2C57A92000996916 /* HandySematic.swift in Sources */,
A5F6D36D2C97099C00FB961F /* DividerViewController.swift in Sources */,
Expand All @@ -476,8 +490,8 @@
02ED76332C5284E6001569F1 /* HandyBoxButton.swift in Sources */,
E5D02AFD2C46C5A70056CE7B /* HandySematic.swift in Sources */,
E5D02B002C480A180056CE7B /* HandyPrimitive.swift in Sources */,
E5D02AFD2C46C5A70056CE7B /* HandySematicColor.swift in Sources */,
E5D02B002C480A180056CE7B /* HandyPrimitiveColor.swift in Sources */,
E5D02AFD2C46C5A70056CE7B /* HandySematic.swift in Sources */,
E5D02B002C480A180056CE7B /* HandyPrimitive.swift in Sources */,
E51FBFA02C54CB260097B0DA /* HandyRadioButton.swift in Sources */,
E5669A3F2C443E7300DABC21 /* HandyBasicColor.swift in Sources */,
02ED76312C5284BB001569F1 /* HandyButtonProtocol.swift in Sources */,
Expand All @@ -488,6 +502,7 @@
029E48002C49FD4000D2F3B7 /* HandyTypography.swift in Sources */,
E5650D432C4D326D002790CC /* HandyCheckBox.swift in Sources */,
029E47FD2C49FD1A00D2F3B7 /* HandyLabel.swift in Sources */,
A5C208A32CDCCD75005F20A1 /* HandyNavigation.swift in Sources */,
A56B3DE22C4E51D300C3610A /* HandyChip.swift in Sources */,
E5650D472C512B07002790CC /* HandyIcon.swift in Sources */,
E5650D472C512B07002790CC /* HandyIcon.swift in Sources */,
Expand Down
123 changes: 123 additions & 0 deletions Handy/Handy/Source/Component/HandyNavigation.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
//
// HandyNavigation.swift
// Handy
//
// Created by 서준영 on 11/7/24.
//

import UIKit

open class HandyNavigation: UITabBarController {

/// 내부에서 사용되는 레이아웃 수치입니다.
let itemImageVerticalInset: CGFloat = 10

/// 상단 탭바에 사용되는 디바이더입니다.
let divider = HandyDivider()

/// 탭바아이템 이미지를 중앙에 놓을지 결정하는 프로퍼티입니다.
public var centerItem: Bool = false

open override func viewDidLoad() {
super.viewDidLoad()
setupView()
}

/// 뷰 세팅
private func setupView() {
setProperties()
setLayouts()
}

/// 프로퍼티 세팅
private func setProperties() {
let appearance = UITabBarAppearance()
appearance.configureWithOpaqueBackground() // 불투명한 배경으로 설정
appearance.backgroundColor = HandySemantic.bgBasicDefault
appearance.shadowColor = .clear // 탭바 그림자 제거

// 탭바 아이템 설정
/// 기본 설정
let tabBarItemAppearance = UITabBarItemAppearance(style: .stacked)
tabBarItemAppearance.normal.iconColor = HandySemantic.iconBasicDisabled // 아이콘 색상
tabBarItemAppearance.normal.titleTextAttributes = [
.foregroundColor: HandySemantic.textBasicDisabled, // 텍스트 색상
.font: HandyFont.C1Rg11] // 텍스트 폰트

/// 선택 되었을 때 설정
tabBarItemAppearance.selected.iconColor = HandySemantic.iconBasicPrimary // 선택된 아이콘 색상
tabBarItemAppearance.selected.titleTextAttributes = [
.foregroundColor: HandySemantic.textBasicPrimary, // 선택된 텍스트 색상
.font: HandyFont.C1Rg11] // 텍스트 폰트

// appearance의 각 레이아웃 스타일에 탭바 아이템 외형 설정을 적용
appearance.stackedLayoutAppearance = tabBarItemAppearance
appearance.compactInlineLayoutAppearance = tabBarItemAppearance
appearance.inlineLayoutAppearance = tabBarItemAppearance

tabBar.standardAppearance = appearance
tabBar.scrollEdgeAppearance = appearance
}

/// 레이아웃 세팅
private func setLayouts() {
tabBar.addSubview(divider)
divider.snp.makeConstraints {
$0.top.leading.trailing.equalToSuperview()
}
}
}

//MARK: - 탭바 높이 설정
extension HandyNavigation {
/// UITabBarController의 tabBar의 frame을 새로 정의하여 tabBar의 높이를 조절합니다.
open override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()

// Safe Area를 고려한 높이 설정
let fixedHeight: CGFloat = 56
var newFrame = tabBar.frame

let safeAreaInsets: CGFloat = {
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first {
return window.safeAreaInsets.bottom
}
return 0
}()

// 탭 바 높이 설정
newFrame.size.height = fixedHeight + safeAreaInsets
newFrame.origin.y = view.frame.height - newFrame.size.height
tabBar.frame = newFrame
}
}

//MARK: - 탭바 아이템 중앙 정렬
extension HandyNavigation {
open override var viewControllers: [UIViewController]? {
didSet { setTabBarItemImageInsets() }
}

open override func setViewControllers(_ viewControllers: [UIViewController]?, animated: Bool) {
super.setViewControllers(viewControllers, animated: true)
setTabBarItemImageInsets()
}

/// centerItem이 true라면 title을 nil로 설정하고, imageInsets을 조정해서 image를 중앙 정렬합니다.
public func setTabBarItemImageInsets() {
viewControllers?.forEach {
if centerItem == true {
$0.tabBarItem.title = nil
$0.tabBarItem.imageInsets = UIEdgeInsets(top: itemImageVerticalInset, left: 0, bottom: -itemImageVerticalInset, right: 0)
} else {
tabBarItem.imageInsets = UIEdgeInsets(
top: itemImageVerticalInset,
left: 0,
bottom: 0,
right: 0
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "icHome.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions Handy/Handy/Source/Foundation/HandyIcon.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public enum HandyIcon {
public static var checkBoxLine: UIImage { .load(name: "checkBoxLine") }
public static var radioButtonLine: UIImage { .load(name: "radioButtonLine") }
public static var radioButtonDisabled: UIImage { .load(name: "radioButtonDisabled") }

public static var icHomeFilled: UIImage { .load(name: "icHomeFilled")}
}

extension UIImage {
Expand Down