cdts/xdts-ios 3/TreeHole/CYHResetCode/CYH/QMUIKit/QMUIComponents/QMUISearchController.m

423 lines
18 KiB
Mathematica
Raw Permalink Normal View History

2023-07-27 09:20:00 +08:00
/**
* Tencent is pleased to support the open source community by making QMUI_iOS available.
* Copyright (C) 2016-2021 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
//
// QMUISearchController.m
// Test
//
// Created by QMUI Team on 16/5/25.
//
#import "QMUISearchController.h"
#import "QMUICore.h"
#import "QMUISearchBar.h"
#import "QMUICommonTableViewController.h"
#import "QMUIEmptyView.h"
#import "UISearchBar+QMUI.h"
#import "UITableView+QMUI.h"
#import "NSString+QMUI.h"
#import "NSObject+QMUI.h"
#import "UIView+QMUI.h"
#import "UIViewController+QMUI.h"
BeginIgnoreDeprecatedWarning
@class QMUISearchResultsTableViewController;
@protocol QMUISearchResultsTableViewControllerDelegate <NSObject>
- (void)didLoadTableViewInSearchResultsTableViewController:(QMUISearchResultsTableViewController *)viewController;
@end
@interface QMUISearchResultsTableViewController : QMUICommonTableViewController
@property(nonatomic,weak) id<QMUISearchResultsTableViewControllerDelegate> delegate;
@end
@implementation QMUISearchResultsTableViewController
- (void)initTableView {
[super initTableView];
self.tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
self.tableView.keyboardDismissMode = UIScrollViewKeyboardDismissModeOnDrag;
if ([self.delegate respondsToSelector:@selector(didLoadTableViewInSearchResultsTableViewController:)]) {
[self.delegate didLoadTableViewInSearchResultsTableViewController:self];
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if ([self.delegate isKindOfClass:QMUISearchController.class]) {
QMUISearchController *searchController = (QMUISearchController *)self.delegate;
if (searchController.emptyViewShowing) {
[searchController layoutEmptyView];
}
}
}
@end
@interface QMUICustomSearchController : UISearchController
@property(nonatomic, strong) UIView *customDimmingView;
@property(nonatomic, strong) UIColor *dimmingColor;
@end
@implementation QMUICustomSearchController
- (instancetype)initWithSearchResultsController:(UIViewController *)searchResultsController {
if (self = [super initWithSearchResultsController:searchResultsController]) {
if (@available(iOS 15.0, *)) {
self.dimsBackgroundDuringPresentation = YES;// iOS 15 NO
}
}
return self;
}
- (void)setCustomDimmingView:(UIView *)customDimmingView {
if (_customDimmingView != customDimmingView) {
[_customDimmingView removeFromSuperview];
}
_customDimmingView = customDimmingView;
self.dimsBackgroundDuringPresentation = !_customDimmingView;
if ([self isViewLoaded]) {
[self addCustomDimmingView];
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self addCustomDimmingView];
}
- (void)addCustomDimmingView {
UIView *superviewOfDimmingView = self.searchResultsController.view.superview;
if (self.customDimmingView && self.customDimmingView.superview != superviewOfDimmingView) {
[superviewOfDimmingView insertSubview:self.customDimmingView atIndex:0];
[self layoutCustomDimmingView];
}
}
- (void)layoutCustomDimmingView {
UIView *searchBarContainerView = nil;
for (UIView *subview in self.view.subviews) {
if ([NSStringFromClass(subview.class) isEqualToString:@"_UISearchBarContainerView"]) {
searchBarContainerView = subview;
break;
}
}
self.customDimmingView.frame = CGRectInsetEdges(self.customDimmingView.superview.bounds, UIEdgeInsetsMake(searchBarContainerView ? CGRectGetMaxY(searchBarContainerView.frame) : 0, 0, 0, 0));
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
if (self.customDimmingView) {
[UIView animateWithDuration:[CATransaction animationDuration] animations:^{
[self layoutCustomDimmingView];
}];
}
}
@end
@interface QMUISearchController () <QMUISearchResultsTableViewControllerDelegate>
@property(nonatomic,strong) QMUICustomSearchController *searchController;
@end
@implementation QMUISearchController
- (instancetype)initWithContentsViewController:(UIViewController *)viewController resultsTableViewStyle:(UITableViewStyle)resultsTableViewStyle {
if (self = [self initWithNibName:nil bundle:nil]) {
// definesPresentationContext YES
// 1searchBarnavigationBar
// 2使tableViewcontentInset.topsearchBar
viewController.definesPresentationContext = YES;
QMUISearchResultsTableViewController *searchResultsViewController = [[QMUISearchResultsTableViewController alloc] initWithStyle:resultsTableViewStyle];
searchResultsViewController.delegate = self;
self.searchController = [[QMUICustomSearchController alloc] initWithSearchResultsController:searchResultsViewController];
self.searchController.searchResultsUpdater = self;
self.searchController.delegate = self;
_searchBar = self.searchController.searchBar;
if (CGRectIsEmpty(self.searchBar.frame)) {
// iOS8 searchBar.frame CGRectZero sizeToFit
[self.searchBar sizeToFit];
}
[self.searchBar qmui_styledAsQMUISearchBar];
self.hidesNavigationBarDuringPresentation = YES;
}
return self;
}
- (instancetype)initWithContentsViewController:(UIViewController *)viewController {
return [self initWithContentsViewController:viewController resultsTableViewStyle:UITableViewStylePlain];
}
- (void)viewDidLoad {
[super viewDidLoad];
// loadView QMUISearchController self.searchController loadView dealloc self.searchController self.searchController loadView
[self.searchController loadViewIfNeeded];
}
- (void)setSearchResultsDelegate:(id<QMUISearchControllerDelegate>)searchResultsDelegate {
_searchResultsDelegate = searchResultsDelegate;
self.tableView.dataSource = _searchResultsDelegate;
self.tableView.delegate = _searchResultsDelegate;
}
- (void)setDimmingColor:(UIColor *)dimmingColor {
_dimmingColor = dimmingColor;
self.searchController.dimmingColor = dimmingColor;
[QMUIHelper executeBlock:^{
// - [UIDimmingView updateBackgroundColor]
OverrideImplementation(NSClassFromString([NSString qmui_stringByConcat:@"UI", @"Dimming", @"View", nil]), NSSelectorFromString([NSString qmui_stringByConcat:@"update", @"Background", @"Color", nil]), ^id(__unsafe_unretained Class originClass, SEL originCMD, IMP (^originalIMPProvider)(void)) {
return ^(UIView *selfObject) {
for (UIView *subview in selfObject.superview.subviews) {
if ([NSStringFromClass(subview.class) isEqualToString:[NSString qmui_stringByConcat:@"_", @"UISearchController", @"View", nil]]) {
UISearchController *searchController = subview.qmui_viewController;
if ([searchController isKindOfClass:UISearchController.class]) {
if ([searchController respondsToSelector:@selector(dimmingColor)]) {
BeginIgnorePerformSelectorLeaksWarning
UIColor *color = [searchController performSelector:@selector(dimmingColor)];
EndIgnorePerformSelectorLeaksWarning
if (color) {
[selfObject qmui_performSelector:@selector(setDimmingColor:) withArguments:&color, nil];
}
}
}
break;
}
}
// call super
void (*originSelectorIMP)(id, SEL);
originSelectorIMP = (void (*)(id, SEL))originalIMPProvider();
originSelectorIMP(selfObject, originCMD);
};
});
} oncePerIdentifier:@"QMUISearchController dimmingColor"];
}
- (BOOL)isActive {
return self.searchController.active;
}
- (void)setActive:(BOOL)active {
[self setActive:active animated:NO];
}
- (void)setActive:(BOOL)active animated:(BOOL)animated {
self.searchController.active = active;
}
- (UITableView *)tableView {
return ((QMUICommonTableViewController *)self.searchController.searchResultsController).tableView;
}
- (void)setLaunchView:(UIView *)dimmingView {
_launchView = dimmingView;
self.searchController.customDimmingView = _launchView;
}
- (BOOL)hidesNavigationBarDuringPresentation {
return self.searchController.hidesNavigationBarDuringPresentation;
}
- (void)setHidesNavigationBarDuringPresentation:(BOOL)hidesNavigationBarDuringPresentation {
self.searchController.hidesNavigationBarDuringPresentation = hidesNavigationBarDuringPresentation;
}
- (void)setQmui_prefersStatusBarHiddenBlock:(BOOL (^)(void))qmui_prefersStatusBarHiddenBlock {
[super setQmui_prefersStatusBarHiddenBlock:qmui_prefersStatusBarHiddenBlock];
self.searchController.qmui_prefersStatusBarHiddenBlock = qmui_prefersStatusBarHiddenBlock;
}
- (void)setQmui_preferredStatusBarStyleBlock:(UIStatusBarStyle (^)(void))qmui_preferredStatusBarStyleBlock {
[super setQmui_preferredStatusBarStyleBlock:qmui_preferredStatusBarStyleBlock];
self.searchController.qmui_preferredStatusBarStyleBlock = qmui_preferredStatusBarStyleBlock;
}
#pragma mark - QMUIEmptyView
- (void)showEmptyView {
// emptyView
// searchController:updateResultsForSearchString:showEmptyViewemptyViewshowEmptyViewsearchBar.text.lengthshowEmptyView便
if (self.searchBar.text.length <= 0) {
return;
}
[super showEmptyView];
//
self.emptyView.backgroundColor = TableViewBackgroundColor ?: UIColorWhite;
if ([self.searchResultsDelegate respondsToSelector:@selector(searchController:willShowEmptyView:)]) {
[self.searchResultsDelegate searchController:self willShowEmptyView:self.emptyView];
}
if (self.searchController) {
UIView *superview = self.searchController.searchResultsController.view;
[superview addSubview:self.emptyView];
} else {
QMUIAssert(NO, NSStringFromClass(self.class), @"QMUISearchController 无法为 emptyView 找到合适的 superview");
}
[self layoutEmptyView];
}
#pragma mark - <QMUISearchResultsTableViewControllerDelegate>
- (void)didLoadTableViewInSearchResultsTableViewController:(QMUISearchResultsTableViewController *)viewController {
if ([self.searchResultsDelegate respondsToSelector:@selector(searchController:didLoadSearchResultsTableView:)]) {
[self.searchResultsDelegate searchController:self didLoadSearchResultsTableView:viewController.tableView];
}
}
#pragma mark - <UISearchResultsUpdating>
- (void)updateSearchResultsForSearchController:(UISearchController *)searchController {
if ([self.searchResultsDelegate respondsToSelector:@selector(searchController:updateResultsForSearchString:)]) {
[self.searchResultsDelegate searchController:self updateResultsForSearchString:searchController.searchBar.text];
}
}
#pragma mark - <UISearchControllerDelegate>
- (void)willPresentSearchController:(UISearchController *)searchController {
if (self.searchController.qmui_prefersStatusBarHiddenBlock || self.searchController.qmui_preferredStatusBarStyleBlock) {
[self.searchController setNeedsStatusBarAppearanceUpdate];
}
if ([self.searchResultsDelegate respondsToSelector:@selector(willPresentSearchController:)]) {
[self.searchResultsDelegate willPresentSearchController:self];
}
}
- (void)didPresentSearchController:(UISearchController *)searchController {
if ([self.searchResultsDelegate respondsToSelector:@selector(didPresentSearchController:)]) {
[self.searchResultsDelegate didPresentSearchController:self];
}
}
- (void)willDismissSearchController:(UISearchController *)searchController {
if (self.searchController.qmui_prefersStatusBarHiddenBlock || self.searchController.qmui_preferredStatusBarStyleBlock) {
[self.searchController setNeedsStatusBarAppearanceUpdate];
}
if ([self.searchResultsDelegate respondsToSelector:@selector(willDismissSearchController:)]) {
[self.searchResultsDelegate willDismissSearchController:self];
}
}
- (void)didDismissSearchController:(UISearchController *)searchController {
// 退emptyView
[self hideEmptyView];
if ([self.searchResultsDelegate respondsToSelector:@selector(didDismissSearchController:)]) {
[self.searchResultsDelegate didDismissSearchController:self];
}
}
@end
EndIgnoreDeprecatedWarning
@implementation QMUICommonTableViewController (Search)
QMUISynthesizeIdStrongProperty(searchController, setSearchController)
QMUISynthesizeIdStrongProperty(searchBar, setSearchBar)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
ExtendImplementationOfVoidMethodWithoutArguments([QMUICommonTableViewController class], @selector(initSubviews), ^(QMUICommonTableViewController *selfObject) {
[selfObject initSearchController];
});
ExtendImplementationOfVoidMethodWithSingleArgument([QMUICommonTableViewController class], @selector(viewWillAppear:), BOOL, ^(QMUICommonTableViewController *selfObject, BOOL firstArgv) {
if (!selfObject.searchController.tableView.allowsMultipleSelection) {
[selfObject.searchController.tableView qmui_clearsSelection];
}
});
ExtendImplementationOfVoidMethodWithoutArguments([QMUICommonTableViewController class], @selector(showEmptyView), ^(QMUICommonTableViewController *selfObject) {
if ([selfObject shouldHideSearchBarWhenEmptyViewShowing] && selfObject.tableView.tableHeaderView == selfObject.searchBar) {
selfObject.tableView.tableHeaderView = nil;
}
});
ExtendImplementationOfVoidMethodWithoutArguments([QMUICommonTableViewController class], @selector(hideEmptyView), ^(QMUICommonTableViewController *selfObject) {
if (selfObject.shouldShowSearchBar && [selfObject shouldHideSearchBarWhenEmptyViewShowing] && selfObject.tableView.tableHeaderView == nil) {
[selfObject initSearchController];
// emptyView tableHeaderView shouldHideTableHeaderViewInitial force YES
// https://github.com/Tencent/QMUI_iOS/issues/128
selfObject.tableView.tableHeaderView = selfObject.searchBar;
[selfObject hideTableHeaderViewInitialIfCanWithAnimated:NO force:YES];
}
});
});
}
static char kAssociatedObjectKey_shouldShowSearchBar;
- (void)setShouldShowSearchBar:(BOOL)shouldShowSearchBar {
BOOL isValueChanged = self.shouldShowSearchBar != shouldShowSearchBar;
if (!isValueChanged) {
return;
}
objc_setAssociatedObject(self, &kAssociatedObjectKey_shouldShowSearchBar, @(shouldShowSearchBar), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
if (shouldShowSearchBar) {
[self initSearchController];
} else {
if (self.searchBar) {
if (self.tableView.tableHeaderView == self.searchBar) {
self.tableView.tableHeaderView = nil;
}
[self.searchBar removeFromSuperview];
self.searchBar = nil;
}
if (self.searchController) {
self.searchController.searchResultsDelegate = nil;
self.searchController = nil;
}
}
}
- (BOOL)shouldShowSearchBar {
return [((NSNumber *)objc_getAssociatedObject(self, &kAssociatedObjectKey_shouldShowSearchBar)) boolValue];
}
- (void)initSearchController {
if ([self isViewLoaded] && self.shouldShowSearchBar && !self.searchController) {
self.searchController = [[QMUISearchController alloc] initWithContentsViewController:self resultsTableViewStyle:self.tableView.style];
self.searchController.searchResultsDelegate = self;
self.searchController.searchBar.placeholder = @"搜索";
self.searchController.searchBar.qmui_usedAsTableHeaderView = YES;// tableHeaderView 使 searchBar YES bug
self.tableView.tableHeaderView = self.searchController.searchBar;
self.searchBar = self.searchController.searchBar;
}
}
- (BOOL)shouldHideSearchBarWhenEmptyViewShowing {
return NO;
}
#pragma mark - <QMUISearchControllerDelegate>
- (void)searchController:(QMUISearchController *)searchController updateResultsForSearchString:(NSString *)searchString {
}
@end