From b1fd8f68731d565aa50d7cd00eb1587bc31de74c Mon Sep 17 00:00:00 2001 From: jeongdung-eo Date: Fri, 13 Jan 2023 16:09:42 +0900 Subject: [PATCH] =?UTF-8?q?[ADD]=20#84=20-=20=EC=84=B1=EC=B7=A8=EB=B7=B0?= =?UTF-8?q?=20=EC=BA=98=EB=A6=B0=EB=8D=94cell=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NotToDo/NotToDo.xcodeproj/project.pbxproj | 4 + .../Cells/CalendarCustomCell.swift | 221 ++++++++++++++++++ 2 files changed, 225 insertions(+) create mode 100644 NotToDo/NotToDo/Presentation/AchievementScene/Cells/CalendarCustomCell.swift diff --git a/NotToDo/NotToDo.xcodeproj/project.pbxproj b/NotToDo/NotToDo.xcodeproj/project.pbxproj index c61b3e9..b488804 100644 --- a/NotToDo/NotToDo.xcodeproj/project.pbxproj +++ b/NotToDo/NotToDo.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 090D3DDB297139B1000F468C /* CalendarCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 090D3DDA297139B1000F468C /* CalendarCustomCell.swift */; }; 090FA2E7295F51BB00918AED /* GoogleService-Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 090FA2E6295F51BB00918AED /* GoogleService-Info.plist */; }; 090FA2F52960B70400918AED /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 090FA2F42960B70400918AED /* SnapKit */; }; 090FA2F82960B74000918AED /* Then in Frameworks */ = {isa = PBXBuildFile; productRef = 090FA2F72960B74000918AED /* Then */; }; @@ -147,6 +148,7 @@ /* End PBXBuildFile section */ /* Begin PBXFileReference section */ + 090D3DDA297139B1000F468C /* CalendarCustomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarCustomCell.swift; sourceTree = ""; }; 090FA2E6295F51BB00918AED /* GoogleService-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; 0951EE8C297130DF004A3B5B /* AchieveCalendarResponseDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AchieveCalendarResponseDTO.swift; sourceTree = ""; }; 09611EE6296FD52700561CAA /* RecommendService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecommendService.swift; sourceTree = ""; }; @@ -348,6 +350,7 @@ 09F695DC296C52F000877EA7 /* SituationTableViewCell.swift */, 099F0727296B94790036CF55 /* StatisticsEmptyTableViewCell.swift */, 09F695DA296C52B600877EA7 /* MissionTableViewCell.swift */, + 090D3DDA297139B1000F468C /* CalendarCustomCell.swift */, ); path = Cells; sourceTree = ""; @@ -1262,6 +1265,7 @@ 3BE0700E296F43B6002CC50A /* Strings.swift in Sources */, 099F06FA2967EE9F0036CF55 /* LabelCollectionViewCell.swift in Sources */, 3BBE56F3296C4EB000771DE4 /* SecondOnboardingViewController.swift in Sources */, + 090D3DDB297139B1000F468C /* CalendarCustomCell.swift in Sources */, 096BDFD92964FEF6009ED396 /* CustomCalendarView.swift in Sources */, 099F072A296B98B90036CF55 /* SituationTitleView.swift in Sources */, 3B2748632970B570005DBD46 /* AddAnotherDayResponseDTO.swift in Sources */, diff --git a/NotToDo/NotToDo/Presentation/AchievementScene/Cells/CalendarCustomCell.swift b/NotToDo/NotToDo/Presentation/AchievementScene/Cells/CalendarCustomCell.swift new file mode 100644 index 0000000..8ca4927 --- /dev/null +++ b/NotToDo/NotToDo/Presentation/AchievementScene/Cells/CalendarCustomCell.swift @@ -0,0 +1,221 @@ +// +// CalendarCustomCell.swift +// NotToDo +// +// Created by JEONGEUN KIM on 2023/01/13. +// + +import UIKit + +import FSCalendar + +enum FilledType: Int { + case none + case all + case some + case today +} + +enum SelectedType: Int { + case not + case single +} + +final class CalendarDayCell: FSCalendarCell { + weak var circleImageView: UIImageView! + weak var selectionLayer: CAShapeLayer! + + var width: CGFloat = 32.0 { + didSet { + setNeedsLayout() + } + } + + var yPosition: CGFloat = 2.0 { + didSet { + setNeedsLayout() + } + } + + var filledType: FilledType = .none { + didSet { + setNeedsLayout() + } + } + + var selectedType: SelectedType = .not { + didSet { + setNeedsLayout() + } + } + + override init(frame: CGRect) { + super.init(frame: frame) + + let circleImageView = UIImageView(image: Image.calenderBackgroundSome) + self.contentView.insertSubview(circleImageView, at: 0) + self.circleImageView = circleImageView + self.shapeLayer.isHidden = true + } + + required init!(coder aDecoder: NSCoder!) { + fatalError() + } + + override func layoutSubviews() { + super.layoutSubviews() + let width = width + let yPosition = yPosition + let distance = (self.contentView.bounds.width - width) / 2 + let frame = CGRect(x: self.contentView.bounds.minX + distance, + y: self.contentView.bounds.minY + yPosition, + width: width, + height: width) + self.circleImageView.frame = frame + + switch selectedType { + case .not: + self.titleLabel.font = .PretendardMedium(size: 14) + case .single: + self.titleLabel.font = UIFont.font(.pretendardBold, ofSize: 22) + } + + switch filledType { + case .all: + self.titleLabel.textColor = Color.white + self.circleImageView.image = Image.calenderBackgroundAll + case .some: + self.titleLabel.textColor = Color.black + self.circleImageView.image = Image.calenderBackgroundSome + case .today: + self.titleLabel.textColor = Color.black + self.circleImageView.image = selectedType == .not ? + Image.calendarBackgroundTodayDefault : Image.calendarBackgroundToday + case .none: + self.titleLabel.textColor = Color.black + self.circleImageView.image = nil + } + } + + func configureUI(isSelected: Bool, with type: FilledType) { + width = isSelected ? 48 : 32 + yPosition = isSelected ? -6 : 2 + selectedType = isSelected ? .single : .not + filledType = type + } +} + +enum SelectionType : Int { + case none + case single + case leftBorder + case middle + case rightBorder +} + +class DIYCalendarCell: FSCalendarCell { + weak var selectionLayer: CAShapeLayer? + weak var connectionLayer: CAShapeLayer? + + var selectionType: SelectionType = .none { + didSet { + if selectionType == .none { + self.selectionLayer?.opacity = 0 + self.connectionLayer?.opacity = 0 + self.selectionLayer?.isHidden = true + self.connectionLayer?.isHidden = true + return + } + setNeedsLayout() + } + } + + required init!(coder aDecoder: NSCoder!) { + fatalError("init(coder:) has not been implemented") + } + + override init(frame: CGRect) { + super.init(frame: frame) + + let selectionLayer = CAShapeLayer() + selectionLayer.fillColor = UIColor(red: 228 / 255, green: 246 / 255, blue: 246 / 255, alpha: 1.0).cgColor + selectionLayer.opacity = 0 + self.contentView.layer.insertSublayer(selectionLayer, below: self.titleLabel.layer) + self.selectionLayer = selectionLayer + self.selectionLayer?.isHidden = true + + let connectionLayer = CAShapeLayer() + connectionLayer.fillColor = UIColor(red: 228 / 255, green: 246 / 255, blue: 246 / 255, alpha: 1.0).cgColor + connectionLayer.opacity = 0 + self.contentView.layer.insertSublayer(connectionLayer, below: self.titleLabel.layer) + self.connectionLayer = connectionLayer + self.connectionLayer?.isHidden = true + + self.shapeLayer.isHidden = true + } + + override func prepareForReuse() { + super.prepareForReuse() + self.selectionLayer?.opacity = 0 + self.connectionLayer?.opacity = 0 + self.contentView.layer.removeAnimation(forKey: "opacity") + } + + override func layoutSubviews() { + super.layoutSubviews() + + self.selectionLayer?.frame = self.contentView.bounds.insetBy(dx: 0, dy: -3) + self.connectionLayer?.frame = self.contentView.bounds.insetBy(dx: 0, dy: -3) + guard var connectionRect = connectionLayer?.bounds else { + return + } + + connectionRect.size.height = connectionRect.height * 5 / 6 + if selectionType == .middle { + self.connectionLayer?.isHidden = false + self.connectionLayer?.opacity = 1 + self.connectionLayer?.path = UIBezierPath(rect: connectionRect).cgPath + self.titleLabel.textColor = UIColor.black + } + else if selectionType == .leftBorder { + self.connectionLayer?.isHidden = false + self.connectionLayer?.opacity = 1 + var rect = connectionRect + rect.origin.x = connectionRect.width / 2 + rect.size.width = connectionRect.width / 2 + self.connectionLayer?.path = UIBezierPath(rect: rect).cgPath + } + else if selectionType == .rightBorder { + self.connectionLayer?.isHidden = false + self.connectionLayer?.opacity = 1 + var rect = connectionRect + rect.size.width = connectionRect.width / 2 + self.connectionLayer?.path = UIBezierPath(rect: rect).cgPath + } + + if selectionType == .single || selectionType == .leftBorder || selectionType == .rightBorder { + self.selectionLayer?.isHidden = false + self.selectionLayer?.opacity = 1 + let diameter: CGFloat = min(connectionRect.height, connectionRect.width) + let rect = CGRect( + x: self.contentView.frame.width / 2 - diameter / 2, + y: 0, + width: diameter, + height: diameter) + self.selectionLayer?.path = UIBezierPath(ovalIn: rect).cgPath + } + + if selectionType == .single { + self.titleLabel.textColor = UIColor(red: 0 / 255, green: 171 / 255, blue: 182 / 255, alpha: 1.0) + } + } + + override func configureAppearance() { + super.configureAppearance() + if self.isPlaceholder { + self.eventIndicator.isHidden = true + self.titleLabel.textColor = UIColor.lightGray + } + } + +}