diff --git a/Handy/Handy-Storybook/Atom/HansySwitchViewController.swift b/Handy/Handy-Storybook/Atom/HansySwitchViewController.swift new file mode 100644 index 0000000..0274a05 --- /dev/null +++ b/Handy/Handy-Storybook/Atom/HansySwitchViewController.swift @@ -0,0 +1,59 @@ +// +// HansySwitchViewController.swift +// Handy-Storybook +// +// Created by 이조은 on 9/18/24. +// + +import Handy +import UIKit + +final class HansySwitchViewController: BaseViewController { + + private let switch1: HandySwitch = { + let uiSwitch = HandySwitch() + uiSwitch.size = .large + return uiSwitch + }() + + private let switch2: HandySwitch = { + let uiSwitch = HandySwitch() + uiSwitch.size = .medium + uiSwitch.isOn = true + return uiSwitch + }() + + private let switch3: HandySwitch = { + let uiSwitch = HandySwitch() + uiSwitch.size = .small + uiSwitch.isDisabled = true + return uiSwitch + }() + + override func viewDidLoad() { + super.viewDidLoad() + + self.view.backgroundColor = .white + } + + override func setViewHierarchies() { + self.view.addSubview(switch1) + self.view.addSubview(switch2) + self.view.addSubview(switch3) + } + + override func setViewLayouts() { + switch1.snp.makeConstraints { + $0.top.equalToSuperview().inset(100) + $0.leading.equalToSuperview().inset(20) + } + switch2.snp.makeConstraints { + $0.top.equalTo(switch1.snp.bottom).offset(36) // -4 + $0.leading.equalToSuperview().inset(13) // -7 + } + switch3.snp.makeConstraints { + $0.top.equalTo(switch2.snp.bottom).offset(28) // -12 + $0.leading.equalToSuperview().inset(8) // -12 + } + } +} diff --git a/Handy/Handy-Storybook/SceneDelegate.swift b/Handy/Handy-Storybook/SceneDelegate.swift index 5fc3b90..dd9feef 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 = SnackbarViewController() + window?.rootViewController = HansySwitchViewController() window?.makeKeyAndVisible() } diff --git a/Handy/Handy.xcodeproj/project.pbxproj b/Handy/Handy.xcodeproj/project.pbxproj index b80090d..fd42298 100644 --- a/Handy/Handy.xcodeproj/project.pbxproj +++ b/Handy/Handy.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ 025776562C4EB7BB00272EC6 /* Pretendard-SemiBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 025776532C4EB7BB00272EC6 /* Pretendard-SemiBold.otf */; }; 025776592C4EB8BC00272EC6 /* Pretendard-Light.otf in Resources */ = {isa = PBXBuildFile; fileRef = 025776582C4EB8BC00272EC6 /* Pretendard-Light.otf */; }; 0257765D2C4EB9EF00272EC6 /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0257765C2C4EB9EF00272EC6 /* BaseViewController.swift */; }; + 02697A242C99D7230027A362 /* HandySwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02697A232C99D7230027A362 /* HandySwitch.swift */; }; + 02697A262C99DDA30027A362 /* HansySwitchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 02697A252C99DDA30027A362 /* HansySwitchViewController.swift */; }; 029C44682C468F8300331F61 /* Pretendard-Light.otf in Resources */ = {isa = PBXBuildFile; fileRef = 029C44652C468F8300331F61 /* Pretendard-Light.otf */; }; 029C44692C468F8300331F61 /* Pretendard-Regular.otf in Resources */ = {isa = PBXBuildFile; fileRef = 029C44662C468F8300331F61 /* Pretendard-Regular.otf */; }; 029C446A2C468F8300331F61 /* Pretendard-SemiBold.otf in Resources */ = {isa = PBXBuildFile; fileRef = 029C44672C468F8300331F61 /* Pretendard-SemiBold.otf */; }; @@ -95,6 +97,8 @@ 025776532C4EB7BB00272EC6 /* Pretendard-SemiBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Pretendard-SemiBold.otf"; path = "Handy-Storybook/Font/Pretendard-SemiBold.otf"; sourceTree = SOURCE_ROOT; }; 025776582C4EB8BC00272EC6 /* Pretendard-Light.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Light.otf"; sourceTree = ""; }; 0257765C2C4EB9EF00272EC6 /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; }; + 02697A232C99D7230027A362 /* HandySwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HandySwitch.swift; sourceTree = ""; }; + 02697A252C99DDA30027A362 /* HansySwitchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HansySwitchViewController.swift; sourceTree = ""; }; 029C44652C468F8300331F61 /* Pretendard-Light.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Light.otf"; sourceTree = ""; }; 029C44662C468F8300331F61 /* Pretendard-Regular.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Regular.otf"; sourceTree = ""; }; 029C44672C468F8300331F61 /* Pretendard-SemiBold.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-SemiBold.otf"; sourceTree = ""; }; @@ -172,6 +176,7 @@ A5F6D36C2C97099C00FB961F /* DividerViewController.swift */, E51FBF9A2C5399A00097B0DA /* CheckBoxViewController.swift */, E51FBFA12C54CD350097B0DA /* RadioButtonViewController.swift */, + 02697A252C99DDA30027A362 /* HansySwitchViewController.swift */, ); path = Atom; sourceTree = ""; @@ -230,6 +235,7 @@ A5F6D36A2C96F32D00FB961F /* HandyDivider.swift */, E51FBF9F2C54CB260097B0DA /* HandyRadioButton.swift */, E5650D422C4D326D002790CC /* HandyCheckBox.swift */, + 02697A232C99D7230027A362 /* HandySwitch.swift */, 02150E492CC8D7AB00EE690E /* HandySnackbar.swift */, ); path = Atom; @@ -462,6 +468,7 @@ E51FBFA22C54CD350097B0DA /* RadioButtonViewController.swift in Sources */, E51FBF9B2C5399A00097B0DA /* CheckBoxViewController.swift in Sources */, 025776352C4EA98C00272EC6 /* AppDelegate.swift in Sources */, + 02697A262C99DDA30027A362 /* HansySwitchViewController.swift in Sources */, 025776372C4EA98C00272EC6 /* SceneDelegate.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -473,6 +480,7 @@ 2D41E8162C5A21B50043161D /* HandyFab.swift in Sources */, 02ED76332C5284E6001569F1 /* HandyBoxButton.swift in Sources */, E5D02AFD2C46C5A70056CE7B /* HandySematic.swift in Sources */, + 02697A242C99D7230027A362 /* HandySwitch.swift in Sources */, 02150E4A2CC8D7AB00EE690E /* HandySnackbar.swift in Sources */, E5D02B002C480A180056CE7B /* HandyPrimitive.swift in Sources */, E5D02AFD2C46C5A70056CE7B /* HandySematic.swift in Sources */, diff --git a/Handy/Handy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Handy/Handy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 1aa4873..747f717 100644 --- a/Handy/Handy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/Handy/Handy.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -4,7 +4,7 @@ { "identity" : "snapkit", "kind" : "remoteSourceControl", - "location" : "https://github.com/SnapKit/SnapKit.git", + "location" : "https://github.com/SnapKit/SnapKit", "state" : { "revision" : "2842e6e84e82eb9a8dac0100ca90d9444b0307f4", "version" : "5.7.1" diff --git a/Handy/Handy/Source/Atom/HandySwitch.swift b/Handy/Handy/Source/Atom/HandySwitch.swift new file mode 100644 index 0000000..136925c --- /dev/null +++ b/Handy/Handy/Source/Atom/HandySwitch.swift @@ -0,0 +1,85 @@ +// +// HandySwitch.swift +// Handy +// +// Created by 이조은 on 9/18/24. +// + +import UIKit + +final public class HandySwitch: UISwitch { + + // MARK: - 외부에서 지정할 수 있는 속성 + @Invalidating(.layout, .display) public var isDisabled: Bool = false + + @Invalidating(.display) public var size: SwitchSize = .medium { + didSet { + updateSwitchSize() // size가 변경될 때 크기 변경 + } + } + + public override var isOn: Bool { + didSet { setNeedsDisplay() } + } + + // MARK: - 외부에서 접근할 수 있는 enum + public enum SwitchSize { + case large + case medium + case small + + fileprivate var ratio: CGFloat { + switch self { + case .large: + return 1.0 + case .medium: + return 0.7 + case .small: + return 0.5 + } + } + + fileprivate var switchWidth: CGFloat { + return 51.0 * self.ratio + } + + fileprivate var switchHeight: CGFloat { + return 31.0 * self.ratio + } + } + + // MARK: - 내부에서 사용되는 변수 + private var fgColor: UIColor? + private var bgColor: UIColor? + + // MARK: - 메소드 + + public init() { + super.init(frame: .zero) + setupView() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupView() { + setSwitchColor() + updateSwitchSize() + } + + private func setSwitchColor() { + self.subviews.first?.subviews.first?.backgroundColor = HandySemantic.switchUnselected + self.onTintColor = HandySemantic.switchSelected + } + + private func updateSwitchSize() { + self.transform = CGAffineTransform(scaleX: size.ratio, y: size.ratio) + } + + public override func layoutSubviews() { + super.layoutSubviews() + isEnabled = !isDisabled + setSwitchColor() + } +} diff --git a/Handy/Handy/Source/Foundation/HandySematic.swift b/Handy/Handy/Source/Foundation/HandySematic.swift index ecd9d95..dc144dd 100644 --- a/Handy/Handy/Source/Foundation/HandySematic.swift +++ b/Handy/Handy/Source/Foundation/HandySematic.swift @@ -295,6 +295,21 @@ public enum HandySemantic { return .gray500 } + // MARK: - Switch + + public static var switchUnselected: UIColor { + return .gray300 + } + + public static var switchSelected: UIColor { + return .violet500 + } + + public static var switchDisabled: UIColor { + return .gray200 + } + + // MARK: - Snackbar public static var snackbarInfo: UIColor {