搜索功能完成
@ -97,6 +97,21 @@
|
||||
BF0FA76F2DE062A700C9E5F2 /* VPRateSelectedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA76E2DE062A700C9E5F2 /* VPRateSelectedView.swift */; };
|
||||
BF0FA7712DE062EB00C9E5F2 /* VPVideoRateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7702DE062EB00C9E5F2 /* VPVideoRateModel.swift */; };
|
||||
BF0FA7732DE0671200C9E5F2 /* VPRateSelectedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7722DE0671200C9E5F2 /* VPRateSelectedCell.swift */; };
|
||||
BF0FA7752DE071B500C9E5F2 /* VPSearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7742DE071B500C9E5F2 /* VPSearchViewController.swift */; };
|
||||
BF0FA7772DE0735800C9E5F2 /* VPSearchInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7762DE0735800C9E5F2 /* VPSearchInputView.swift */; };
|
||||
BF0FA7792DE075FF00C9E5F2 /* VPSearchHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7782DE075FF00C9E5F2 /* VPSearchHomeView.swift */; };
|
||||
BF0FA77B2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA77A2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift */; };
|
||||
BF0FA77D2DE078D400C9E5F2 /* VPSearchRecommendedView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA77C2DE078D400C9E5F2 /* VPSearchRecommendedView.swift */; };
|
||||
BF0FA7812DE150F700C9E5F2 /* VPSearchRecommendedContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7802DE150F700C9E5F2 /* VPSearchRecommendedContentView.swift */; };
|
||||
BF0FA7832DE1533E00C9E5F2 /* VPGradientLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7822DE1533E00C9E5F2 /* VPGradientLabel.swift */; };
|
||||
BF0FA7852DE1561D00C9E5F2 /* VPSearchRecommendedCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7842DE1561D00C9E5F2 /* VPSearchRecommendedCell.swift */; };
|
||||
BF0FA7872DE1601200C9E5F2 /* VPTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7862DE1601200C9E5F2 /* VPTextField.swift */; };
|
||||
BF0FA7892DE161F200C9E5F2 /* VPSearchResultView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7882DE161F200C9E5F2 /* VPSearchResultView.swift */; };
|
||||
BF0FA78B2DE164C100C9E5F2 /* VPSearchResultCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA78A2DE164C100C9E5F2 /* VPSearchResultCell.swift */; };
|
||||
BF0FA78D2DE16A8B00C9E5F2 /* VPSearchViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA78C2DE16A8B00C9E5F2 /* VPSearchViewModel.swift */; };
|
||||
BF0FA78F2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA78E2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift */; };
|
||||
BF0FA7912DE16CBF00C9E5F2 /* VPSearchHistoryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7902DE16CBF00C9E5F2 /* VPSearchHistoryView.swift */; };
|
||||
BF0FA7942DE16E9300C9E5F2 /* JXTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0FA7922DE16E9300C9E5F2 /* JXTagView.swift */; };
|
||||
F939C04AD4003BA127F15C28 /* Pods_Veloria.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 34F57E87E765BF8D72A43DCA /* Pods_Veloria.framework */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@ -200,6 +215,21 @@
|
||||
BF0FA76E2DE062A700C9E5F2 /* VPRateSelectedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPRateSelectedView.swift; sourceTree = "<group>"; };
|
||||
BF0FA7702DE062EB00C9E5F2 /* VPVideoRateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPVideoRateModel.swift; sourceTree = "<group>"; };
|
||||
BF0FA7722DE0671200C9E5F2 /* VPRateSelectedCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPRateSelectedCell.swift; sourceTree = "<group>"; };
|
||||
BF0FA7742DE071B500C9E5F2 /* VPSearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchViewController.swift; sourceTree = "<group>"; };
|
||||
BF0FA7762DE0735800C9E5F2 /* VPSearchInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchInputView.swift; sourceTree = "<group>"; };
|
||||
BF0FA7782DE075FF00C9E5F2 /* VPSearchHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchHomeView.swift; sourceTree = "<group>"; };
|
||||
BF0FA77A2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIStackView+VPAdd.swift"; sourceTree = "<group>"; };
|
||||
BF0FA77C2DE078D400C9E5F2 /* VPSearchRecommendedView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchRecommendedView.swift; sourceTree = "<group>"; };
|
||||
BF0FA7802DE150F700C9E5F2 /* VPSearchRecommendedContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchRecommendedContentView.swift; sourceTree = "<group>"; };
|
||||
BF0FA7822DE1533E00C9E5F2 /* VPGradientLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPGradientLabel.swift; sourceTree = "<group>"; };
|
||||
BF0FA7842DE1561D00C9E5F2 /* VPSearchRecommendedCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchRecommendedCell.swift; sourceTree = "<group>"; };
|
||||
BF0FA7862DE1601200C9E5F2 /* VPTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPTextField.swift; sourceTree = "<group>"; };
|
||||
BF0FA7882DE161F200C9E5F2 /* VPSearchResultView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchResultView.swift; sourceTree = "<group>"; };
|
||||
BF0FA78A2DE164C100C9E5F2 /* VPSearchResultCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchResultCell.swift; sourceTree = "<group>"; };
|
||||
BF0FA78C2DE16A8B00C9E5F2 /* VPSearchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchViewModel.swift; sourceTree = "<group>"; };
|
||||
BF0FA78E2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPUserDefaultsKey.swift; sourceTree = "<group>"; };
|
||||
BF0FA7902DE16CBF00C9E5F2 /* VPSearchHistoryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VPSearchHistoryView.swift; sourceTree = "<group>"; };
|
||||
BF0FA7922DE16E9300C9E5F2 /* JXTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JXTagView.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 */
|
||||
|
||||
@ -284,6 +314,7 @@
|
||||
1B056E362DDAC1E8007EE38D /* Class */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA7952DE1948A00C9E5F2 /* MyList */,
|
||||
1B056E522DDACBF4007EE38D /* Home */,
|
||||
BF0FA7422DDF024400C9E5F2 /* Explore */,
|
||||
BF0FA6FD2DDC65F300C9E5F2 /* Player */,
|
||||
@ -324,6 +355,8 @@
|
||||
BF0FA7252DDC8F7600C9E5F2 /* VPCollectionView.swift */,
|
||||
BF0FA7272DDC91F800C9E5F2 /* VPCollectionViewCell.swift */,
|
||||
BF0FA76C2DE053C100C9E5F2 /* VPScrollView.swift */,
|
||||
BF0FA7822DE1533E00C9E5F2 /* VPGradientLabel.swift */,
|
||||
BF0FA7862DE1601200C9E5F2 /* VPTextField.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -350,6 +383,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1B056E4A2DDAC6BA007EE38D /* VPDefine.swift */,
|
||||
BF0FA78E2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift */,
|
||||
);
|
||||
path = Define;
|
||||
sourceTree = "<group>";
|
||||
@ -378,6 +412,7 @@
|
||||
BF0FA7212DDC859D00C9E5F2 /* NSNumber+VPAdd.swift */,
|
||||
BF0FA72F2DDEBB1600C9E5F2 /* UIButton+VPAdd.swift */,
|
||||
BF0FA7402DDEFBC700C9E5F2 /* UIScrollView+VPRefresh.swift */,
|
||||
BF0FA77A2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift */,
|
||||
);
|
||||
path = Extension;
|
||||
sourceTree = "<group>";
|
||||
@ -406,6 +441,7 @@
|
||||
children = (
|
||||
1B056E562DDACC6B007EE38D /* VPHomePageViewController.swift */,
|
||||
BF0FA7382DDECF8900C9E5F2 /* VPHomeListViewController.swift */,
|
||||
BF0FA7742DE071B500C9E5F2 /* VPSearchViewController.swift */,
|
||||
);
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
@ -462,6 +498,7 @@
|
||||
BF0FA6E82DDC5F6F00C9E5F2 /* Thirdparty */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA7932DE16E9300C9E5F2 /* JXTagView */,
|
||||
BF0FA6ED2DDC5F8700C9E5F2 /* JXUUID */,
|
||||
BF0FA7152DDC78FF00C9E5F2 /* ZKCycleScrollView-Swift */,
|
||||
BF0FA71F2DDC83AE00C9E5F2 /* JXButton */,
|
||||
@ -536,6 +573,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA7042DDC67AC00C9E5F2 /* VPHomeViewModel.swift */,
|
||||
BF0FA78C2DE16A8B00C9E5F2 /* VPSearchViewModel.swift */,
|
||||
);
|
||||
path = ViewModel;
|
||||
sourceTree = "<group>";
|
||||
@ -552,6 +590,14 @@
|
||||
BF0FA72D2DDD7DD400C9E5F2 /* VPHomeRankingCell.swift */,
|
||||
BF0FA73A2DDED1C700C9E5F2 /* VPHomeListCell.swift */,
|
||||
BF0FA73E2DDEF26E00C9E5F2 /* VPHomeSearchButton.swift */,
|
||||
BF0FA7762DE0735800C9E5F2 /* VPSearchInputView.swift */,
|
||||
BF0FA7782DE075FF00C9E5F2 /* VPSearchHomeView.swift */,
|
||||
BF0FA77C2DE078D400C9E5F2 /* VPSearchRecommendedView.swift */,
|
||||
BF0FA7802DE150F700C9E5F2 /* VPSearchRecommendedContentView.swift */,
|
||||
BF0FA7842DE1561D00C9E5F2 /* VPSearchRecommendedCell.swift */,
|
||||
BF0FA7882DE161F200C9E5F2 /* VPSearchResultView.swift */,
|
||||
BF0FA78A2DE164C100C9E5F2 /* VPSearchResultCell.swift */,
|
||||
BF0FA7902DE16CBF00C9E5F2 /* VPSearchHistoryView.swift */,
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
@ -657,6 +703,37 @@
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BF0FA7932DE16E9300C9E5F2 /* JXTagView */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA7922DE16E9300C9E5F2 /* JXTagView.swift */,
|
||||
);
|
||||
path = JXTagView;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BF0FA7952DE1948A00C9E5F2 /* MyList */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
BF0FA7972DE1949B00C9E5F2 /* View */,
|
||||
BF0FA7962DE1949300C9E5F2 /* Controller */,
|
||||
);
|
||||
path = MyList;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BF0FA7962DE1949300C9E5F2 /* Controller */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
path = Controller;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
BF0FA7972DE1949B00C9E5F2 /* View */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
path = View;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@ -786,16 +863,20 @@
|
||||
BF0FA7002DDC665300C9E5F2 /* VPShortModel.swift in Sources */,
|
||||
1B056E7B2DDB37BA007EE38D /* VPGradientView.swift in Sources */,
|
||||
BF0FA7262DDC8F7600C9E5F2 /* VPCollectionView.swift in Sources */,
|
||||
BF0FA78B2DE164C100C9E5F2 /* VPSearchResultCell.swift in Sources */,
|
||||
BF0FA71D2DDC807200C9E5F2 /* UIImageView+VPAdd.swift in Sources */,
|
||||
BF0FA6DC2DDC5CD700C9E5F2 /* VPTokenModel.swift in Sources */,
|
||||
BF0FA7572DDF159B00C9E5F2 /* VPExploreViewController.swift in Sources */,
|
||||
1B056E772DDB3641007EE38D /* VPTabBarItemNormalVew.swift in Sources */,
|
||||
1B056E4B2DDAC6BA007EE38D /* VPDefine.swift in Sources */,
|
||||
1B056E702DDB019B007EE38D /* VPTabBarItemContainer.swift in Sources */,
|
||||
BF0FA7752DE071B500C9E5F2 /* VPSearchViewController.swift in Sources */,
|
||||
BF0FA78D2DE16A8B00C9E5F2 /* VPSearchViewModel.swift in Sources */,
|
||||
1B056E592DDACD44007EE38D /* VPTabBarItemContentView.swift in Sources */,
|
||||
1B056E2B2DDAC0FD007EE38D /* AppDelegate.swift in Sources */,
|
||||
1B056E6C2DDADAA1007EE38D /* VPTabBar.swift in Sources */,
|
||||
BF0FA72E2DDD7DD400C9E5F2 /* VPHomeRankingCell.swift in Sources */,
|
||||
BF0FA7792DE075FF00C9E5F2 /* VPSearchHomeView.swift in Sources */,
|
||||
BF0FA7302DDEBB1600C9E5F2 /* UIButton+VPAdd.swift in Sources */,
|
||||
BF0FA74C2DDF060200C9E5F2 /* VPVideoPlayerViewController.swift in Sources */,
|
||||
BF0FA76D2DE053C100C9E5F2 /* VPScrollView.swift in Sources */,
|
||||
@ -809,12 +890,17 @@
|
||||
BF0FA7592DDF1C2800C9E5F2 /* VPPlayerProgressView.swift in Sources */,
|
||||
BF0FA71B2DDC7FF200C9E5F2 /* VPImageView.swift in Sources */,
|
||||
BF0FA7522DDF134700C9E5F2 /* VPVideoPlayerControlView.swift in Sources */,
|
||||
BF0FA7852DE1561D00C9E5F2 /* VPSearchRecommendedCell.swift in Sources */,
|
||||
BF0FA7832DE1533E00C9E5F2 /* VPGradientLabel.swift in Sources */,
|
||||
1B056E2C2DDAC0FD007EE38D /* SceneDelegate.swift in Sources */,
|
||||
BF0FA75D2DDF208400C9E5F2 /* VPExplorePlayerControlView.swift in Sources */,
|
||||
1B056E462DDAC370007EE38D /* UIScreen+VPAdd.swift in Sources */,
|
||||
BF0FA7692DE0502900C9E5F2 /* VPEpisodeCell.swift in Sources */,
|
||||
BF0FA73D2DDED2D000C9E5F2 /* VPVideoAPI.swift in Sources */,
|
||||
BF0FA6EE2DDC5F8700C9E5F2 /* JXUUID.m in Sources */,
|
||||
BF0FA77D2DE078D400C9E5F2 /* VPSearchRecommendedView.swift in Sources */,
|
||||
BF0FA7812DE150F700C9E5F2 /* VPSearchRecommendedContentView.swift in Sources */,
|
||||
BF0FA7872DE1601200C9E5F2 /* VPTextField.swift in Sources */,
|
||||
BF0FA7052DDC67AC00C9E5F2 /* VPHomeViewModel.swift in Sources */,
|
||||
BF0FA6EF2DDC5F8700C9E5F2 /* PDKeyChain.m in Sources */,
|
||||
BF0FA75F2DDFFDB000C9E5F2 /* VPDetailPlayerViewController.swift in Sources */,
|
||||
@ -823,11 +909,13 @@
|
||||
BF0FA6DA2DDC5CB600C9E5F2 /* VPLoginManager.swift in Sources */,
|
||||
BF0FA74A2DDF04E200C9E5F2 /* VPPlayerProtocol.swift in Sources */,
|
||||
BF0FA72C2DDD7B7300C9E5F2 /* VPHomeRankingContentCell.swift in Sources */,
|
||||
BF0FA7942DE16E9300C9E5F2 /* JXTagView.swift in Sources */,
|
||||
BF0FA7652DE00A0E00C9E5F2 /* VPDetailPlayerControlView.swift in Sources */,
|
||||
BF0FA7342DDEC74500C9E5F2 /* VPCategoryModel.swift in Sources */,
|
||||
1B056E4F2DDAC7FC007EE38D /* VPNavigationController.swift in Sources */,
|
||||
1B056E3F2DDAC2DB007EE38D /* VPCryptorService.swift in Sources */,
|
||||
BF0FA7202DDC83AE00C9E5F2 /* JXButton.swift in Sources */,
|
||||
BF0FA7912DE16CBF00C9E5F2 /* VPSearchHistoryView.swift in Sources */,
|
||||
BF0FA7072DDC687C00C9E5F2 /* VPHomeDataItem.swift in Sources */,
|
||||
BF0FA7452DDF027900C9E5F2 /* VPPlayer.swift in Sources */,
|
||||
BF0FA70E2DDC6ACC00C9E5F2 /* VPHomeItemContentCell.swift in Sources */,
|
||||
@ -836,10 +924,14 @@
|
||||
BF0FA76B2DE0533400C9E5F2 /* VPEpisodeMenuView.swift in Sources */,
|
||||
1B056E6A2DDAD0BF007EE38D /* VPLocalizedManager.swift in Sources */,
|
||||
BF0FA7242DDC888F00C9E5F2 /* VPHomeRecommandContentCell.swift in Sources */,
|
||||
BF0FA78F2DE16B2A00C9E5F2 /* VPUserDefaultsKey.swift in Sources */,
|
||||
BF0FA7192DDC7F4900C9E5F2 /* VPHomeBannerCell.swift in Sources */,
|
||||
BF0FA7712DE062EB00C9E5F2 /* VPVideoRateModel.swift in Sources */,
|
||||
BF0FA7022DDC667C00C9E5F2 /* VPVideoInfoModel.swift in Sources */,
|
||||
BF0FA77B2DE0788A00C9E5F2 /* UIStackView+VPAdd.swift in Sources */,
|
||||
BF0FA76F2DE062A700C9E5F2 /* VPRateSelectedView.swift in Sources */,
|
||||
BF0FA7772DE0735800C9E5F2 /* VPSearchInputView.swift in Sources */,
|
||||
BF0FA7892DE161F200C9E5F2 /* VPSearchResultView.swift in Sources */,
|
||||
1B056E792DDB365A007EE38D /* VPTabBarItemSelectedView.swift in Sources */,
|
||||
1B056E722DDB022F007EE38D /* VPTabBarItem.swift in Sources */,
|
||||
1B056E412DDAC30A007EE38D /* VPModel.swift in Sources */,
|
||||
|
@ -88,7 +88,7 @@ extension VPTabBarController {
|
||||
|
||||
let nav1 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_01"), selectedImage: UIImage(named: "tabbar_icon_01_selected"))
|
||||
let nav2 = createNavigationController(viewController: VPExploreViewController(), title: "Explore".localized, image: UIImage(named: "tabbar_icon_02"), selectedImage: UIImage(named: "tabbar_icon_02_selected"))
|
||||
let nav3 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_03_selected"))
|
||||
let nav3 = createNavigationController(viewController: VPHomePageViewController(), title: "My List".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_03_selected"))
|
||||
let nav4 = createNavigationController(viewController: VPHomePageViewController(), title: "Home".localized, image: UIImage(named: "tabbar_icon_03"), selectedImage: UIImage(named: "tabbar_icon_04_selected"))
|
||||
|
||||
viewControllers = [nav1, nav2, nav3, nav4]
|
||||
|
11
Veloria/Base/Define/VPUserDefaultsKey.swift
Normal file
@ -0,0 +1,11 @@
|
||||
//
|
||||
// VPUserDefaultsKey.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
///搜索记录
|
||||
let kVPSearchHistoryDefaultsKey = "kVPSearchHistoryDefaultsKey"
|
@ -11,6 +11,10 @@ extension UIColor {
|
||||
static func backgroundColor() -> UIColor {
|
||||
return color000000()
|
||||
}
|
||||
|
||||
static func placeholderColor() -> UIColor {
|
||||
return colorFFFFFF(alpha: 0.3)
|
||||
}
|
||||
}
|
||||
|
||||
extension UIColor {
|
||||
@ -69,4 +73,28 @@ extension UIColor {
|
||||
static func color1C2D2F(alpha: CGFloat = 1) -> UIColor {
|
||||
return UIColor(rgb: 0x1C2D2F, alpha: alpha)
|
||||
}
|
||||
|
||||
static func colorA87A46(alpha: CGFloat = 1) -> UIColor {
|
||||
return UIColor(rgb: 0xA87A46, alpha: alpha)
|
||||
}
|
||||
|
||||
static func colorFBF2C7(alpha: CGFloat = 1) -> UIColor {
|
||||
return UIColor(rgb: 0xFBF2C7, alpha: alpha)
|
||||
}
|
||||
|
||||
static func colorA8A38E(alpha: CGFloat = 1) -> UIColor {
|
||||
return UIColor(rgb: 0xA8A38E, alpha: alpha)
|
||||
}
|
||||
|
||||
static func color555555(alpha: CGFloat = 1) -> UIColor {
|
||||
return UIColor(rgb: 0x555555, alpha: alpha)
|
||||
}
|
||||
|
||||
static func colorFFBFBE(alpha: CGFloat = 1) -> UIColor {
|
||||
return UIColor(rgb: 0xFFBFBE, alpha: alpha)
|
||||
}
|
||||
|
||||
static func colorD87675(alpha: CGFloat = 1) -> UIColor {
|
||||
return UIColor(rgb: 0xD87675, alpha: alpha)
|
||||
}
|
||||
}
|
||||
|
20
Veloria/Base/Extension/UIStackView+VPAdd.swift
Normal file
@ -0,0 +1,20 @@
|
||||
//
|
||||
// UIStackView+VPAdd.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
extension UIStackView {
|
||||
|
||||
func removeAllArrangedSubview() {
|
||||
let arrangedSubviews = self.arrangedSubviews
|
||||
|
||||
arrangedSubviews.forEach {
|
||||
self.removeArrangedSubview($0)
|
||||
$0.removeFromSuperview()
|
||||
}
|
||||
}
|
||||
}
|
@ -19,4 +19,38 @@ class VPHomeAPI: NSObject {
|
||||
completer?(response.data?.list)
|
||||
}
|
||||
}
|
||||
|
||||
///热门搜索
|
||||
static func requestHotSearchList(completer: ((_ list: [VPShortModel]?) -> Void)?) {
|
||||
var param = VPNetworkParameters(path: "/search/hots")
|
||||
param.method = .get
|
||||
|
||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPListModel<VPShortModel>>) in
|
||||
completer?(response.data?.list)
|
||||
}
|
||||
}
|
||||
|
||||
///搜索排行
|
||||
static func requestTopSearchList(completer: ((_ list: [VPShortModel]?) -> Void)?) {
|
||||
var param = VPNetworkParameters(path: "/getVisitTop")
|
||||
param.method = .get
|
||||
|
||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<[VPShortModel]>) in
|
||||
completer?(response.data)
|
||||
}
|
||||
}
|
||||
|
||||
///搜索
|
||||
static func requestSearch(text: String, completer: ((_ list: [VPShortModel]?) -> Void)?) {
|
||||
var param = VPNetworkParameters(path: "/search")
|
||||
param.method = .get
|
||||
param.parameters = [
|
||||
"search" : text
|
||||
]
|
||||
|
||||
VPNetwork.request(parameters: param) { (response: VPNetworkResponse<VPListModel<VPShortModel>>) in
|
||||
completer?(response.data?.list)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
51
Veloria/Base/View/VPGradientLabel.swift
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// VPGradientLabel.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPGradientLabel: UILabel {
|
||||
|
||||
private(set) var gradientLayer: CAGradientLayer = {
|
||||
// 创建渐变层
|
||||
let gradient = CAGradientLayer()
|
||||
gradient.colors = [
|
||||
UIColor.red.cgColor,
|
||||
UIColor.blue.cgColor
|
||||
]
|
||||
gradient.startPoint = CGPoint(x: 0, y: 0.5)
|
||||
gradient.endPoint = CGPoint(x: 1, y: 0.5)
|
||||
gradient.locations = [0, 1]
|
||||
return gradient
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
layer.addSublayer(gradientLayer)
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
gradientLayer.frame = bounds
|
||||
|
||||
// 创建一个文字图层
|
||||
let textLayer = CATextLayer()
|
||||
textLayer.string = attributedText ?? NSAttributedString(string: text ?? "")
|
||||
textLayer.frame = bounds
|
||||
textLayer.alignmentMode = .center
|
||||
textLayer.contentsScale = UIScreen.main.scale
|
||||
|
||||
gradientLayer.mask = textLayer
|
||||
|
||||
}
|
||||
|
||||
}
|
126
Veloria/Base/View/VPTextField.swift
Normal file
@ -0,0 +1,126 @@
|
||||
//
|
||||
// VPTextField.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPTextField: UITextField {
|
||||
|
||||
///0 不限制字数
|
||||
var maxNumber = 0
|
||||
|
||||
var currentNumber = 0
|
||||
|
||||
|
||||
var textDidChange: ((_ text: String) -> Void)?
|
||||
|
||||
var vp_placeholder: String? {
|
||||
set {
|
||||
_createAttributedPlaceholder()
|
||||
let newStr = NSMutableAttributedString(string: newValue ?? "")
|
||||
newStr.font = self.vp_placeholderFont
|
||||
newStr.color = self.vp_placeholderColor
|
||||
_attributedPlaceholder = newStr
|
||||
self.attributedPlaceholder = _attributedPlaceholder
|
||||
}
|
||||
get {
|
||||
return _attributedPlaceholder?.string
|
||||
}
|
||||
}
|
||||
|
||||
var vp_placeholderFont: UIFont? {
|
||||
|
||||
set {
|
||||
_createAttributedPlaceholder()
|
||||
_attributedPlaceholder?.font = newValue
|
||||
self.attributedPlaceholder = _attributedPlaceholder
|
||||
}
|
||||
get {
|
||||
if let font = _attributedPlaceholder?.font {
|
||||
return font
|
||||
} else {
|
||||
return self.font
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var vp_placeholderColor: UIColor? {
|
||||
set {
|
||||
_createAttributedPlaceholder()
|
||||
_attributedPlaceholder?.color = newValue
|
||||
self.attributedPlaceholder = _attributedPlaceholder
|
||||
}
|
||||
get {
|
||||
if let color = _attributedPlaceholder?.color {
|
||||
return color
|
||||
} else {
|
||||
return .placeholderColor()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var _attributedPlaceholder: NSMutableAttributedString?
|
||||
|
||||
|
||||
private func _createAttributedPlaceholder() {
|
||||
if self._attributedPlaceholder == nil {
|
||||
_attributedPlaceholder = NSMutableAttributedString(string: "")
|
||||
_attributedPlaceholder?.font = self.font
|
||||
_attributedPlaceholder?.color = .placeholderColor()
|
||||
self.attributedPlaceholder = _attributedPlaceholder
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
NotificationCenter.default.removeObserver(self)
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
NotificationCenter.default.addObserver(self, selector: #selector(textDidChangeNotification(sender:)), name: UITextField.textDidChangeNotification, object: nil)
|
||||
|
||||
// var iq = self.iq
|
||||
// iq.enableMode = .enabled
|
||||
|
||||
self.textColor = .colorFFFFFF()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPTextField {
|
||||
@objc func textDidChangeNotification(sender: Notification){
|
||||
|
||||
guard let object = sender.object else { return }
|
||||
if !(object is UITextField) {return}
|
||||
if (object as! UITextField) != self {return}
|
||||
|
||||
|
||||
let selectedRange: UITextRange? = self.markedTextRange
|
||||
|
||||
|
||||
if selectedRange == nil {
|
||||
|
||||
if maxNumber > 0 {
|
||||
if self.text?.count ?? 0 > self.maxNumber {
|
||||
var string = self.text
|
||||
string?.removeLast(self.text!.count - self.maxNumber)
|
||||
self.text = string
|
||||
}
|
||||
}
|
||||
if let textDidChange = textDidChange {
|
||||
textDidChange(self.text ?? "")
|
||||
}
|
||||
|
||||
|
||||
self.currentNumber = self.text?.count ?? 0
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -111,6 +111,7 @@ class VPHomePageViewController: VPViewController {
|
||||
|
||||
private lazy var searchButton: VPHomeSearchButton = {
|
||||
let button = VPHomeSearchButton()
|
||||
button.addTarget(self, action: #selector(handleSearchButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
@ -164,10 +165,13 @@ class VPHomePageViewController: VPViewController {
|
||||
self.pageView.upSc.addSubview(menuBgView)
|
||||
|
||||
self.pageView.upSc.sendSubviewToBack(menuBgView)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@objc private func handleSearchButton() {
|
||||
let vc = VPSearchViewController()
|
||||
self.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPHomePageViewController {
|
||||
|
111
Veloria/Class/Home/Controller/VPSearchViewController.swift
Normal file
@ -0,0 +1,111 @@
|
||||
//
|
||||
// VPSearchViewController.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchViewController: VPViewController {
|
||||
|
||||
|
||||
private lazy var viewModel = VPSearchViewModel()
|
||||
|
||||
private lazy var backButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(UIImage(named: "arrow_left_icon_01"), for: .normal)
|
||||
button.addTarget(self, action: #selector(handleBack), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var textView: VPSearchInputView = {
|
||||
let view = VPSearchInputView()
|
||||
view.textDidChange = { [weak self] text in
|
||||
self?.textDidChange(text: text)
|
||||
}
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var homeView: VPSearchHomeView = {
|
||||
let view = VPSearchHomeView()
|
||||
view.viewModel = viewModel
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var resultView: VPSearchResultView = {
|
||||
let view = VPSearchResultView()
|
||||
view.viewModel = viewModel
|
||||
view.isHidden = true
|
||||
return view
|
||||
}()
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
vp_setupUI()
|
||||
vp_addAction()
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool) {
|
||||
super.viewWillAppear(animated)
|
||||
self.navigationController?.setNavigationBarHidden(true, animated: true)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPSearchViewController {
|
||||
|
||||
///文本发生变化
|
||||
func textDidChange(text: String) {
|
||||
if text.count > 0 {
|
||||
self.resultView.isHidden = false
|
||||
self.homeView.isHidden = true
|
||||
} else {
|
||||
self.resultView.isHidden = true
|
||||
self.homeView.isHidden = false
|
||||
}
|
||||
self.resultView.search(text: text)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPSearchViewController {
|
||||
|
||||
private func vp_setupUI() {
|
||||
view.addSubview(backButton)
|
||||
view.addSubview(textView)
|
||||
view.addSubview(homeView)
|
||||
view.addSubview(resultView)
|
||||
|
||||
backButton.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(UIScreen.statusBarHeight)
|
||||
make.width.equalTo(48)
|
||||
make.height.equalTo(44)
|
||||
}
|
||||
|
||||
textView.snp.makeConstraints { make in
|
||||
make.left.equalTo(backButton.snp.right)
|
||||
make.right.equalToSuperview().offset(-15)
|
||||
make.centerY.equalTo(backButton)
|
||||
make.height.equalTo(40)
|
||||
}
|
||||
|
||||
homeView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalTo(textView.snp.bottom)
|
||||
}
|
||||
|
||||
resultView.snp.makeConstraints { make in
|
||||
make.edges.equalTo(homeView)
|
||||
}
|
||||
}
|
||||
|
||||
private func vp_addAction() {
|
||||
self.viewModel.searchHandle = { [weak self] text in
|
||||
self?.textView.text = text
|
||||
self?.textDidChange(text: text)
|
||||
}
|
||||
}
|
||||
}
|
115
Veloria/Class/Home/View/VPSearchHistoryView.swift
Normal file
@ -0,0 +1,115 @@
|
||||
//
|
||||
// VPSearchHistoryView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchHistoryView: UIView {
|
||||
|
||||
var historyArr: [String] = [] {
|
||||
didSet {
|
||||
tagView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
var viewModel: VPSearchViewModel?
|
||||
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontRegular(ofSize: 13)
|
||||
label.textColor = .colorFFFFFF()
|
||||
label.text = "Recent Searches".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var deleteButton: UIButton = {
|
||||
let button = UIButton(type: .custom)
|
||||
button.setImage(UIImage(named: "delete_icon_01"), for: .normal)
|
||||
button.addTarget(self, action: #selector(handleDeleteButton), for: .touchUpInside)
|
||||
return button
|
||||
}()
|
||||
|
||||
private lazy var tagView: JXTagView = {
|
||||
let tagView = JXTagView(frame: .init(x: 0, y: 0, width: UIScreen.width, height: 10))
|
||||
tagView.tagBackgroundColor = .colorFFFFFF(alpha: 0.1)
|
||||
tagView.tagHeight = 24
|
||||
tagView.textMargin = 5
|
||||
tagView.tagCornerRadius = 12
|
||||
tagView.tagHorizontalGap = 8
|
||||
tagView.tagVerticalGap = 8
|
||||
tagView.textFont = .fontRegular(ofSize: 11)
|
||||
tagView.textColor = .colorFFFFFF(alpha: 0.7)
|
||||
tagView.delegate = self
|
||||
tagView.dataSource = self
|
||||
tagView.setContentHuggingPriority(.required, for: .horizontal)
|
||||
tagView.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
return tagView
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
setContentHuggingPriority(.required, for: .horizontal)
|
||||
setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
@objc private func handleDeleteButton() {
|
||||
self.viewModel?.cleanHistory()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPSearchHistoryView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
addSubview(titleLabel)
|
||||
addSubview(deleteButton)
|
||||
addSubview(tagView)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.top.equalToSuperview().offset(20)
|
||||
}
|
||||
|
||||
deleteButton.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(titleLabel)
|
||||
make.right.equalToSuperview().offset(-5)
|
||||
make.width.equalTo(36)
|
||||
make.height.equalTo(40)
|
||||
}
|
||||
|
||||
tagView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(48)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- JXTagViewDelegate JXTagViewDataSource --------------
|
||||
extension VPSearchHistoryView: JXTagViewDelegate, JXTagViewDataSource {
|
||||
|
||||
func jx_tagView(tagView: JXTagView, titleForIndex index: Int) -> String? {
|
||||
return historyArr[index]
|
||||
}
|
||||
|
||||
func jx_number(in tagView: JXTagView) -> Int {
|
||||
return historyArr.count
|
||||
}
|
||||
|
||||
func jx_tagView(tagView: JXTagView, didSelectedTagAt index: Int) {
|
||||
self.viewModel?.searchHandle?(historyArr[index])
|
||||
}
|
||||
|
||||
}
|
84
Veloria/Class/Home/View/VPSearchHomeView.swift
Normal file
@ -0,0 +1,84 @@
|
||||
//
|
||||
// VPSearchHomeView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchHomeView: UIView {
|
||||
|
||||
var viewModel: VPSearchViewModel? {
|
||||
didSet {
|
||||
viewModel?.addObserver(self, forKeyPath: "historyArr", context: nil)
|
||||
historyView.historyArr = viewModel?.historyArr ?? []
|
||||
updateLayout()
|
||||
|
||||
historyView.viewModel = viewModel
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let view = UIStackView(arrangedSubviews: [historyView, recommendedView])
|
||||
view.axis = .vertical
|
||||
view.spacing = 30
|
||||
view.distribution = .equalSpacing
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var historyView: VPSearchHistoryView = {
|
||||
let view = VPSearchHistoryView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var recommendedView: VPSearchRecommendedView = {
|
||||
let view = VPSearchRecommendedView()
|
||||
return view
|
||||
}()
|
||||
|
||||
deinit {
|
||||
viewModel?.removeObserver(self, forKeyPath: "historyArr")
|
||||
}
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
|
||||
if keyPath == "historyArr" {
|
||||
historyView.historyArr = viewModel?.historyArr ?? []
|
||||
updateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
private func updateLayout() {
|
||||
stackView.removeAllArrangedSubview()
|
||||
|
||||
if (viewModel?.historyArr.count ?? 0) > 0 {
|
||||
stackView.addArrangedSubview(historyView)
|
||||
}
|
||||
stackView.addArrangedSubview(recommendedView)
|
||||
}
|
||||
}
|
||||
|
||||
extension VPSearchHomeView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
addSubview(stackView)
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(20)
|
||||
make.bottom.equalToSuperview()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
76
Veloria/Class/Home/View/VPSearchInputView.swift
Normal file
@ -0,0 +1,76 @@
|
||||
//
|
||||
// VPSearchInputView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchInputView: UIView {
|
||||
|
||||
var textDidChange: ((_ text: String) -> Void)?
|
||||
|
||||
var text: String? {
|
||||
set {
|
||||
textField.text = newValue
|
||||
}
|
||||
get {
|
||||
return textField.text
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var iconImageView: UIImageView = {
|
||||
let imageView = UIImageView(image: UIImage(named: "search_icon_01"))
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var textField: VPTextField = {
|
||||
let textField = VPTextField()
|
||||
textField.font = .fontRegular(ofSize: 14)
|
||||
textField.vp_placeholder = "kSearchPlaceholderText2".localized
|
||||
textField.vp_placeholderFont = textField.font
|
||||
textField.textDidChange = { [weak self] text in
|
||||
self?.textDidChange?(text)
|
||||
}
|
||||
return textField
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
extension VPSearchInputView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
layer.cornerRadius = 6
|
||||
layer.masksToBounds = true
|
||||
layer.borderWidth = 0.7
|
||||
layer.borderColor = UIColor.colorFFFFFF(alpha: 0.1).cgColor
|
||||
backgroundColor = UIColor.colorFFFFFF(alpha: 0.05)
|
||||
|
||||
addSubview(iconImageView)
|
||||
addSubview(textField)
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.centerY.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(10)
|
||||
}
|
||||
|
||||
textField.snp.makeConstraints { make in
|
||||
make.top.bottom.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(45)
|
||||
make.right.equalToSuperview().offset(-10)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
142
Veloria/Class/Home/View/VPSearchRecommendedCell.swift
Normal file
@ -0,0 +1,142 @@
|
||||
//
|
||||
// VPSearchRecommendedCell.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchRecommendedCell: VPCollectionViewCell {
|
||||
|
||||
var model: VPShortModel? {
|
||||
didSet {
|
||||
coverImageView.vp_setImage(url: model?.image_url)
|
||||
titleLabel.text = model?.name
|
||||
desLabel.text = model?.vp_description
|
||||
|
||||
if let category = model?.category?.first, !category.isEmpty {
|
||||
tagView.isHidden = false
|
||||
tagView.setTitle(category, for: .normal)
|
||||
} else {
|
||||
tagView.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var row: Int = 0 {
|
||||
didSet {
|
||||
if row < 3 {
|
||||
numBgView.image = UIImage(named: "num_icon_01")
|
||||
} else {
|
||||
numBgView.image = UIImage(named: "num_icon_02")
|
||||
}
|
||||
numLabel.text = "\(row + 1)"
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var coverImageView: VPImageView = {
|
||||
let imageView = VPImageView()
|
||||
imageView.layer.cornerRadius = 6
|
||||
imageView.layer.masksToBounds = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 12)
|
||||
label.textColor = .colorFFFFFF()
|
||||
label.numberOfLines = 2
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var tagView: UIButton = {
|
||||
let view = JXButton(type: .custom)
|
||||
view.isUserInteractionEnabled = false
|
||||
view.jx_font = .fontRegular(ofSize: 10)
|
||||
view.setTitleColor(.colorAFAFAF(), for: .normal)
|
||||
view.backgroundColor = .colorFFFFFF(alpha: 0.1)
|
||||
view.layer.cornerRadius = 3
|
||||
view.layer.masksToBounds = true
|
||||
view.leftAndRightMargin = 5
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var desLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.numberOfLines = 2
|
||||
label.font = .fontRegular(ofSize: 10)
|
||||
label.textColor = .colorFFFFFF(alpha: 0.6)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var numBgView: UIImageView = {
|
||||
let view = UIImageView()
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var numLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .numberFont(ofSize: 18)
|
||||
label.textColor = .colorFFFFFB()
|
||||
return label
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
extension VPSearchRecommendedCell {
|
||||
|
||||
private func vp_setupUI() {
|
||||
contentView.addSubview(coverImageView)
|
||||
coverImageView.addSubview(numBgView)
|
||||
coverImageView.addSubview(numLabel)
|
||||
contentView.addSubview(titleLabel)
|
||||
contentView.addSubview(tagView)
|
||||
contentView.addSubview(desLabel)
|
||||
|
||||
coverImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.top.bottom.equalToSuperview()
|
||||
make.width.equalTo(68)
|
||||
}
|
||||
|
||||
numBgView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview()
|
||||
make.top.equalToSuperview()
|
||||
}
|
||||
|
||||
numLabel.snp.makeConstraints { make in
|
||||
make.centerX.equalTo(numBgView).offset(2)
|
||||
make.centerY.equalTo(numBgView).offset(2)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(coverImageView.snp.right).offset(10)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
make.centerY.equalTo(coverImageView.snp.top).offset(15)
|
||||
}
|
||||
|
||||
tagView.snp.makeConstraints { make in
|
||||
make.left.equalTo(titleLabel)
|
||||
make.top.equalToSuperview().offset(39)
|
||||
make.height.equalTo(16)
|
||||
}
|
||||
|
||||
desLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(titleLabel)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-3)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
170
Veloria/Class/Home/View/VPSearchRecommendedContentView.swift
Normal file
@ -0,0 +1,170 @@
|
||||
//
|
||||
// VPSearchRecommendedContentView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchRecommendedContentView: VPGradientView {
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return .init(width: 256, height: 500)
|
||||
}
|
||||
|
||||
var dataArr: [VPShortModel] = [] {
|
||||
didSet {
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
|
||||
var iconImage: UIImage? {
|
||||
didSet {
|
||||
iconImageView.image = iconImage
|
||||
}
|
||||
}
|
||||
|
||||
var title: String? {
|
||||
didSet {
|
||||
titleLabel.text = title
|
||||
}
|
||||
}
|
||||
|
||||
var borderColors: [CGColor] = [] {
|
||||
didSet {
|
||||
borderGradientLayout.colors = borderColors
|
||||
}
|
||||
}
|
||||
|
||||
var titleColors: [CGColor] = [] {
|
||||
didSet {
|
||||
titleLabel.gradientLayer.colors = titleColors
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
///渐变边框
|
||||
private lazy var borderGradientLayout: CAGradientLayer = {
|
||||
let layer = CAGradientLayer()
|
||||
layer.locations = [0, 0.1, 0.3, 1]
|
||||
layer.startPoint = .init(x: 0.5, y: 0)
|
||||
layer.endPoint = .init(x: 0.5, y: 1)
|
||||
layer.mask = borderShapeLayer
|
||||
return layer
|
||||
}()
|
||||
|
||||
private lazy var borderShapeLayer: CAShapeLayer = {
|
||||
let shapeLayer = CAShapeLayer()
|
||||
shapeLayer.lineWidth = 1
|
||||
shapeLayer.fillColor = UIColor.clear.cgColor
|
||||
shapeLayer.strokeColor = UIColor.black.cgColor
|
||||
return shapeLayer
|
||||
}()
|
||||
|
||||
private lazy var iconImageView: UIImageView = {
|
||||
let imageView = UIImageView()
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var titleLabel: VPGradientLabel = {
|
||||
let label = VPGradientLabel()
|
||||
label.font = .fontBold(ofSize: 14)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: intrinsicContentSize.width - 20, height: 90)
|
||||
layout.sectionInset = .init(top: 0, left: 10, bottom: 0, right: 10)
|
||||
layout.minimumLineSpacing = 10
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: VPCollectionView = {
|
||||
let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.showsVerticalScrollIndicator = false
|
||||
collectionView.register(VPSearchRecommendedCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
colors = [UIColor.colorA87A46(alpha: 0.18).cgColor, UIColor.colorA87A46(alpha: 0.05).cgColor, UIColor.colorA87A46(alpha: 0).cgColor]
|
||||
locations = [0, 0.5, 1]
|
||||
startPoint = .init(x: 0.5, y: 0)
|
||||
endPoint = .init(x: 0.5, y: 1)
|
||||
layer.cornerRadius = 10
|
||||
layer.masksToBounds = true
|
||||
|
||||
self.layer.addSublayer(borderGradientLayout)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
|
||||
borderGradientLayout.frame = self.bounds
|
||||
let path = UIBezierPath(roundedRect: bounds.insetBy(dx: borderShapeLayer.lineWidth / 2, dy: borderShapeLayer.lineWidth / 2), cornerRadius: layer.cornerRadius)
|
||||
borderShapeLayer.path = path.cgPath
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPSearchRecommendedContentView {
|
||||
private func vp_setupUI() {
|
||||
addSubview(iconImageView)
|
||||
addSubview(titleLabel)
|
||||
addSubview(collectionView)
|
||||
|
||||
iconImageView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(10)
|
||||
make.top.equalToSuperview().offset(10)
|
||||
make.width.height.equalTo(18)
|
||||
}
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.centerY.equalTo(iconImageView)
|
||||
make.left.equalTo(iconImageView.snp.right).offset(4)
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(39)
|
||||
make.bottom.equalToSuperview().offset(-10)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//MARK: -------------- UICollectionViewDelegate UICollectionViewDataSource --------------
|
||||
extension VPSearchRecommendedContentView: UICollectionViewDelegate, UICollectionViewDataSource {
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPSearchRecommendedCell
|
||||
cell.model = dataArr[indexPath.row]
|
||||
cell.row = 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 = VPDetailPlayerViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
}
|
||||
|
||||
}
|
122
Veloria/Class/Home/View/VPSearchRecommendedView.swift
Normal file
@ -0,0 +1,122 @@
|
||||
//
|
||||
// VPSearchRecommendedView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/23.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchRecommendedView: UIView {
|
||||
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
return .init(width: UIScreen.width, height: UIScreen.height)
|
||||
}
|
||||
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 15)
|
||||
label.textColor = .colorFFFFFF()
|
||||
label.text = "Recommended For You".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var scrollView: VPScrollView = {
|
||||
let scrollView = VPScrollView()
|
||||
scrollView.showsHorizontalScrollIndicator = false
|
||||
return scrollView
|
||||
}()
|
||||
|
||||
private lazy var stackView: UIStackView = {
|
||||
let view = UIStackView(arrangedSubviews: [topView, newView])
|
||||
view.axis = .horizontal
|
||||
view.spacing = 20
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var topView: VPSearchRecommendedContentView = {
|
||||
let view = VPSearchRecommendedContentView()
|
||||
view.borderColors = [UIColor.colorFBF2C7(alpha: 0.6).cgColor, UIColor.colorA8A38E(alpha: 0.4).cgColor, UIColor.color555555(alpha: 0.3).cgColor, UIColor.colorFBF2C7(alpha: 0.05).cgColor]
|
||||
view.titleColors = [UIColor.colorFBF2C7().cgColor, UIColor.colorA87A46().cgColor]
|
||||
view.iconImage = UIImage(named: "top_icon_01")
|
||||
view.title = "Trending Top 10".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
private lazy var newView: VPSearchRecommendedContentView = {
|
||||
let view = VPSearchRecommendedContentView()
|
||||
view.borderColors = [UIColor.colorFFBFBE(alpha: 0.6).cgColor, UIColor.colorFFBFBE(alpha: 0.4).cgColor, UIColor.color555555(alpha: 0.3).cgColor, UIColor.colorFFBFBE(alpha: 0.05).cgColor]
|
||||
view.titleColors = [UIColor.colorFFBFBE().cgColor, UIColor.colorD87675().cgColor]
|
||||
view.iconImage = UIImage(named: "hot_icon_02")
|
||||
view.title = "Latest Trends".localized
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
vp_setupUI()
|
||||
|
||||
requestTopData()
|
||||
requestHotData()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
extension VPSearchRecommendedView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
addSubview(titleLabel)
|
||||
addSubview(scrollView)
|
||||
scrollView.addSubview(stackView)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.top.equalToSuperview()
|
||||
make.left.equalToSuperview().offset(15)
|
||||
}
|
||||
|
||||
scrollView.snp.makeConstraints { make in
|
||||
make.left.right.equalToSuperview()
|
||||
make.bottom.equalToSuperview()
|
||||
make.top.equalToSuperview().offset(30)
|
||||
}
|
||||
|
||||
stackView.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.right.equalToSuperview().offset(-15)
|
||||
make.top.equalToSuperview()
|
||||
make.height.equalTo(self).offset(-(30 + UIScreen.tabbarSafeBottomMargin))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension VPSearchRecommendedView {
|
||||
|
||||
private func requestTopData() {
|
||||
VPHomeAPI.requestTopSearchList { [weak self] list in
|
||||
guard let self = self else { return }
|
||||
if let list = list {
|
||||
self.topView.dataArr = list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func requestHotData() {
|
||||
|
||||
VPHomeAPI.requestHotSearchList { [weak self] list in
|
||||
guard let self = self else { return }
|
||||
if let list = list {
|
||||
self.newView.dataArr = list
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
111
Veloria/Class/Home/View/VPSearchResultCell.swift
Normal file
@ -0,0 +1,111 @@
|
||||
//
|
||||
// VPSearchResultCell.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchResultCell: VPCollectionViewCell {
|
||||
|
||||
var searchText: String? {
|
||||
didSet {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var model: VPShortModel? {
|
||||
didSet {
|
||||
coverImageView.vp_setImage(url: model?.image_url)
|
||||
videoNameLabel.text = model?.name
|
||||
desLabel.text = model?.vp_description
|
||||
|
||||
let watchCount = model?.watch_total ?? 0
|
||||
if watchCount > 1000 {
|
||||
let numStr = NSNumber(floatLiteral: CGFloat(watchCount) / 1000).toString(maximumFractionDigits: 1)
|
||||
hotView.setTitle("\(numStr)K", for: .normal)
|
||||
} else {
|
||||
hotView.setTitle("\(watchCount)", for: .normal)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private lazy var coverImageView: VPImageView = {
|
||||
let imageView = VPImageView()
|
||||
imageView.layer.cornerRadius = 6
|
||||
imageView.layer.masksToBounds = true
|
||||
return imageView
|
||||
}()
|
||||
|
||||
private lazy var videoNameLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.numberOfLines = 2
|
||||
label.font = .fontMedium(ofSize: 14)
|
||||
label.textColor = .colorFFFFFF()
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var desLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.numberOfLines = 2
|
||||
label.font = .fontRegular(ofSize: 11)
|
||||
label.textColor = .colorFFFFFF(alpha: 0.6)
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var hotView: UIButton = {
|
||||
let view = JXButton(type: .custom)
|
||||
view.isUserInteractionEnabled = false
|
||||
view.titleDirection = .right
|
||||
view.jx_font = .fontRegular(ofSize: 10)
|
||||
view.setTitleColor(.colorDEDEDE(), for: .normal)
|
||||
view.setImage(UIImage(named: "hot_icon_01"), for: .normal)
|
||||
view.space = 1
|
||||
return view
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
@MainActor required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPSearchResultCell {
|
||||
|
||||
private func vp_setupUI() {
|
||||
contentView.addSubview(coverImageView)
|
||||
contentView.addSubview(videoNameLabel)
|
||||
contentView.addSubview(desLabel)
|
||||
contentView.addSubview(hotView)
|
||||
|
||||
coverImageView.snp.makeConstraints { make in
|
||||
make.left.top.bottom.equalToSuperview()
|
||||
make.width.equalTo(84)
|
||||
}
|
||||
|
||||
videoNameLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(coverImageView.snp.right).offset(12)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
make.centerY.equalTo(coverImageView.snp.top).offset(21)
|
||||
}
|
||||
|
||||
desLabel.snp.makeConstraints { make in
|
||||
make.left.equalTo(videoNameLabel)
|
||||
make.right.lessThanOrEqualToSuperview()
|
||||
make.bottom.equalToSuperview().offset(-3)
|
||||
}
|
||||
|
||||
hotView.snp.makeConstraints { make in
|
||||
make.left.equalTo(videoNameLabel)
|
||||
make.top.equalToSuperview().offset(51)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
115
Veloria/Class/Home/View/VPSearchResultView.swift
Normal file
@ -0,0 +1,115 @@
|
||||
//
|
||||
// VPSearchResultView.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchResultView: UIView {
|
||||
|
||||
var viewModel: VPSearchViewModel?
|
||||
|
||||
private lazy var dataArr: [VPShortModel] = []
|
||||
private(set) lazy var searchText: String = ""
|
||||
|
||||
//MARK: UI属性
|
||||
private lazy var titleLabel: UILabel = {
|
||||
let label = UILabel()
|
||||
label.font = .fontMedium(ofSize: 13)
|
||||
label.textColor = .colorFFFFFF()
|
||||
label.text = "Search Results".localized
|
||||
return label
|
||||
}()
|
||||
|
||||
private lazy var collectionViewLayout: UICollectionViewFlowLayout = {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.itemSize = .init(width: UIScreen.width - 30, height: 108)
|
||||
layout.sectionInset = .init(top: 0, left: 15, bottom: UIScreen.tabbarSafeBottomMargin + 10, right: 15)
|
||||
layout.minimumLineSpacing = 10
|
||||
return layout
|
||||
}()
|
||||
|
||||
private lazy var collectionView: VPCollectionView = {
|
||||
let collectionView = VPCollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
|
||||
collectionView.delegate = self
|
||||
collectionView.dataSource = self
|
||||
collectionView.register(VPSearchResultCell.self, forCellWithReuseIdentifier: "cell")
|
||||
return collectionView
|
||||
}()
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
vp_setupUI()
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func search(text: String) {
|
||||
searchText = text
|
||||
requestSearch(text: text)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension VPSearchResultView {
|
||||
|
||||
private func vp_setupUI() {
|
||||
addSubview(titleLabel)
|
||||
addSubview(collectionView)
|
||||
|
||||
titleLabel.snp.makeConstraints { make in
|
||||
make.left.equalToSuperview().offset(15)
|
||||
make.top.equalToSuperview().offset(20)
|
||||
}
|
||||
|
||||
collectionView.snp.makeConstraints { make in
|
||||
make.left.right.bottom.equalToSuperview()
|
||||
make.top.equalTo(titleLabel.snp.bottom).offset(10)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//MARK: -------------- UICollectionViewDataSource UICollectionViewDelegate --------------
|
||||
extension VPSearchResultView: UICollectionViewDataSource, UICollectionViewDelegate {
|
||||
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! VPSearchResultCell
|
||||
cell.searchText = self.searchText
|
||||
cell.model = dataArr[indexPath.row]
|
||||
return cell
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return self.dataArr.count
|
||||
}
|
||||
|
||||
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
||||
let model = dataArr[indexPath.row]
|
||||
|
||||
let vc = VPDetailPlayerViewController()
|
||||
vc.shortPlayId = model.short_play_id
|
||||
self.viewController?.navigationController?.pushViewController(vc, animated: true)
|
||||
|
||||
self.viewModel?.addHistory(text: self.searchText)
|
||||
}
|
||||
}
|
||||
|
||||
extension VPSearchResultView {
|
||||
|
||||
private func requestSearch(text: String) {
|
||||
VPHomeAPI.requestSearch(text: text) { [weak self] list in
|
||||
guard let self = self else { return }
|
||||
if self.searchText != text { return; }
|
||||
|
||||
if let list = list {
|
||||
self.dataArr = list
|
||||
self.collectionView.reloadData()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
60
Veloria/Class/Home/ViewModel/VPSearchViewModel.swift
Normal file
@ -0,0 +1,60 @@
|
||||
//
|
||||
// VPSearchViewModel.swift
|
||||
// Veloria
|
||||
//
|
||||
// Created by 湖南秦九 on 2025/5/24.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
class VPSearchViewModel: NSObject {
|
||||
|
||||
@objc dynamic var historyArr: [String] = VPSearchViewModel.getSearchHistory()
|
||||
|
||||
func addHistory(text: String) {
|
||||
guard text.count > 0 else { return }
|
||||
|
||||
VPSearchViewModel.addSearchHistory(text: text)
|
||||
historyArr = VPSearchViewModel.getSearchHistory()
|
||||
}
|
||||
|
||||
func cleanHistory() {
|
||||
VPSearchViewModel.cleanSearchHistory()
|
||||
historyArr.removeAll()
|
||||
}
|
||||
|
||||
var searchHandle: ((_ text: String) -> Void)?
|
||||
|
||||
}
|
||||
|
||||
|
||||
extension VPSearchViewModel {
|
||||
///添加历史记录
|
||||
static func addSearchHistory(text: String) {
|
||||
var arr = getSearchHistory()
|
||||
for (i, value) in arr.enumerated() {
|
||||
if value == text {
|
||||
arr.remove(at: i)
|
||||
break
|
||||
}
|
||||
}
|
||||
arr.insert(text, at: 0)
|
||||
if arr.count > 10 {
|
||||
arr.removeLast()
|
||||
}
|
||||
UserDefaults.standard.set(arr, forKey: kVPSearchHistoryDefaultsKey)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
|
||||
///获取历史记录
|
||||
static func getSearchHistory() -> [String] {
|
||||
let arr = UserDefaults.standard.object(forKey: kVPSearchHistoryDefaultsKey) as? [String]
|
||||
return arr ?? []
|
||||
}
|
||||
|
||||
///清空历史记录
|
||||
static func cleanSearchHistory() {
|
||||
UserDefaults.standard.set([], forKey: kVPSearchHistoryDefaultsKey)
|
||||
UserDefaults.standard.synchronize()
|
||||
}
|
||||
}
|
@ -19,7 +19,7 @@ class VPShortModel: VPModel, SmartCodable {
|
||||
var all_coins: String?
|
||||
var buy_type: String?
|
||||
var collect_total: Int?
|
||||
var sp_description: String?
|
||||
var vp_description: String?
|
||||
var episode_total: Int?
|
||||
var horizontally_img: String?
|
||||
var image_url: String?
|
||||
@ -41,12 +41,12 @@ class VPShortModel: VPModel, SmartCodable {
|
||||
@IgnoredKey
|
||||
var titleAttributedString: NSAttributedString?
|
||||
@IgnoredKey
|
||||
var sp_isSelected: Bool?
|
||||
var vp_isSelected: Bool?
|
||||
|
||||
|
||||
static func mappingForKey() -> [SmartKeyTransformer]? {
|
||||
return [
|
||||
CodingKeys.sp_description <--- ["description"]
|
||||
CodingKeys.vp_description <--- ["description"]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ class VPEpisodeView: HWPanModalContentView {
|
||||
} else {
|
||||
tagView.isHidden = true
|
||||
}
|
||||
desLabel.text = shortModel?.sp_description
|
||||
desLabel.text = shortModel?.vp_description
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -188,7 +188,7 @@ extension VPPlayerProgressView {
|
||||
|
||||
case .changed:
|
||||
let point = sender.translation(in: self)
|
||||
let offsetX = point.x / self.width
|
||||
let offsetX = point.x / (self.width - self.insets.left - self.insets.right)
|
||||
self.panProgress = self.tempProgress + offsetX
|
||||
if self.panProgress < 0 {
|
||||
self.panProgress = 0
|
||||
@ -206,7 +206,7 @@ extension VPPlayerProgressView {
|
||||
|
||||
@objc func handleTapGesture(sender: UITapGestureRecognizer) {
|
||||
let point = sender.location(in: self)
|
||||
let offsetX = point.x / self.width
|
||||
let offsetX = (point.x - self.insets.left) / (self.width - self.insets.left - self.insets.right)
|
||||
self.panFinish?(offsetX)
|
||||
}
|
||||
}
|
||||
|
22
Veloria/Source/Assets.xcassets/icon/delete_icon_01.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/delete_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 484 B |
BIN
Veloria/Source/Assets.xcassets/icon/delete_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 637 B |
22
Veloria/Source/Assets.xcassets/icon/hot_icon_02.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_02.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/hot_icon_02.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.8 KiB |
22
Veloria/Source/Assets.xcassets/icon/num_icon_02.imageset/Contents.json
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"filename" : "Ellipse 4@2x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x"
|
||||
},
|
||||
{
|
||||
"filename" : "Ellipse 4@3x.png",
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"author" : "xcode",
|
||||
"version" : 1
|
||||
}
|
||||
}
|
BIN
Veloria/Source/Assets.xcassets/icon/num_icon_02.imageset/Ellipse 4@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/num_icon_02.imageset/Ellipse 4@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.9 KiB |
22
Veloria/Source/Assets.xcassets/icon/top_icon_01.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/top_icon_01.imageset/Frame@2x.png
vendored
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
Veloria/Source/Assets.xcassets/icon/top_icon_01.imageset/Frame@3x.png
vendored
Normal file
After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 691 B After Width: | Height: | Size: 912 B |
Before Width: | Height: | Size: 945 B After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 382 B After Width: | Height: | Size: 499 B |
Before Width: | Height: | Size: 476 B After Width: | Height: | Size: 689 B |
@ -12,9 +12,15 @@
|
||||
"Explore" = "Explore";
|
||||
"EP.%@" = "EP.%@";
|
||||
"All %@ Episodes" = "All %@ Episodes";
|
||||
|
||||
"Recommended For You" = "Recommended For You";
|
||||
"Trending Top 10" = "Trending Top 10";
|
||||
"Latest Trends" = "Latest Trends";
|
||||
"Search Results" = "Search Results";
|
||||
"Recent Searches" = "Recent Searches";
|
||||
"My List" = "My List";
|
||||
|
||||
|
||||
"kHomeTitleText" = "10,000+ addictive shorts await!";
|
||||
"kSearchPlaceholderText1" = "Search dramas";
|
||||
"kSearchPlaceholderText2" = "#Recersal of fate";
|
||||
"kHomeMenuTitle" = "Select Categories";
|
||||
|
307
Veloria/Thirdparty/JXTagView/JXTagView.swift
vendored
Normal file
@ -0,0 +1,307 @@
|
||||
//
|
||||
// JXTagView.swift
|
||||
// YDLive
|
||||
//
|
||||
// Created by 曾觉新 on 2020/11/7.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
@objc protocol JXTagViewDataSource: NSObjectProtocol {
|
||||
|
||||
@objc optional func jx_tagView(tagView: JXTagView, titleForIndex index: Int) -> String?
|
||||
@objc optional func jx_tagView(tagView: JXTagView, attributedTitleForIndex index: Int) -> NSAttributedString?
|
||||
func jx_number(in tagView: JXTagView) -> Int
|
||||
|
||||
}
|
||||
|
||||
@objc protocol JXTagViewDelegate: NSObjectProtocol {
|
||||
|
||||
@objc optional func jx_tagView(tagView: JXTagView, didSelectedTagAt index: Int)
|
||||
|
||||
@objc optional func jx_tagView(tagView: JXTagView, enableForIndex index: Int) -> Bool
|
||||
|
||||
@objc optional func jx_tagView(tagView: JXTagView, selectedForIndex index: Int) -> Bool
|
||||
}
|
||||
|
||||
class JXTagView: UIView {
|
||||
enum LayoutDirection: Int {
|
||||
case vertical = 0
|
||||
case horizontal = 1
|
||||
}
|
||||
|
||||
|
||||
weak var delegate: JXTagViewDelegate?
|
||||
weak var dataSource: JXTagViewDataSource?
|
||||
|
||||
var layoutDirection: LayoutDirection = .vertical
|
||||
|
||||
var tagBackgroundColor: UIColor = .systemBackground
|
||||
var tagSelectedBackgroundColor: UIColor = .systemBackground
|
||||
var tagDisabledBackgroundColor: UIColor = .systemBackground
|
||||
|
||||
var textFont: UIFont = .systemFont(ofSize: 14)
|
||||
|
||||
var textColor: UIColor = .colorFFFFFF()
|
||||
var textSelectedColor: UIColor = .colorFFFFFF()
|
||||
var textDisabledColor: UIColor = .gray
|
||||
|
||||
var tagCornerRadius: CGFloat = 14
|
||||
|
||||
var tagBorderWidth: CGFloat = 0
|
||||
var tagBorderColor: UIColor?
|
||||
var tagBorderSelectedColor: UIColor?
|
||||
|
||||
/// 0表示自适应
|
||||
var tagWidth: CGFloat = 0
|
||||
var tagHeight: CGFloat = 28
|
||||
var tagMinWidth: CGFloat = 0
|
||||
///文本边距
|
||||
var textMargin: CGFloat = 0
|
||||
///横向间隙
|
||||
var tagHorizontalGap: CGFloat = 10
|
||||
///纵向间隙
|
||||
var tagVerticalGap: CGFloat = 10
|
||||
///左右边距
|
||||
var leftAndRightMargin: CGFloat = 15
|
||||
///上下边距
|
||||
var topAndBottomMargin: CGFloat = 0
|
||||
///当前选中的标签
|
||||
private(set) var selectedIndex: Int?
|
||||
|
||||
private var oneReload = true
|
||||
|
||||
//MARK:-------------- 黄金分割线 --------------
|
||||
private(set) var buttonArr: [UIButton] = []
|
||||
|
||||
private var contentHeight: CGFloat = 0
|
||||
|
||||
override var intrinsicContentSize: CGSize {
|
||||
let height = (self.buttonArr.last?.frame.maxY ?? 0) + self.topAndBottomMargin
|
||||
if layoutDirection == .vertical {
|
||||
return CGSize(width: UIScreen.main.bounds.size.width, height: height)
|
||||
} else {
|
||||
let width = (self.buttonArr.last?.frame.maxX ?? 0) + self.leftAndRightMargin
|
||||
return CGSize(width: width, height: height)
|
||||
}
|
||||
}
|
||||
|
||||
// deinit {
|
||||
// NotificationCenter.default.removeObserver(self)
|
||||
// }
|
||||
|
||||
override init(frame: CGRect) {
|
||||
super.init(frame: frame)
|
||||
|
||||
}
|
||||
|
||||
required init?(coder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
if oneReload {
|
||||
self.reloadData()
|
||||
oneReload = false
|
||||
}
|
||||
|
||||
self.buttonArr.enumerated().forEach {
|
||||
let isEnble: Bool = self.delegate?.jx_tagView?(tagView: self, enableForIndex: $0) ?? true
|
||||
let isSelected: Bool = self.delegate?.jx_tagView?(tagView: self, selectedForIndex: $0) ?? false
|
||||
|
||||
let button = $1
|
||||
button.isSelected = isSelected
|
||||
button.isEnabled = isEnble
|
||||
|
||||
if isSelected {
|
||||
button.layer.borderColor = tagBorderSelectedColor?.cgColor
|
||||
} else {
|
||||
button.layer.borderColor = tagBorderColor?.cgColor
|
||||
}
|
||||
button.setBackgroundImage(UIImage(color: tagBackgroundColor), for: .normal)
|
||||
button.setBackgroundImage(UIImage(color: tagSelectedBackgroundColor), for: .selected)
|
||||
button.setBackgroundImage(UIImage(color: tagSelectedBackgroundColor), for: [.highlighted, .selected])
|
||||
button.setBackgroundImage(UIImage(color: tagDisabledBackgroundColor), for: .disabled)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
///数据没有变化,只是变化状态
|
||||
func updateState() {
|
||||
self.setNeedsLayout()
|
||||
self.layoutIfNeeded()
|
||||
}
|
||||
|
||||
///重置布局:当数据发生变化时,需要重置布局
|
||||
@objc func reloadData() {
|
||||
selectedIndex = nil
|
||||
for button in buttonArr {
|
||||
button.removeFromSuperview()
|
||||
}
|
||||
buttonArr.removeAll()
|
||||
|
||||
let number = self.dataSource?.jx_number(in: self) ?? 0
|
||||
if number == 0 {
|
||||
self.invalidateIntrinsicContentSize()
|
||||
return
|
||||
}
|
||||
|
||||
for index in 0...(number - 1) {
|
||||
let text = self.dataSource?.jx_tagView?(tagView: self, titleForIndex: index)
|
||||
let attributedTitle = self.dataSource?.jx_tagView?(tagView: self, attributedTitleForIndex: index)
|
||||
let isEnble: Bool = self.delegate?.jx_tagView?(tagView: self, enableForIndex: index) ?? true
|
||||
let isSelected: Bool = self.delegate?.jx_tagView?(tagView: self, selectedForIndex: index) ?? false
|
||||
|
||||
|
||||
let button = UIButton(type: .custom)
|
||||
button.tag = index
|
||||
button.setTitle(text, for: .normal)
|
||||
button.setAttributedTitle(attributedTitle, for: .normal)
|
||||
button.setTitleColor(textColor, for: .normal)
|
||||
button.setTitleColor(textSelectedColor, for: .selected)
|
||||
button.setTitleColor(textSelectedColor, for: [.highlighted, .selected])
|
||||
button.setTitleColor(textDisabledColor, for: .disabled)
|
||||
button.titleLabel?.font = textFont
|
||||
button.layer.cornerRadius = tagCornerRadius
|
||||
button.layer.masksToBounds = true
|
||||
button.layer.borderWidth = tagBorderWidth
|
||||
button.addTarget(self, action: #selector(handleButton(sender:)), for: .touchUpInside)
|
||||
button.isEnabled = isEnble
|
||||
button.titleLabel?.lineBreakMode = .byTruncatingTail
|
||||
button.titleEdgeInsets = UIEdgeInsets(top: 0, left: textMargin, bottom: 0, right: textMargin)
|
||||
|
||||
//修改选中状态
|
||||
button.isSelected = isSelected
|
||||
|
||||
if isSelected {
|
||||
selectedIndex = index
|
||||
}
|
||||
|
||||
self.addSubview(button)
|
||||
self.buttonArr.append(button)
|
||||
}
|
||||
self.updateLayout()
|
||||
|
||||
}
|
||||
|
||||
|
||||
///更新布局
|
||||
func updateLayout() {
|
||||
var x = leftAndRightMargin
|
||||
var y = topAndBottomMargin
|
||||
let height = tagHeight
|
||||
var width: CGFloat = 0
|
||||
|
||||
for button in buttonArr {
|
||||
if tagWidth <= 0 {
|
||||
if let string = button.currentTitle {
|
||||
width = string.size(font: textFont).width + (textMargin * 2)
|
||||
} else if let string = button.currentAttributedTitle {
|
||||
// width = string.size(font: textFont).width + (textMargin * 2)
|
||||
width = string.size().width + textMargin * 2
|
||||
}
|
||||
|
||||
//限制宽度不能超出屏幕
|
||||
if layoutDirection == .vertical {
|
||||
if width > self.width - (leftAndRightMargin * 2) {
|
||||
width = self.width - (leftAndRightMargin * 2)
|
||||
}
|
||||
}
|
||||
|
||||
//限制不能小于圆弧大小
|
||||
if width < tagCornerRadius * 2 {
|
||||
width = tagCornerRadius * 2
|
||||
}
|
||||
} else {
|
||||
width = tagWidth
|
||||
}
|
||||
|
||||
if width < tagMinWidth {
|
||||
width = tagMinWidth
|
||||
}
|
||||
|
||||
if layoutDirection == .vertical {
|
||||
//判断是否需要换行
|
||||
if Float(x + width + leftAndRightMargin) > Float(self.width) {
|
||||
x = leftAndRightMargin
|
||||
y = y + height + tagVerticalGap
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
button.frame = CGRect(x: x, y: y, width: width, height: height)
|
||||
|
||||
x = x + width + tagHorizontalGap
|
||||
}
|
||||
self.invalidateIntrinsicContentSize()
|
||||
}
|
||||
|
||||
|
||||
@objc func handleButton(sender: UIButton) {
|
||||
self.delegate?.jx_tagView?(tagView: self, didSelectedTagAt: sender.tag)
|
||||
}
|
||||
|
||||
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
|
||||
super.traitCollectionDidChange(previousTraitCollection)
|
||||
updateState()
|
||||
}
|
||||
|
||||
|
||||
// private func _setButtonBackgroundColor(button: UIButton, isSelected: Bool, isEnble: Bool) {
|
||||
// if !isEnble {
|
||||
// button.backgroundColor = tagDisabledBackgroundColor
|
||||
// } else if isSelected {
|
||||
// button.backgroundColor = tagSelectedBackgroundColor
|
||||
// } else {
|
||||
// button.backgroundColor = tagBackgroundColor
|
||||
// }
|
||||
//
|
||||
// if isSelected {
|
||||
// button.layer.borderColor = tagBorderSelectedColor?.cgColor
|
||||
// } else {
|
||||
// button.layer.borderColor = tagBorderColor?.cgColor
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
extension UIButton {
|
||||
// private struct AssociatedKeys {
|
||||
// static var borderColors: Int?
|
||||
// }
|
||||
|
||||
|
||||
|
||||
func jx_setBackgroundImage(_ image: UIImage?, for state: UIControl.State) {
|
||||
self.setBackgroundImage(image, for: state)
|
||||
if state == .selected {
|
||||
self.setBackgroundImage(image, for: [state, .highlighted])
|
||||
}
|
||||
}
|
||||
|
||||
func jx_setImage(_ image: UIImage?, for state: UIControl.State) {
|
||||
self.setImage(image, for: state)
|
||||
if state == .selected {
|
||||
self.setImage(image, for: [state, .highlighted])
|
||||
}
|
||||
}
|
||||
|
||||
func jx_setTitle(_ title: String?, for state: UIControl.State) {
|
||||
self.setTitle(title, for: state)
|
||||
if state == .selected {
|
||||
self.setTitle(title, for: [state, .highlighted])
|
||||
}
|
||||
}
|
||||
|
||||
func jx_setTitleColor(_ color: UIColor?, for state: UIControl.State) {
|
||||
self.setTitleColor(color, for: state)
|
||||
if state == .selected {
|
||||
self.setTitleColor(color, for: [state, .highlighted])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|