287 lines
11 KiB
Swift
287 lines
11 KiB
Swift
//
|
||
// MPPositive_SearchResultShowViewController.swift
|
||
// MusicPlayer
|
||
//
|
||
// Created by Mr.Zhou on 2024/5/12.
|
||
//
|
||
|
||
import UIKit
|
||
///搜索结果控制器
|
||
class MPPositive_SearchResultShowViewController: MPPositive_BaseViewController, UIViewControllerTransitioningDelegate {
|
||
//MARK: - 导航View中的控件
|
||
//顶部搜索textField
|
||
private lazy var searchTextField:UITextField = {
|
||
let textField = UITextField()
|
||
textField.delegate = self
|
||
textField.font = .systemFont(ofSize: 14*width, weight: .regular)
|
||
textField.textColor = .white
|
||
//设置一个富文本占位符
|
||
let attributedText = NSAttributedString(string: "Search songs,artists,playlists", attributes: [.font:UIFont.systemFont(ofSize: 14*width, weight: .regular), .foregroundColor:UIColor(hex: "#666666")])
|
||
textField.attributedPlaceholder = attributedText
|
||
return textField
|
||
}()
|
||
//删除文本按钮
|
||
private lazy var deleteBtn:UIButton = {
|
||
let btn:UIButton = .init()
|
||
btn.setBackgroundImage(UIImage(named: "Search_Delete'logo"), for: .normal)
|
||
btn.addTarget(self, action: #selector(deleteTextClick(_ :)), for: .touchUpInside)
|
||
return btn
|
||
}()
|
||
//cancel按钮
|
||
private lazy var cancelBtn:UIButton = {
|
||
let btn:UIButton = .init()
|
||
btn.setTitle("Cancel", for: .normal)
|
||
btn.setTitleColor(.init(hex: "#FFFFFF", alpha: 0.85), for: .normal)
|
||
btn.titleLabel?.font = .systemFont(ofSize: 14*width, weight: .regular)
|
||
btn.addTarget(self, action: #selector(backPopClick(_ :)), for: .touchUpInside)
|
||
return btn
|
||
}()
|
||
|
||
//搜索限定计时器
|
||
private var debounceTimer: Timer?
|
||
//对用户展示的搜索建议组
|
||
private var suggestionList:MPPositive_SearchSuggestionItemListModel!{
|
||
didSet{
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
guard let self = self else {return}
|
||
if suggestionList != nil {
|
||
//搜索建议组存在,将其显现
|
||
suggestionView.isHidden = false
|
||
suggestionView.suggestions = suggestionList.attributedTexts
|
||
MP_AnalyticsManager.shared.search_sug_showAction()
|
||
}else {
|
||
suggestionView.isHidden = true
|
||
suggestionView.suggestions = nil
|
||
}
|
||
}
|
||
}
|
||
}
|
||
private var isShowAd = true
|
||
//搜索文本
|
||
private var searchText:String?
|
||
///搜索历史View
|
||
private lazy var historyView:MPPositive_SearchHistoryView = .init(frame: .zero)
|
||
///搜索建议View
|
||
private lazy var suggestionView:MPPositive_SearchSuggestionsView = .init(frame: .zero)
|
||
///结果展示View
|
||
private lazy var resultsShowView:MPPositive_SearchResultsShowView = .init(frame: .zero, isShowAd: self.isShowAd)
|
||
|
||
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
|
||
super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil)
|
||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||
[weak self] in
|
||
guard let self = self else {return}
|
||
searchTextField.becomeFirstResponder()
|
||
}
|
||
}
|
||
|
||
init(_ text:String, isShowAd:Bool = true) {
|
||
super.init(nibName: nil, bundle: nil)
|
||
self.isShowAd = isShowAd
|
||
searchTextField.text = text
|
||
searchText = text
|
||
resultsShowView.loadModel = .init(text)
|
||
MP_AnalyticsManager.shared.search_sug_clickAction(text)
|
||
}
|
||
|
||
required init?(coder: NSCoder) {
|
||
super.init(coder: coder)
|
||
}
|
||
deinit {
|
||
debounceTimer?.invalidate()
|
||
debounceTimer = nil
|
||
}
|
||
override func viewDidLoad() {
|
||
super.viewDidLoad()
|
||
setTitle("Result")
|
||
setPopBtn()
|
||
configure()
|
||
historyView.selectedTagBlock = {
|
||
[weak self] (text) in
|
||
guard let self = self else {return}
|
||
searchText = text
|
||
searchTextField.text = text
|
||
resultsShowView.loadModel = .init(text)
|
||
MP_AnalyticsManager.shared.search_sug_clickAction(text)
|
||
suggestionView.isHidden = true
|
||
historyView.isHidden = true
|
||
}
|
||
suggestionView.selectedTextBlock = {
|
||
[weak self] (text) in
|
||
guard let self = self else {return}
|
||
searchText = text
|
||
searchTextField.text = text
|
||
resultsShowView.loadModel = .init(text)
|
||
MP_AnalyticsManager.shared.search_sug_clickAction(text)
|
||
suggestionView.isHidden = true
|
||
historyView.isHidden = true
|
||
}
|
||
resultsShowView.scrollBlock = {
|
||
[weak self] in
|
||
guard let self = self else {return}
|
||
DispatchQueue.main.async {
|
||
self.view?.endEditing(true)
|
||
}
|
||
}
|
||
|
||
|
||
errorBlock = {
|
||
[weak self] in
|
||
MP_HUD.hideNow()
|
||
self?.resultsShowView.isHidden = false
|
||
self?.resultsShowView.emptyImageView.isHidden = false
|
||
}
|
||
}
|
||
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
|
||
return MPPositive_PresentationController(presentedViewController: presented, presenting: presenting)
|
||
}
|
||
private func configure() {
|
||
//配置导航栏
|
||
let searchView = createSearchView()
|
||
navView.addSubview(searchView)
|
||
searchView.snp.makeConstraints { make in
|
||
make.width.equalTo(275*width)
|
||
make.height.equalTo(40*width)
|
||
make.centerY.equalToSuperview()
|
||
make.left.equalToSuperview().offset(18*width)
|
||
}
|
||
navView.addSubview(cancelBtn)
|
||
cancelBtn.snp.makeConstraints { make in
|
||
make.right.equalToSuperview().offset(-18*width)
|
||
make.centerY.equalToSuperview()
|
||
}
|
||
//添加historyView
|
||
view.addSubview(historyView)
|
||
historyView.snp.makeConstraints { make in
|
||
make.left.right.bottom.equalToSuperview()
|
||
make.top.equalTo(navView.snp.bottom)
|
||
}
|
||
historyView.isHidden = false
|
||
historyView.reloadHistory()
|
||
//添加suggestionView
|
||
view.addSubview(suggestionView)
|
||
suggestionView.snp.makeConstraints { make in
|
||
make.left.right.bottom.equalToSuperview()
|
||
make.top.equalTo(navView.snp.bottom)
|
||
}
|
||
suggestionView.isHidden = true
|
||
//添加resultsShowView
|
||
view.addSubview(resultsShowView)
|
||
resultsShowView.snp.makeConstraints { make in
|
||
make.left.right.bottom.equalToSuperview()
|
||
make.top.equalTo(navView.snp.bottom)
|
||
}
|
||
resultsShowView.isHidden = true
|
||
}
|
||
//生成一个顶部搜索框
|
||
private func createSearchView() -> UIView{
|
||
let searchView:UIView = UIView()
|
||
searchView.backgroundColor = .init(hex: "#000000")
|
||
searchView.isUserInteractionEnabled = true
|
||
searchView.layer.masksToBounds = true
|
||
searchView.layer.cornerRadius = 20*width
|
||
//添加一个icon
|
||
let iconImageView = UIImageView(image: .init(named: "Search_ICON'logo"))
|
||
searchView.addSubview(iconImageView)
|
||
iconImageView.snp.makeConstraints { make in
|
||
make.height.width.equalTo(24*width)
|
||
make.left.equalToSuperview().offset(8*width)
|
||
make.centerY.equalToSuperview()
|
||
}
|
||
searchView.addSubview(deleteBtn)
|
||
deleteBtn.snp.makeConstraints { make in
|
||
make.height.width.equalTo(24*width)
|
||
make.right.equalToSuperview().offset(-12*width)
|
||
make.centerY.equalToSuperview()
|
||
}
|
||
//添加textField
|
||
searchView.addSubview(searchTextField)
|
||
searchTextField.snp.makeConstraints { make in
|
||
make.top.bottom.equalToSuperview()
|
||
make.left.equalTo(iconImageView.snp.right).offset(14*width)
|
||
make.right.equalTo(deleteBtn.snp.left).offset(-12*width)
|
||
}
|
||
return searchView
|
||
}
|
||
|
||
//删除输入框文本
|
||
@objc private func deleteTextClick(_ sender:UIButton) {
|
||
//清空文本框内容,并隐藏两个View
|
||
searchTextField.text = ""
|
||
searchText = ""
|
||
suggestionView.suggestions = nil
|
||
resultsShowView.loadModel = nil
|
||
historyView.isHidden = false
|
||
}
|
||
//取消并返回上一页
|
||
@objc private func backPopClick(_ sender:UIButton) {
|
||
MPPositive_Debouncer.shared.call {
|
||
[weak self] in
|
||
guard let self = self else {return}
|
||
navigationController?.popToRootViewController(animated: false)
|
||
}
|
||
}
|
||
}
|
||
//MARK: - UITextFieldDelegate
|
||
extension MPPositive_SearchResultShowViewController:UITextFieldDelegate {
|
||
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
|
||
let text = (textField.text! as NSString).replacingCharacters(in: range, with: string)
|
||
guard text.count <= 30 else {
|
||
return false
|
||
}
|
||
//文本出现变化,隐藏结果View
|
||
resultsShowView.isHidden = true
|
||
historyView.isHidden = true
|
||
if text.isEmpty {
|
||
self.suggestionList = nil
|
||
cancelDebounceTimer()
|
||
historyView.isHidden = false
|
||
}else {
|
||
//触发网络请求
|
||
loadSearchSuggestions(text)
|
||
}
|
||
return true
|
||
}
|
||
//避免重复请求
|
||
private func cancelDebounceTimer() {
|
||
debounceTimer?.invalidate()
|
||
debounceTimer = nil
|
||
}
|
||
//当用户输入文本通过后进行检索
|
||
private func loadSearchSuggestions(_ text:String) {
|
||
cancelDebounceTimer()
|
||
//停止输入0.5秒后调用
|
||
debounceTimer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: false) { [weak self] _ in
|
||
self?.searchText = text
|
||
self?.fetchSearchSuggestions(text)
|
||
}
|
||
}
|
||
//获取建议组
|
||
private func fetchSearchSuggestions(_ text:String) {
|
||
MP_NetWorkManager.shared.requestSearchSuggestions(text) { [weak self] (result) in
|
||
self?.suggestionList = .init(self?.searchText ?? "", suggestions: result)
|
||
}
|
||
}
|
||
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
|
||
//判断textField是否存在文本
|
||
if let text = textField.text, text.isEmpty != true {
|
||
MPPositive_Debouncer.shared.call {
|
||
[weak self] in
|
||
guard let self = self else {return}
|
||
self.searchText = text
|
||
//用户输入了文本
|
||
resultsShowView.loadModel = .init(text)
|
||
MP_AnalyticsManager.shared.search_sug_clickAction(text)
|
||
suggestionView.isHidden = true
|
||
//停止输入
|
||
view.endEditing(true)
|
||
}
|
||
return true
|
||
}else {
|
||
return false
|
||
}
|
||
}
|
||
}
|
||
|