From 601f19e572661f2a9d3d936bc8979ab024601ed5 Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Sat, 16 Jul 2022 17:59:51 +0900 Subject: [PATCH 1/6] =?UTF-8?q?[Chore]=20CVC=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=ED=8F=B4=EB=8D=94=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HealthFoodMe.xcodeproj/project.pbxproj | 38 +++++++++++++++---- .../{ => BlogReview}/BlogReviewCVC.swift | 0 .../{ => Common}/ReviewEmptyViewCVC.swift | 0 .../Cells/{ => Common}/ReviewHeaderCVC.swift | 0 .../Cells/{ => Review}/ReviewCVC.swift | 0 .../Cells/{ => Review}/ReviewPhotoCVC.swift | 0 .../Cells/{ => Review}/TagCVC.swift | 0 7 files changed, 30 insertions(+), 8 deletions(-) rename HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/{ => BlogReview}/BlogReviewCVC.swift (100%) rename HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/{ => Common}/ReviewEmptyViewCVC.swift (100%) rename HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/{ => Common}/ReviewHeaderCVC.swift (100%) rename HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/{ => Review}/ReviewCVC.swift (100%) rename HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/{ => Review}/ReviewPhotoCVC.swift (100%) rename HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/{ => Review}/TagCVC.swift (100%) diff --git a/HealthFoodMe/HealthFoodMe.xcodeproj/project.pbxproj b/HealthFoodMe/HealthFoodMe.xcodeproj/project.pbxproj index dfb65c4a..2e4ff8c4 100644 --- a/HealthFoodMe/HealthFoodMe.xcodeproj/project.pbxproj +++ b/HealthFoodMe/HealthFoodMe.xcodeproj/project.pbxproj @@ -230,8 +230,6 @@ 695758DF2881228700E36789 /* CopingHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopingHeaderView.swift; sourceTree = ""; }; 695758E228812B3100E36789 /* CopingDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopingDataModel.swift; sourceTree = ""; }; 695758E42881852E00E36789 /* CopingEmptyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CopingEmptyView.swift; sourceTree = ""; }; - 695758C9288057D700E36789 /* Config.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Config.swift; sourceTree = ""; }; - 695758CF2880ACF000E36789 /* addToolBar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = addToolBar.swift; sourceTree = ""; }; 6E596B9EBEC8B18D4DE266B6 /* Pods-HealthFoodMe.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-HealthFoodMe.release.xcconfig"; path = "Target Support Files/Pods-HealthFoodMe/Pods-HealthFoodMe.release.xcconfig"; sourceTree = ""; }; A9325273287D3065001EDF50 /* SearchResultTVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultTVC.swift; sourceTree = ""; }; A9325276287D4F10001EDF50 /* SearchResultModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultModel.swift; sourceTree = ""; }; @@ -415,6 +413,33 @@ path = HamburgerBarScene; sourceTree = ""; }; + 3B3DCF472882B534009256BD /* Common */ = { + isa = PBXGroup; + children = ( + 3BDE7F282882054200EE7F47 /* ReviewEmptyViewCVC.swift */, + 3BC01F88287F1DFA006C2181 /* ReviewHeaderCVC.swift */, + ); + path = Common; + sourceTree = ""; + }; + 3B3DCF482882B540009256BD /* BlogReview */ = { + isa = PBXGroup; + children = ( + 3BC01F83287EAE48006C2181 /* BlogReviewCVC.swift */, + ); + path = BlogReview; + sourceTree = ""; + }; + 3B3DCF492882B55D009256BD /* Review */ = { + isa = PBXGroup; + children = ( + 3B723C902880037100822B7C /* ReviewPhotoCVC.swift */, + 3BC01F7A287E89D2006C2181 /* ReviewCVC.swift */, + 3B723C8A287FF81800822B7C /* TagCVC.swift */, + ); + path = Review; + sourceTree = ""; + }; 3B723CA72881D43B00822B7C /* VC */ = { isa = PBXGroup; children = ( @@ -427,12 +452,9 @@ 3BC01F79287E8917006C2181 /* Cells */ = { isa = PBXGroup; children = ( - 3BC01F83287EAE48006C2181 /* BlogReviewCVC.swift */, - 3BC01F88287F1DFA006C2181 /* ReviewHeaderCVC.swift */, - 3BC01F7A287E89D2006C2181 /* ReviewCVC.swift */, - 3B723C8A287FF81800822B7C /* TagCVC.swift */, - 3B723C902880037100822B7C /* ReviewPhotoCVC.swift */, - 3BDE7F282882054200EE7F47 /* ReviewEmptyViewCVC.swift */, + 3B3DCF492882B55D009256BD /* Review */, + 3B3DCF482882B540009256BD /* BlogReview */, + 3B3DCF472882B534009256BD /* Common */, ); path = Cells; sourceTree = ""; diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/BlogReviewCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/BlogReview/BlogReviewCVC.swift similarity index 100% rename from HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/BlogReviewCVC.swift rename to HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/BlogReview/BlogReviewCVC.swift diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/ReviewEmptyViewCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Common/ReviewEmptyViewCVC.swift similarity index 100% rename from HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/ReviewEmptyViewCVC.swift rename to HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Common/ReviewEmptyViewCVC.swift diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/ReviewHeaderCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Common/ReviewHeaderCVC.swift similarity index 100% rename from HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/ReviewHeaderCVC.swift rename to HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Common/ReviewHeaderCVC.swift diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/ReviewCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift similarity index 100% rename from HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/ReviewCVC.swift rename to HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/ReviewPhotoCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewPhotoCVC.swift similarity index 100% rename from HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/ReviewPhotoCVC.swift rename to HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewPhotoCVC.swift diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/TagCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/TagCVC.swift similarity index 100% rename from HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/TagCVC.swift rename to HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/TagCVC.swift From 5d1729eec937c553f9981f0bdaf56e08b69e4a2f Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Sat, 16 Jul 2022 18:23:46 +0900 Subject: [PATCH 2/6] =?UTF-8?q?[Fix]=20#93=20-=20=EC=85=80=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=A0=84=EB=8B=AC=20=EA=B3=BC=EC=A0=95=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=201.=20fetchData()=20=EC=83=9D=EC=84=B1=202.?= =?UTF-8?q?=20processViewModel=20=EC=83=9D=EC=84=B1=203.=20=EC=85=80=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=A0=84=EB=8B=AC=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReviewTabScene/VC/ReviewDetailVC.swift | 50 ++++++++++++------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift index fbf11867..acd50252 100644 --- a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift +++ b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift @@ -15,6 +15,7 @@ class ReviewDetailVC: UIViewController { private let withoutImageAndContents = 3 private var reviewData: [ReviewCellViewModel] = [] + private var blogReviewData: [BlogReviewDataModel] = [] var selectedCustomSegment = 0 { didSet { @@ -39,6 +40,7 @@ class ReviewDetailVC: UIViewController { setLayout() setDelegate() registerCell() + fetchData() } } @@ -86,18 +88,29 @@ extension ReviewDetailVC { private func fetchData() { // 데이터를 서버에서 받아와야 함 - let data = ReviewDataModel.sampleData // 서버에서 받아와야 할 데이터 - processViewModel(data) + let reviewData = ReviewDataModel.sampleData // 서버에서 받아와야 할 데이터 + let blogReviewData = BlogReviewDataModel.sampleData + processViewModel(reviewData, blogReviewData) } - private func processViewModel(_ dataList: [ReviewDataModel]) { - var result: [ReviewCellViewModel] = [] - for data in dataList { - let height = calculateReviewHeight(data.reviewContents ?? "") - result.append(ReviewCellViewModel.init(data: data, + private func processViewModel(_ reviewDataList: [ReviewDataModel], + _ blogReviewDataList: [BlogReviewDataModel]) { + var reviewResult: [ReviewCellViewModel] = [] + var blogReviewResult: [BlogReviewDataModel] = [] + for reviewData in reviewDataList { + let height = calculateReviewHeight(reviewData.reviewContents ?? "") + reviewResult.append(ReviewCellViewModel.init(data: reviewData, foldRequired: height > 55)) } - self.reviewData = result + + for blogReviewData in blogReviewDataList { + blogReviewResult.append( + BlogReviewDataModel.init(blogReviewTitle: blogReviewData.blogReviewTitle, + blogReviewContents: blogReviewData.blogReviewContents)) + } + + self.reviewData = reviewResult + self.blogReviewData = blogReviewResult } private func calculateReviewHeight(_ text: String) -> CGFloat { @@ -124,16 +137,16 @@ extension ReviewDetailVC: UICollectionViewDataSource { return 1 case 1: if selectedCustomSegment == 0 { - if ReviewDataModel.sampleData.count == 0 { + if reviewData.count == 0 { return 1 } else { - return ReviewDataModel.sampleData.count + return reviewData.count } } else { - if BlogReviewDataModel.sampleData.count == 0 { + if blogReviewData.count == 0 { return 1 } else { - return BlogReviewDataModel.sampleData.count + return blogReviewData.count } } default: @@ -156,8 +169,8 @@ extension ReviewDetailVC: UICollectionViewDataSource { } else { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ReviewCVC.className, for: indexPath) as? ReviewCVC else { return UICollectionViewCell() } cell.reviewSeperatorView.isHidden = indexPath.item == 0 - cell.setData(reviewData: ReviewDataModel.sampleData[indexPath.row]) - cell.setEnumValue = setEnumValue(data: ReviewDataModel.sampleData[indexPath.row]) + cell.setData(reviewData: reviewData[indexPath.row].data) + cell.setEnumValue = setEnumValue(data: reviewData[indexPath.row].data) cell.setLayout() return cell } @@ -169,7 +182,7 @@ extension ReviewDetailVC: UICollectionViewDataSource { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BlogReviewCVC.className, for: indexPath) as? BlogReviewCVC else { return UICollectionViewCell() } cell.reviewSeperatorView.isHidden = indexPath.item == 0 - cell.setData(blogReviewData: BlogReviewDataModel.sampleData[indexPath.row]) + cell.setData(blogReviewData: blogReviewData[indexPath.row]) return cell } } @@ -195,12 +208,13 @@ extension ReviewDetailVC: UICollectionViewDelegateFlowLayout { return CGSize(width: cellWidth, height: cellHeight) } else { let cellWidth = width - let cellHeight = calculateReviewCellHeight(containsPhoto: ReviewDataModel.sampleData[indexPath.row].reviewImageURLList?.count != 0, - reviewText: ReviewDataModel.sampleData[indexPath.row].reviewContents) + print("index", indexPath.row) + let cellHeight = calculateReviewCellHeight(containsPhoto: reviewData[indexPath.row].data.reviewImageURLList?.count != 0, + reviewText: reviewData[indexPath.row].data.reviewContents) return CGSize(width: cellWidth, height: cellHeight) } } else { - if BlogReviewDataModel.sampleData.count == 0 { + if blogReviewData.count == 0 { let cellWidth = width let cellHeight = width * 200/width return CGSize(width: cellWidth, height: cellHeight) From 51e3bce56f69d4ef908515244c42343746a230d1 Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Sat, 16 Jul 2022 23:22:46 +0900 Subject: [PATCH 3/6] =?UTF-8?q?[Add]=20#93=20-=20=EB=A6=AC=EB=B7=B0=20?= =?UTF-8?q?=EC=BB=A8=ED=85=90=EC=B8=A0=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=9E=AC=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ReviewTabScene/VC/ReviewDetailVC.swift | 39 ++++++++++++++++++- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift index acd50252..8d5f7178 100644 --- a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift +++ b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift @@ -113,6 +113,40 @@ extension ReviewDetailVC { self.blogReviewData = blogReviewResult } + private func cutReviewContents(_ reviewDataContents: String) -> String { + var reviewContentsList: String = "" + var lineCount: Int = 0 + var previousHeight: CGFloat = 0 + var eraseCount: Int = 0 + + for char in reviewDataContents { + reviewContentsList += String(char) + if (previousHeight != calculateReviewHeight(reviewContentsList)) { + previousHeight = calculateReviewHeight(reviewContentsList) + lineCount += 1 + } + if lineCount == 4 { + break + } + } + + if lineCount > 3 { + for char in reviewContentsList { + eraseCount += 1 + reviewContentsList.popLast() + if eraseCount > 7 { + reviewContentsList.append(" 더보기") + break + } else { + if char == " " { + continue + } + } + } + } + return reviewContentsList + } + private func calculateReviewHeight(_ text: String) -> CGFloat { let textView = UITextView(frame: CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width - 40, height: 0)) textView.textContainer.lineFragmentPadding = .zero @@ -163,7 +197,7 @@ extension ReviewDetailVC: UICollectionViewDataSource { return header case 1: if selectedCustomSegment == 0 { - if ReviewDataModel.sampleData.count == 0 { + if reviewData.count == 0 { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ReviewEmptyViewCVC.className, for: indexPath) as? ReviewEmptyViewCVC else { return UICollectionViewCell() } return cell } else { @@ -171,11 +205,12 @@ extension ReviewDetailVC: UICollectionViewDataSource { cell.reviewSeperatorView.isHidden = indexPath.item == 0 cell.setData(reviewData: reviewData[indexPath.row].data) cell.setEnumValue = setEnumValue(data: reviewData[indexPath.row].data) + cell.changeContents(cutReviewContents(reviewData[indexPath.row].data.reviewContents ?? "")) cell.setLayout() return cell } } else { - if BlogReviewDataModel.sampleData.count == 0 { + if blogReviewData.count == 0 { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ReviewEmptyViewCVC.className, for: indexPath) as? ReviewEmptyViewCVC else { return UICollectionViewCell() } return cell } else { From 62bacf52f62c05ede000b7385e8ac8b3670455d5 Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Sat, 16 Jul 2022 23:24:00 +0900 Subject: [PATCH 4/6] =?UTF-8?q?[Feat]=20#93=20-=20=EC=BB=A8=ED=85=90?= =?UTF-8?q?=EC=B8=A0=20=EA=B8=B8=EC=9D=B4=EC=97=90=20=EB=94=B0=EB=9D=BC=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=EC=97=B4=20=EC=A1=B0=EC=9E=91=ED=95=98?= =?UTF-8?q?=EC=97=AC=20=EC=85=80=EC=97=90=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=ED=95=A0=EB=8B=B9=201.=203=EC=A4=84=EB=A7=8C=ED=81=BC=EC=9D=98?= =?UTF-8?q?=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EC=B6=9C=202.=20?= =?UTF-8?q?=EB=81=9D=EC=97=90=20=EC=9D=BC=EB=B6=80=20=EA=B3=B5=EA=B0=84?= =?UTF-8?q?=EB=A7=8C=ED=81=BC=20=EA=B8=80=EC=9E=90=20=EC=A7=80=EC=9A=B0?= =?UTF-8?q?=EA=B8=B0=203.=20=EB=8D=94=EB=B3=B4=EA=B8=B0=20=ED=85=8D?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EB=B6=99=EC=9D=B4=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift index c1edac30..9b7fa00f 100644 --- a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift +++ b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift @@ -262,6 +262,11 @@ extension ReviewCVC { reviewContents.sizeToFit() self.contentView.layoutIfNeeded() } + + func changeContents(_ cutText: String) { + reviewContents.text = cutText + reviewContents.sizeToFit() + } } extension ReviewCVC: UICollectionViewDelegate { From 2a58c5d5b508d32fbb766bbc9e9916816ded0678 Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Sun, 17 Jul 2022 00:07:23 +0900 Subject: [PATCH 5/6] =?UTF-8?q?[Feat]=20#93=20-=20=ED=8A=B9=EC=A0=95=20?= =?UTF-8?q?=ED=85=8D=EC=8A=A4=ED=8A=B8=EC=9D=98=20CGRect=20=EA=B0=92=20?= =?UTF-8?q?=EC=B0=BE=EA=B8=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Cells/Review/ReviewCVC.swift | 19 +++++++++++++++++++ .../ReviewTabScene/VC/ReviewDetailVC.swift | 5 ++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift index 9b7fa00f..26395e06 100644 --- a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift +++ b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift @@ -267,6 +267,25 @@ extension ReviewCVC { reviewContents.text = cutText reviewContents.sizeToFit() } + + func calculateCGRect(_ subString: String) -> CGRect? { + // NSTextStorage >> NSLayoutManager >> NSTextContainer >> View + guard let attributedText = self.reviewContents.attributedText else { return nil } + let textStorage = NSTextStorage(attributedString: attributedText) + + let layoutManager = NSLayoutManager() + textStorage.addLayoutManager(layoutManager) + + let textContainer = NSTextContainer(size: self.bounds.size) + textContainer.lineFragmentPadding = 0.0 + + layoutManager.addTextContainer(textContainer) + + guard let text = self.reviewContents.text, + let subRange = text.range(of: subString) else { return nil } + let range = NSRange(subRange, in: text) + return layoutManager.boundingRect(forGlyphRange: range, in: textContainer) + } } extension ReviewCVC: UICollectionViewDelegate { diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift index 8d5f7178..597b6baf 100644 --- a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift +++ b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift @@ -16,6 +16,7 @@ class ReviewDetailVC: UIViewController { private var reviewData: [ReviewCellViewModel] = [] private var blogReviewData: [BlogReviewDataModel] = [] + var moreContentsButtonRect: CGRect = CGRect(x: 0, y: 0, width: 0, height: 0) var selectedCustomSegment = 0 { didSet { @@ -143,7 +144,8 @@ extension ReviewDetailVC { } } } - } + } + return reviewContentsList } @@ -206,6 +208,7 @@ extension ReviewDetailVC: UICollectionViewDataSource { cell.setData(reviewData: reviewData[indexPath.row].data) cell.setEnumValue = setEnumValue(data: reviewData[indexPath.row].data) cell.changeContents(cutReviewContents(reviewData[indexPath.row].data.reviewContents ?? "")) + moreContentsButtonRect = cell.calculateCGRect("더보기") ?? CGRect(x: 0, y: 0, width: 0, height: 0) cell.setLayout() return cell } From 790cb628a6665c5f5ecbe09cc17c23138d3f02fe Mon Sep 17 00:00:00 2001 From: yungu0010 Date: Sun, 17 Jul 2022 02:34:08 +0900 Subject: [PATCH 6/6] =?UTF-8?q?[Feat]=20#93=20-=20=EB=8D=94=EB=B3=B4?= =?UTF-8?q?=EA=B8=B0=20=EB=B2=84=ED=8A=BC=EC=97=90=20=EB=94=B0=EB=9D=BC=20?= =?UTF-8?q?=EC=85=80=20=ED=81=AC=EA=B8=B0=20=EC=A1=B0=EC=A0=88=20=EB=B0=8F?= =?UTF-8?q?=20=EB=82=B4=EC=9A=A9=20=EC=A1=B0=EC=A0=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Cells/Review/ReviewCVC.swift | 92 +++++++++++----- .../ReviewTabScene/VC/ReviewDetailVC.swift | 103 ++++++++++++++---- 2 files changed, 146 insertions(+), 49 deletions(-) diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift index 26395e06..e3aef419 100644 --- a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift +++ b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/Cells/Review/ReviewCVC.swift @@ -20,10 +20,11 @@ class ReviewCVC: UICollectionViewCell, UICollectionViewRegisterable { } } - var setEnumValue = 0 + var layoutEnumValue = 0 let width = UIScreen.main.bounds.width - + var clickedEvent: ((Int) -> Void)? + var isFolded: Bool = true // MARK: - UI Components private var nameLabel: UILabel = { @@ -83,6 +84,16 @@ class ReviewCVC: UICollectionViewCell, UICollectionViewRegisterable { return view }() + lazy var moreTapButton: UIButton = { + let button = UIButton() + button.backgroundColor = .clear + button.press { + guard let index = self.getIndexPath() else { return } + self.clickedEvent?(index) + } + return button + }() + // MARK: - Life Cycle Part override init(frame: CGRect) { @@ -121,7 +132,7 @@ extension ReviewCVC { func setDefaultLayout() { contentView.addSubviews(nameLabel, starView, tagCV, - reviewPhotoCV, reviewContents, reviewSeperatorView) + reviewPhotoCV, reviewContents, reviewSeperatorView,moreTapButton) let width = UIScreen.main.bounds.width @@ -166,10 +177,19 @@ extension ReviewCVC { make.bottom.equalToSuperview().offset(-28) make.width.equalTo(width - 40) } + + moreTapButton.snp.makeConstraints { make in + make.bottom.equalToSuperview().offset(-28) + make.trailing.equalToSuperview().offset(-30) + make.width.equalTo(width - 40) + make.height.equalToSuperview() + } + + } func setLayout() { - switch setEnumValue { + switch layoutEnumValue { case 0: setLayoutWithImageAndContents() case 1: @@ -253,38 +273,58 @@ extension ReviewCVC { } } - func setData(reviewData: ReviewDataModel) { + func setData(reviewData: ReviewDataModel, + text: String, + isFoldRequired: Bool, + expanded: Bool) { nameLabel.text = reviewData.reviewer nameLabel.sizeToFit() starView.rate = CGFloat(reviewData.starLate) self.cellViewModel = reviewData - reviewContents.text = reviewData.reviewContents + reviewContents.text = text reviewContents.sizeToFit() + + if isFoldRequired { + moreTapButton.isHidden = false + } else { + moreTapButton.isHidden = true + } + + if !expanded { + setPartContentsAttributes() + } else { + let attributedString = NSMutableAttributedString(string: text) + reviewContents.attributedText = attributedString + } + self.contentView.layoutIfNeeded() } - func changeContents(_ cutText: String) { - reviewContents.text = cutText - reviewContents.sizeToFit() + private func getIndexPath() -> Int? { + guard let superView = self.superview as? UICollectionView else { + return nil + } + let indexPath = superView.indexPath(for: self) + return indexPath?.row } - func calculateCGRect(_ subString: String) -> CGRect? { - // NSTextStorage >> NSLayoutManager >> NSTextContainer >> View - guard let attributedText = self.reviewContents.attributedText else { return nil } - let textStorage = NSTextStorage(attributedString: attributedText) - - let layoutManager = NSLayoutManager() - textStorage.addLayoutManager(layoutManager) - - let textContainer = NSTextContainer(size: self.bounds.size) - textContainer.lineFragmentPadding = 0.0 - - layoutManager.addTextContainer(textContainer) - - guard let text = self.reviewContents.text, - let subRange = text.range(of: subString) else { return nil } - let range = NSRange(subRange, in: text) - return layoutManager.boundingRect(forGlyphRange: range, in: textContainer) + func setPartContentsAttributes() { + var textCount = 0 + var length = 0 + if reviewContents.text?.count ?? 0 < 3 { + textCount = 3 + length = reviewContents.text?.count ?? 0 + } else { + textCount = reviewContents.text?.count ?? 0 + length = 3 + } + let fullText = reviewContents.text + let range = NSRange(location: textCount - 3, length: length) + + let attributedString = NSMutableAttributedString(string: fullText ?? "") + attributedString.addAttribute(.font, value: UIFont.NotoRegular(size: 12), range: range) + attributedString.addAttribute(.foregroundColor, value: UIColor.helfmeGray2, range: range) + reviewContents.attributedText = attributedString } } diff --git a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift index 597b6baf..6f48bb18 100644 --- a/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift +++ b/HealthFoodMe/HealthFoodMe/Presentation/Detail/ReviewTabScene/VC/ReviewDetailVC.swift @@ -7,6 +7,13 @@ import UIKit +enum ReviewDetailCellLayoutType: Int { + case withImageAndContents = 1 + case withImage = 2 + case withContents = 3 + case withoutImageAndContents = 4 +} + class ReviewDetailVC: UIViewController { private let withImageAndContents = 0 @@ -14,8 +21,13 @@ class ReviewDetailVC: UIViewController { private let withContents = 2 private let withoutImageAndContents = 3 - private var reviewData: [ReviewCellViewModel] = [] + private var reviewData: [ReviewCellViewModel] = [] { didSet { + fetchCutStringList() + fetchExpendStateList() + }} private var blogReviewData: [BlogReviewDataModel] = [] + private var cutLabelList: [String] = [] + private var expendStateList: [Bool] = [] var moreContentsButtonRect: CGRect = CGRect(x: 0, y: 0, width: 0, height: 0) var selectedCustomSegment = 0 { @@ -87,6 +99,21 @@ extension ReviewDetailVC { } } + private func fetchCutStringList() { + for viewModel in reviewData { + if let reviewText = viewModel.data.reviewContents { + let cutText = cutReviewContents(reviewText) + cutLabelList.append(cutText) + } else { + cutLabelList.append("") + } + } + } + + private func fetchExpendStateList() { + expendStateList = Array(repeating: false, count: reviewData.count) + } + private func fetchData() { // 데이터를 서버에서 받아와야 함 let reviewData = ReviewDataModel.sampleData // 서버에서 받아와야 할 데이터 @@ -114,29 +141,35 @@ extension ReviewDetailVC { self.blogReviewData = blogReviewResult } - private func cutReviewContents(_ reviewDataContents: String) -> String { - var reviewContentsList: String = "" - var lineCount: Int = 0 + private func calculateTextInSize(review: String) -> (Int,String) { + var calculatedText: String = "" var previousHeight: CGFloat = 0 - var eraseCount: Int = 0 - - for char in reviewDataContents { - reviewContentsList += String(char) - if (previousHeight != calculateReviewHeight(reviewContentsList)) { - previousHeight = calculateReviewHeight(reviewContentsList) + var lineCount: Int = 0 + + for char in review { + calculatedText += String(char) + if (previousHeight != calculateReviewHeight(calculatedText)) { + previousHeight = calculateReviewHeight(calculatedText) lineCount += 1 } if lineCount == 4 { - break + return (4,calculatedText) } } + return (lineCount,calculatedText) + } + + private func cutReviewContents(_ reviewDataContents: String) -> String { + var eraseCount: Int = 0 + var (lineCount,cutText) = calculateTextInSize(review: reviewDataContents) if lineCount > 3 { - for char in reviewContentsList { + + for char in cutText { eraseCount += 1 - reviewContentsList.popLast() + cutText.popLast() if eraseCount > 7 { - reviewContentsList.append(" 더보기") + cutText.append(" 더보기") break } else { if char == " " { @@ -146,7 +179,7 @@ extension ReviewDetailVC { } } - return reviewContentsList + return cutText } private func calculateReviewHeight(_ text: String) -> CGFloat { @@ -205,10 +238,29 @@ extension ReviewDetailVC: UICollectionViewDataSource { } else { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ReviewCVC.className, for: indexPath) as? ReviewCVC else { return UICollectionViewCell() } cell.reviewSeperatorView.isHidden = indexPath.item == 0 - cell.setData(reviewData: reviewData[indexPath.row].data) - cell.setEnumValue = setEnumValue(data: reviewData[indexPath.row].data) - cell.changeContents(cutReviewContents(reviewData[indexPath.row].data.reviewContents ?? "")) - moreContentsButtonRect = cell.calculateCGRect("더보기") ?? CGRect(x: 0, y: 0, width: 0, height: 0) + cell.clickedEvent = { clickedIndex in + self.expendStateList[clickedIndex].toggle() + self.reviewCV.reloadData() + } + + let isFoldRequired = reviewData[indexPath.row].foldRequired + if isFoldRequired { + let originalText = reviewData[indexPath.row].data.reviewContents + let cutText = cutLabelList[indexPath.row] + let reviewText = expendStateList[indexPath.row] ? originalText : cutText + cell.setData(reviewData: reviewData[indexPath.row].data, + text: reviewText ?? "", + isFoldRequired: true, + expanded: expendStateList[indexPath.row]) + + } else { + cell.setData(reviewData: reviewData[indexPath.row].data, + text: reviewData[indexPath.row].data.reviewContents ?? "", + isFoldRequired: false, expanded: false) + } + + // 레이아웃 분기처리 코드 + cell.layoutEnumValue = setEnumValue(data: reviewData[indexPath.row].data) cell.setLayout() return cell } @@ -246,9 +298,10 @@ extension ReviewDetailVC: UICollectionViewDelegateFlowLayout { return CGSize(width: cellWidth, height: cellHeight) } else { let cellWidth = width - print("index", indexPath.row) let cellHeight = calculateReviewCellHeight(containsPhoto: reviewData[indexPath.row].data.reviewImageURLList?.count != 0, - reviewText: reviewData[indexPath.row].data.reviewContents) + reviewText: reviewData[indexPath.row].data.reviewContents, + isExpandState: expendStateList[indexPath.row]) + return CGSize(width: cellWidth, height: cellHeight) } } else { @@ -267,7 +320,7 @@ extension ReviewDetailVC: UICollectionViewDelegateFlowLayout { } } - private func calculateReviewCellHeight(containsPhoto: Bool, reviewText: String? ) -> CGFloat { + private func calculateReviewCellHeight(containsPhoto: Bool, reviewText: String?,isExpandState: Bool) -> CGFloat { var cellHeight: CGFloat = 0 let topPadding: CGFloat = 28 let nameLabelHeight: CGFloat = 20 @@ -291,7 +344,11 @@ extension ReviewDetailVC: UICollectionViewDelegateFlowLayout { let textViewHeight = calculateReviewHeight(reviewText ?? "") if textViewHeight >= threeLineHeight { - cellHeight += (threeLineHeight + bottomPadding) + if !isExpandState { + cellHeight += (threeLineHeight + bottomPadding) + } else { + cellHeight += (textViewHeight + bottomPadding) + } } else { cellHeight += (textViewHeight + bottomPadding) }