From c38b0f9824ce905a2fe2163a78e4a2267ddfe071 Mon Sep 17 00:00:00 2001 From: jysuhr Date: Thu, 14 Nov 2024 17:52:26 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[#26]=20HandyNavigation=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Component/NavigationViewController.swift | 61 ++++++++++ Handy/Handy-Storybook/SceneDelegate.swift | 2 +- Handy/Handy.xcodeproj/project.pbxproj | 37 ++++-- .../Source/Component/HandyNavigation.swift | 114 ++++++++++++++++++ .../navigation/Contents.json | 6 + .../icHomeFilled.imageset/Contents.json | 23 ++++ .../icHomeFilled.imageset/icHome.png | Bin 0 -> 324 bytes .../icHomeFilled.imageset/icHome@2.png | Bin 0 -> 528 bytes .../icHomeFilled.imageset/icHome@3.png | Bin 0 -> 784 bytes Handy/Handy/Source/Foundation/HandyIcon.swift | 2 + 10 files changed, 233 insertions(+), 12 deletions(-) create mode 100644 Handy/Handy-Storybook/Component/NavigationViewController.swift create mode 100644 Handy/Handy/Source/Component/HandyNavigation.swift create mode 100644 Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/Contents.json create mode 100644 Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/Contents.json create mode 100644 Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome.png create mode 100644 Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome@2.png create mode 100644 Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome@3.png diff --git a/Handy/Handy-Storybook/Component/NavigationViewController.swift b/Handy/Handy-Storybook/Component/NavigationViewController.swift new file mode 100644 index 0000000..bc7577d --- /dev/null +++ b/Handy/Handy-Storybook/Component/NavigationViewController.swift @@ -0,0 +1,61 @@ +// +// 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.bgBasicStrong + viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled) + return viewController + }() + + let page2: UIViewController = { + let viewController = UIViewController() + viewController.view.backgroundColor = HandySemantic.bgStatusPositive + 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.bgBasicLight + viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled) + return viewController + }() + + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + + self.setViewControllers([page1, page2, page3, page4, page5], animated: true) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + } +} diff --git a/Handy/Handy-Storybook/SceneDelegate.swift b/Handy/Handy-Storybook/SceneDelegate.swift index 9b73cc0..cbb779e 100644 --- a/Handy/Handy-Storybook/SceneDelegate.swift +++ b/Handy/Handy-Storybook/SceneDelegate.swift @@ -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() } diff --git a/Handy/Handy.xcodeproj/project.pbxproj b/Handy/Handy.xcodeproj/project.pbxproj index 7456aa6..b18b6af 100644 --- a/Handy/Handy.xcodeproj/project.pbxproj +++ b/Handy/Handy.xcodeproj/project.pbxproj @@ -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 */; }; @@ -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 */; }; @@ -112,6 +111,8 @@ 2D41E8152C5A21B50043161D /* HandyFab.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyFab.swift; sourceTree = ""; }; A56B3DE12C4E51D300C3610A /* HandyChip.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyChip.swift; sourceTree = ""; }; A5A12A7C2C57A6C200996916 /* ChipViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChipViewController.swift; sourceTree = ""; }; + A5C208A22CDCCD75005F20A1 /* HandyNavigation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyNavigation.swift; sourceTree = ""; }; + A5C208C52CE3BCE1005F20A1 /* NavigationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationViewController.swift; sourceTree = ""; }; A5F6D36A2C96F32D00FB961F /* HandyDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyDivider.swift; sourceTree = ""; }; A5F6D36C2C97099C00FB961F /* DividerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DividerViewController.swift; sourceTree = ""; }; E51FBF9A2C5399A00097B0DA /* CheckBoxViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckBoxViewController.swift; sourceTree = ""; }; @@ -120,9 +121,6 @@ E5650D422C4D326D002790CC /* HandyCheckBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyCheckBox.swift; sourceTree = ""; }; E5650D442C4E366F002790CC /* HandyIcon.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HandyIcon.xcassets; sourceTree = ""; }; E5650D462C512B07002790CC /* HandyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyIcon.swift; sourceTree = ""; }; - E5650D422C4D326D002790CC /* HandyCheckBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyCheckBox.swift; sourceTree = ""; }; - E5650D442C4E366F002790CC /* HandyIcon.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HandyIcon.xcassets; sourceTree = ""; }; - E5650D462C512B07002790CC /* HandyIcon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyIcon.swift; sourceTree = ""; }; E5669A3E2C443E7300DABC21 /* HandyBasicColor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandyBasicColor.swift; sourceTree = ""; }; E5669A422C443FE500DABC21 /* HandyBasicColor.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = HandyBasicColor.xcassets; sourceTree = ""; }; E5D02AFC2C46C5A70056CE7B /* HandySematic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandySematic.swift; sourceTree = ""; }; @@ -152,6 +150,7 @@ 025776332C4EA98C00272EC6 /* Handy-Storybook */ = { isa = PBXGroup; children = ( + A5C208C22CE3BC53005F20A1 /* Component */, 025776482C4EB0E700272EC6 /* Atom */, 025776572C4EB7C700272EC6 /* Font */, 0257765A2C4EB9B800272EC6 /* Storybook */, @@ -229,7 +228,6 @@ 2D41E8152C5A21B50043161D /* HandyFab.swift */, A56B3DE12C4E51D300C3610A /* HandyChip.swift */, A5F6D36A2C96F32D00FB961F /* HandyDivider.swift */, - E5650D422C4D326D002790CC /* HandyCheckBox.swift */, E51FBF9F2C54CB260097B0DA /* HandyRadioButton.swift */, E5650D422C4D326D002790CC /* HandyCheckBox.swift */, ); @@ -268,6 +266,7 @@ 02BDB7F92C3E962D0050FB67 /* Source */ = { isa = PBXGroup; children = ( + A5C208A12CDCCD4E005F20A1 /* Component */, 02ED76482C577998001569F1 /* Extension */, 029C446B2C468F8E00331F61 /* Font */, 029E47FE2C49FD2E00D2F3B7 /* Atom */, @@ -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 */, @@ -310,6 +307,22 @@ path = Extension; sourceTree = ""; }; + A5C208A12CDCCD4E005F20A1 /* Component */ = { + isa = PBXGroup; + children = ( + A5C208A22CDCCD75005F20A1 /* HandyNavigation.swift */, + ); + path = Component; + sourceTree = ""; + }; + A5C208C22CE3BC53005F20A1 /* Component */ = { + isa = PBXGroup; + children = ( + A5C208C52CE3BCE1005F20A1 /* NavigationViewController.swift */, + ); + path = Component; + sourceTree = ""; + }; E5650D412C4D30B9002790CC /* Asset */ = { isa = PBXGroup; children = ( @@ -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 */, @@ -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 */, @@ -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 */, diff --git a/Handy/Handy/Source/Component/HandyNavigation.swift b/Handy/Handy/Source/Component/HandyNavigation.swift new file mode 100644 index 0000000..8696df4 --- /dev/null +++ b/Handy/Handy/Source/Component/HandyNavigation.swift @@ -0,0 +1,114 @@ +// +// HandyNavigation.swift +// Handy +// +// Created by 서준영 on 11/7/24. +// + +import UIKit + +open class HandyNavigation: UITabBarController { + + /// 내부에서 사용되는 레이아웃 수치입니다. + let itemImageVerticalInset: CGFloat = 10 + + /// 상단 탭바에 사용되는 디바이더입니다. + let divider = HandyDivider() + + 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: UIFont.systemFont(ofSize: 11)] // 텍스트 폰트 사이즈 + + /// 선택 되었을 때 설정 + tabBarItemAppearance.selected.iconColor = HandySemantic.iconBasicPrimary // 선택된 아이콘 색상 + tabBarItemAppearance.selected.titleTextAttributes = [ + .foregroundColor: HandySemantic.textBasicPrimary, // 선택된 텍스트 색상 + .font: UIFont.systemFont(ofSize: 11)] // 텍스트 폰트 사이즈 + + // 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 { + open override var viewControllers: [UIViewController]? { + didSet { setTabBarItemImageInsets() } + } + + open override func setViewControllers(_ viewControllers: [UIViewController]?, animated: Bool) { + super.setViewControllers(viewControllers, animated: true) + setTabBarItemImageInsets() + } + + /// title이 nil이라면 imageInsets을 조정해서 image를 중앙 정렬합니다. + public func setTabBarItemImageInsets() { + viewControllers?.forEach { + if $0.tabBarItem.title == nil { + // title이 없는 경우 + $0.tabBarItem.imageInsets = UIEdgeInsets(top: itemImageVerticalInset, + left: 0, + bottom: -itemImageVerticalInset, + right: 0) + } else { + // FIXME: 레이아웃 적용 안됨 + // title이 있는 경우: 이미지와 텍스트 위치 조정 + tabBarItem.imageInsets = UIEdgeInsets( + top: itemImageVerticalInset, + left: 0, + bottom: 0, + right: 0 + ) + } + } + } +} + +/** + TODO: 레이아웃 간격 + - UITabBar의 높이 설정 불가 + - UITabBar의 아이콘 크기 설정 불가 + */ + +/** + 파일 변경점 + 1. Component폴더 생성 + 2. HandyNavigation.swift 생성 + 3. HandyIcon.swift 파일에 icHomeFilled 추가 + 4. Asset/HandyIcon에 이미지 추가 + */ diff --git a/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/Contents.json b/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/Contents.json b/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/Contents.json new file mode 100644 index 0000000..81bdfc8 --- /dev/null +++ b/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "icHome.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "icHome@2.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "icHome@3.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome.png b/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome.png new file mode 100644 index 0000000000000000000000000000000000000000..88a210c2bda3a7603a0f79efd6ec90945a001ac8 GIT binary patch literal 324 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz&H|6fVg?3oVGw3ym^DWND9BhG zjf1bW zu9s`toB9_2dnc8Rij!E{x1DHET+jLN{bd7>6dC38Cv${MTee6xO^)|mD`1yt$vP*A zQM@fziIwfeM}_YZ8xMp(6Vndnn!;rLY}dyhcN7jQO}xRrq;XE#vq<>@^?-+_tem1k zCqJ^!+01`9X?DP`b*eEI-8x^?3K%B)Deh?&aGtj@$G_*hm5#-v*8k5r-$j4$^PKP> Q7#s`?p00i_>zopr03i=|$^ZZW literal 0 HcmV?d00001 diff --git a/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome@2.png b/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome@2.png new file mode 100644 index 0000000000000000000000000000000000000000..a7572e3495082e27567d615bf3f44cc9cce32f3b GIT binary patch literal 528 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=oCO|{#S9E$svykh8Km+7D9BhG z-&}~vkiC-1JR1Zu?3Pf z-0Pa_4CKBaG2 zU9T48o%CO%nsl-{(b~;J=cnAy2j$1U74@{R&75>Tv$IY6a-jW(z%4C{^G+^*v+{-z z?{xdyOQRlfCR!cnzr&|!!lFN|MeM_=9E}rFA5O&tcZhxP^7ZR7UsCC!f3o_#XM?l8 z?<;QZOBE%>CdcM*%`ln9kk+T#Ff*Am;aLRJ3`;1t*gG=pAb(2bvQPeBf~PIW%E{`u zZjl=KPeV2OL3+Tfie6FClV?k0MB8op{#1K~H5}=>pk8$3Q~8{0S>2oMWo|60K78q@ zcarp%NprM|gg&&!b@@!=z5X+JaSLzj3&!QqzpaXLR7p2~ry1~`p zhiu=b-45P2i`{NM-@_q$=;QYO?{yYsS5l3C$kw=j-Nyg` literal 0 HcmV?d00001 diff --git a/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome@3.png b/Handy/Handy/Source/Foundation/Asset/HandyIcon.xcassets/navigation/icHomeFilled.imageset/icHome@3.png new file mode 100644 index 0000000000000000000000000000000000000000..89922941f46463c2cce9fe95f12108480588c886 GIT binary patch literal 784 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGooCO|{#S9FJK(?X*8o|0J?9Ffc9kba4!+V0?S`W8q~3k>elbWtgXM3J6c& zeZ~8NEv0#rqnn0w3$KQ-%G`#$gc%As0xFa4ZQZ$KW6DkcqJ8sse|N9moBgZqs!~)Out>P|Ks)R?d#p+`S)G>y?&zO7!{u{7r}B!xB~ut8?iEIrh^({euhoT>v2HN`W<#APGN$6qd5o|DIGH_!!#&JM`Q9_v^8K2|g!;2fyqNOu8;=*(=j<)N;X+jl~&Xa=CPvc7*P<%T5tf zf4HH~PKI^q+?K<_$zR@bM$DRV|ADu#_q>N!6&v=*Dc9R+HoS;0a{Q+e!+k2&gk#DV`B4FW`h{tTGK~;Z+qLSFBh-9nvtS?_3nl_TcWA-Z z;Xz>M8y?%5@`K?0txelF{r G5}E+Md0$}w literal 0 HcmV?d00001 diff --git a/Handy/Handy/Source/Foundation/HandyIcon.swift b/Handy/Handy/Source/Foundation/HandyIcon.swift index 05892f9..71ead37 100644 --- a/Handy/Handy/Source/Foundation/HandyIcon.swift +++ b/Handy/Handy/Source/Foundation/HandyIcon.swift @@ -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 { From 2911ac37fdaf5923fd480c0d99f2ecf1ebe30a3d Mon Sep 17 00:00:00 2001 From: jysuhr Date: Sat, 30 Nov 2024 01:33:00 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[#26]=20HandyNavigation=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Component/NavigationViewController.swift | 18 +++----- .../Source/Component/HandyNavigation.swift | 42 +++++++++++-------- 2 files changed, 29 insertions(+), 31 deletions(-) diff --git a/Handy/Handy-Storybook/Component/NavigationViewController.swift b/Handy/Handy-Storybook/Component/NavigationViewController.swift index bc7577d..41d1e11 100644 --- a/Handy/Handy-Storybook/Component/NavigationViewController.swift +++ b/Handy/Handy-Storybook/Component/NavigationViewController.swift @@ -10,16 +10,17 @@ import Handy import SnapKit class NavigationViewController: HandyNavigation { + let page1: UIViewController = { let viewController = UIViewController() - viewController.view.backgroundColor = HandySemantic.bgBasicStrong + 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.bgStatusPositive + viewController.view.backgroundColor = HandySemantic.bgBasicBlack viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled) return viewController }() @@ -40,22 +41,13 @@ class NavigationViewController: HandyNavigation { let page5: UIViewController = { let viewController = UIViewController() - viewController.view.backgroundColor = HandySemantic.bgBasicLight + viewController.view.backgroundColor = HandySemantic.iconBasicSecondary viewController.tabBarItem = UITabBarItem(title: "Label", image: HandyIcon.icHomeFilled, selectedImage: HandyIcon.icHomeFilled) return viewController }() - override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { - super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - - self.setViewControllers([page1, page2, page3, page4, page5], animated: true) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - override func viewDidLoad() { super.viewDidLoad() + setViewControllers([page1, page2, page3, page4, page5], animated: false) } } diff --git a/Handy/Handy/Source/Component/HandyNavigation.swift b/Handy/Handy/Source/Component/HandyNavigation.swift index 8696df4..c4bb90b 100644 --- a/Handy/Handy/Source/Component/HandyNavigation.swift +++ b/Handy/Handy/Source/Component/HandyNavigation.swift @@ -15,6 +15,8 @@ open class HandyNavigation: UITabBarController { /// 상단 탭바에 사용되는 디바이더입니다. let divider = HandyDivider() + private let customTabBar = CustomTabBar() + open override func viewDidLoad() { super.viewDidLoad() setupView() @@ -22,6 +24,7 @@ open class HandyNavigation: UITabBarController { /// 뷰 세팅 private func setupView() { + setValue(customTabBar, forKey: "tabBar") setProperties() setLayouts() } @@ -81,13 +84,8 @@ extension HandyNavigation { viewControllers?.forEach { if $0.tabBarItem.title == nil { // title이 없는 경우 - $0.tabBarItem.imageInsets = UIEdgeInsets(top: itemImageVerticalInset, - left: 0, - bottom: -itemImageVerticalInset, - right: 0) + $0.tabBarItem.imageInsets = UIEdgeInsets(top: itemImageVerticalInset, left: 0, bottom: -itemImageVerticalInset, right: 0) } else { - // FIXME: 레이아웃 적용 안됨 - // title이 있는 경우: 이미지와 텍스트 위치 조정 tabBarItem.imageInsets = UIEdgeInsets( top: itemImageVerticalInset, left: 0, @@ -99,16 +97,24 @@ extension HandyNavigation { } } -/** - TODO: 레이아웃 간격 - - UITabBar의 높이 설정 불가 - - UITabBar의 아이콘 크기 설정 불가 - */ +//MARK: - 네비게이션 바 레이아웃 설정 (Safe Area 처리) +class CustomTabBar: UITabBar { + let fixedHeight: CGFloat = 56 -/** - 파일 변경점 - 1. Component폴더 생성 - 2. HandyNavigation.swift 생성 - 3. HandyIcon.swift 파일에 icHomeFilled 추가 - 4. Asset/HandyIcon에 이미지 추가 - */ + override func layoutSubviews() { + super.layoutSubviews() + + // Safe Area를 고려한 높이 설정 + var newFrame = self.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 = UIScreen.main.bounds.height - newFrame.size.height + self.frame = newFrame + } +} From 89903061fa662cefa8ef3b6901dc67003ce4c1f7 Mon Sep 17 00:00:00 2001 From: jysuhr Date: Wed, 15 Jan 2025 01:52:19 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[#26]=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Component/NavigationViewController.swift | 1 + .../Source/Component/HandyNavigation.swift | 61 ++++++++++--------- 2 files changed, 33 insertions(+), 29 deletions(-) diff --git a/Handy/Handy-Storybook/Component/NavigationViewController.swift b/Handy/Handy-Storybook/Component/NavigationViewController.swift index 41d1e11..558b17a 100644 --- a/Handy/Handy-Storybook/Component/NavigationViewController.swift +++ b/Handy/Handy-Storybook/Component/NavigationViewController.swift @@ -48,6 +48,7 @@ class NavigationViewController: HandyNavigation { override func viewDidLoad() { super.viewDidLoad() + centerItem = false setViewControllers([page1, page2, page3, page4, page5], animated: false) } } diff --git a/Handy/Handy/Source/Component/HandyNavigation.swift b/Handy/Handy/Source/Component/HandyNavigation.swift index c4bb90b..fdd1acd 100644 --- a/Handy/Handy/Source/Component/HandyNavigation.swift +++ b/Handy/Handy/Source/Component/HandyNavigation.swift @@ -15,7 +15,8 @@ open class HandyNavigation: UITabBarController { /// 상단 탭바에 사용되는 디바이더입니다. let divider = HandyDivider() - private let customTabBar = CustomTabBar() + /// 탭바아이템 이미지를 중앙에 놓을지 결정하는 프로퍼티입니다. + public var centerItem: Bool = false open override func viewDidLoad() { super.viewDidLoad() @@ -24,7 +25,6 @@ open class HandyNavigation: UITabBarController { /// 뷰 세팅 private func setupView() { - setValue(customTabBar, forKey: "tabBar") setProperties() setLayouts() } @@ -42,13 +42,13 @@ open class HandyNavigation: UITabBarController { tabBarItemAppearance.normal.iconColor = HandySemantic.iconBasicDisabled // 아이콘 색상 tabBarItemAppearance.normal.titleTextAttributes = [ .foregroundColor: HandySemantic.textBasicDisabled, // 텍스트 색상 - .font: UIFont.systemFont(ofSize: 11)] // 텍스트 폰트 사이즈 + .font: HandyFont.C1Rg11] // 텍스트 폰트 /// 선택 되었을 때 설정 tabBarItemAppearance.selected.iconColor = HandySemantic.iconBasicPrimary // 선택된 아이콘 색상 tabBarItemAppearance.selected.titleTextAttributes = [ .foregroundColor: HandySemantic.textBasicPrimary, // 선택된 텍스트 색상 - .font: UIFont.systemFont(ofSize: 11)] // 텍스트 폰트 사이즈 + .font: HandyFont.C1Rg11] // 텍스트 폰트 // appearance의 각 레이아웃 스타일에 탭바 아이템 외형 설정을 적용 appearance.stackedLayoutAppearance = tabBarItemAppearance @@ -68,6 +68,31 @@ open class HandyNavigation: UITabBarController { } } +//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]? { @@ -79,11 +104,11 @@ extension HandyNavigation { setTabBarItemImageInsets() } - /// title이 nil이라면 imageInsets을 조정해서 image를 중앙 정렬합니다. + /// centerItem이 true라면 title을 nil로 설정하고, imageInsets을 조정해서 image를 중앙 정렬합니다. public func setTabBarItemImageInsets() { viewControllers?.forEach { - if $0.tabBarItem.title == nil { - // title이 없는 경우 + if centerItem == true { + $0.tabBarItem.title = nil $0.tabBarItem.imageInsets = UIEdgeInsets(top: itemImageVerticalInset, left: 0, bottom: -itemImageVerticalInset, right: 0) } else { tabBarItem.imageInsets = UIEdgeInsets( @@ -96,25 +121,3 @@ extension HandyNavigation { } } } - -//MARK: - 네비게이션 바 레이아웃 설정 (Safe Area 처리) -class CustomTabBar: UITabBar { - let fixedHeight: CGFloat = 56 - - override func layoutSubviews() { - super.layoutSubviews() - - // Safe Area를 고려한 높이 설정 - var newFrame = self.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 = UIScreen.main.bounds.height - newFrame.size.height - self.frame = newFrame - } -}