跑马灯,首页数据整理,空白页面,账号配置,细节处理
1
Podfile
@ -26,7 +26,6 @@ target 'Veloria' do
|
||||
pod 'KTVHTTPCache' #视频缓存
|
||||
pod 'Kingfisher' #图片加载
|
||||
pod 'HWPanModal' #底部弹出控制器
|
||||
pod "ESTabBarController-swift"
|
||||
pod 'WMZPageController' #分页控制器
|
||||
pod 'ZFPlayer/AVPlayer' #播放器
|
||||
pod 'EmptyDataSet-Swift' #空数据页面
|
||||
|
@ -2,7 +2,6 @@ PODS:
|
||||
- Alamofire (5.10.2)
|
||||
- CocoaAsyncSocket (7.6.5)
|
||||
- EmptyDataSet-Swift (5.0.0)
|
||||
- ESTabBarController-swift (2.8.0)
|
||||
- HWPanModal (0.9.9)
|
||||
- Kingfisher (8.3.2)
|
||||
- KTVHTTPCache (3.0.2):
|
||||
@ -30,7 +29,6 @@ PODS:
|
||||
|
||||
DEPENDENCIES:
|
||||
- EmptyDataSet-Swift
|
||||
- ESTabBarController-swift
|
||||
- HWPanModal
|
||||
- Kingfisher
|
||||
- KTVHTTPCache
|
||||
@ -49,7 +47,6 @@ SPEC REPOS:
|
||||
- Alamofire
|
||||
- CocoaAsyncSocket
|
||||
- EmptyDataSet-Swift
|
||||
- ESTabBarController-swift
|
||||
- HWPanModal
|
||||
- Kingfisher
|
||||
- KTVHTTPCache
|
||||
@ -67,7 +64,6 @@ SPEC CHECKSUMS:
|
||||
Alamofire: 7193b3b92c74a07f85569e1a6c4f4237291e7496
|
||||
CocoaAsyncSocket: 065fd1e645c7abab64f7a6a2007a48038fdc6a99
|
||||
EmptyDataSet-Swift: eb382c0c87a2d9c678077385a595cec52da38171
|
||||
ESTabBarController-swift: 05593a6ad64700b03c0eb60ff625916370aa4136
|
||||
HWPanModal: b57a6717d3cdcd666bff44f9dd2a5be9f4d6f5d2
|
||||
Kingfisher: 0621d0ac0c78fecb19f6dc5303bde2b52abaf2f5
|
||||
KTVHTTPCache: 5711692cdf9a5ecfe829b1e16577deb3ffe3dc86
|
||||
@ -81,6 +77,6 @@ SPEC CHECKSUMS:
|
||||
YYKit: 7cda43304a8dc3696c449041e2cb3107b4e236e7
|
||||
ZFPlayer: 5cf39e8d9f0c2394a014b0db4767b5b5a6bffe13
|
||||
|
||||
PODFILE CHECKSUM: 5a8b71939b2bf65623c166084b1e01d877b2979d
|
||||
PODFILE CHECKSUM: e2712ae0c35ebb37af30822c851f06195b8f41d7
|
||||
|
||||
COCOAPODS: 1.16.2
|
||||
|
@ -44,11 +44,9 @@
|
||||
BF0FA6F42DDC604500C9E5F2 /* VPHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA6F32DDC604500C9E5F2 /* VPHUD.swift */; };
|
||||
BF0FA6F62DDC616300C9E5F2 /* VPToast.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA6F52DDC616300C9E5F2 /* VPToast.swift */; };
|
||||
BF0FA6F92DDC64E700C9E5F2 /* VPHomeAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA6F82DDC64E700C9E5F2 /* VPHomeAPI.swift */; };
|
||||
BF0FA6FC2DDC657500C9E5F2 /* VPHomeDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA6FB2DDC657500C9E5F2 /* VPHomeDataModel.swift */; };
|
||||
BF0FA7002DDC665300C9E5F2 /* VPShortModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA6FF2DDC665300C9E5F2 /* VPShortModel.swift */; };
|
||||
BF0FA7022DDC667C00C9E5F2 /* VPVideoInfoModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7012DDC667C00C9E5F2 /* VPVideoInfoModel.swift */; };
|
||||
BF0FA7052DDC67AC00C9E5F2 /* VPHomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7042DDC67AC00C9E5F2 /* VPHomeViewModel.swift */; };
|
||||
BF0FA7072DDC687C00C9E5F2 /* VPHomeDataItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7062DDC687C00C9E5F2 /* VPHomeDataItem.swift */; };
|
||||
BF0FA70A2DDC69C800C9E5F2 /* VPTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7092DDC69C800C9E5F2 /* VPTableViewCell.swift */; };
|
||||
BF0FA70C2DDC6A3800C9E5F2 /* VPHomeBannerContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA70B2DDC6A3800C9E5F2 /* VPHomeBannerContentCell.swift */; };
|
||||
BF0FA70E2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA70D2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift */; };
|
||||
@ -136,6 +134,18 @@
|
||||
BF5E75B82DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75B72DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift */; };
|
||||
BF5E75BC2DE546AD00DE9DFE /* VPAboutUsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75BB2DE546AD00DE9DFE /* VPAboutUsCell.swift */; };
|
||||
BF5E75BE2DE54B2800DE9DFE /* VPAboutUsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75BD2DE54B2800DE9DFE /* VPAboutUsHeaderView.swift */; };
|
||||
BF5E75C02DE5566200DE9DFE /* VPHomePageControlView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75BF2DE5566200DE9DFE /* VPHomePageControlView.swift */; };
|
||||
BF5E75CB2DE5692D00DE9DFE /* UINavigationController+JXTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C82DE5692D00DE9DFE /* UINavigationController+JXTransition.swift */; };
|
||||
BF5E75CC2DE5692D00DE9DFE /* JXTransitionDefine.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C52DE5692D00DE9DFE /* JXTransitionDefine.swift */; };
|
||||
BF5E75CD2DE5692D00DE9DFE /* JXTransitionDelegateBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C62DE5692D00DE9DFE /* JXTransitionDelegateBridge.swift */; };
|
||||
BF5E75CE2DE5692D00DE9DFE /* JXPushAnimatedTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C42DE5692D00DE9DFE /* JXPushAnimatedTransition.swift */; };
|
||||
BF5E75CF2DE5692D00DE9DFE /* UIViewController+JXTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C92DE5692D00DE9DFE /* UIViewController+JXTransition.swift */; };
|
||||
BF5E75D02DE5692D00DE9DFE /* UIGestureRecognizer+JXTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C72DE5692D00DE9DFE /* UIGestureRecognizer+JXTransition.swift */; };
|
||||
BF5E75D12DE5692D00DE9DFE /* JXPopAnimatedTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C32DE5692D00DE9DFE /* JXPopAnimatedTransition.swift */; };
|
||||
BF5E75D22DE5692D00DE9DFE /* JXNavigationInteractiveTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C22DE5692D00DE9DFE /* JXNavigationInteractiveTransition.swift */; };
|
||||
BF5E75D32DE5692D00DE9DFE /* JXBaseAnimatedTransition.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75C12DE5692D00DE9DFE /* JXBaseAnimatedTransition.swift */; };
|
||||
BF5E75D52DE56B2000DE9DFE /* VPHomeCagetoryRecommandContentCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75D42DE56B2000DE9DFE /* VPHomeCagetoryRecommandContentCell.swift */; };
|
||||
BF5E75DB2DE5B8B700DE9DFE /* VPMarqueeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5E75DA2DE5B8B700DE9DFE /* VPMarqueeView.swift */; };
|
||||
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -186,11 +196,9 @@
|
||||
BF0FA6F32DDC604500C9E5F2 /* VPHUD.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHUD.swift; sourceTree = "<group>"; };
|
||||
BF0FA6F52DDC616300C9E5F2 /* VPToast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPToast.swift; sourceTree = "<group>"; };
|
||||
BF0FA6F82DDC64E700C9E5F2 /* VPHomeAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHomeAPI.swift; sourceTree = "<group>"; };
|
||||
BF0FA6FB2DDC657500C9E5F2 /* VPHomeDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHomeDataModel.swift; sourceTree = "<group>"; };
|
||||
BF0FA6FF2DDC665300C9E5F2 /* VPShortModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPShortModel.swift; sourceTree = "<group>"; };
|
||||
BF0FA7012DDC667C00C9E5F2 /* VPVideoInfoModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPVideoInfoModel.swift; sourceTree = "<group>"; };
|
||||
BF0FA7042DDC67AC00C9E5F2 /* VPHomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHomeViewModel.swift; sourceTree = "<group>"; };
|
||||
BF0FA7062DDC687C00C9E5F2 /* VPHomeDataItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHomeDataItem.swift; sourceTree = "<group>"; };
|
||||
BF0FA7092DDC69C800C9E5F2 /* VPTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPTableViewCell.swift; sourceTree = "<group>"; };
|
||||
BF0FA70B2DDC6A3800C9E5F2 /* VPHomeBannerContentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHomeBannerContentCell.swift; sourceTree = "<group>"; };
|
||||
BF0FA70D2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHomeItemContentCell.swift; sourceTree = "<group>"; };
|
||||
@ -278,6 +286,18 @@
|
||||
BF5E75B72DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPNetworkReachabilityManager.swift; sourceTree = "<group>"; };
|
||||
BF5E75BB2DE546AD00DE9DFE /* VPAboutUsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAboutUsCell.swift; sourceTree = "<group>"; };
|
||||
BF5E75BD2DE54B2800DE9DFE /* VPAboutUsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPAboutUsHeaderView.swift; sourceTree = "<group>"; };
|
||||
BF5E75BF2DE5566200DE9DFE /* VPHomePageControlView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHomePageControlView.swift; sourceTree = "<group>"; };
|
||||
BF5E75C12DE5692D00DE9DFE /* JXBaseAnimatedTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXBaseAnimatedTransition.swift; sourceTree = "<group>"; };
|
||||
BF5E75C22DE5692D00DE9DFE /* JXNavigationInteractiveTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXNavigationInteractiveTransition.swift; sourceTree = "<group>"; };
|
||||
BF5E75C32DE5692D00DE9DFE /* JXPopAnimatedTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXPopAnimatedTransition.swift; sourceTree = "<group>"; };
|
||||
BF5E75C42DE5692D00DE9DFE /* JXPushAnimatedTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXPushAnimatedTransition.swift; sourceTree = "<group>"; };
|
||||
BF5E75C52DE5692D00DE9DFE /* JXTransitionDefine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXTransitionDefine.swift; sourceTree = "<group>"; };
|
||||
BF5E75C62DE5692D00DE9DFE /* JXTransitionDelegateBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXTransitionDelegateBridge.swift; sourceTree = "<group>"; };
|
||||
BF5E75C72DE5692D00DE9DFE /* UIGestureRecognizer+JXTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+JXTransition.swift"; sourceTree = "<group>"; };
|
||||
BF5E75C82DE5692D00DE9DFE /* UINavigationController+JXTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+JXTransition.swift"; sourceTree = "<group>"; };
|
||||
BF5E75C92DE5692D00DE9DFE /* UIViewController+JXTransition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+JXTransition.swift"; sourceTree = "<group>"; };
|
||||
BF5E75D42DE56B2000DE9DFE /* VPHomeCagetoryRecommandContentCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPHomeCagetoryRecommandContentCell.swift; sourceTree = "<group>"; };
|
||||
BF5E75DA2DE5B8B700DE9DFE /* VPMarqueeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPMarqueeView.swift; sourceTree = "<group>"; };
|
||||
E0BDA3570E00C90877E45AA0 /* Pods-VideoPlayer.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-VideoPlayer.debug.xcconfig"; path = "Target Support Files/Pods-VideoPlayer/Pods-VideoPlayer.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@ -350,6 +370,7 @@
|
||||
1B056E352DDAC1DE007EE38D /* Libs */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF5E75D92DE5B89300DE9DFE /* MarqueeView */,
|
||||
BF5E75B42DE46D9500DE9DFE /* Empty */,
|
||||
BF0FA7BF2DE45D4500C9E5F2 /* User */,
|
||||
BF0FA7432DDF025A00C9E5F2 /* Player */,
|
||||
@ -556,6 +577,7 @@
|
||||
BF0FA6E82DDC5F6F00C9E5F2 /* Thirdparty */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF5E75CA2DE5692D00DE9DFE /* JXTransition */,
|
||||
BF0FA7932DE16E9300C9E5F2 /* JXTagView */,
|
||||
BF0FA6ED2DDC5F8700C9E5F2 /* JXUUID */,
|
||||
BF0FA7152DDC78FF00C9E5F2 /* ZKCycleScrollView-Swift */,
|
||||
@ -597,8 +619,6 @@
|
||||
BF0FA6FA2DDC652000C9E5F2 /* Model */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA6FB2DDC657500C9E5F2 /* VPHomeDataModel.swift */,
|
||||
BF0FA7062DDC687C00C9E5F2 /* VPHomeDataItem.swift */,
|
||||
BF0FA7112DDC6D2C00C9E5F2 /* VPHomeModuleItem.swift */,
|
||||
BF0FA7332DDEC74500C9E5F2 /* VPCategoryModel.swift */,
|
||||
);
|
||||
@ -644,6 +664,7 @@
|
||||
BF0FA70B2DDC6A3800C9E5F2 /* VPHomeBannerContentCell.swift */,
|
||||
BF0FA7232DDC888F00C9E5F2 /* VPHomeRecommandContentCell.swift */,
|
||||
BF0FA72B2DDD7B7300C9E5F2 /* VPHomeRankingContentCell.swift */,
|
||||
BF5E75D42DE56B2000DE9DFE /* VPHomeCagetoryRecommandContentCell.swift */,
|
||||
BF0FA7182DDC7F4900C9E5F2 /* VPHomeBannerCell.swift */,
|
||||
BF0FA7292DDC922F00C9E5F2 /* VPHomeRecommandCell.swift */,
|
||||
BF0FA72D2DDD7DD400C9E5F2 /* VPHomeRankingCell.swift */,
|
||||
@ -657,6 +678,7 @@
|
||||
BF0FA7882DE161F200C9E5F2 /* VPSearchResultView.swift */,
|
||||
BF0FA78A2DE164C100C9E5F2 /* VPSearchResultCell.swift */,
|
||||
BF0FA7902DE16CBF00C9E5F2 /* VPSearchHistoryView.swift */,
|
||||
BF5E75BF2DE5566200DE9DFE /* VPHomePageControlView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -862,6 +884,30 @@
|
||||
path = Empty;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BF5E75CA2DE5692D00DE9DFE /* JXTransition */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF5E75C12DE5692D00DE9DFE /* JXBaseAnimatedTransition.swift */,
|
||||
BF5E75C22DE5692D00DE9DFE /* JXNavigationInteractiveTransition.swift */,
|
||||
BF5E75C32DE5692D00DE9DFE /* JXPopAnimatedTransition.swift */,
|
||||
BF5E75C42DE5692D00DE9DFE /* JXPushAnimatedTransition.swift */,
|
||||
BF5E75C52DE5692D00DE9DFE /* JXTransitionDefine.swift */,
|
||||
BF5E75C62DE5692D00DE9DFE /* JXTransitionDelegateBridge.swift */,
|
||||
BF5E75C72DE5692D00DE9DFE /* UIGestureRecognizer+JXTransition.swift */,
|
||||
BF5E75C82DE5692D00DE9DFE /* UINavigationController+JXTransition.swift */,
|
||||
BF5E75C92DE5692D00DE9DFE /* UIViewController+JXTransition.swift */,
|
||||
);
|
||||
path = JXTransition;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BF5E75D92DE5B89300DE9DFE /* MarqueeView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF5E75DA2DE5B8B700DE9DFE /* VPMarqueeView.swift */,
|
||||
);
|
||||
path = MarqueeView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -990,11 +1036,13 @@
|
||||
BF0FA7B82DE44FCC00C9E5F2 /* VPWebViewController.swift in Sources */,
|
||||
BF0FA72A2DDC922F00C9E5F2 /* VPHomeRecommandCell.swift in Sources */,
|
||||
BF0FA7322DDEBD6400C9E5F2 /* AppDelegate+Config.swift in Sources */,
|
||||
BF5E75D52DE56B2000DE9DFE /* VPHomeCagetoryRecommandContentCell.swift in Sources */,
|
||||
BF0FA7B32DE447FE00C9E5F2 /* VPMeCell.swift in Sources */,
|
||||
BF0FA6DF2DDC5E4D00C9E5F2 /* String+VPAdd.swift in Sources */,
|
||||
BF0FA7002DDC665300C9E5F2 /* VPShortModel.swift in Sources */,
|
||||
1B056E7B2DDB37BA007EE38D /* VPGradientView.swift in Sources */,
|
||||
BF0FA7262DDC8F7600C9E5F2 /* VPCollectionView.swift in Sources */,
|
||||
BF5E75DB2DE5B8B700DE9DFE /* VPMarqueeView.swift in Sources */,
|
||||
BF0FA7C32DE45DE300C9E5F2 /* VPUserAPI.swift in Sources */,
|
||||
BF0FA78B2DE164C100C9E5F2 /* VPSearchResultCell.swift in Sources */,
|
||||
BF0FA71D2DDC807200C9E5F2 /* UIImageView+VPAdd.swift in Sources */,
|
||||
@ -1031,6 +1079,15 @@
|
||||
BF0FA7B12DE447EB00C9E5F2 /* VPMeItem.swift in Sources */,
|
||||
1B056E2C2DDAC0FD007EE38D /* SceneDelegate.swift in Sources */,
|
||||
BF0FA75D2DDF208400C9E5F2 /* VPExplorePlayerControlView.swift in Sources */,
|
||||
BF5E75CB2DE5692D00DE9DFE /* UINavigationController+JXTransition.swift in Sources */,
|
||||
BF5E75CC2DE5692D00DE9DFE /* JXTransitionDefine.swift in Sources */,
|
||||
BF5E75CD2DE5692D00DE9DFE /* JXTransitionDelegateBridge.swift in Sources */,
|
||||
BF5E75CE2DE5692D00DE9DFE /* JXPushAnimatedTransition.swift in Sources */,
|
||||
BF5E75CF2DE5692D00DE9DFE /* UIViewController+JXTransition.swift in Sources */,
|
||||
BF5E75D02DE5692D00DE9DFE /* UIGestureRecognizer+JXTransition.swift in Sources */,
|
||||
BF5E75D12DE5692D00DE9DFE /* JXPopAnimatedTransition.swift in Sources */,
|
||||
BF5E75D22DE5692D00DE9DFE /* JXNavigationInteractiveTransition.swift in Sources */,
|
||||
BF5E75D32DE5692D00DE9DFE /* JXBaseAnimatedTransition.swift in Sources */,
|
||||
1B056E462DDAC370007EE38D /* UIScreen+VPAdd.swift in Sources */,
|
||||
BF0FA7692DE0502900C9E5F2 /* VPEpisodeCell.swift in Sources */,
|
||||
BF5E75BE2DE54B2800DE9DFE /* VPAboutUsHeaderView.swift in Sources */,
|
||||
@ -1047,6 +1104,7 @@
|
||||
BF0FA75F2DDFFDB000C9E5F2 /* VPDetailPlayerViewController.swift in Sources */,
|
||||
BF0FA7732DE0671200C9E5F2 /* VPRateSelectedCell.swift in Sources */,
|
||||
1B056E4D2DDAC7C1007EE38D /* VPTabBarController.swift in Sources */,
|
||||
BF5E75C02DE5566200DE9DFE /* VPHomePageControlView.swift in Sources */,
|
||||
BF0FA6DA2DDC5CB600C9E5F2 /* VPLoginManager.swift in Sources */,
|
||||
BF0FA74A2DDF04E200C9E5F2 /* VPPlayerProtocol.swift in Sources */,
|
||||
BF0FA72C2DDD7B7300C9E5F2 /* VPHomeRankingContentCell.swift in Sources */,
|
||||
@ -1059,7 +1117,6 @@
|
||||
1B056E3F2DDAC2DB007EE38D /* VPCryptorService.swift in Sources */,
|
||||
BF0FA7202DDC83AE00C9E5F2 /* JXButton.swift in Sources */,
|
||||
BF0FA7912DE16CBF00C9E5F2 /* VPSearchHistoryView.swift in Sources */,
|
||||
BF0FA7072DDC687C00C9E5F2 /* VPHomeDataItem.swift in Sources */,
|
||||
BF0FA7992DE1951A00C9E5F2 /* VPMyListViewController.swift in Sources */,
|
||||
BF0FA7452DDF027900C9E5F2 /* VPPlayer.swift in Sources */,
|
||||
BF0FA70E2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift in Sources */,
|
||||
@ -1096,7 +1153,6 @@
|
||||
BF5E75B82DE46F7100DE9DFE /* VPNetworkReachabilityManager.swift in Sources */,
|
||||
BF0FA6D52DDC5B5D00C9E5F2 /* VPApi.swift in Sources */,
|
||||
BF0FA7C12DE45D5D00C9E5F2 /* VPUserInfo.swift in Sources */,
|
||||
BF0FA6FC2DDC657500C9E5F2 /* VPHomeDataModel.swift in Sources */,
|
||||
BF0FA7392DDECF8900C9E5F2 /* VPHomeListViewController.swift in Sources */,
|
||||
BF0FA6F62DDC616300C9E5F2 /* VPToast.swift in Sources */,
|
||||
BF0FA7B62DE44E8000C9E5F2 /* VPWebView.swift in Sources */,
|
||||
@ -1140,7 +1196,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = 394VH538M8;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Veloria/Source/Info.plist;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
@ -1154,7 +1210,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.zeng.VideoPlayer;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.qjwl168.veloria.ios;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
@ -1175,7 +1231,7 @@
|
||||
CLANG_ENABLE_MODULES = YES;
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 1;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
DEVELOPMENT_TEAM = 394VH538M8;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
INFOPLIST_FILE = Veloria/Source/Info.plist;
|
||||
INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
|
||||
@ -1189,7 +1245,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 1.0;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.zeng.VideoPlayer;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.qjwl168.veloria.ios;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
|
||||
SUPPORTS_MACCATALYST = NO;
|
||||
|
@ -11,8 +11,7 @@ class VPNavigationController: UINavigationController {
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
// self.interactivePopGestureRecognizer?.delegate = self
|
||||
self.jx_transitionAwake()
|
||||
}
|
||||
|
||||
override func pushViewController(_ viewController: UIViewController, animated: Bool) {
|
||||
|
@ -17,8 +17,8 @@ let VPCampaignWebURL = "https://campaign.qjwl168.com"
|
||||
let VPBaseURL = "https://api-qjwl168.qjwl168.com"
|
||||
let VPURLPathPrefix = "/velo"
|
||||
|
||||
let VPWebBaseURL = "https://www.thimratv.com"
|
||||
let VPCampaignWebURL = "https://campaign.moviatv.com"
|
||||
let VPWebBaseURL = "https://www.qjwl168.com"
|
||||
let VPCampaignWebURL = "https://campaign.qjwl168.com"
|
||||
#endif
|
||||
|
||||
///用户协议
|
||||
@ -43,4 +43,4 @@ let kVPFeedBackListWebUrl = VPCampaignWebURL + "/pages/leave/list"
|
||||
///反馈详情
|
||||
let kVPFeedBackDetailWebUrl = VPCampaignWebURL + "/pages/leave/detail"
|
||||
///活动页面
|
||||
let kVPRewardsWebUrl = VPCampaignWebURL
|
||||
let kVPRewardsWebUrl = VPCampaignWebURL + "/pages/reward/theme4"
|
||||
|
@ -6,7 +6,6 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import ESTabBarController_swift
|
||||
|
||||
class VPTabBarItemContentView: UIView {
|
||||
|
||||
|
@ -64,13 +64,13 @@ class VPHomePageViewController: VPViewController {
|
||||
let height = UIScreen.height - y
|
||||
let pageView = WMZPageView(frame: CGRect(x: 0, y: y, width: width, height: height), param: pageParam, parentReponder: self)
|
||||
pageView.param = pageParam
|
||||
// pageView.downSc?.delegate = self
|
||||
pageView.downSc?.dataSource = self
|
||||
pageView.downSc?.isScrollEnabled = true
|
||||
pageView.downSc?.separatorStyle = .none
|
||||
pageView.downSc?.register(VPHomeItemContentCell.self, forCellReuseIdentifier: "cell")
|
||||
pageView.downSc?.register(VPHomeBannerContentCell.self, forCellReuseIdentifier: VPHomeBannerContentCell.moduleKey.rawValue)
|
||||
pageView.downSc?.register(VPHomeRecommandContentCell.self, forCellReuseIdentifier: VPHomeRecommandContentCell.moduleKey.rawValue)
|
||||
pageView.downSc?.register(VPHomeCagetoryRecommandContentCell.self, forCellReuseIdentifier: VPHomeCagetoryRecommandContentCell.moduleKey.rawValue)
|
||||
pageView.downSc?.register(VPHomeRankingContentCell.self, forCellReuseIdentifier: VPHomeRankingContentCell.moduleKey.rawValue)
|
||||
pageView.downSc?.vp_addRefreshHeader(block: { [weak self] in
|
||||
self?.handleHeaderRefresh(nil)
|
||||
@ -146,6 +146,7 @@ class VPHomePageViewController: VPViewController {
|
||||
} else {
|
||||
self.pageView.downSc?.vp_endHeaderRefreshing()
|
||||
}
|
||||
self.requestHomeData()
|
||||
|
||||
}
|
||||
|
||||
@ -246,9 +247,13 @@ extension VPHomePageViewController {
|
||||
guard let self = self else { return }
|
||||
if let list = list {
|
||||
self.viewModel.oldModuleList = list
|
||||
self.pageParam.wTitleArr = self.viewModel.categoryTitleList
|
||||
self.pageView.updateMenuData()
|
||||
self.setupPageView()
|
||||
if self.viewModel.needUpdateCategory {
|
||||
self.viewModel.needUpdateCategory = false
|
||||
self.pageParam.wTitleArr = self.viewModel.categoryTitleList
|
||||
self.pageView.updateMenuData()
|
||||
self.setupPageView()
|
||||
}
|
||||
self.searchButton.marqueeArr = self.viewModel.marqueeArr
|
||||
|
||||
self.pageView.downSc?.reloadData()
|
||||
}
|
||||
|
@ -21,6 +21,7 @@ class VPSearchViewController: VPViewController {
|
||||
|
||||
private lazy var textView: VPSearchInputView = {
|
||||
let view = VPSearchInputView()
|
||||
view.textField.delegate = self
|
||||
view.textDidChange = { [weak self] text in
|
||||
self?.textDidChange(text: text)
|
||||
}
|
||||
@ -45,12 +46,20 @@ class VPSearchViewController: VPViewController {
|
||||
|
||||
vp_setupUI()
|
||||
vp_addAction()
|
||||
|
||||
let tap = UITapGestureRecognizer(target: self, action: #selector(handleScreen))
|
||||
self.view.addGestureRecognizer(tap)
|
||||
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
||||
}
|
||||
|
||||
@objc private func handleScreen() {
|
||||
VPAppTool.keyWindow?.endEditing(true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -109,3 +118,13 @@ extension VPSearchViewController {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -------------- UITextFieldDelegate --------------
|
||||
extension VPSearchViewController: UITextFieldDelegate {
|
||||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||||
self.viewModel.addHistory(text: textField.text ?? "")
|
||||
VPAppTool.keyWindow?.endEditing(true)
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +0,0 @@
|
||||
//
|
||||
// VPHomeDataItem.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by Veloria on 2025/5/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPHomeDataItem: VPModel {
|
||||
enum ItemType: String {
|
||||
case banner
|
||||
}
|
||||
|
||||
|
||||
var type: ItemType = .banner
|
||||
var list: [VPShortModel]?
|
||||
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
//
|
||||
// VPHomeDataModel.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by Veloria on 2025/5/20.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SmartCodable
|
||||
|
||||
class VPHomeDataModel: VPModel, SmartCodable {
|
||||
|
||||
|
||||
var bannerData: [VPShortModel]?
|
||||
///首页九宫格数据
|
||||
var nineSquare: VPNineSquareModel?
|
||||
///新剧列表
|
||||
var manualNewestRecommand: [VPShortModel]?
|
||||
///热门排行
|
||||
var hotData: [VPShortModel]?
|
||||
}
|
||||
|
||||
class VPNineSquareModel: VPModel, SmartCodable {
|
||||
|
||||
var list: [VPShortModel]?
|
||||
var title: String?
|
||||
}
|
@ -13,8 +13,12 @@ class VPHomeModuleItem: VPModel, SmartCodable {
|
||||
enum ModuleKey: String, SmartCaseDefaultable {
|
||||
case banner = "home_banner"
|
||||
case v3_recommand = "home_v3_recommand"
|
||||
///分类推荐
|
||||
case cagetory_recommand = "home_cagetory_recommand"
|
||||
case week_ranking = "week_ranking"
|
||||
case category_navigation = "category_navigation"
|
||||
///跑马灯
|
||||
case marquee = "marquee"
|
||||
}
|
||||
|
||||
|
||||
@ -41,6 +45,7 @@ class VPHomeModuleItem: VPModel, SmartCodable {
|
||||
dataList = list
|
||||
|
||||
} else if let list = data["shortPlayList"] as? [[String : Any]] {
|
||||
self.title = data["category_name"] as? String
|
||||
dataList = list
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ class VPHomeBannerContentCell: VPHomeItemContentCell {
|
||||
|
||||
override var item: VPHomeModuleItem? {
|
||||
didSet {
|
||||
pageControl.count = item?.list?.count ?? 0
|
||||
bannerView.reloadData()
|
||||
}
|
||||
}
|
||||
@ -26,9 +27,18 @@ class VPHomeBannerContentCell: VPHomeItemContentCell {
|
||||
view.hidesPageControl = true
|
||||
view.layer.cornerRadius = 10
|
||||
view.layer.masksToBounds = true
|
||||
view.loadCompletion = { [weak self] in
|
||||
guard let self = self else { return }
|
||||
self.pageControl.currentIndex = self.bannerView.currentIdx
|
||||
}
|
||||
view.register(VPHomeBannerCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var pageControl: VPHomePageControlView = {
|
||||
let view = VPHomePageControlView()
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
|
||||
super.init(style: style, reuseIdentifier: reuseIdentifier)
|
||||
@ -46,6 +56,7 @@ extension VPHomeBannerContentCell {
|
||||
|
||||
private func vp_setupUI() {
|
||||
containerView.addSubview(bannerView)
|
||||
bannerView.addSubview(pageControl)
|
||||
|
||||
bannerView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
@ -54,6 +65,11 @@ extension VPHomeBannerContentCell {
|
||||
make.bottom.equalToSuperview()
|
||||
make.height.equalTo(182)
|
||||
}
|
||||
|
||||
pageControl.snp.makeConstraints { make in
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
make.right.equalToSuperview().offset(-10)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -72,6 +88,10 @@ extension VPHomeBannerContentCell: ZKCycleScrollViewDataSource, ZKCycleScrollVie
|
||||
return cell
|
||||
}
|
||||
|
||||
func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, didScrollFromIndex fromIndex: Int, toIndex: Int) {
|
||||
pageControl.currentIndex = toIndex
|
||||
}
|
||||
|
||||
func cycleScrollView(_ cycleScrollView: ZKCycleScrollView, didSelectItemAt index: Int) {
|
||||
guard let model = self.item?.list?[index] else { return }
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
//
|
||||
// VPHomeCagetoryRecommandContentCell.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/27.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPHomeCagetoryRecommandContentCell: VPHomeRecommandContentCell {
|
||||
|
||||
override class var moduleKey: VPHomeModuleItem.ModuleKey {
|
||||
return .cagetory_recommand
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
90
Veloria/Class/Home/View/VPHomePageControlView.swift
Normal file
@ -0,0 +1,90 @@
|
||||
//
|
||||
// VPHomePageControlView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/27.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPHomePageControlView: UIView {
|
||||
|
||||
var currentIndex: Int = 0 {
|
||||
didSet {
|
||||
if count == 0 { return }
|
||||
if currentIndex >= count {
|
||||
currentIndex = 0
|
||||
return
|
||||
}
|
||||
|
||||
for view in self.stackView.arrangedSubviews {
|
||||
if let view = view as? UIButton {
|
||||
view.isSelected = view.tag == currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var count = 0 {
|
||||
didSet {
|
||||
self.stackView.removeAllArrangedSubview()
|
||||
|
||||
for i in 0..<count {
|
||||
let view = createDotView()
|
||||
view.tag = i
|
||||
view.isSelected = i == currentIndex
|
||||
stackView.addArrangedSubview(view)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let view = UIStackView()
|
||||
view.axis = .horizontal
|
||||
view.spacing = 4
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
addSubview(stackView)
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.edges.equalToSuperview()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
private func createDotView() -> UIButton {
|
||||
var config = UIButton.Configuration.plain()
|
||||
config.contentInsets = .zero
|
||||
|
||||
let button = UIButton(configuration: config)
|
||||
button.configurationUpdateHandler = { [weak self] button in
|
||||
guard let _ = self else { return }
|
||||
if button.isSelected {
|
||||
button.backgroundColor = .color7C174F()
|
||||
button.layer.borderWidth = 0
|
||||
} else {
|
||||
button.backgroundColor = .clear
|
||||
button.layer.borderWidth = 1
|
||||
}
|
||||
}
|
||||
button.layer.cornerRadius = 3
|
||||
button.layer.masksToBounds = true
|
||||
button.layer.borderColor = UIColor.colorFFFFFF(alpha: 0.35).cgColor
|
||||
button.snp.makeConstraints { make in
|
||||
make.width.height.equalTo(6)
|
||||
}
|
||||
|
||||
return button
|
||||
}
|
||||
|
||||
}
|
@ -15,6 +15,12 @@ class VPHomeRankingContentCell: VPHomeItemContentCell {
|
||||
|
||||
override var item: VPHomeModuleItem? {
|
||||
didSet {
|
||||
let list = item?.list ?? []
|
||||
if list.count > 3, list.count % 3 != 0 {
|
||||
var newCount = list.count / 3
|
||||
newCount = newCount * 3
|
||||
item?.list = Array(list.prefix(upTo: newCount))
|
||||
}
|
||||
collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
@ -20,6 +20,11 @@ class VPHomeRecommandContentCell: VPHomeItemContentCell {
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var iconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "hot_icon_03"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 15)
|
||||
@ -63,11 +68,29 @@ extension VPHomeRecommandContentCell {
|
||||
containerView.addSubview(titleLabel)
|
||||
containerView.addSubview(collectionView)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.top.equalToSuperview()
|
||||
if Self.moduleKey == .v3_recommand {
|
||||
|
||||
containerView.addSubview(iconImageView)
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(38)
|
||||
make.centerY.equalTo(iconImageView)
|
||||
}
|
||||
} else {
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
// make.centerY.equalTo(iconImageView)
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
|
@ -9,11 +9,27 @@ import UIKit
|
||||
|
||||
class VPHomeSearchButton: UIControl {
|
||||
|
||||
var marqueeArr: [VPShortModel] = [] {
|
||||
didSet {
|
||||
marqueeView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var currentIndex = 0
|
||||
|
||||
private lazy var iconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "search_icon_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
|
||||
private lazy var marqueeView: VPMarqueeView = {
|
||||
let view = VPMarqueeView()
|
||||
view.dataSource = self
|
||||
view.start()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var textLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontRegular(ofSize: 14)
|
||||
@ -46,7 +62,7 @@ extension VPHomeSearchButton {
|
||||
|
||||
|
||||
addSubview(iconImageView)
|
||||
addSubview(textLabel)
|
||||
addSubview(marqueeView)
|
||||
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
@ -54,10 +70,32 @@ extension VPHomeSearchButton {
|
||||
make.left.equalToSuperview().offset(10)
|
||||
}
|
||||
|
||||
textLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
marqueeView.snp.makeConstraints { make in
|
||||
make.left.equalTo(iconImageView.snp.right).offset(6)
|
||||
make.top.bottom.equalToSuperview()
|
||||
make.right.equalToSuperview().offset(-10)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPHomeSearchButton: VPMarqueeViewDataSource {
|
||||
func numberOfItems(_ marqueeView: VPMarqueeView) -> Int {
|
||||
return marqueeArr.count == 0 ? 1 : marqueeArr.count
|
||||
}
|
||||
|
||||
func marqueeView(_ marqueeView: VPMarqueeView, cellForItemAt index: Int) -> NSAttributedString {
|
||||
var text: String
|
||||
if marqueeArr.count == 0 {
|
||||
text = "kSearchPlaceholderText1".localized
|
||||
} else {
|
||||
text = marqueeArr[index].name ?? ""
|
||||
}
|
||||
|
||||
let string = NSMutableAttributedString(string: text)
|
||||
string.font = .fontRegular(ofSize: 14)
|
||||
string.color = .colorFFFFFF(alpha: 0.3)
|
||||
|
||||
return string
|
||||
}
|
||||
}
|
||||
|
@ -78,7 +78,7 @@ extension VPSearchHistoryView {
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.top.equalToSuperview().offset(20)
|
||||
make.top.equalToSuperview().offset(0)
|
||||
}
|
||||
|
||||
deleteButton.snp.makeConstraints { make in
|
||||
@ -90,7 +90,7 @@ extension VPSearchHistoryView {
|
||||
|
||||
tagView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(48)
|
||||
make.top.equalToSuperview().offset(28)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
@ -25,9 +25,10 @@ class VPSearchInputView: UIView {
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var textField: VPTextField = {
|
||||
private(set) lazy var textField: VPTextField = {
|
||||
let textField = VPTextField()
|
||||
textField.font = .fontRegular(ofSize: 14)
|
||||
textField.returnKeyType = .search
|
||||
textField.vp_placeholder = "kSearchPlaceholderText2".localized
|
||||
textField.vp_placeholderFont = textField.font
|
||||
textField.textDidChange = { [weak self] text in
|
||||
|
@ -88,6 +88,7 @@ class VPSearchRecommendedContentView: VPGradientView {
|
||||
collectionView.dataSource = self
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.register(VPSearchRecommendedCell.self, forCellWithReuseIdentifier: "cell")
|
||||
collectionView.keyboardDismissMode = .onDrag
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
|
@ -90,7 +90,7 @@ extension VPSearchRecommendedView {
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.right.equalToSuperview().offset(-15)
|
||||
make.top.equalToSuperview()
|
||||
make.height.equalTo(self).offset(-(30 + UIScreen.tabbarSafeBottomMargin))
|
||||
make.height.equalTo(self).offset(-(30 + UIScreen.tabbarSafeBottomMargin + 10))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,6 +36,8 @@ class VPSearchResultView: UIView {
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.register(VPSearchResultCell.self, forCellWithReuseIdentifier: "cell")
|
||||
collectionView.vp_addNormalEmpty(image: UIImage(named: "empty_image_02"))
|
||||
collectionView.keyboardDismissMode = .onDrag
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
|
@ -19,10 +19,16 @@ class VPHomeViewModel: VPModel {
|
||||
///筛选后的数据
|
||||
private(set) lazy var newModuleList: [VPHomeModuleItem] = []
|
||||
|
||||
|
||||
///需要更新分类数据
|
||||
var needUpdateCategory = true
|
||||
///分类列表
|
||||
private(set) lazy var categoryList: [VPCategoryModel] = []
|
||||
private(set) lazy var categoryTitleList: [String] = []
|
||||
|
||||
///跑马灯数据
|
||||
private(set) lazy var marqueeArr: [VPShortModel] = []
|
||||
|
||||
|
||||
///筛选模版数据
|
||||
private func filterModuleData() {
|
||||
@ -33,20 +39,24 @@ class VPHomeViewModel: VPModel {
|
||||
if key == .banner {
|
||||
newModuleList.insert($0, at: 0)
|
||||
|
||||
} else if key == .category_navigation {
|
||||
categoryList.removeAll()
|
||||
categoryTitleList.removeAll()
|
||||
|
||||
let allCategory = VPCategoryModel()
|
||||
allCategory.category_name = "All".localized
|
||||
allCategory.category_id = "0"
|
||||
categoryList.append(allCategory)
|
||||
categoryList += ($0.categoryList ?? [])
|
||||
|
||||
categoryList.forEach { model in
|
||||
categoryTitleList.append(model.category_name ?? "")
|
||||
} else if key == .category_navigation { //分类数据
|
||||
if needUpdateCategory {
|
||||
categoryList.removeAll()
|
||||
categoryTitleList.removeAll()
|
||||
|
||||
let allCategory = VPCategoryModel()
|
||||
allCategory.category_name = "All".localized
|
||||
allCategory.category_id = "0"
|
||||
categoryList.append(allCategory)
|
||||
categoryList += ($0.categoryList ?? [])
|
||||
|
||||
categoryList.forEach { model in
|
||||
categoryTitleList.append(model.category_name ?? "")
|
||||
}
|
||||
}
|
||||
|
||||
} else if key == .marquee { //跑马灯数据
|
||||
marqueeArr = $0.list ?? []
|
||||
} else {
|
||||
newModuleList.append($0)
|
||||
}
|
||||
|
@ -64,7 +64,8 @@ class VPCollectListViewController: VPViewController {
|
||||
private lazy var dataArr: [VPShortModel] = []
|
||||
private var page: Int = 1
|
||||
|
||||
|
||||
///更新节点,当节点大于1时,下次进入页面会更新列表
|
||||
private var updateNode = 0
|
||||
|
||||
private lazy var allSelectedButton: UIButton = {
|
||||
var config = UIButton.Configuration.plain()
|
||||
@ -117,9 +118,14 @@ class VPCollectListViewController: VPViewController {
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(updateShortCollectStateNotification), name: VPVideoAPI.updateShortCollectStateNotification, object: nil)
|
||||
|
||||
self.bgImageView.isHidden = true
|
||||
self.view.backgroundColor = .clear
|
||||
|
||||
@ -128,6 +134,14 @@ class VPCollectListViewController: VPViewController {
|
||||
requestDataArr(page: 1, completer: nil)
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool) {
|
||||
super.viewDidAppear(animated)
|
||||
if updateNode > 0 {
|
||||
updateNode = 0
|
||||
requestDataArr(page: 1, completer: nil)
|
||||
}
|
||||
}
|
||||
|
||||
override func handleHeaderRefresh(_ completer: (() -> Void)?) {
|
||||
requestDataArr(page: 1) { [weak self] in
|
||||
self?.collectionView.vp_endHeaderRefreshing()
|
||||
@ -220,6 +234,15 @@ extension VPCollectListViewController: UICollectionViewDelegate, UICollectionVie
|
||||
|
||||
}
|
||||
|
||||
extension VPCollectListViewController {
|
||||
|
||||
@objc private func updateShortCollectStateNotification() {
|
||||
if !self.isDidAppear {
|
||||
updateNode += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension VPCollectListViewController {
|
||||
|
||||
private func requestDataArr(page: Int, completer: (() -> Void)?) {
|
||||
|
@ -47,7 +47,8 @@ class VPShortModel: VPModel, SmartCodable {
|
||||
|
||||
static func mappingForKey() -> [SmartKeyTransformer]? {
|
||||
return [
|
||||
CodingKeys.vp_description <--- ["description"]
|
||||
CodingKeys.vp_description <--- ["description"],
|
||||
CodingKeys.name <--- ["short_video_title", "name"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
131
Veloria/Libs/MarqueeView/VPMarqueeView.swift
Normal file
@ -0,0 +1,131 @@
|
||||
//
|
||||
// VPMarqueeView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/27.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
protocol VPMarqueeViewDataSource: NSObjectProtocol {
|
||||
|
||||
/// MARK: - 多少条数据
|
||||
func numberOfItems(_ marqueeView:VPMarqueeView) -> Int
|
||||
/// MARK: - 每条的attributedString
|
||||
func marqueeView(_ marqueeView:VPMarqueeView, cellForItemAt index:Int) -> NSAttributedString
|
||||
}
|
||||
|
||||
class VPMarqueeView: UIView {
|
||||
|
||||
weak var dataSource: VPMarqueeViewDataSource?
|
||||
|
||||
|
||||
private var timer: Timer?
|
||||
|
||||
private var totalCount = 0
|
||||
|
||||
private var currentIndex = 0
|
||||
|
||||
private var isFirstLayout = true
|
||||
|
||||
private lazy var scrollView: UIScrollView = {
|
||||
let scrollView = UIScrollView()
|
||||
scrollView.delegate = self
|
||||
scrollView.contentInsetAdjustmentBehavior = .never
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var oneLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var twoLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
self.isUserInteractionEnabled = false
|
||||
addSubview(scrollView)
|
||||
scrollView.addSubview(oneLabel)
|
||||
scrollView.addSubview(twoLabel)
|
||||
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
scrollView.frame = self.bounds
|
||||
oneLabel.frame = self.bounds
|
||||
twoLabel.frame = .init(x: 0, y: self.bounds.height, width: self.bounds.width, height: self.bounds.height)
|
||||
scrollView.contentSize = CGSize(width: self.bounds.width, height: self.bounds.height * 2)
|
||||
|
||||
if isFirstLayout {
|
||||
isFirstLayout = false
|
||||
reloadData()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func reloadData() {
|
||||
totalCount = self.dataSource?.numberOfItems(self) ?? 0
|
||||
_setData()
|
||||
}
|
||||
|
||||
func start() {
|
||||
if self.timer == nil {
|
||||
self.timer = Timer.scheduledTimer(timeInterval: 4, target: YYWeakProxy(target: self), selector: #selector(handleTimer), userInfo: nil, repeats: true)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension VPMarqueeView {
|
||||
|
||||
///设置数据
|
||||
private func _setData() {
|
||||
guard totalCount > 0 else { return }
|
||||
let nextIndex = getNextIndex()
|
||||
|
||||
oneLabel.attributedText = self.dataSource?.marqueeView(self, cellForItemAt: currentIndex)
|
||||
twoLabel.attributedText = self.dataSource?.marqueeView(self, cellForItemAt: nextIndex)
|
||||
|
||||
}
|
||||
|
||||
@objc private func handleTimer() {
|
||||
self.scrollView.setContentOffset(.init(x: 0, y: self.bounds.height), animated: true)
|
||||
}
|
||||
|
||||
private func getNextIndex() -> Int {
|
||||
guard totalCount > 0 else { return 0 }
|
||||
var nextIndex = currentIndex + 1
|
||||
if nextIndex >= totalCount {
|
||||
nextIndex = 0
|
||||
}
|
||||
return nextIndex
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: UIScrollViewDelegate
|
||||
extension VPMarqueeView: UIScrollViewDelegate {
|
||||
|
||||
func scrollViewDidEndScrollingAnimation(_ scrollView: UIScrollView) {
|
||||
guard totalCount > 0 else { return }
|
||||
let nextIndex = getNextIndex()
|
||||
|
||||
currentIndex = nextIndex
|
||||
_setData()
|
||||
self.scrollView.contentOffset = .zero
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -45,23 +45,24 @@ class VPUserInfo: VPModel, SmartCodable, NSSecureCoding {
|
||||
|
||||
|
||||
func encode(with coder: NSCoder) {
|
||||
// coder.encode(id, forKey: "id")
|
||||
// coder.encode(phone, forKey: "phone")
|
||||
// coder.encode(userToken, forKey: "userToken")
|
||||
// coder.encode(ipAddress, forKey: "ipAddress")
|
||||
// coder.encode(audioNum, forKey: "audioNum")
|
||||
// coder.encode(audioSeconds, forKey: "audioSeconds")
|
||||
coder.encode(id, forKey: "id")
|
||||
coder.encode(customer_id, forKey: "customer_id")
|
||||
coder.encode(is_tourist, forKey: "is_tourist")
|
||||
coder.encode(is_vip, forKey: "is_vip")
|
||||
coder.encode(avator, forKey: "avator")
|
||||
coder.encode(family_name, forKey: "family_name")
|
||||
coder.encode(giving_name, forKey: "giving_name")
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
super.init()
|
||||
|
||||
// id = coder.decodeObject(of: NSString.self, forKey: "id") as? String
|
||||
// phone = coder.decodeObject(of: NSString.self, forKey: "phone") as? String
|
||||
// userToken = coder.decodeObject(of: NSString.self, forKey: "userToken") as? String
|
||||
// ipAddress = coder.decodeObject(of: NSString.self, forKey: "ipAddress") as? String
|
||||
// audioNum = coder.decodeObject(of: NSNumber.self, forKey: "audioNum")?.intValue
|
||||
// audioSeconds = coder.decodeObject(of: NSNumber.self, forKey: "audioSeconds")?.intValue
|
||||
id = coder.decodeObject(of: NSString.self, forKey: "id") as? String
|
||||
customer_id = coder.decodeObject(of: NSString.self, forKey: "customer_id") as? String
|
||||
is_tourist = coder.decodeObject(of: NSNumber.self, forKey: "is_tourist")?.boolValue
|
||||
is_vip = coder.decodeObject(of: NSNumber.self, forKey: "is_vip")?.boolValue
|
||||
avator = coder.decodeObject(of: NSString.self, forKey: "avator") as? String
|
||||
family_name = coder.decodeObject(of: NSString.self, forKey: "family_name") as? String
|
||||
giving_name = coder.decodeObject(of: NSString.self, forKey: "giving_name") as? String
|
||||
}
|
||||
|
||||
}
|
||||
|
22
Veloria/Source/Assets.xcassets/icon/hot_icon_03.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Frame@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/icon/hot_icon_03.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/hot_icon_03.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.6 KiB |
22
Veloria/Source/Assets.xcassets/image/empty_image_02.imageset/Contents.json
vendored
Normal file
@ -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
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/image/empty_image_02.imageset/缺省页-搜索不到-切图图层@2x.png
vendored
Normal file
After Width: | Height: | Size: 40 KiB |
BIN
Veloria/Source/Assets.xcassets/image/empty_image_02.imageset/缺省页-搜索不到-切图图层@3x.png
vendored
Normal file
After Width: | Height: | Size: 72 KiB |
@ -0,0 +1,6 @@
|
||||
{
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
22
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_bg.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "bg@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "bg@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_bg.imageset/bg@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.0 MiB |
BIN
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_bg.imageset/bg@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.3 MiB |
22
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_logo_01.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "logo 8@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "logo 8@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_logo_01.imageset/logo 8@2x.png
vendored
Normal file
After Width: | Height: | Size: 32 KiB |
BIN
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_logo_01.imageset/logo 8@3x.png
vendored
Normal file
After Width: | Height: | Size: 64 KiB |
22
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_logo_02.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Veloria-白 2@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Veloria-白 2@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_logo_02.imageset/Veloria-白 2@2x.png
vendored
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
Veloria/Source/Assets.xcassets/launchScreen/launch_screen_logo_02.imageset/Veloria-白 2@3x.png
vendored
Normal file
After Width: | Height: | Size: 13 KiB |
@ -1,7 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23506"/>
|
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
@ -11,10 +13,31 @@
|
||||
<objects>
|
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" xcode11CocoaTouchSystemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
||||
<subviews>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_screen_bg" translatesAutoresizingMaskIntoConstraints="NO" id="qWu-nj-f9Q">
|
||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_screen_logo_01" translatesAutoresizingMaskIntoConstraints="NO" id="EQ4-Jv-Z6q">
|
||||
<rect key="frame" x="146.66666666666666" y="180" width="100" height="100"/>
|
||||
</imageView>
|
||||
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="launch_screen_logo_02" translatesAutoresizingMaskIntoConstraints="NO" id="Qh8-hT-7Mf">
|
||||
<rect key="frame" x="145.66666666666666" y="305" width="102" height="23"/>
|
||||
</imageView>
|
||||
</subviews>
|
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||
<constraints>
|
||||
<constraint firstItem="qWu-nj-f9Q" firstAttribute="leading" secondItem="Ze5-6b-2t3" secondAttribute="leading" id="5Xc-kg-HlL"/>
|
||||
<constraint firstItem="qWu-nj-f9Q" firstAttribute="top" secondItem="EQ4-Jv-Z6q" secondAttribute="top" constant="-180" id="AhQ-4f-lgy"/>
|
||||
<constraint firstAttribute="trailing" secondItem="qWu-nj-f9Q" secondAttribute="trailing" id="IpB-7D-pNp"/>
|
||||
<constraint firstItem="qWu-nj-f9Q" firstAttribute="top" secondItem="Ze5-6b-2t3" secondAttribute="top" id="R3a-fq-9AO"/>
|
||||
<constraint firstItem="EQ4-Jv-Z6q" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="dgm-le-gMF"/>
|
||||
<constraint firstItem="Qh8-hT-7Mf" firstAttribute="top" secondItem="EQ4-Jv-Z6q" secondAttribute="bottom" constant="25" id="wDA-4J-bqp"/>
|
||||
<constraint firstItem="Qh8-hT-7Mf" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="yZa-Ua-bSM"/>
|
||||
<constraint firstAttribute="bottom" secondItem="qWu-nj-f9Q" secondAttribute="bottom" id="z8R-Xt-OX9"/>
|
||||
</constraints>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@ -22,4 +45,9 @@
|
||||
<point key="canvasLocation" x="53" y="375"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="launch_screen_bg" width="375" height="812"/>
|
||||
<image name="launch_screen_logo_01" width="100" height="100"/>
|
||||
<image name="launch_screen_logo_02" width="102" height="23"/>
|
||||
</resources>
|
||||
</document>
|
||||
|
86
Veloria/Thirdparty/JXTransition/JXBaseAnimatedTransition.swift
vendored
Normal file
@ -0,0 +1,86 @@
|
||||
//
|
||||
// JXBaseAnimatedTransition.swift
|
||||
// Test
|
||||
//
|
||||
// Created by 曾觉新 on 2022/10/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class JXBaseAnimatedTransition: NSObject {
|
||||
|
||||
open var isHideTabBar = false
|
||||
|
||||
open var transitionContext: UIViewControllerContextTransitioning?
|
||||
open weak var containerView: UIView?
|
||||
open weak var fromViewController: UIViewController?
|
||||
open weak var toViewController: UIViewController?
|
||||
|
||||
open var contentView: UIView?
|
||||
|
||||
// open var isScale = false
|
||||
// open var shadowView: UIView!
|
||||
// open var isHideTabBar = false
|
||||
// open var contentView: UIView?
|
||||
|
||||
|
||||
open func getCapture(with view: UIView) -> UIImage? {
|
||||
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.isOpaque, 0)
|
||||
view.drawHierarchy(in: view.bounds, afterScreenUpdates: false)
|
||||
let image = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
return image
|
||||
}
|
||||
}
|
||||
|
||||
extension JXBaseAnimatedTransition: UIViewControllerAnimatedTransitioning {
|
||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||
return TimeInterval(UINavigationController.hideShowBarDuration)
|
||||
}
|
||||
|
||||
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
|
||||
let containerView = transitionContext.containerView
|
||||
|
||||
let fromVC = transitionContext.viewController(forKey: .from)
|
||||
let toVC = transitionContext.viewController(forKey: .to)
|
||||
|
||||
self.containerView = containerView
|
||||
self.fromViewController = fromVC
|
||||
self.toViewController = toVC
|
||||
self.transitionContext = transitionContext
|
||||
|
||||
animateTransition()
|
||||
}
|
||||
|
||||
|
||||
@objc open func animateTransition() {
|
||||
// SubClass Implementation
|
||||
}
|
||||
|
||||
public func completeTransition() {
|
||||
guard let transitionContext = self.transitionContext else { return }
|
||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||
}
|
||||
|
||||
public func animationDuration() -> TimeInterval {
|
||||
return self.transitionDuration(using: self.transitionContext)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension UIViewController {
|
||||
fileprivate struct AssociatedKeys {
|
||||
static var defCaptureImage: Int?
|
||||
}
|
||||
|
||||
public var jx_captureImage: UIImage? {
|
||||
get {
|
||||
guard let obj = objc_getAssociatedObject(self, &AssociatedKeys.defCaptureImage) else { return nil }
|
||||
return obj as? UIImage
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.defCaptureImage, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
}
|
||||
}
|
202
Veloria/Thirdparty/JXTransition/JXNavigationInteractiveTransition.swift
vendored
Normal file
@ -0,0 +1,202 @@
|
||||
//
|
||||
// JXNavigationInteractiveTransition.swift
|
||||
// Test
|
||||
//
|
||||
// Created by 曾觉新 on 2022/10/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class JXNavigationInteractiveTransition: NSObject {
|
||||
|
||||
|
||||
var interactionController: UIPercentDrivenInteractiveTransition?
|
||||
|
||||
var isGesturePush = false
|
||||
|
||||
weak var navigationController: UINavigationController!
|
||||
weak var visibleVC: UIViewController?
|
||||
|
||||
}
|
||||
|
||||
extension JXNavigationInteractiveTransition {
|
||||
|
||||
@objc func panGestureRecognizerAction(_ sender: UIPanGestureRecognizer) {
|
||||
guard let view = sender.view else { return }
|
||||
|
||||
|
||||
var progress = sender.translation(in: view).x / UIScreen.main.bounds.width
|
||||
let velocity = sender.velocity(in: sender.view)
|
||||
|
||||
|
||||
// 在手势开始的时候判断是push操作还是pop操作
|
||||
if sender.state == .began {
|
||||
isGesturePush = velocity.x < 0 ? true : false
|
||||
visibleVC = self.navigationController.visibleViewController
|
||||
}
|
||||
|
||||
if isGesturePush {
|
||||
progress = -progress
|
||||
}
|
||||
|
||||
progress = min(1, max(0, progress))
|
||||
// bcLog(message: progress)
|
||||
|
||||
switch sender.state {
|
||||
case .began:
|
||||
if self.isGesturePush {
|
||||
if let visibleVC = self.visibleVC {
|
||||
if visibleVC.jx_pushDelegate != nil {
|
||||
self.interactionController = UIPercentDrivenInteractiveTransition()
|
||||
visibleVC.jx_pushDelegate?.pushToNextViewController?()
|
||||
self.pushScrollBegan()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self.interactionController = UIPercentDrivenInteractiveTransition()
|
||||
self.navigationController.popViewController(animated: true)
|
||||
self.popScrollBegan()
|
||||
}
|
||||
|
||||
case .changed:
|
||||
self.interactionController?.update(progress)
|
||||
|
||||
if self.isGesturePush {
|
||||
self.pushScrollUpdate(progress: progress)
|
||||
} else {
|
||||
self.popScrollUpdate(progress: progress)
|
||||
}
|
||||
|
||||
default:
|
||||
|
||||
var pushFinished: Bool = false
|
||||
|
||||
var finishProgress = 0.5
|
||||
if self.isGesturePush {
|
||||
finishProgress = 0.3
|
||||
}
|
||||
|
||||
if progress > finishProgress {
|
||||
pushFinished = true
|
||||
self.interactionController?.finish()
|
||||
} else {
|
||||
pushFinished = false
|
||||
self.interactionController?.cancel()
|
||||
}
|
||||
|
||||
if self.isGesturePush {
|
||||
pushScrollEnded(finished: pushFinished)
|
||||
} else {
|
||||
popScrollEnded(finished: pushFinished)
|
||||
}
|
||||
|
||||
self.interactionController = nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func pushScrollBegan() {
|
||||
if let visibleVC = self.visibleVC {
|
||||
visibleVC.jx_pushDelegate?.viewControllerPushScrollBegan?()
|
||||
}
|
||||
}
|
||||
|
||||
func pushScrollUpdate(progress: CGFloat) {
|
||||
if let visibleVC = self.visibleVC {
|
||||
visibleVC.jx_pushDelegate?.viewControllerPushScrollUpdate?(progress: progress)
|
||||
}
|
||||
}
|
||||
|
||||
func pushScrollEnded(finished: Bool) {
|
||||
if let visibleVC = self.visibleVC {
|
||||
visibleVC.jx_pushDelegate?.viewControllerPushScrollEnded?(finished: finished)
|
||||
}
|
||||
}
|
||||
|
||||
func popScrollBegan() {
|
||||
if let visibleVC = self.visibleVC {
|
||||
visibleVC.jx_popDelegate?.viewControllerPopScrollBegan?()
|
||||
}
|
||||
}
|
||||
|
||||
func popScrollUpdate(progress: CGFloat) {
|
||||
if let visibleVC = self.visibleVC {
|
||||
visibleVC.jx_popDelegate?.viewControllerPopScrollUpdate?(progress: progress)
|
||||
}
|
||||
}
|
||||
|
||||
func popScrollEnded(finished: Bool) {
|
||||
if let visibleVC = self.visibleVC {
|
||||
visibleVC.jx_popDelegate?.viewControllerPopScrollEnded?(finished: finished)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension JXNavigationInteractiveTransition: UIGestureRecognizerDelegate {
|
||||
|
||||
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
|
||||
// ydLog(message: "滑动========\(gestureRecognizer.jxTag ?? "")")
|
||||
guard let jxTag = gestureRecognizer.jxTag else { return true }
|
||||
|
||||
// 忽略导航控制器正在做转场动画
|
||||
if self.navigationController.jx_isTransitioning == true { return false }
|
||||
|
||||
// 如果没有visibleViewController,不作处理
|
||||
guard let visibleVC = self.navigationController.visibleViewController else { return true }
|
||||
|
||||
//页面禁止了手势
|
||||
if visibleVC.jx_popGestureType == .disabled { return false }
|
||||
|
||||
if let _ = gestureRecognizer as? UIScreenEdgePanGestureRecognizer {
|
||||
if visibleVC.jx_popGestureType == .fullScreen { return false } //当前是全屏手势直接返回
|
||||
// 修复边缘侧滑返回失效的bug
|
||||
if self.navigationController.viewControllers.count <= 1 { return false }
|
||||
// ydLog(message: "滑动========这里是边缘手势返回")
|
||||
return true
|
||||
|
||||
} else if let panGesture = gestureRecognizer as? UIPanGestureRecognizer { //全屏滑动手势处理
|
||||
// 根据transition判断是左滑还是右滑
|
||||
let transition = panGesture.translation(in: gestureRecognizer.view)
|
||||
if transition.x == 0 { return false }
|
||||
|
||||
if jxTag == "pop" {
|
||||
if visibleVC.jx_popGestureType == .edge { return false }
|
||||
if transition.x <= 0 { return false } //左滑直接返回
|
||||
if self.navigationController.viewControllers.count <= 1 { return false }
|
||||
if visibleVC.jx_popDelegate?.viewControllerPopShouldScrollBegan?() == false { return false }
|
||||
visibleVC.jx_popDelegate?.viewControllerPopScrollBegan?()
|
||||
// ydLog(message: "滑动========这里是pop滑动")
|
||||
return true
|
||||
} else if jxTag == "push" {
|
||||
if transition.x >= 0 { return false } //右滑直接返回
|
||||
if visibleVC.jx_pushDelegate == nil { return false }
|
||||
// ydLog(message: "滑动========这里是push滑动")
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
extension JXNavigationInteractiveTransition: UINavigationControllerDelegate {
|
||||
|
||||
|
||||
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
|
||||
if interactionController != nil, operation == .pop {
|
||||
return JXPopAnimatedTransition()
|
||||
} else if interactionController != nil, operation == .push {
|
||||
return JXPushAnimatedTransition()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
///处理交互式转场
|
||||
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
|
||||
if animationController.isKind(of: JXBaseAnimatedTransition.self) {
|
||||
return interactionController
|
||||
}
|
||||
return nil
|
||||
}
|
||||
}
|
72
Veloria/Thirdparty/JXTransition/JXPopAnimatedTransition.swift
vendored
Normal file
@ -0,0 +1,72 @@
|
||||
//
|
||||
// JXPopAnimatedTransition.swift
|
||||
// Test
|
||||
//
|
||||
// Created by 曾觉新 on 2022/10/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class JXPopAnimatedTransition: JXBaseAnimatedTransition {
|
||||
|
||||
override func animateTransition() {
|
||||
guard let fromView = self.fromViewController?.view else { return }
|
||||
|
||||
var toView = self.toViewController?.view
|
||||
|
||||
if toView == nil { return }
|
||||
|
||||
self.containerView?.insertSubview(toView!, belowSubview: fromView)
|
||||
|
||||
let size = self.containerView?.bounds.size ?? .zero
|
||||
|
||||
self.isHideTabBar = (self.toViewController?.tabBarController != nil) && (self.fromViewController?.hidesBottomBarWhenPushed == true) && (self.toViewController?.jx_captureImage != nil)
|
||||
|
||||
if self.isHideTabBar {
|
||||
let captureView = UIImageView(image: self.toViewController?.jx_captureImage!)
|
||||
|
||||
captureView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
|
||||
self.containerView?.insertSubview(captureView, belowSubview: fromView)
|
||||
toView = captureView
|
||||
self.toViewController?.view.isHidden = true
|
||||
self.toViewController?.tabBarController?.tabBar.isHidden = true
|
||||
}
|
||||
self.contentView = toView
|
||||
|
||||
|
||||
fromView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
|
||||
toView!.frame = CGRect(x: -(0.3 * size.width), y: 0, width: size.width, height: size.height)
|
||||
|
||||
fromView.layer.shadowColor = UIColor.black.cgColor
|
||||
fromView.layer.shadowOpacity = 0.15
|
||||
fromView.layer.shadowRadius = 3.0
|
||||
|
||||
UIView.animate(withDuration: animationDuration(), delay: 0, options: .curveEaseInOut) {
|
||||
|
||||
fromView.frame = CGRect(x: size.width, y: 0, width: size.width, height: size.height)
|
||||
|
||||
if #available(iOS 11.0, *) {
|
||||
toView!.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
|
||||
}else {
|
||||
toView!.transform = .identity
|
||||
}
|
||||
|
||||
} completion: { finish in
|
||||
|
||||
if self.isHideTabBar {
|
||||
if self.contentView != nil {
|
||||
self.contentView?.removeFromSuperview()
|
||||
self.contentView = nil
|
||||
}
|
||||
self.toViewController?.view.isHidden = false
|
||||
if self.toViewController?.navigationController?.children.count == 1 {
|
||||
self.toViewController?.tabBarController?.tabBar.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
self.completeTransition()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
79
Veloria/Thirdparty/JXTransition/JXPushAnimatedTransition.swift
vendored
Normal file
@ -0,0 +1,79 @@
|
||||
//
|
||||
// JXPushAnimatedTransition.swift
|
||||
// Test
|
||||
//
|
||||
// Created by 曾觉新 on 2022/10/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class JXPushAnimatedTransition: JXBaseAnimatedTransition {
|
||||
|
||||
|
||||
override func animateTransition() {
|
||||
guard let toView = self.toViewController?.view else { return }
|
||||
|
||||
var fromView = self.fromViewController?.view
|
||||
|
||||
let size = self.containerView?.bounds.size ?? .zero
|
||||
|
||||
// 解决UITabBarController左滑push时的显示问题
|
||||
self.isHideTabBar = (self.fromViewController?.tabBarController != nil) && (self.toViewController?.hidesBottomBarWhenPushed == true)
|
||||
|
||||
|
||||
if self.isHideTabBar {
|
||||
// 获取fromViewController的截图
|
||||
let view: UIView?
|
||||
if self.fromViewController?.view.window != nil {
|
||||
view = self.fromViewController?.view.window
|
||||
}else {
|
||||
view = self.fromViewController?.view
|
||||
}
|
||||
|
||||
if view != nil {
|
||||
let captureImage = self.getCapture(with: view!)
|
||||
let captureView = UIImageView(image: captureImage)
|
||||
captureView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
|
||||
containerView?.addSubview(captureView)
|
||||
fromView = captureView
|
||||
self.fromViewController?.jx_captureImage = captureImage
|
||||
self.fromViewController?.view.isHidden = true
|
||||
self.fromViewController?.tabBarController?.tabBar.isHidden = true
|
||||
}
|
||||
}
|
||||
self.contentView = fromView
|
||||
|
||||
|
||||
self.containerView?.addSubview(toView)
|
||||
|
||||
|
||||
toView.frame = CGRect(x: size.width, y: 0, width: size.width, height: size.height)
|
||||
|
||||
toView.layer.shadowColor = UIColor.black.cgColor
|
||||
toView.layer.shadowOpacity = 0.15
|
||||
toView.layer.shadowRadius = 3.0
|
||||
|
||||
|
||||
UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, options: .curveEaseInOut) {
|
||||
|
||||
fromView?.frame = CGRect(x: -(0.3 * size.width), y: 0, width: size.width, height: size.height)
|
||||
toView.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height)
|
||||
|
||||
} completion: { finish in
|
||||
if self.isHideTabBar {
|
||||
if self.contentView != nil {
|
||||
self.contentView!.removeFromSuperview()
|
||||
self.contentView = nil
|
||||
}
|
||||
self.fromViewController?.view.isHidden = false
|
||||
|
||||
if self.fromViewController?.navigationController?.children.count == 1 {
|
||||
self.fromViewController?.tabBarController?.tabBar.isHidden = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
self.completeTransition()
|
||||
}
|
||||
}
|
||||
}
|
47
Veloria/Thirdparty/JXTransition/JXTransitionDefine.swift
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// JXTransitionDefine.swift
|
||||
// Test
|
||||
//
|
||||
// Created by 曾觉新 on 2022/10/11.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
public func jx_swizzled_instanceMethod(_ prefix: String, oldClass: Swift.AnyClass!, oldSelector: String, newClass: Swift.AnyClass) {
|
||||
let newSelector = prefix + "_" + oldSelector;
|
||||
|
||||
let originalSelector = NSSelectorFromString(oldSelector)
|
||||
let swizzledSelector = NSSelectorFromString(newSelector)
|
||||
|
||||
let originalMethod = class_getInstanceMethod(oldClass, originalSelector)
|
||||
let swizzledMethod = class_getInstanceMethod(newClass, swizzledSelector)
|
||||
|
||||
let isAdd = class_addMethod(oldClass, originalSelector, method_getImplementation(swizzledMethod!), method_getTypeEncoding(swizzledMethod!))
|
||||
|
||||
if isAdd {
|
||||
class_replaceMethod(newClass, swizzledSelector, method_getImplementation(originalMethod!), method_getTypeEncoding(originalMethod!))
|
||||
}else {
|
||||
method_exchangeImplementations(originalMethod!, swizzledMethod!)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Swizzling会改变全局状态,所以用DispatchQueue.once来确保无论多少线程都只会被执行一次
|
||||
extension DispatchQueue {
|
||||
private static var onceTracker = [String]()
|
||||
// Executes a block of code, associated with a unique token, only once. The code is thread safe and will only execute the code once even in the presence of multithreaded calls.
|
||||
public class func once(token: String, block: () -> Void) {
|
||||
// 保证被 objc_sync_enter 和 objc_sync_exit 包裹的代码可以有序同步地执行
|
||||
objc_sync_enter(self)
|
||||
defer { // 作用域结束后执行defer中的代码
|
||||
objc_sync_exit(self)
|
||||
}
|
||||
|
||||
if onceTracker.contains(token) {
|
||||
return
|
||||
}
|
||||
|
||||
onceTracker.append(token)
|
||||
block()
|
||||
}
|
||||
}
|
16
Veloria/Thirdparty/JXTransition/JXTransitionDelegateBridge.swift
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
//
|
||||
// JXTransitionDelegateBridge.swift
|
||||
// Test
|
||||
//
|
||||
// Created by 曾觉新 on 2022/10/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class JXTransitionDelegateBridge: NSObject {
|
||||
|
||||
weak var jx_pushDelegate: JXViewControllerPushDelegate?
|
||||
|
||||
weak var jx_popDelegate: JXViewControllerPopDelegate?
|
||||
|
||||
}
|
25
Veloria/Thirdparty/JXTransition/UIGestureRecognizer+JXTransition.swift
vendored
Normal file
@ -0,0 +1,25 @@
|
||||
//
|
||||
// UIGestureRecognizer+JXTransition.swift
|
||||
// YDLive
|
||||
//
|
||||
// Created by 曾觉新 on 2022/11/29.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIGestureRecognizer {
|
||||
|
||||
fileprivate struct AssociatedKeys {
|
||||
static var jxTag: Int?
|
||||
}
|
||||
|
||||
var jxTag: String? {
|
||||
get {
|
||||
guard let obj = objc_getAssociatedObject(self, &AssociatedKeys.jxTag) as? String else { return nil }
|
||||
return obj
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.jxTag, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
}
|
||||
}
|
130
Veloria/Thirdparty/JXTransition/UINavigationController+JXTransition.swift
vendored
Normal file
@ -0,0 +1,130 @@
|
||||
//
|
||||
// UINavigationController+JXTransition.swift
|
||||
// Test
|
||||
//
|
||||
// Created by 曾觉新 on 2022/10/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
extension UINavigationController {
|
||||
|
||||
/**
|
||||
承载手势的视图
|
||||
*/
|
||||
private var gestureView: UIView? {
|
||||
return self.interactivePopGestureRecognizer?.view
|
||||
}
|
||||
/**
|
||||
激活转场动画
|
||||
*/
|
||||
func jx_transitionAwake() {
|
||||
// UIViewController.jxTransitionAwake()
|
||||
|
||||
self.delegate = self.interactiveTransition
|
||||
self.interactivePopGestureRecognizer?.isEnabled = false
|
||||
|
||||
self.gestureView?.addGestureRecognizer(pushGesture)
|
||||
self.gestureView?.addGestureRecognizer(popGesture)
|
||||
self.gestureView?.addGestureRecognizer(edgePopGesture)
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension UINavigationController {
|
||||
fileprivate struct AssociatedKeys {
|
||||
static var screenPanGesture: Int?
|
||||
static var panGesture: Int?
|
||||
static var panPushGesture: Int?
|
||||
static var transition: Int?
|
||||
}
|
||||
|
||||
var interactiveTransition: JXNavigationInteractiveTransition {
|
||||
get {
|
||||
var transition = objc_getAssociatedObject(self, &AssociatedKeys.transition) as? JXNavigationInteractiveTransition
|
||||
if transition == nil {
|
||||
transition = JXNavigationInteractiveTransition()
|
||||
transition?.navigationController = self
|
||||
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.transition, transition, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
return transition!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
边缘滑动手势
|
||||
*/
|
||||
var edgePopGesture: UIScreenEdgePanGestureRecognizer {
|
||||
get {
|
||||
var panGesture = objc_getAssociatedObject(self, &AssociatedKeys.screenPanGesture) as? UIScreenEdgePanGestureRecognizer
|
||||
if panGesture == nil {
|
||||
panGesture = UIScreenEdgePanGestureRecognizer(target: self.systemTarget, action: self.systemAction)
|
||||
panGesture?.jxTag = "edgePop"
|
||||
panGesture?.edges = .left
|
||||
panGesture?.delegate = self.interactiveTransition
|
||||
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.screenPanGesture, panGesture, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
return panGesture!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
全屏返回手势
|
||||
*/
|
||||
var popGesture: UIPanGestureRecognizer {
|
||||
get {
|
||||
var panGesture = objc_getAssociatedObject(self, &AssociatedKeys.panGesture) as? UIPanGestureRecognizer
|
||||
if panGesture == nil {
|
||||
panGesture = UIPanGestureRecognizer(target: self.systemTarget, action: self.systemAction)
|
||||
panGesture?.jxTag = "pop"
|
||||
panGesture?.maximumNumberOfTouches = 1
|
||||
panGesture?.delegate = self.interactiveTransition
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.panGesture, panGesture, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
return panGesture!
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
全屏push手势
|
||||
*/
|
||||
var pushGesture: UIPanGestureRecognizer {
|
||||
get {
|
||||
var panGesture = objc_getAssociatedObject(self, &AssociatedKeys.panPushGesture) as? UIPanGestureRecognizer
|
||||
if panGesture == nil {
|
||||
panGesture = UIPanGestureRecognizer(target: self.interactiveTransition, action: #selector(self.interactiveTransition.panGestureRecognizerAction(_:)))
|
||||
panGesture?.jxTag = "push"
|
||||
panGesture?.maximumNumberOfTouches = 1
|
||||
panGesture?.delegate = self.interactiveTransition
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.panPushGesture, panGesture, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
return panGesture!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
var systemTarget: Any? {
|
||||
get {
|
||||
let internalTargets = self.interactivePopGestureRecognizer?.value(forKey: "targets") as? [AnyObject]
|
||||
let internamTarget = internalTargets?.first?.value(forKey: "target")
|
||||
return internamTarget
|
||||
}
|
||||
}
|
||||
var systemAction: Selector {
|
||||
return NSSelectorFromString("handleNavigationTransition:")
|
||||
}
|
||||
|
||||
/**
|
||||
是否正在做转场动画
|
||||
*/
|
||||
var jx_isTransitioning: Bool? {
|
||||
return value(forKey: "_isTransitioning") as? Bool
|
||||
}
|
||||
}
|
127
Veloria/Thirdparty/JXTransition/UIViewController+JXTransition.swift
vendored
Normal file
@ -0,0 +1,127 @@
|
||||
//
|
||||
// UIViewController+JXTransition.swift
|
||||
// Test
|
||||
//
|
||||
// Created by 曾觉新 on 2022/10/10.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
// 左滑push代理
|
||||
@objc public protocol JXViewControllerPushDelegate: NSObjectProtocol {
|
||||
/// 左滑push,在这里创建将要push的控制器
|
||||
@objc optional func pushToNextViewController()
|
||||
|
||||
/// push手势滑动开始
|
||||
@objc optional func viewControllerPushScrollBegan()
|
||||
|
||||
/// push手势滑动进度更新
|
||||
/// - Parameter progress: 进度(0-1)
|
||||
@objc optional func viewControllerPushScrollUpdate(progress: CGFloat)
|
||||
|
||||
/// push手势滑动结束
|
||||
/// - Parameter finished: 是否完成push操作(true:push成功 false:push取消)
|
||||
@objc optional func viewControllerPushScrollEnded(finished: Bool)
|
||||
}
|
||||
|
||||
// 右滑pop代理
|
||||
@objc public protocol JXViewControllerPopDelegate: NSObjectProtocol {
|
||||
|
||||
@objc optional func viewControllerPopShouldScrollBegan() -> Bool
|
||||
|
||||
/// pop手势滑动开始
|
||||
@objc optional func viewControllerPopScrollBegan()
|
||||
|
||||
/// pop手势滑动进度更新
|
||||
/// - Parameter progress: 进度(0-1)
|
||||
@objc optional func viewControllerPopScrollUpdate(progress: CGFloat)
|
||||
|
||||
/// pop手势滑动结束
|
||||
/// - Parameter finished: 是否完成pop操作(true:pop成功 false:pop取消)
|
||||
@objc optional func viewControllerPopScrollEnded(finished: Bool)
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
|
||||
// // MARK: - 重新系统方法
|
||||
// private static let onceToken = UUID().uuidString
|
||||
// @objc public static func jxTransitionAwake() {
|
||||
// DispatchQueue.once(token: onceToken) {
|
||||
// let oriSels = ["viewDidAppear:",]
|
||||
// for oriSel in oriSels {
|
||||
// jx_swizzled_instanceMethod("jxGesture", oldClass: self, oldSelector: oriSel, newClass: self)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// @objc func jxGesture_viewDidAppear(_ animated: Bool) {
|
||||
// jxGesture_viewDidAppear(animated)
|
||||
// }
|
||||
}
|
||||
|
||||
extension UIViewController {
|
||||
enum GestureTransitionType: Int {
|
||||
///全屏手势
|
||||
case fullScreen
|
||||
///边缘手势
|
||||
case edge
|
||||
///禁用手势
|
||||
case disabled
|
||||
|
||||
}
|
||||
|
||||
fileprivate struct AssociatedKeys {
|
||||
static var jxDelegateBridge: Int?
|
||||
static var jx_gestureType: Int?
|
||||
}
|
||||
|
||||
/**
|
||||
手势类型
|
||||
*/
|
||||
var jx_popGestureType: GestureTransitionType {
|
||||
get {
|
||||
guard let obj = objc_getAssociatedObject(self, &AssociatedKeys.jx_gestureType) as? GestureTransitionType else { return .fullScreen }
|
||||
return obj
|
||||
}
|
||||
set {
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.jx_gestureType, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
代理桥接
|
||||
*/
|
||||
fileprivate var jx_delegateBridge: JXTransitionDelegateBridge {
|
||||
get {
|
||||
var bridge = objc_getAssociatedObject(self, &AssociatedKeys.jxDelegateBridge) as? JXTransitionDelegateBridge
|
||||
if bridge == nil {
|
||||
bridge = JXTransitionDelegateBridge()
|
||||
objc_setAssociatedObject(self, &AssociatedKeys.jxDelegateBridge, bridge, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
|
||||
}
|
||||
return bridge!
|
||||
}
|
||||
}
|
||||
|
||||
var jx_pushDelegate: JXViewControllerPushDelegate? {
|
||||
get {
|
||||
return jx_delegateBridge.jx_pushDelegate
|
||||
}
|
||||
set {
|
||||
jx_delegateBridge.jx_pushDelegate = newValue
|
||||
}
|
||||
}
|
||||
|
||||
var jx_popDelegate: JXViewControllerPopDelegate? {
|
||||
get {
|
||||
return jx_delegateBridge.jx_popDelegate
|
||||
}
|
||||
set {
|
||||
jx_delegateBridge.jx_popDelegate = newValue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|