diff --git a/BeeReel.xcodeproj/project.pbxproj b/BeeReel.xcodeproj/project.pbxproj index 30e0a62..7a15c39 100644 --- a/BeeReel.xcodeproj/project.pbxproj +++ b/BeeReel.xcodeproj/project.pbxproj @@ -90,6 +90,14 @@ BFC676992E1280E3006659E5 /* BRSpotlightRecommandCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676982E1280E3006659E5 /* BRSpotlightRecommandCell.swift */; }; BFC6769B2E1285C5006659E5 /* BRPagerViewTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC6769A2E1285C5006659E5 /* BRPagerViewTransformer.swift */; }; BFC6769D2E129794006659E5 /* BRHomeTop10ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */; }; + BFC676A42E129D60006659E5 /* BRHomeTop10Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676A32E129D5A006659E5 /* BRHomeTop10Cell.swift */; }; + BFC676A72E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676A52E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift */; }; + BFC676AB2E1372BD006659E5 /* BRHomeTop3Cell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676AA2E1372BD006659E5 /* BRHomeTop3Cell.swift */; }; + BFC676B12E137D2F006659E5 /* BRPopularPicksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676B02E137D2F006659E5 /* BRPopularPicksViewController.swift */; }; + BFC676B72E137DFC006659E5 /* BRPopularPicksCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676B62E137DFC006659E5 /* BRPopularPicksCell.swift */; }; + BFC676B92E1385FC006659E5 /* BRPopularPicksSmallCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676B82E1385FC006659E5 /* BRPopularPicksSmallCell.swift */; }; + BFC676BC2E138ABB006659E5 /* BRNewReleasesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676BB2E138ABB006659E5 /* BRNewReleasesViewController.swift */; }; + BFC676BE2E13A8EB006659E5 /* UIScrollView+BRRefresh.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC676BD2E13A8DD006659E5 /* UIScrollView+BRRefresh.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -189,6 +197,14 @@ BFC676982E1280E3006659E5 /* BRSpotlightRecommandCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRSpotlightRecommandCell.swift; sourceTree = ""; }; BFC6769A2E1285C5006659E5 /* BRPagerViewTransformer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPagerViewTransformer.swift; sourceTree = ""; }; BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRHomeTop10ViewController.swift; sourceTree = ""; }; + BFC676A32E129D5A006659E5 /* BRHomeTop10Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRHomeTop10Cell.swift; sourceTree = ""; }; + BFC676A52E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WaterfallMutiSectionFlowLayout.swift; sourceTree = ""; }; + BFC676AA2E1372BD006659E5 /* BRHomeTop3Cell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRHomeTop3Cell.swift; sourceTree = ""; }; + BFC676B02E137D2F006659E5 /* BRPopularPicksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPopularPicksViewController.swift; sourceTree = ""; }; + BFC676B62E137DFC006659E5 /* BRPopularPicksCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPopularPicksCell.swift; sourceTree = ""; }; + BFC676B82E1385FC006659E5 /* BRPopularPicksSmallCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRPopularPicksSmallCell.swift; sourceTree = ""; }; + BFC676BB2E138ABB006659E5 /* BRNewReleasesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BRNewReleasesViewController.swift; sourceTree = ""; }; + BFC676BD2E13A8DD006659E5 /* UIScrollView+BRRefresh.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIScrollView+BRRefresh.swift"; sourceTree = ""; }; C8F11086BA392585E9563BA7 /* Pods-ShortBox.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShortBox.release.xcconfig"; path = "Target Support Files/Pods-ShortBox/Pods-ShortBox.release.xcconfig"; sourceTree = ""; }; F06627B1DEE86552C2A87AEC /* Pods-BeeReel.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BeeReel.debug.xcconfig"; path = "Target Support Files/Pods-BeeReel/Pods-BeeReel.debug.xcconfig"; sourceTree = ""; }; F70FA1F4169364C4C53534CE /* Pods-BeeReel.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-BeeReel.release.xcconfig"; path = "Target Support Files/Pods-BeeReel/Pods-BeeReel.release.xcconfig"; sourceTree = ""; }; @@ -308,6 +324,7 @@ BF692AF72E0A480E00A5C2DA /* Thirdparty */ = { isa = PBXGroup; children = ( + BFC676A62E12AF04006659E5 /* FlowLayout */, BFC676612E0E2C8E006659E5 /* WMZBanner */, BF692B292E0A84F700A5C2DA /* JXUUID */, ); @@ -353,6 +370,7 @@ BF692B0C2E0A7A9A00A5C2DA /* Extension */ = { isa = PBXGroup; children = ( + BFC676BD2E13A8DD006659E5 /* UIScrollView+BRRefresh.swift */, BFC6768C2E123D67006659E5 /* AttributedString+BRAdd.swift */, BFC6767A2E0E9736006659E5 /* UIStackView+BRAdd.swift */, BFC6766E2E0E3B51006659E5 /* UIImageView+BRAdd.swift */, @@ -517,6 +535,8 @@ BF692B6A2E0BC85300A5C2DA /* BRHomeViewController.swift */, BFC676702E0E9234006659E5 /* BRSpotlightViewViewController.swift */, BFC6769C2E129794006659E5 /* BRHomeTop10ViewController.swift */, + BFC676B02E137D2F006659E5 /* BRPopularPicksViewController.swift */, + BFC676BB2E138ABB006659E5 /* BRNewReleasesViewController.swift */, ); path = Controller; sourceTree = ""; @@ -524,6 +544,9 @@ BF692B6C2E0BD4B200A5C2DA /* View */ = { isa = PBXGroup; children = ( + BFC676BA2E138A9A006659E5 /* NewReleases */, + BFC676AC2E137687006659E5 /* PopularPicks */, + BFC6769E2E129CE5006659E5 /* Top10 */, BFC676762E0E950A006659E5 /* Spotlight */, BF692B6D2E0BD4CB00A5C2DA /* BRHomeHeaderView.swift */, BFC6766A2E0E395F006659E5 /* BRHomeHeaderBannerCell.swift */, @@ -607,6 +630,39 @@ path = Spotlight; sourceTree = ""; }; + BFC6769E2E129CE5006659E5 /* Top10 */ = { + isa = PBXGroup; + children = ( + BFC676A32E129D5A006659E5 /* BRHomeTop10Cell.swift */, + BFC676AA2E1372BD006659E5 /* BRHomeTop3Cell.swift */, + ); + path = Top10; + sourceTree = ""; + }; + BFC676A62E12AF04006659E5 /* FlowLayout */ = { + isa = PBXGroup; + children = ( + BFC676A52E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift */, + ); + path = FlowLayout; + sourceTree = ""; + }; + BFC676AC2E137687006659E5 /* PopularPicks */ = { + isa = PBXGroup; + children = ( + BFC676B62E137DFC006659E5 /* BRPopularPicksCell.swift */, + BFC676B82E1385FC006659E5 /* BRPopularPicksSmallCell.swift */, + ); + path = PopularPicks; + sourceTree = ""; + }; + BFC676BA2E138A9A006659E5 /* NewReleases */ = { + isa = PBXGroup; + children = ( + ); + path = NewReleases; + sourceTree = ""; + }; DF948F1E234E75684255568B /* Frameworks */ = { isa = PBXGroup; children = ( @@ -736,7 +792,9 @@ buildActionMask = 2147483647; files = ( BFC676992E1280E3006659E5 /* BRSpotlightRecommandCell.swift in Sources */, + BFC676A42E129D60006659E5 /* BRHomeTop10Cell.swift in Sources */, BF692B3C2E0A8D0200A5C2DA /* BRNavigationController.swift in Sources */, + BFC676B12E137D2F006659E5 /* BRPopularPicksViewController.swift in Sources */, BFC676692E0E34DA006659E5 /* BRUserAPI.swift in Sources */, BFC676782E0E9553006659E5 /* BRSpotlightMainBaseCell.swift in Sources */, BFC676732E0E938B006659E5 /* BRTableView.swift in Sources */, @@ -765,10 +823,12 @@ BF692B102E0A7B4300A5C2DA /* BRUserDefaultsKey.swift in Sources */, BFC676852E122D9E006659E5 /* BRVideoDetailViewController.swift in Sources */, BFC676912E126248006659E5 /* BRSpotlightTopCell.swift in Sources */, + BFC676B72E137DFC006659E5 /* BRPopularPicksCell.swift in Sources */, BF692B422E0A8FB500A5C2DA /* UIFont+BRAdd.swift in Sources */, BF692AEC2E0A475D00A5C2DA /* SceneDelegate.swift in Sources */, BF692B492E0A9D0E00A5C2DA /* UIView+BRAdd.swift in Sources */, BFC676812E122733006659E5 /* BRPlayerProtocol.swift in Sources */, + BFC676BC2E138ABB006659E5 /* BRNewReleasesViewController.swift in Sources */, BF692B5F2E0B812800A5C2DA /* BRTabBarItemContainer.swift in Sources */, BF692B652E0BC53900A5C2DA /* CGMutablePath+BRRoundedCorner.swift in Sources */, BFC676752E0E93B3006659E5 /* BRTableViewCell.swift in Sources */, @@ -776,6 +836,7 @@ BF692B092E0A775500A5C2DA /* BRLoginToken.swift in Sources */, BF692AFC2E0A6F8000A5C2DA /* BRNetworkTarget.swift in Sources */, BF692B3A2E0A8C6000A5C2DA /* BRViewController.swift in Sources */, + BFC676BE2E13A8EB006659E5 /* UIScrollView+BRRefresh.swift in Sources */, BF692B182E0A7D8900A5C2DA /* BRToast.swift in Sources */, BF692B0E2E0A7AF300A5C2DA /* UserDefaults+BRAdd.swift in Sources */, BF692B582E0AAA6F00A5C2DA /* UIScreen+BRAdd.swift in Sources */, @@ -783,6 +844,7 @@ BF692B612E0B814F00A5C2DA /* BRTabBarItemContentView.swift in Sources */, BF692B012E0A74A200A5C2DA /* BRDefine.swift in Sources */, BFC6767B2E0E973B006659E5 /* UIStackView+BRAdd.swift in Sources */, + BFC676AB2E1372BD006659E5 /* BRHomeTop3Cell.swift in Sources */, BFC676892E122FDD006659E5 /* BRVideoAPI.swift in Sources */, BFC6769B2E1285C5006659E5 /* BRPagerViewTransformer.swift in Sources */, BFC676832E122CC5006659E5 /* BRPlayerViewModel.swift in Sources */, @@ -809,8 +871,10 @@ BF692B562E0AA92100A5C2DA /* BRCollectionViewCell.swift in Sources */, BF692B072E0A771C00A5C2DA /* BRModel.swift in Sources */, BF692B752E0D39D000A5C2DA /* BRListModel.swift in Sources */, + BFC676B92E1385FC006659E5 /* BRPopularPicksSmallCell.swift in Sources */, BF692B512E0AA8C600A5C2DA /* BRPlayerListViewController.swift in Sources */, BFC676522E0D4EFD006659E5 /* BRHomeViewModel.swift in Sources */, + BFC676A72E12AF04006659E5 /* WaterfallMutiSectionFlowLayout.swift in Sources */, BF692B2A2E0A84F700A5C2DA /* JXUUID.m in Sources */, BF692B2B2E0A84F700A5C2DA /* PDKeyChain.m in Sources */, BFC6766B2E0E395F006659E5 /* BRHomeHeaderBannerCell.swift in Sources */, diff --git a/BeeReel/Base/Controller/BRViewController.swift b/BeeReel/Base/Controller/BRViewController.swift index 81ff9f3..92025e9 100644 --- a/BeeReel/Base/Controller/BRViewController.swift +++ b/BeeReel/Base/Controller/BRViewController.swift @@ -48,7 +48,11 @@ class BRViewController: UIViewController { return statusBarStyle } - func handleHeaderRefresh(_ completer: (() -> Void)?) {} + func handleHeaderRefresh(_ completer: (() -> Void)?) { + completer?() + } - func handleFooterRefresh(_ completer: (() -> Void)?) {} + func handleFooterRefresh(_ completer: (() -> Void)?) { + completer?() + } } diff --git a/BeeReel/Base/Extension/UIColor+BRAdd.swift b/BeeReel/Base/Extension/UIColor+BRAdd.swift index 930d0ba..63b8d65 100644 --- a/BeeReel/Base/Extension/UIColor+BRAdd.swift +++ b/BeeReel/Base/Extension/UIColor+BRAdd.swift @@ -50,4 +50,12 @@ extension UIColor { static func colorFF7489(alpha: CGFloat = 1) -> UIColor { return UIColor(rgb: 0xFF7489, alpha: alpha) } + + static func color777777(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0x777777, alpha: alpha) + } + + static func colorE3FC37(alpha: CGFloat = 1) -> UIColor { + return UIColor(rgb: 0xE3FC37, alpha: alpha) + } } diff --git a/BeeReel/Base/Extension/UIScrollView+BRRefresh.swift b/BeeReel/Base/Extension/UIScrollView+BRRefresh.swift new file mode 100644 index 0000000..5e6382b --- /dev/null +++ b/BeeReel/Base/Extension/UIScrollView+BRRefresh.swift @@ -0,0 +1,57 @@ +// +// UIScrollView+BRRefresh.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/7/1. +// + +import UIKit +import MJRefresh + +extension UIScrollView { + + func br_addRefreshHeader(insetTop: CGFloat = 0, block: (() -> Void)?) { + + + self.mj_header = MJRefreshNormalHeader(refreshingBlock: { + block?() + }) + self.mj_header?.ignoredScrollViewContentInsetTop = insetTop + } + + func br_addRefreshFooter(insetBottom: CGFloat = 0, block: (() -> Void)?) { + let footer = MJRefreshAutoNormalFooter(refreshingBlock: { + block?() + }) + footer.ignoredScrollViewContentInsetBottom = insetBottom + + self.mj_footer = footer + } + + + func br_addRefreshBackFooter(insetBottom: CGFloat = 0, block: (() -> Void)?) { + self.mj_footer = MJRefreshBackNormalFooter(refreshingBlock: { + block?() + }) + + self.mj_footer?.ignoredScrollViewContentInsetBottom = insetBottom + } + + func br_endHeaderRefreshing() { + self.mj_header?.endRefreshing() + } + + func br_endFooterRefreshing() { + if self.mj_footer?.state == .noMoreData { return } + self.mj_footer?.endRefreshing() + } + + ///重置没有更多 + func br_resetNoMoreData() { + self.mj_footer?.resetNoMoreData() + } + + func br_endRefreshingWithNoMoreData() { + self.mj_footer?.endRefreshingWithNoMoreData() + } +} diff --git a/BeeReel/Base/Network/API/BRHomeAPI.swift b/BeeReel/Base/Network/API/BRHomeAPI.swift index 0ad9ca4..2d97e19 100644 --- a/BeeReel/Base/Network/API/BRHomeAPI.swift +++ b/BeeReel/Base/Network/API/BRHomeAPI.swift @@ -28,5 +28,31 @@ class BRHomeAPI { } } + ///受欢迎的短剧 + static func requestPopularPicksList(completer: ((_ list: [BRShortModel]?) -> Void)?) { + var param = BRNetworkParameters(path: "/highestPaymentAndHottestVideo") + param.method = .get + param.parameters = [ + "buy_count_num" : "0", + "hottest_num" : "20" + ] + + BRNetwork.request(parameters: param) { (response: BRNetworkResponse>) in + completer?(response.data?.list) + } + } + + static func requestNewReleasesList(page: Int, completer: ((_ list: [BRShortModel]?) -> Void)?) { + var param = BRNetworkParameters(path: "/newShortPlayList") + param.method = .get + param.parameters = [ + "current_page" : page, + "page_size" : "20" + ] + + BRNetwork.request(parameters: param) { (response: BRNetworkResponse>) in + completer?(response.data?.list) + } + } } diff --git a/BeeReel/Base/Network/Base/BRNetwork.swift b/BeeReel/Base/Network/Base/BRNetwork.swift index e5ef104..2faa6e3 100644 --- a/BeeReel/Base/Network/Base/BRNetwork.swift +++ b/BeeReel/Base/Network/Base/BRNetwork.swift @@ -117,19 +117,13 @@ struct BRNetwork { brLog(message: parameters.parameters) brLog(message: parameters.path) - - DispatchQueue.global().async { - let response: BRNetworkResponse = _deserialize(data: tempData) - - DispatchQueue.main.async { - if response.code != BRNetworkCodeSucceed { - if parameters.isToast { - BRToast.show(text: response.msg) - } - } - completion?(response) + let response: BRNetworkResponse = _deserialize(data: tempData) + if response.code != BRNetworkCodeSucceed { + if parameters.isToast { + BRToast.show(text: response.msg) } } + completion?(response) } catch { var res = BRNetworkResponse() diff --git a/BeeReel/Class/Home/Controller/BRHomeTop10ViewController.swift b/BeeReel/Class/Home/Controller/BRHomeTop10ViewController.swift index 1548dca..56cd66e 100644 --- a/BeeReel/Class/Home/Controller/BRHomeTop10ViewController.swift +++ b/BeeReel/Class/Home/Controller/BRHomeTop10ViewController.swift @@ -10,33 +10,181 @@ import UIKit class BRHomeTop10ViewController: BRViewController { - private lazy var dataArr: [BRShortModel] = [] + private lazy var dataArr: [[BRShortModel]] = [] -// private lazy var collectionView: BRCollectionView = { -// let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: <#T##UICollectionViewLayout#>) -// }() + private lazy var collectionViewLayout: WaterfallMutiSectionFlowLayout = { + let layout = WaterfallMutiSectionFlowLayout() + layout.delegate = self + return layout + }() + + private lazy var collectionView: BRCollectionView = { + let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + collectionView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.customTabBarHeight + 10, right: 0) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.register(BRHomeTop10Cell.self, forCellWithReuseIdentifier: "cell") + collectionView.register(BRHomeTop3Cell.self, forCellWithReuseIdentifier: "BRHomeTop3Cell") + return collectionView + }() override func viewDidLoad() { super.viewDidLoad() requestDataArr() + + br_setupUI() } - + override func handleHeaderRefresh(_ completer: (() -> Void)?) { + requestDataArr { + completer?() + } + } } extension BRHomeTop10ViewController { - private func requestDataArr() { + private func br_setupUI() { + view.addSubview(collectionView) + + collectionView.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.bottom.equalToSuperview() + make.top.equalToSuperview().offset(20) + } + } + + +} + +//MARK: -------------- WMZPageProtocol -------------- +extension BRHomeTop10ViewController: WMZPageProtocol { + + func getMyScrollView() -> UIScrollView { + return self.collectionView + } +} + + +//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource -------------- +extension BRHomeTop10ViewController: UICollectionViewDelegate, UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let model = self.dataArr[indexPath.section][indexPath.row] + + if indexPath.section == 0 { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "BRHomeTop3Cell", for: indexPath) as! BRHomeTop3Cell + cell.model = model + cell.num = indexPath.row + 1 + return cell + } else { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRHomeTop10Cell + cell.model = model + cell.num = indexPath.row + 4 + return cell + } + } + + func numberOfSections(in collectionView: UICollectionView) -> Int { + return self.dataArr.count + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return self.dataArr[section].count + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let model = self.dataArr[indexPath.section][indexPath.row] + + let vc = BRVideoDetailViewController() + vc.shortPlayId = model.short_play_id + self.navigationController?.pushViewController(vc, animated: true) + } +} + +//MARK: -------------- WaterfallMutiSectionDelegate -------------- +extension BRHomeTop10ViewController: WaterfallMutiSectionDelegate { + + func heightForRowAtIndexPath(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, indexPath: IndexPath, itemWidth: CGFloat) -> CGFloat { + if indexPath.section == 0 { + if indexPath.row == 0 { + return 240 + } else { + return 115 + } + } + return 126 + } + + func columnNumber(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> Int { + if section == 0 { + return 2 + } else { + return 1 + } + } + + func lineSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat { + if section == 0 { + return 10 + } else { + return 12 + } + } + + func interitemSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat { + return 10 + } + + func referenceSizeForHeader(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize { + if section > 0 { + return .init(width: UIScreen.width, height: 10) + } else { + return .zero + } + } + + func insetForSection(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> UIEdgeInsets { + return .init(top: 0, left: 15, bottom: 0, right: 15) + } +} + +extension BRHomeTop10ViewController { + + private func requestDataArr(completer: (() -> Void)? = nil) { BRHomeAPI.requestTop10List { [weak self] list in guard let self = self else { return } - guard let list = list else { return } - self.dataArr = list + guard let list = list else { + completer?() + return + } + self.dataArr.removeAll() + + var arr1: [BRShortModel] = [] + var arr2: [BRShortModel] = [] + + list.enumerated().forEach { + if $0 < 3 { + arr1.append($1) + } else { + arr2.append($1) + } + } + if arr1.count > 0 { + self.dataArr.append(arr1) + } + if arr2.count > 0 { + self.dataArr.append(arr2) + } + self.collectionView.reloadData() + + completer?() } } diff --git a/BeeReel/Class/Home/Controller/BRHomeViewController.swift b/BeeReel/Class/Home/Controller/BRHomeViewController.swift index 0aa13c5..9c8a9fa 100644 --- a/BeeReel/Class/Home/Controller/BRHomeViewController.swift +++ b/BeeReel/Class/Home/Controller/BRHomeViewController.swift @@ -23,12 +23,14 @@ class BRHomeViewController: BRViewController { return [ spotlightVC, BRHomeTop10ViewController(), - BRViewController(), - BRViewController(), + BRPopularPicksViewController(), + BRNewReleasesViewController(), BRViewController() ] }() + private lazy var requestGroup = DispatchGroup() + private lazy var pageParam: WMZPageParam = { let param = WMZPageParam() param.wTitleArr = [ @@ -75,7 +77,7 @@ class BRHomeViewController: BRViewController { return 0 } param.wCustomTabbarY = { _ in - return UIScreen.customTabBarHeight + return 0 } @@ -96,6 +98,9 @@ class BRHomeViewController: BRViewController { let view = WMZPageView(frame: self.view.bounds, autoFix: true, param: pageParam, parentReponder: self) view.backgroundColor = .clear view.downSc?.backgroundColor = .clear + view.downSc?.br_addRefreshHeader { [weak self] in + self?.handleHeaderRefresh(nil) + } return view }() @@ -162,6 +167,25 @@ class BRHomeViewController: BRViewController { } } + override func handleHeaderRefresh(_ completer: (() -> Void)?) { + + self.requestGroup.enter() + requestHomeData { [weak self] in + self?.requestGroup.leave() + } + + if let vc = self.pageView.upSc.currentVC as? BRViewController { + self.requestGroup.enter() + vc.handleHeaderRefresh { [weak self] in + self?.requestGroup.leave() + } + } + + self.requestGroup.notify(queue: .main) { [weak self] in + self?.pageView.downSc?.br_endHeaderRefreshing() + } + + } } @@ -215,21 +239,24 @@ extension BRHomeViewController { extension BRHomeViewController { - private func requestHomeData() { + private func requestHomeData(completer: (() -> Void)? = nil) { BRHomeAPI.requestHomeData { [weak self] list in guard let self = self else { return } - self.viewModel.homeOldDataArr = list ?? [] - - self.headerView.bannerArr = self.viewModel.bannerArr - if let bannerArr = self.viewModel.bannerArr, bannerArr.count > 0 { - self.bgImageView.isHidden = false - self.pageView.updateHeadView() - } else { - self.bgImageView.isHidden = true + if let list = list { + self.viewModel.homeOldDataArr = list + + self.headerView.bannerArr = self.viewModel.bannerArr + if let bannerArr = self.viewModel.bannerArr, bannerArr.count > 0 { + self.bgImageView.isHidden = false + self.pageView.updateHeadView() + } else { + self.bgImageView.isHidden = true + } + self.spotlightVC.reloadData() } - self.spotlightVC.reloadData() self.updateStatusBarStyle() + completer?() } } diff --git a/BeeReel/Class/Home/Controller/BRNewReleasesViewController.swift b/BeeReel/Class/Home/Controller/BRNewReleasesViewController.swift new file mode 100644 index 0000000..eefebf5 --- /dev/null +++ b/BeeReel/Class/Home/Controller/BRNewReleasesViewController.swift @@ -0,0 +1,125 @@ +// +// BRNewReleasesViewController.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/7/1. +// + +import UIKit + +class BRNewReleasesViewController: BRViewController { + + + private lazy var dataArr: [BRShortModel] = [] + + private lazy var page: Int = 1 + + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { + let width = floor((UIScreen.width - 30 - 10) / 2) + + let layout = UICollectionViewFlowLayout() + layout.itemSize = .init(width: width, height: 222) + layout.minimumLineSpacing = 10 + layout.minimumInteritemSpacing = 10 + layout.sectionInset = .init(top: 0, left: 15, bottom: 0, right: 15) + return layout + }() + + private lazy var collectionView: BRCollectionView = { + let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.customTabBarHeight + 10, right: 0) + collectionView.br_addRefreshBackFooter(insetBottom: 0) { [weak self] in + self?.handleFooterRefresh(nil) + } + collectionView.register(BRSpotlightNewCell.self, forCellWithReuseIdentifier: "cell") + return collectionView + }() + + override func viewDidLoad() { + super.viewDidLoad() + + requestDataArr(page: 1) + + br_setupUI() + } + + override func handleHeaderRefresh(_ completer: (() -> Void)?) { + requestDataArr(page: 1) { + completer?() + } + } + + override func handleFooterRefresh(_ completer: (() -> Void)?) { + requestDataArr(page: self.page + 1) { [weak self] in + self?.collectionView.br_endFooterRefreshing() + } + } + +} + +extension BRNewReleasesViewController { + + private func br_setupUI() { + view.addSubview(collectionView) + + collectionView.snp.makeConstraints { make in + make.left.right.equalToSuperview() + make.top.equalToSuperview().offset(20) + make.bottom.equalToSuperview() + } + } + +} + +//MARK: -------------- WMZPageProtocol -------------- +extension BRNewReleasesViewController: WMZPageProtocol { + func getMyScrollView() -> UIScrollView { + return self.collectionView + } +} + +//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource -------------- +extension BRNewReleasesViewController: UICollectionViewDelegate, UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRSpotlightNewCell + cell.model = self.dataArr[indexPath.row] + return cell + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return dataArr.count + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let model = dataArr[indexPath.row] + + let vc = BRVideoDetailViewController() + vc.shortPlayId = model.short_play_id + self.navigationController?.pushViewController(vc, animated: true) + } +} + +extension BRNewReleasesViewController { + + private func requestDataArr(page: Int, completer: (() -> Void)? = nil) { + + BRHomeAPI.requestNewReleasesList(page: page) { [weak self] list in + guard let self = self else { return } + if let list = list { + if page == 1 { + self.dataArr.removeAll() + } + self.dataArr += list + self.page = page + + self.collectionView.reloadData() + } + completer?() + } + } + +} + diff --git a/BeeReel/Class/Home/Controller/BRPopularPicksViewController.swift b/BeeReel/Class/Home/Controller/BRPopularPicksViewController.swift new file mode 100644 index 0000000..9daf21b --- /dev/null +++ b/BeeReel/Class/Home/Controller/BRPopularPicksViewController.swift @@ -0,0 +1,174 @@ +// +// BRPopularPicksViewController.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/7/1. +// + +import UIKit + +class BRPopularPicksViewController: BRViewController { + + + private lazy var dataArr: [BRShortModel] = [] + + private lazy var contentView: UIView = { + let view = UIView() + view.backgroundColor = .colorFFFFFF() + view.layer.cornerRadius = 10 + view.layer.masksToBounds = true + return view + }() + + private lazy var collectionViewLayout: UICollectionViewFlowLayout = { + let layout = UICollectionViewFlowLayout() + layout.itemSize = .init(width: UIScreen.width - 90 - 20, height: 196) + layout.sectionInset = .init(top: 10, left: 10, bottom: 0, right: 10) + layout.minimumLineSpacing = 10 + return layout + }() + + private lazy var collectionView: BRCollectionView = { + let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.contentInset = .init(top: 0, left: 0, bottom: 10, right: 0) + collectionView.register(BRPopularPicksCell.self, forCellWithReuseIdentifier: "cell") + return collectionView + }() + + private lazy var smallCollectionViewLayout: UICollectionViewFlowLayout = { + let layout = UICollectionViewFlowLayout() + layout.itemSize = .init(width: 44, height: 58) + layout.minimumLineSpacing = 10 + return layout + }() + + private lazy var smallCollectionView: BRCollectionView = { + let collectionView = BRCollectionView(frame: .zero, collectionViewLayout: smallCollectionViewLayout) + collectionView.delegate = self + collectionView.dataSource = self + collectionView.showsVerticalScrollIndicator = false + collectionView.register(BRPopularPicksSmallCell.self, forCellWithReuseIdentifier: "cell") + return collectionView + }() + + private lazy var topButton: UIButton = { + let button = UIButton(type: .custom) + button.setImage(UIImage(named: "top_button_01"), for: .normal) + button.addTarget(self, action: #selector(handleTopButton), for: .touchUpInside) + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + + br_setupUI() + + requestDataArr() + } + + + @objc private func handleTopButton() { + + collectionView.scrollToTop(animated: true) + smallCollectionView.scrollToTop(animated: true) + } + + override func handleHeaderRefresh(_ completer: (() -> Void)?) { + requestDataArr { + completer?() + } + } + +} + +extension BRPopularPicksViewController { + + private func br_setupUI() { + view.addSubview(contentView) + contentView.addSubview(collectionView) + view.addSubview(smallCollectionView) + view.addSubview(topButton) + + contentView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(15) + make.right.equalToSuperview().offset(-75) + make.top.equalToSuperview().offset(20) + make.bottom.equalToSuperview().offset(-(UIScreen.customTabBarHeight + 15)) + } + + collectionView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + smallCollectionView.snp.makeConstraints { make in + make.top.equalTo(contentView) + make.right.equalToSuperview().offset(-15) + make.width.equalTo(self.smallCollectionViewLayout.itemSize.width) +// make.bottom.equalTo(contentView) + make.bottom.equalTo(topButton.snp.top).offset(-10) + } + + topButton.snp.makeConstraints { make in + make.centerX.equalTo(smallCollectionView) + make.bottom.equalTo(contentView) + } + } + +} + +//MARK: -------------- WMZPageProtocol -------------- +extension BRPopularPicksViewController: WMZPageProtocol { + func getMyScrollViews() -> [UIScrollView] { + return [self.collectionView, self.smallCollectionView] + } +} + +//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource -------------- +extension BRPopularPicksViewController: UICollectionViewDelegate, UICollectionViewDataSource { + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let model = self.dataArr[indexPath.row] + if collectionView == self.collectionView { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRPopularPicksCell + cell.model = model + return cell + } else { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRPopularPicksSmallCell + cell.model = model + return cell + } + } + + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return self.dataArr.count + } + + func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + let model = self.dataArr[indexPath.row] + + let vc = BRVideoDetailViewController() + vc.shortPlayId = model.short_play_id + self.navigationController?.pushViewController(vc, animated: true) + } +} + + +extension BRPopularPicksViewController { + + private func requestDataArr(completer: (() -> Void)? = nil) { + + BRHomeAPI.requestPopularPicksList { [weak self] list in + guard let self = self else { return } + + if let list = list { + self.dataArr = list + self.collectionView.reloadData() + self.smallCollectionView.reloadData() + } + completer?() + } + } + +} diff --git a/BeeReel/Class/Home/Controller/BRSpotlightViewViewController.swift b/BeeReel/Class/Home/Controller/BRSpotlightViewViewController.swift index 4ef9fa4..d31403d 100644 --- a/BeeReel/Class/Home/Controller/BRSpotlightViewViewController.swift +++ b/BeeReel/Class/Home/Controller/BRSpotlightViewViewController.swift @@ -15,6 +15,7 @@ class BRSpotlightViewViewController: BRViewController, WMZPageProtocol { let tableView = BRTableView(frame: .zero, style: .plain) tableView.delegate = self tableView.dataSource = self + tableView.contentInset = .init(top: 0, left: 0, bottom: UIScreen.customTabBarHeight, right: 0) tableView.register(BRSpotlightMainBaseCell.self, forCellReuseIdentifier: "cell") tableView.register(BRSpotlightHotMainCell.self, forCellReuseIdentifier: BRHomeModuleItem.ModuleKey.v3_recommand.rawValue) tableView.register(BRSpotlightTopMainCell.self, forCellReuseIdentifier: BRHomeModuleItem.ModuleKey.week_ranking.rawValue) @@ -46,7 +47,7 @@ extension BRSpotlightViewViewController { tableView.snp.makeConstraints { make in make.left.right.bottom.equalToSuperview() - make.top.equalToSuperview().offset(15) + make.top.equalToSuperview().offset(20) } } diff --git a/BeeReel/Class/Home/Model/BRShortModel.swift b/BeeReel/Class/Home/Model/BRShortModel.swift index 57a3f5f..d456906 100644 --- a/BeeReel/Class/Home/Model/BRShortModel.swift +++ b/BeeReel/Class/Home/Model/BRShortModel.swift @@ -45,7 +45,7 @@ class BRShortModel: BRModel, SmartCodable { var all_coins: String? var buy_type: String? var collect_total: Int? - var vp_description: String? + var br_description: String? var episode_total: Int? var horizontally_img: String? var image_url: String? @@ -70,12 +70,12 @@ class BRShortModel: BRModel, SmartCodable { @IgnoredKey var titleAttributedString: NSAttributedString? @IgnoredKey - var vp_isSelected: Bool? + var br_isSelected: Bool? static func mappingForKey() -> [SmartKeyTransformer]? { return [ - CodingKeys.vp_description <--- ["description", "short_video_description"], + CodingKeys.br_description <--- ["description", "short_video_description"], CodingKeys.name <--- ["short_video_title", "name"] ] } diff --git a/BeeReel/Class/Home/View/PopularPicks/BRPopularPicksCell.swift b/BeeReel/Class/Home/View/PopularPicks/BRPopularPicksCell.swift new file mode 100644 index 0000000..7e108e9 --- /dev/null +++ b/BeeReel/Class/Home/View/PopularPicks/BRPopularPicksCell.swift @@ -0,0 +1,125 @@ +// +// BRPopularPicksCell.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/7/1. +// + +import UIKit + +class BRPopularPicksCell: BRCollectionViewCell { + + var model: BRShortModel? { + didSet { + coverImageView.br_setImage(url: model?.image_url) + titleLabel.text = model?.name + categoryLabel.text = model?.category?.first + desLabel.text = model?.br_description + + hotView.setNeedsUpdateConfiguration() + } + } + + private lazy var coverImageView: BRImageView = { + let imageView = BRImageView() + imageView.layer.cornerRadius = 8 + imageView.layer.masksToBounds = true + return imageView + }() + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .fontMedium(ofSize: 14) + label.textColor = .color1C1C1C() + label.numberOfLines = 3 + return label + }() + + private lazy var categoryLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 10) + label.textColor = .color899D00() + return label + }() + + private lazy var desLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 10) + label.textColor = .color777777() + label.numberOfLines = 4 + return label + }() + + private lazy var hotView: UIButton = { + var config = UIButton.Configuration.plain() + config.image = UIImage(named: "hot_icon_02") + config.imagePlacement = .leading + config.imagePadding = 2 + config.contentInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0) + + let button = UIButton(configuration: config) + button.isUserInteractionEnabled = false + button.configurationUpdateHandler = { [weak self] button in + guard let self = self else { return } + let count = model?.watch_total ?? 0 + var string = "\(count)" + if count > 100 { + string = String(format: "%.1fk", Float(count) / 1000) + } + button.configuration?.attributedTitle = AttributedString.br_createAttributedString(string: string, color: .colorFF7489(), font: .fontRegular(ofSize: 10)) + + } + return button + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + br_setupUI() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension BRPopularPicksCell { + + private func br_setupUI() { + contentView.addSubview(coverImageView) + contentView.addSubview(titleLabel) + contentView.addSubview(categoryLabel) + contentView.addSubview(desLabel) + contentView.addSubview(hotView) + + coverImageView.snp.makeConstraints { make in + make.left.top.bottom.equalToSuperview() + make.width.equalTo(152) + } + + titleLabel.snp.makeConstraints { make in + make.left.equalTo(coverImageView.snp.right).offset(10) + make.right.lessThanOrEqualToSuperview().offset(-10) + make.centerY.equalTo(self.contentView.snp.top).offset(30) + } + + categoryLabel.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.top.equalToSuperview().offset(75) + } + + desLabel.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.right.lessThanOrEqualToSuperview().offset(-10) + make.centerY.equalTo(self.contentView.snp.top).offset(27.5 + 94) + } + + hotView.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.bottom.equalToSuperview().offset(-17) + } + + } + +} diff --git a/BeeReel/Class/Home/View/PopularPicks/BRPopularPicksSmallCell.swift b/BeeReel/Class/Home/View/PopularPicks/BRPopularPicksSmallCell.swift new file mode 100644 index 0000000..fad143c --- /dev/null +++ b/BeeReel/Class/Home/View/PopularPicks/BRPopularPicksSmallCell.swift @@ -0,0 +1,38 @@ +// +// BRPopularPicksSmallCell.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/7/1. +// + +import UIKit + +class BRPopularPicksSmallCell: BRCollectionViewCell { + + var model: BRShortModel? { + didSet { + coverImageView.br_setImage(url: model?.image_url) + } + } + + private lazy var coverImageView: BRImageView = { + let imageView = BRImageView() + imageView.layer.cornerRadius = 4 + imageView.layer.masksToBounds = true + return imageView + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + contentView.addSubview(coverImageView) + + coverImageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } +} diff --git a/BeeReel/Class/Home/View/Spotlight/BRSpotlightTopCell.swift b/BeeReel/Class/Home/View/Spotlight/BRSpotlightTopCell.swift index 73cebe4..17c58fd 100644 --- a/BeeReel/Class/Home/View/Spotlight/BRSpotlightTopCell.swift +++ b/BeeReel/Class/Home/View/Spotlight/BRSpotlightTopCell.swift @@ -20,6 +20,23 @@ class BRSpotlightTopCell: BRCollectionViewCell { } } + var num: Int = 0 { + didSet { + switch num { + case 1: + numView.image = UIImage(named: "number_icon_01") + numView.isHidden = false + case 2: + numView.image = UIImage(named: "number_icon_02") + numView.isHidden = false + case 3: + numView.image = UIImage(named: "number_icon_03") + numView.isHidden = false + default: + numView.isHidden = true + } + } + } private lazy var coverImageView: BRImageView = { let imageView = BRImageView() @@ -41,6 +58,11 @@ class BRSpotlightTopCell: BRCollectionViewCell { return imageView }() + private lazy var numView: UIImageView = { + let imageView = UIImageView() + return imageView + }() + private lazy var titleLabel: UILabel = { let label = UILabel() label.font = .fontMedium(ofSize: 12) @@ -98,6 +120,7 @@ extension BRSpotlightTopCell { contentView.addSubview(coverImageView) + coverImageView.addSubview(numView) coverImageView.addSubview(coverMarkView) contentView.addSubview(playImageView) coverImageView.addSubview(textBgView) @@ -109,6 +132,11 @@ extension BRSpotlightTopCell { make.edges.equalToSuperview() } + numView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(10) + make.top.equalToSuperview().offset(10) + } + coverMarkView.snp.makeConstraints { make in make.right.bottom.equalToSuperview() } diff --git a/BeeReel/Class/Home/View/Spotlight/BRSpotlightTopMainCell.swift b/BeeReel/Class/Home/View/Spotlight/BRSpotlightTopMainCell.swift index 37b081a..a8b690c 100644 --- a/BeeReel/Class/Home/View/Spotlight/BRSpotlightTopMainCell.swift +++ b/BeeReel/Class/Home/View/Spotlight/BRSpotlightTopMainCell.swift @@ -64,6 +64,7 @@ extension BRSpotlightTopMainCell: UICollectionViewDelegate, UICollectionViewData func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! BRSpotlightTopCell cell.model = self.moduleItem?.list?[indexPath.row] + cell.num = indexPath.row + 1 return cell } diff --git a/BeeReel/Class/Home/View/Top10/BRHomeTop10Cell.swift b/BeeReel/Class/Home/View/Top10/BRHomeTop10Cell.swift new file mode 100644 index 0000000..5385bfa --- /dev/null +++ b/BeeReel/Class/Home/View/Top10/BRHomeTop10Cell.swift @@ -0,0 +1,167 @@ +// +// BRHomeTop10Cell.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/6/30. +// + +import UIKit + + +class BRHomeTop10Cell: BRCollectionViewCell { + + + var model: BRShortModel? { + didSet { + coverImageView.br_setImage(url: model?.image_url) + titleLabel.text = model?.name + categoryLabel.text = model?.category?.first + desLabel.text = model?.br_description + + hotView.setNeedsUpdateConfiguration() + } + } + + var num: Int = 0 { + didSet { + numLabel.text = "\(num)" + } + } + + private lazy var bgImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "top_bg_image_01")) + return imageView + }() + + private lazy var coverImageView: BRImageView = { + let imageView = BRImageView() + imageView.layer.cornerRadius = 8 + imageView.layer.masksToBounds = true + return imageView + }() + + private lazy var titleLabel: UILabel = { + let label = UILabel() + label.font = .fontMedium(ofSize: 14) + label.textColor = .color1C1C1C() + return label + }() + + private lazy var categoryLabel: UILabel = { + let label = UILabel() + label.font = .fontRegular(ofSize: 10) + label.textColor = .color899D00() + return label + }() + + private lazy var desLabel: UILabel = { + let label = UILabel() + label.numberOfLines = 2 + label.font = .fontRegular(ofSize: 10) + label.textColor = .color777777() + return label + }() + + private lazy var hotView: UIButton = { + var config = UIButton.Configuration.plain() + config.image = UIImage(named: "hot_icon_02") + config.imagePlacement = .leading + config.imagePadding = 2 + config.contentInsets = .init(top: 0, leading: 0, bottom: 0, trailing: 0) + + let button = UIButton(configuration: config) + button.isUserInteractionEnabled = false + button.configurationUpdateHandler = { [weak self] button in + guard let self = self else { return } + let count = model?.watch_total ?? 0 + var string = "\(count)" + if count > 100 { + string = String(format: "%.1fk", Float(count) / 1000) + } + button.configuration?.attributedTitle = AttributedString.br_createAttributedString(string: string, color: .colorFF7489(), font: .fontRegular(ofSize: 10)) + + } + return button + }() + + private lazy var numBgView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "number_bg_icon_01")) + return imageView + }() + + private lazy var numLabel: UILabel = { + let label = UILabel() + label.font = .fontMedium(ofSize: 15) + label.textColor = .color000000() + return label + }() + + override init(frame: CGRect) { + super.init(frame: frame) + + br_setupUI() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension BRHomeTop10Cell { + + private func br_setupUI() { + contentView.addSubview(bgImageView) + bgImageView.addSubview(coverImageView) + bgImageView.addSubview(titleLabel) + bgImageView.addSubview(categoryLabel) + bgImageView.addSubview(desLabel) + bgImageView.addSubview(hotView) + bgImageView.addSubview(numBgView) + bgImageView.addSubview(numLabel) + + bgImageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + coverImageView.snp.makeConstraints { make in + make.centerY.equalToSuperview() + make.left.equalToSuperview().offset(7) + make.width.equalTo(90) + make.height.equalTo(112) + } + + titleLabel.snp.makeConstraints { make in + make.left.equalTo(coverImageView.snp.right).offset(20) + make.top.equalToSuperview().offset(16) + make.right.lessThanOrEqualToSuperview().offset(-48) + } + + categoryLabel.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.top.equalToSuperview().offset(41) + } + + desLabel.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.top.equalToSuperview().offset(60) + make.right.lessThanOrEqualToSuperview().offset(-48) + } + + hotView.snp.makeConstraints { make in + make.left.equalTo(titleLabel) + make.bottom.equalToSuperview().offset(-17) + } + + numBgView.snp.makeConstraints { make in + make.centerX.equalTo(self.bgImageView.snp.right).offset(-15) + make.centerY.equalToSuperview().offset(-3) + } + + numLabel.snp.makeConstraints { make in + make.centerX.equalTo(numBgView) + make.centerY.equalToSuperview().offset(3) + } + } + +} diff --git a/BeeReel/Class/Home/View/Top10/BRHomeTop3Cell.swift b/BeeReel/Class/Home/View/Top10/BRHomeTop3Cell.swift new file mode 100644 index 0000000..ec61315 --- /dev/null +++ b/BeeReel/Class/Home/View/Top10/BRHomeTop3Cell.swift @@ -0,0 +1,110 @@ +// +// BRHomeTop3Cell.swift +// BeeReel +// +// Created by 湖南秦九 on 2025/6/30. +// + +import UIKit + +class BRHomeTop3Cell: BRCollectionViewCell { + + + var model: BRShortModel? { + didSet { + coverImageView.br_setImage(url: model?.image_url) + } + } + + var num: Int = 0 { + didSet { + numLabel.text = "NO.\(num)" + if num == 1 { + coverImageView.snp.updateConstraints { make in + make.top.equalToSuperview().offset(32) + } + } else { + coverImageView.snp.updateConstraints { make in + make.top.equalToSuperview().offset(28) + } + } + } + } + + private lazy var coverImageView: BRImageView = { + let imageView = BRImageView() + imageView.layer.cornerRadius = 8 + imageView.layer.masksToBounds = true + return imageView + }() + + private lazy var numLabel: UILabel = { + let label = UILabel() + label.font = .fontMedium(ofSize: 14) + label.textColor = .colorE3FC37() + return label + }() + + private lazy var numIconImageView: UIImageView = { + let imageView = UIImageView(image: UIImage(named: "num_icon_01")) + return imageView + }() + + private lazy var dotView: UIView = { + let view = UIView() + view.backgroundColor = .colorE3FC37() + view.layer.cornerRadius = 3 + view.layer.masksToBounds = true + return view + }() + + + override init(frame: CGRect) { + super.init(frame: frame) + + self.contentView.backgroundColor = .color1C1C1C() + self.contentView.layer.cornerRadius = 12 + self.contentView.layer.masksToBounds = true + + br_setupUI() + } + + @MainActor required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + +} + +extension BRHomeTop3Cell { + + private func br_setupUI() { + contentView.addSubview(coverImageView) + contentView.addSubview(dotView) + contentView.addSubview(numLabel) + contentView.addSubview(numIconImageView) + + coverImageView.snp.makeConstraints { make in + make.left.equalToSuperview().offset(5) + make.centerX.equalToSuperview() + make.bottom.equalToSuperview().offset(-5) + make.top.equalToSuperview().offset(32) + } + + dotView.snp.makeConstraints { make in + make.right.equalToSuperview().offset(-5) + make.top.equalToSuperview().offset(12) + make.width.height.equalTo(6) + } + + numLabel.snp.makeConstraints { make in + make.left.equalToSuperview().offset(5) + make.centerY.equalTo(dotView) + } + + numIconImageView.snp.makeConstraints { make in + make.centerY.equalTo(numLabel) + make.left.equalTo(numLabel.snp.right).offset(10) + } + } + +} diff --git a/BeeReel/Delegate/AppDelegate+BRConfig.swift b/BeeReel/Delegate/AppDelegate+BRConfig.swift index e4c9c80..6452bf1 100644 --- a/BeeReel/Delegate/AppDelegate+BRConfig.swift +++ b/BeeReel/Delegate/AppDelegate+BRConfig.swift @@ -5,10 +5,15 @@ // Created by 湖南秦九 on 2025/6/25. // +import MJRefresh + extension AppDelegate { func addConfig() { UIView.vp_Awake() + + //设置刷新控件的语言 + MJRefreshConfig.default.languageCode = BRLocalizedManager.manager.mjLocalizedKey } } diff --git a/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/Contents.json new file mode 100644 index 0000000..8d14046 --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "箭头@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "箭头@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/箭头@2x.png b/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/箭头@2x.png new file mode 100644 index 0000000..b54171f Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/箭头@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/箭头@3x.png b/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/箭头@3x.png new file mode 100644 index 0000000..2af8efa Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/num_icon_01.imageset/箭头@3x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Contents.json new file mode 100644 index 0000000..a101a14 --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Ellipse 9@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Ellipse 9@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Ellipse 9@2x.png b/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Ellipse 9@2x.png new file mode 100644 index 0000000..5cb09e4 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Ellipse 9@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Ellipse 9@3x.png b/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Ellipse 9@3x.png new file mode 100644 index 0000000..59b4234 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/number_bg_icon_01.imageset/Ellipse 9@3x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/Contents.json new file mode 100644 index 0000000..793a9fd --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "金 1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "金 1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/金 1@2x.png b/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/金 1@2x.png new file mode 100644 index 0000000..e5f19c8 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/金 1@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/金 1@3x.png b/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/金 1@3x.png new file mode 100644 index 0000000..d0145c9 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/number_icon_01.imageset/金 1@3x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/Contents.json new file mode 100644 index 0000000..d000b87 --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "金 2@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "金 2@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/金 2@2x.png b/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/金 2@2x.png new file mode 100644 index 0000000..f2c97b3 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/金 2@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/金 2@3x.png b/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/金 2@3x.png new file mode 100644 index 0000000..f7a5162 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/number_icon_02.imageset/金 2@3x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/Contents.json new file mode 100644 index 0000000..9cb554c --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "铜 1@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "铜 1@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/铜 1@2x.png b/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/铜 1@2x.png new file mode 100644 index 0000000..f268baa Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/铜 1@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/铜 1@3x.png b/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/铜 1@3x.png new file mode 100644 index 0000000..1466cc1 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/number_icon_03.imageset/铜 1@3x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Contents.json new file mode 100644 index 0000000..fe5f3fb --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Contents.json @@ -0,0 +1,22 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "Frame 21@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "Frame 21@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Frame 21@2x.png b/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Frame 21@2x.png new file mode 100644 index 0000000..6271661 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Frame 21@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Frame 21@3x.png b/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Frame 21@3x.png new file mode 100644 index 0000000..3b6951e Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/icon/top_button_01.imageset/Frame 21@3x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/Contents.json b/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/Contents.json new file mode 100644 index 0000000..57dd8b4 --- /dev/null +++ b/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/Contents.json @@ -0,0 +1,44 @@ +{ + "images" : [ + { + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "bg@2x.png", + "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "left" : 300, + "right" : 94 + }, + "center" : { + "mode" : "tile", + "width" : 1 + }, + "mode" : "3-part-horizontal" + }, + "scale" : "2x" + }, + { + "filename" : "bg@3x.png", + "idiom" : "universal", + "resizing" : { + "cap-insets" : { + "left" : 431, + "right" : 127 + }, + "center" : { + "mode" : "tile", + "width" : 1 + }, + "mode" : "3-part-horizontal" + }, + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/bg@2x.png b/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/bg@2x.png new file mode 100644 index 0000000..18feaae Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/bg@2x.png differ diff --git a/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/bg@3x.png b/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/bg@3x.png new file mode 100644 index 0000000..2dbdae8 Binary files /dev/null and b/BeeReel/Sources/Assets.xcassets/image/top_bg_image_01.imageset/bg@3x.png differ diff --git a/BeeReel/Thirdparty/FlowLayout/WaterfallMutiSectionFlowLayout.swift b/BeeReel/Thirdparty/FlowLayout/WaterfallMutiSectionFlowLayout.swift new file mode 100644 index 0000000..f79d863 --- /dev/null +++ b/BeeReel/Thirdparty/FlowLayout/WaterfallMutiSectionFlowLayout.swift @@ -0,0 +1,193 @@ +// +// WaterfallMutiSectionFlowLayout.swift +// gymbo +// +// Created by drogan Zheng on 2020/5/7. +// Copyright © 2020 Gymbo.co. All rights reserved. +// https://github.com/RoganZheng/WaterfallMultiSectionFlowLayout +// + +import UIKit + +@objc protocol WaterfallMutiSectionDelegate: NSObjectProtocol { + // 必选delegate实现 + /// collectionItem高度 + func heightForRowAtIndexPath(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, indexPath: IndexPath, itemWidth: CGFloat) -> CGFloat + + // 可选delegate实现 + /// 每个section 列数(默认2列) + @objc optional func columnNumber(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> Int + + /// header高度(默认为0) + @objc optional func referenceSizeForHeader(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize + + /// footer高度(默认为0) + @objc optional func referenceSizeForFooter(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGSize + + /// 每个section 边距(默认为0) + @objc optional func insetForSection(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> UIEdgeInsets + + /// 每个section item上下间距(默认为0) + @objc optional func lineSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat + + /// 每个section item左右间距(默认为0) + @objc optional func interitemSpacing(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat + + /// section头部header与上个section尾部footer间距(默认为0) + @objc optional func spacingWithLastSection(collectionView collection: UICollectionView, layout: WaterfallMutiSectionFlowLayout, section: Int) -> CGFloat +} + +class WaterfallMutiSectionFlowLayout: UICollectionViewFlowLayout { + weak var delegate: WaterfallMutiSectionDelegate? + + private var sectionInsets: UIEdgeInsets = .zero + private var columnCount: Int = 2 + private var lineSpacing: CGFloat = 0 + private var interitemSpacing: CGFloat = 0 + private var headerSize: CGSize = .zero + private var footerSize: CGSize = .zero + + //存放attribute的数组 + private var attrsArray: [UICollectionViewLayoutAttributes] = [] + //存放每个section中各个列的最后一个高度 + private var columnHeights: [CGFloat] = [] + //collectionView的Content的高度 + private var contentHeight: CGFloat = 0 + //记录上个section高度最高一列的高度 + private var lastContentHeight: CGFloat = 0 + //每个section的header与上个section的footer距离 + private var spacingWithLastSection: CGFloat = 0 + + + override func prepare() { + super.prepare() + self.contentHeight = 0 + self.lastContentHeight = 0 + self.spacingWithLastSection = 0 + self.lineSpacing = 0 + self.sectionInsets = .zero + self.headerSize = .zero + self.footerSize = .zero + self.columnHeights.removeAll() + self.attrsArray.removeAll() + + let sectionCount = self.collectionView!.numberOfSections + // 遍历section + for idx in 0.. [UICollectionViewLayoutAttributes]? { + return self.attrsArray + } + + override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + if let column = self.delegate?.columnNumber?(collectionView: self.collectionView!, layout: self, section: indexPath.section) { + self.columnCount = column + } + if let lineSpacing = self.delegate?.lineSpacing?(collectionView: self.collectionView!, layout: self, section: indexPath.section) { + self.lineSpacing = lineSpacing + } + if let interitem = self.delegate?.interitemSpacing?(collectionView: self.collectionView!, layout: self, section: indexPath.section) { + self.interitemSpacing = interitem + } + + let attri = UICollectionViewLayoutAttributes(forCellWith: indexPath) + let weight = self.collectionView!.frame.size.width + let itemSpacing = CGFloat(self.columnCount - 1) * self.interitemSpacing + let allWeight = weight - self.sectionInsets.left - self.sectionInsets.right - itemSpacing + let cellWeight = allWeight / CGFloat(self.columnCount) + let cellHeight: CGFloat = (self.delegate?.heightForRowAtIndexPath(collectionView: self.collectionView!, layout: self, indexPath: indexPath, itemWidth: cellWeight))! + + var tmpMinColumn = 0 + var minColumnHeight = self.columnHeights[0] + for i in 0.. columnH { + minColumnHeight = columnH + tmpMinColumn = i + } + } + let cellX = self.sectionInsets.left + CGFloat(tmpMinColumn) * (cellWeight + self.interitemSpacing) + var cellY: CGFloat = 0 + cellY = minColumnHeight + if cellY != self.lastContentHeight { + cellY += self.lineSpacing + } + + if self.contentHeight < minColumnHeight { + self.contentHeight = minColumnHeight + } + + attri.frame = CGRect(x: cellX, y: cellY, width: cellWeight, height: cellHeight) + self.columnHeights[tmpMinColumn] = attri.frame.maxY + //取最大的 + for i in 0.. UICollectionViewLayoutAttributes? { + let attri = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, with: indexPath) + if elementKind == UICollectionView.elementKindSectionHeader { + if let headerSize = self.delegate?.referenceSizeForHeader?(collectionView: self.collectionView!, layout: self, section: indexPath.section) { + self.headerSize = headerSize + } + self.contentHeight += self.spacingWithLastSection + attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.headerSize.width, height: self.headerSize.height) + self.contentHeight += self.headerSize.height + self.contentHeight += self.sectionInsets.top + } else if elementKind == UICollectionView.elementKindSectionFooter { + if let footerSize = self.delegate?.referenceSizeForFooter?(collectionView: self.collectionView!, layout: self, section: indexPath.section) { + self.footerSize = footerSize + } + self.contentHeight += self.sectionInsets.bottom + attri.frame = CGRect(x: 0, y: self.contentHeight, width: self.footerSize.width, height: self.footerSize.height) + self.contentHeight += self.footerSize.height + } + return attri + } + + override var collectionViewContentSize: CGSize { + return CGSize(width: self.collectionView!.frame.size.width, height: self.contentHeight) + } +} diff --git a/Podfile b/Podfile index 5d07fe5..40b4c58 100644 --- a/Podfile +++ b/Podfile @@ -27,6 +27,6 @@ target 'BeeReel' do pod 'YYCategories' pod 'YYText' pod 'FSPagerView' #banner - + pod 'MJRefresh' #刷新控件 end