diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..cc20623 Binary files /dev/null and b/.DS_Store differ diff --git a/iOS-Practice/iOS-Practice.xcodeproj/project.pbxproj b/iOS-Practice/iOS-Practice.xcodeproj/project.pbxproj index 8710e77..328081c 100644 --- a/iOS-Practice/iOS-Practice.xcodeproj/project.pbxproj +++ b/iOS-Practice/iOS-Practice.xcodeproj/project.pbxproj @@ -7,20 +7,32 @@ objects = { /* Begin PBXBuildFile section */ + 0481FBDF2B44078600D4EF60 /* RoutineViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481FBDE2B44078600D4EF60 /* RoutineViewController.swift */; }; + 0481FBE12B44079500D4EF60 /* RoutineCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481FBE02B44079500D4EF60 /* RoutineCollectionViewCell.swift */; }; + 0481FBE32B4407A500D4EF60 /* RoutineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481FBE22B4407A500D4EF60 /* RoutineView.swift */; }; + 0481FBE62B4408C300D4EF60 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 0481FBE52B4408C300D4EF60 /* SnapKit */; }; + 0481FBE82B4408C300D4EF60 /* SnapKit-Dynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 0481FBE72B4408C300D4EF60 /* SnapKit-Dynamic */; }; + 0481FBEA2B44091000D4EF60 /* UICollectionViewRegisterable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481FBE92B44091000D4EF60 /* UICollectionViewRegisterable.swift */; }; + 0481FBEC2B44095500D4EF60 /* NSObject+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481FBEB2B44095500D4EF60 /* NSObject+.swift */; }; + 0481FBEE2B440E1700D4EF60 /* UIView+.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481FBED2B440E1700D4EF60 /* UIView+.swift */; }; + 0481FBF02B441CFF00D4EF60 /* RoutineEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0481FBEF2B441CFF00D4EF60 /* RoutineEntity.swift */; }; A42C334F2B3FF46100C4B477 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42C334E2B3FF46100C4B477 /* AppDelegate.swift */; }; A42C33512B3FF46100C4B477 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42C33502B3FF46100C4B477 /* SceneDelegate.swift */; }; - A42C33532B3FF46100C4B477 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42C33522B3FF46100C4B477 /* ViewController.swift */; }; - A42C33562B3FF46100C4B477 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A42C33542B3FF46100C4B477 /* Main.storyboard */; }; A42C33582B3FF46300C4B477 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A42C33572B3FF46300C4B477 /* Assets.xcassets */; }; A42C335B2B3FF46300C4B477 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A42C33592B3FF46300C4B477 /* LaunchScreen.storyboard */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 0481FBDE2B44078600D4EF60 /* RoutineViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutineViewController.swift; sourceTree = ""; }; + 0481FBE02B44079500D4EF60 /* RoutineCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutineCollectionViewCell.swift; sourceTree = ""; }; + 0481FBE22B4407A500D4EF60 /* RoutineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutineView.swift; sourceTree = ""; }; + 0481FBE92B44091000D4EF60 /* UICollectionViewRegisterable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UICollectionViewRegisterable.swift; sourceTree = ""; }; + 0481FBEB2B44095500D4EF60 /* NSObject+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSObject+.swift"; sourceTree = ""; }; + 0481FBED2B440E1700D4EF60 /* UIView+.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+.swift"; sourceTree = ""; }; + 0481FBEF2B441CFF00D4EF60 /* RoutineEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoutineEntity.swift; sourceTree = ""; }; A42C334B2B3FF46100C4B477 /* iOS-Practice.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "iOS-Practice.app"; sourceTree = BUILT_PRODUCTS_DIR; }; A42C334E2B3FF46100C4B477 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; A42C33502B3FF46100C4B477 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = ""; }; - A42C33522B3FF46100C4B477 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; - A42C33552B3FF46100C4B477 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; A42C33572B3FF46300C4B477 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; A42C335A2B3FF46300C4B477 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; A42C335C2B3FF46300C4B477 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -31,6 +43,8 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 0481FBE62B4408C300D4EF60 /* SnapKit in Frameworks */, + 0481FBE82B4408C300D4EF60 /* SnapKit-Dynamic in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -58,11 +72,16 @@ children = ( A42C334E2B3FF46100C4B477 /* AppDelegate.swift */, A42C33502B3FF46100C4B477 /* SceneDelegate.swift */, - A42C33522B3FF46100C4B477 /* ViewController.swift */, - A42C33542B3FF46100C4B477 /* Main.storyboard */, A42C33572B3FF46300C4B477 /* Assets.xcassets */, A42C33592B3FF46300C4B477 /* LaunchScreen.storyboard */, A42C335C2B3FF46300C4B477 /* Info.plist */, + 0481FBDE2B44078600D4EF60 /* RoutineViewController.swift */, + 0481FBE02B44079500D4EF60 /* RoutineCollectionViewCell.swift */, + 0481FBE22B4407A500D4EF60 /* RoutineView.swift */, + 0481FBE92B44091000D4EF60 /* UICollectionViewRegisterable.swift */, + 0481FBEB2B44095500D4EF60 /* NSObject+.swift */, + 0481FBED2B440E1700D4EF60 /* UIView+.swift */, + 0481FBEF2B441CFF00D4EF60 /* RoutineEntity.swift */, ); path = "iOS-Practice"; sourceTree = ""; @@ -83,6 +102,10 @@ dependencies = ( ); name = "iOS-Practice"; + packageProductDependencies = ( + 0481FBE52B4408C300D4EF60 /* SnapKit */, + 0481FBE72B4408C300D4EF60 /* SnapKit-Dynamic */, + ); productName = "iOS-Practice"; productReference = A42C334B2B3FF46100C4B477 /* iOS-Practice.app */; productType = "com.apple.product-type.application"; @@ -111,6 +134,9 @@ Base, ); mainGroup = A42C33422B3FF46100C4B477; + packageReferences = ( + 0481FBE42B4408C300D4EF60 /* XCRemoteSwiftPackageReference "SnapKit" */, + ); productRefGroup = A42C334C2B3FF46100C4B477 /* Products */; projectDirPath = ""; projectRoot = ""; @@ -127,7 +153,6 @@ files = ( A42C335B2B3FF46300C4B477 /* LaunchScreen.storyboard in Resources */, A42C33582B3FF46300C4B477 /* Assets.xcassets in Resources */, - A42C33562B3FF46100C4B477 /* Main.storyboard in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -138,23 +163,21 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A42C33532B3FF46100C4B477 /* ViewController.swift in Sources */, + 0481FBF02B441CFF00D4EF60 /* RoutineEntity.swift in Sources */, A42C334F2B3FF46100C4B477 /* AppDelegate.swift in Sources */, + 0481FBE12B44079500D4EF60 /* RoutineCollectionViewCell.swift in Sources */, + 0481FBE32B4407A500D4EF60 /* RoutineView.swift in Sources */, + 0481FBEA2B44091000D4EF60 /* UICollectionViewRegisterable.swift in Sources */, + 0481FBEE2B440E1700D4EF60 /* UIView+.swift in Sources */, + 0481FBEC2B44095500D4EF60 /* NSObject+.swift in Sources */, A42C33512B3FF46100C4B477 /* SceneDelegate.swift in Sources */, + 0481FBDF2B44078600D4EF60 /* RoutineViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ - A42C33542B3FF46100C4B477 /* Main.storyboard */ = { - isa = PBXVariantGroup; - children = ( - A42C33552B3FF46100C4B477 /* Base */, - ); - name = Main.storyboard; - sourceTree = ""; - }; A42C33592B3FF46300C4B477 /* LaunchScreen.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -292,7 +315,6 @@ INFOPLIST_FILE = "iOS-Practice/Info.plist"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = ( @@ -320,7 +342,6 @@ INFOPLIST_FILE = "iOS-Practice/Info.plist"; INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UIMainStoryboardFile = Main; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; LD_RUNPATH_SEARCH_PATHS = ( @@ -358,6 +379,30 @@ defaultConfigurationName = Release; }; /* End XCConfigurationList section */ + +/* Begin XCRemoteSwiftPackageReference section */ + 0481FBE42B4408C300D4EF60 /* XCRemoteSwiftPackageReference "SnapKit" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/SnapKit/SnapKit"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 5.7.0; + }; + }; +/* End XCRemoteSwiftPackageReference section */ + +/* Begin XCSwiftPackageProductDependency section */ + 0481FBE52B4408C300D4EF60 /* SnapKit */ = { + isa = XCSwiftPackageProductDependency; + package = 0481FBE42B4408C300D4EF60 /* XCRemoteSwiftPackageReference "SnapKit" */; + productName = SnapKit; + }; + 0481FBE72B4408C300D4EF60 /* SnapKit-Dynamic */ = { + isa = XCSwiftPackageProductDependency; + package = 0481FBE42B4408C300D4EF60 /* XCRemoteSwiftPackageReference "SnapKit" */; + productName = "SnapKit-Dynamic"; + }; +/* End XCSwiftPackageProductDependency section */ }; rootObject = A42C33432B3FF46100C4B477 /* Project object */; } diff --git a/iOS-Practice/iOS-Practice.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/iOS-Practice/iOS-Practice.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..1e7f7e0 --- /dev/null +++ b/iOS-Practice/iOS-Practice.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "snapkit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/SnapKit/SnapKit", + "state" : { + "revision" : "e74fe2a978d1216c3602b129447c7301573cc2d8", + "version" : "5.7.0" + } + } + ], + "version" : 2 +} diff --git a/iOS-Practice/iOS-Practice.xcodeproj/xcshareddata/xcschemes/iOS-Practice.xcscheme b/iOS-Practice/iOS-Practice.xcodeproj/xcshareddata/xcschemes/iOS-Practice.xcscheme new file mode 100644 index 0000000..d1ffe42 --- /dev/null +++ b/iOS-Practice/iOS-Practice.xcodeproj/xcshareddata/xcschemes/iOS-Practice.xcscheme @@ -0,0 +1,77 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOS-Practice/iOS-Practice/Base.lproj/Main.storyboard b/iOS-Practice/iOS-Practice/Base.lproj/Main.storyboard deleted file mode 100644 index 25a7638..0000000 --- a/iOS-Practice/iOS-Practice/Base.lproj/Main.storyboard +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/iOS-Practice/iOS-Practice/Info.plist b/iOS-Practice/iOS-Practice/Info.plist index dd3c9af..0eb786d 100644 --- a/iOS-Practice/iOS-Practice/Info.plist +++ b/iOS-Practice/iOS-Practice/Info.plist @@ -15,8 +15,6 @@ Default Configuration UISceneDelegateClassName $(PRODUCT_MODULE_NAME).SceneDelegate - UISceneStoryboardFile - Main diff --git a/iOS-Practice/iOS-Practice/NSObject+.swift b/iOS-Practice/iOS-Practice/NSObject+.swift new file mode 100644 index 0000000..4388587 --- /dev/null +++ b/iOS-Practice/iOS-Practice/NSObject+.swift @@ -0,0 +1,14 @@ +// +// NSObject+.swift +// iOS-Practice +// +// Created by Woo Jye Lee on 1/2/24. +// + +import Foundation + +extension NSObject { + static var className: String { + NSStringFromClass(self.classForCoder()).components(separatedBy: ".").last! + } +} diff --git a/iOS-Practice/iOS-Practice/RoutineCollectionViewCell.swift b/iOS-Practice/iOS-Practice/RoutineCollectionViewCell.swift new file mode 100644 index 0000000..3ffc551 --- /dev/null +++ b/iOS-Practice/iOS-Practice/RoutineCollectionViewCell.swift @@ -0,0 +1,101 @@ +// +// RoutineCollectionViewCell.swift +// iOS-Practice +// +// Created by Woo Jye Lee on 1/2/24. +// + +import UIKit + +import SnapKit + +final class RoutineCollectionViewCell: UICollectionViewCell, UICollectionViewRegisterable { + + // MARK: - Properties + + static let isFromNib: Bool = false + + // MARK: - UI Components + + let imageView: UIImageView = { + let image = UIImageView() + image.image = UIImage(systemName: "apple.logo") + return image + }() + + lazy var dateLabel: UILabel = { + let label = UILabel() + return label + }() + + lazy var routineLabel: UILabel = { + let label = UILabel() + return label + }() + + lazy var achieveLabel: UILabel = { + let label = UILabel() + label.text = "달성완료" + label.textAlignment = .center + label.backgroundColor = UIColor.green // 배경색 설정 + label.layer.cornerRadius = 10 // 테두리를 둥글게 만들기 위한 코너 반지름 설정 + label.clipsToBounds = true + return label + }() + + // MARK: - Life Cycles + + override init(frame: CGRect) { + super.init(frame: frame) + + setUI() + setHierarchy() + setLayout() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - Extensions + +extension RoutineCollectionViewCell { + + func setUI() { + self.layer.cornerRadius = 20 + self.layer.borderWidth = 0.5 + self.layer.borderColor = UIColor.lightGray.cgColor + self.backgroundColor = .white + } + + func setHierarchy() { + self.addSubviews(imageView, dateLabel, routineLabel, achieveLabel) + } + + func setLayout() { + imageView.snp.makeConstraints { + $0.centerY.equalToSuperview() + $0.leading.equalToSuperview().inset(30) + $0.size.equalTo(80) + } + dateLabel.snp.makeConstraints { + $0.top.equalToSuperview().inset(21) + $0.leading.equalTo(imageView.snp.trailing).offset(21) + } + routineLabel.snp.makeConstraints { + $0.top.equalTo(dateLabel.snp.bottom).inset(4) + $0.leading.equalTo(dateLabel) + } + achieveLabel.snp.makeConstraints { + $0.leading.equalTo(dateLabel) + $0.trailing.equalToSuperview().inset(70) + $0.bottom.equalToSuperview().inset(10) + } + } + + func setDatabind(model: RoutineEntity) { + self.dateLabel.text = "\(model.dateLabel)일 달성중" + self.routineLabel.text = model.routineLabel + } +} diff --git a/iOS-Practice/iOS-Practice/RoutineEntity.swift b/iOS-Practice/iOS-Practice/RoutineEntity.swift new file mode 100644 index 0000000..7e10b54 --- /dev/null +++ b/iOS-Practice/iOS-Practice/RoutineEntity.swift @@ -0,0 +1,26 @@ +// +// RoutineEntity.swift +// iOS-Practice +// +// Created by Woo Jye Lee on 1/2/24. +// + +import Foundation + +struct RoutineEntity { + let dateLabel: String + let routineLabel: String + let imageName: String +} + +extension RoutineEntity { + static func routineDummy() -> [RoutineEntity] { + return [ + RoutineEntity(dateLabel: "5", routineLabel: "이불 개기", imageName: "apple.logo"), + RoutineEntity(dateLabel: "5", routineLabel: "이불 개기", imageName: "apple.logo"), + RoutineEntity(dateLabel: "5", routineLabel: "이불 개기", imageName: "apple.logo"), + RoutineEntity(dateLabel: "5", routineLabel: "이불 개기", imageName: "apple.logo"), + RoutineEntity(dateLabel: "5", routineLabel: "이불 개기", imageName: "apple.logo") + ] + } +} diff --git a/iOS-Practice/iOS-Practice/RoutineView.swift b/iOS-Practice/iOS-Practice/RoutineView.swift new file mode 100644 index 0000000..f7acb5b --- /dev/null +++ b/iOS-Practice/iOS-Practice/RoutineView.swift @@ -0,0 +1,116 @@ +// +// RoutineView.swift +// iOS-Practice +// +// Created by Woo Jye Lee on 1/2/24. +// + +import UIKit + +import SnapKit + +final class RoutineView: UIView { + + // MARK: - Properties + var shouldHideFirstView: Bool? { // 상단 세그먼트컨트롤 터치를 감지하는 프로퍼티 + didSet { + guard let shouldHideFirstView = self.shouldHideFirstView else { return } + self.collectionView.isHidden = shouldHideFirstView + self.secondView.isHidden = !self.collectionView.isHidden + } + } + + // MARK: - UI Components + let segmentedControl: UISegmentedControl = { + let control = UISegmentedControl(items: ["데일리 루틴", "행복 루틴"]) + control.translatesAutoresizingMaskIntoConstraints = false + control.backgroundColor = .white + let titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.black] + control.setTitleTextAttributes(titleTextAttributes, for: .normal) + let titleTextAttributes2 = [NSAttributedString.Key.foregroundColor: UIColor.red] + control.setTitleTextAttributes(titleTextAttributes2, for: .selected) + return control + }() + + let secondView: UIView = { // 행복 루틴 페이지 + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + let collectionView: UICollectionView = { + let flowLayout = UICollectionViewFlowLayout() + flowLayout.itemSize = CGSize(width: 315, height: 94) + let view = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) + return view + }() + + // MARK: - Life Cycles + + override init(frame: CGRect) { + super.init(frame: frame) + + setUI() + setHierarchy() + setLayout() + setAddTarget() + setRegisterCell() + self.segmentedControl.addTarget(self, action: #selector(didChangeValue(segment:)), for: .valueChanged) + self.segmentedControl.selectedSegmentIndex = 0 + self.didChangeValue(segment: self.segmentedControl) + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - Extensions + +extension RoutineView { + + func setUI() { + self.backgroundColor = .white + } + + func setHierarchy() { + self.addSubviews(collectionView, segmentedControl, secondView) + } + + func setLayout() { + segmentedControl.snp.makeConstraints() { + $0.leading.trailing.top.equalToSuperview() + $0.height.equalTo(38) + } + collectionView.snp.makeConstraints { + $0.leading.trailing.bottom.equalToSuperview() // 여기서 가리키는 superView는? + $0.top.equalTo(segmentedControl.snp.bottom) + } + secondView.snp.makeConstraints() { + $0.leading.trailing.bottom.equalToSuperview() + $0.top.equalTo(segmentedControl.snp.bottom) + } + } + + func setAddTarget() { + + } + + @objc + func buttonTapped() { + + } + + func setRegisterCell() { + RoutineCollectionViewCell.register(target: collectionView) + } + + func setDataBind() { + + } + + @objc private func didChangeValue(segment: UISegmentedControl) { + self.shouldHideFirstView = segment.selectedSegmentIndex != 0 + } +} diff --git a/iOS-Practice/iOS-Practice/RoutineViewController.swift b/iOS-Practice/iOS-Practice/RoutineViewController.swift new file mode 100644 index 0000000..499848d --- /dev/null +++ b/iOS-Practice/iOS-Practice/RoutineViewController.swift @@ -0,0 +1,75 @@ +// +// RoutineViewController.swift +// iOS-Practice +// +// Created by Woo Jye Lee on 1/2/24. +// + +import UIKit +import SnapKit + +final class RoutineViewController: UIViewController { + + // MARK: - Properties + + let dummy = RoutineEntity.routineDummy() + + // MARK: - UI Components + private let routineView = RoutineView() + private lazy var collectionview = routineView.collectionView + + + + // MARK: - Life Cycles + + override func loadView() { + super.loadView() + + self.view = routineView + } + + override func viewDidLoad() { + super.viewDidLoad() + + setUI() + setHierarchy() + setLayout() + setDelegate() + } +} + +// MARK: - Extensions + +extension RoutineViewController { + + func setUI() { + view.backgroundColor = .white + } + + func setHierarchy() { + } + + func setLayout() { + } + + func setDelegate() { + collectionview.delegate = self + collectionview.dataSource = self + } +} + +extension RoutineViewController: UICollectionViewDelegate { + +} + +extension RoutineViewController: UICollectionViewDataSource { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return dummy.count + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = RoutineCollectionViewCell.dequeueReusableCell(collectionView: collectionView, indexPath: indexPath) + cell.setDatabind(model: dummy[indexPath.item]) + return cell + } +} diff --git a/iOS-Practice/iOS-Practice/SceneDelegate.swift b/iOS-Practice/iOS-Practice/SceneDelegate.swift index d518115..0839f99 100644 --- a/iOS-Practice/iOS-Practice/SceneDelegate.swift +++ b/iOS-Practice/iOS-Practice/SceneDelegate.swift @@ -17,8 +17,17 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). - guard let _ = (scene as? UIWindowScene) else { return } - } + guard let scene = (scene as? UIWindowScene) else { return } + window = UIWindow(frame: scene.coordinateSpace.bounds) + window?.windowScene = scene + + // root view controller 지정 + let rootViewController = RoutineViewController() + + // 네비게이션 컨트롤러 생성 + let navigationController = UINavigationController(rootViewController: rootViewController) + window?.rootViewController = navigationController + window?.makeKeyAndVisible() } func sceneDidDisconnect(_ scene: UIScene) { // Called as the scene is being released by the system. diff --git a/iOS-Practice/iOS-Practice/TopViewView.swift b/iOS-Practice/iOS-Practice/TopViewView.swift new file mode 100644 index 0000000..e2c7729 --- /dev/null +++ b/iOS-Practice/iOS-Practice/TopViewView.swift @@ -0,0 +1,70 @@ +// +// TopViewView.swift +// iOS-Practice +// +// Created by Woo Jye Lee on 1/6/24. +// + +import UIKit + +import SnapKit + +final class TopViewView: UIView { + + // MARK: - Properties + + + // MARK: - UI Components + + + // MARK: - Life Cycles + + override init(frame: CGRect) { + super.init(frame: frame) + + setUI() + setHierarchy() + setLayout() + setAddTarget() + setRegisterCell() + } + + @available(*, unavailable) + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} + +// MARK: - Extensions + +extension TopViewView { + + func setUI() { + + } + + func setHierarchy() { + + } + + func setLayout() { + + } + + func setAddTarget() { + + } + + @objc + func buttonTapped() { + + } + + func setRegisterCell() { + + } + + func setDataBind() { + + } +} diff --git a/iOS-Practice/iOS-Practice/UICollectionViewRegisterable.swift b/iOS-Practice/iOS-Practice/UICollectionViewRegisterable.swift new file mode 100644 index 0000000..2f546cf --- /dev/null +++ b/iOS-Practice/iOS-Practice/UICollectionViewRegisterable.swift @@ -0,0 +1,79 @@ +// +// UICollectionViewRegisterable.swift +// iOS-Practice +// +// Created by Woo Jye Lee on 1/2/24. +// + +import Foundation + +import UIKit + +protocol UICollectionViewRegisterable { + static var isFromNib: Bool { get } + static func register(target: UICollectionView) + static func dequeueReusableCell(collectionView: UICollectionView, indexPath: IndexPath) -> Self +} + +extension UICollectionViewRegisterable where Self: UICollectionViewCell { + static func register(target: UICollectionView) { + if self.isFromNib { + target.register(UINib(nibName: Self.className, bundle: nil), forCellWithReuseIdentifier: Self.className) + } else { + target.register(self, forCellWithReuseIdentifier: Self.className) + } + } + + static func dequeueReusableCell(collectionView: UICollectionView, indexPath: IndexPath) -> Self { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: Self.className, for: indexPath) as? Self else { fatalError()} + return cell + } +} + +protocol UICollectionHeaderViewRegisterable { + static var isFromNib: Bool { get } + static func register(target: UICollectionView) + static func dequeueReusableHeaderView(collectionView: UICollectionView, indexPath: IndexPath) -> Self +} + +extension UICollectionHeaderViewRegisterable where Self: UICollectionReusableView { + static func register(target: UICollectionView) { + if self.isFromNib { + target.register(UINib(nibName: Self.className, bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: Self.className) + } else { + target.register(self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: Self.className) + } + } + + static func dequeueReusableHeaderView(collectionView: UICollectionView, indexPath: IndexPath) -> Self { + guard let headerView = collectionView.dequeueReusableSupplementaryView( + ofKind: UICollectionView.elementKindSectionHeader, + withReuseIdentifier: self.className, + for: indexPath) as? Self else { return UICollectionReusableView() as! Self } + return headerView + } +} + +protocol UICollectionFooterViewRegisterable { + static var isFromNib: Bool { get } + static func register(target: UICollectionView) + static func dequeueReusableFooterView(collectionView: UICollectionView, indexPath: IndexPath) -> Self +} + +extension UICollectionFooterViewRegisterable where Self: UICollectionReusableView { + static func register(target: UICollectionView) { + if self.isFromNib { + target.register(UINib(nibName: Self.className, bundle: nil), forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: Self.className) + } else { + target.register(self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: Self.className) + } + } + + static func dequeueReusableFooterView(collectionView: UICollectionView, indexPath: IndexPath) -> Self { + guard let footerView = collectionView.dequeueReusableSupplementaryView( + ofKind: UICollectionView.elementKindSectionFooter, + withReuseIdentifier: self.className, + for: indexPath) as? Self else { return UICollectionReusableView() as! Self } + return footerView + } +} diff --git a/iOS-Practice/iOS-Practice/UIView+.swift b/iOS-Practice/iOS-Practice/UIView+.swift new file mode 100644 index 0000000..5302b50 --- /dev/null +++ b/iOS-Practice/iOS-Practice/UIView+.swift @@ -0,0 +1,20 @@ +// +// UIView+.swift +// iOS-Practice +// +// Created by Woo Jye Lee on 1/2/24. +// + +import UIKit + +extension UIView { + func addSubviews(_ views: UIView...) { + views.forEach { self.addSubview($0) } + } + + func roundCorners(cornerRadius: CGFloat, maskedCorners: CACornerMask) { + clipsToBounds = true + layer.cornerRadius = cornerRadius + layer.maskedCorners = CACornerMask(arrayLiteral: maskedCorners) + } +} diff --git a/iOS-Practice/iOS-Practice/ViewController.swift b/iOS-Practice/iOS-Practice/ViewController.swift deleted file mode 100644 index 44a1d2a..0000000 --- a/iOS-Practice/iOS-Practice/ViewController.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// ViewController.swift -// iOS-Practice -// -// Created by 고아라 on 2023/12/30. -// - -import UIKit - -class ViewController: UIViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - } - - -}