├── .gitignore ├── LICENSE ├── LLSearchViewController ├── LLSearchViewController.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata ├── LLSearchViewController │ ├── Assets.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ ├── Contents.json │ │ ├── navi_back_w.imageset │ │ │ ├── Contents.json │ │ │ ├── navi_back_w@2x.png │ │ │ └── navi_back_w@3x.png │ │ └── nearbyshop_showMap.imageset │ │ │ ├── Contents.json │ │ │ ├── nearbyshop_showMap@2x.png │ │ │ └── nearbyshop_showMap@3x.png │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── Class │ │ ├── Base │ │ │ ├── BaseCommonSearchVC.h │ │ │ └── BaseCommonSearchVC.m │ │ ├── CommonVC │ │ │ ├── Base.lproj │ │ │ │ └── Main.storyboard │ │ │ ├── CategoryAndHistoryVC.h │ │ │ ├── CategoryAndHistoryVC.m │ │ │ ├── HistoryAnimationVC.h │ │ │ ├── HistoryAnimationVC.m │ │ │ ├── HistoryVC.h │ │ │ ├── HistoryVC.m │ │ │ ├── LLTestViewController.h │ │ │ ├── LLTestViewController.m │ │ │ ├── ViewController.h │ │ │ └── ViewController.m │ │ ├── Const │ │ │ ├── ZYHTFileNameConst.h │ │ │ └── ZYHTFileNameConst.m │ │ ├── MainVC │ │ │ ├── AppDelegate.h │ │ │ └── AppDelegate.m │ │ └── SearchVC │ │ │ ├── HistoryAndCategorySearchVC.h │ │ │ ├── HistoryAndCategorySearchVC.m │ │ │ ├── HistorySearchVC.h │ │ │ ├── HistorySearchVC.m │ │ │ ├── Model │ │ │ ├── TagTypeModel.h │ │ │ └── TagTypeModel.m │ │ │ └── Presenter │ │ │ ├── HistoryAndCategorySearchCategoryViewP.h │ │ │ ├── HistoryAndCategorySearchCategoryViewP.m │ │ │ ├── HistoryAndCategorySearchHistroyViewP.h │ │ │ ├── HistoryAndCategorySearchHistroyViewP.m │ │ │ ├── HistorySearchHistroyViewP.h │ │ │ └── HistorySearchHistroyViewP.m │ ├── Info.plist │ ├── LLSearchViewControllerBase │ │ ├── ExtensionPresenter │ │ │ ├── NBSSearchShopCategoryViewCellP.h │ │ │ └── NBSSearchShopCategoryViewCellP.m │ │ ├── ExtensionView │ │ │ ├── LLSearchResultListView.h │ │ │ ├── LLSearchResultListView.m │ │ │ ├── NBSSearchShopCategoryView.h │ │ │ ├── NBSSearchShopCategoryView.m │ │ │ ├── NBSSearchShopHistoryView.h │ │ │ └── NBSSearchShopHistoryView.m │ │ ├── SearchBar │ │ │ ├── LLSearchBar.h │ │ │ └── LLSearchBar.m │ │ ├── SearchNaviBarView │ │ │ ├── LLSearchNaviBarView.h │ │ │ └── LLSearchNaviBarView.m │ │ ├── SearchSavePresenter │ │ │ ├── LLNaviSearchHistorySaveBasePresenter.h │ │ │ └── LLNaviSearchHistorySaveBasePresenter.m │ │ ├── SearchVC │ │ │ ├── LLNaviSearchBaseVC.h │ │ │ └── LLNaviSearchBaseVC.m │ │ ├── Utils │ │ │ ├── Category │ │ │ │ ├── LLSearchVCConst.h │ │ │ │ ├── LLSearchVCConst.m │ │ │ │ ├── UIColor+LLHex.h │ │ │ │ ├── UIColor+LLHex.m │ │ │ │ ├── UIView+LLRect.h │ │ │ │ └── UIView+LLRect.m │ │ │ ├── LLSearchHistorySaveUtils.h │ │ │ ├── LLSearchHistorySaveUtils.m │ │ │ ├── LLTagViewUtils.h │ │ │ └── LLTagViewUtils.m │ │ └── search_icon │ │ │ ├── clearImage@2x.png │ │ │ ├── clearImage@3x.png │ │ │ ├── search@2x.png │ │ │ └── search@3x.png │ └── Supporting Files │ │ └── main.m ├── LLSearchViewControllerTests │ ├── Info.plist │ └── LLSearchViewControllerTests.m └── LLSearchViewControllerUITests │ ├── Info.plist │ └── LLSearchViewControllerUITests.m ├── MLeaksFinder ├── MLeakedObjectProxy.h ├── MLeakedObjectProxy.m ├── MLeaksFinder.h ├── MLeaksMessenger.h ├── MLeaksMessenger.m ├── NSObject+MemoryLeak.h ├── NSObject+MemoryLeak.m ├── UIApplication+MemoryLeak.h ├── UIApplication+MemoryLeak.m ├── UINavigationController+MemoryLeak.h ├── UINavigationController+MemoryLeak.m ├── UIPageViewController+MemoryLeak.h ├── UIPageViewController+MemoryLeak.m ├── UISplitViewController+MemoryLeak.h ├── UISplitViewController+MemoryLeak.m ├── UITabBarController+MemoryLeak.h ├── UITabBarController+MemoryLeak.m ├── UITouch+MemoryLeak.h ├── UITouch+MemoryLeak.m ├── UIView+MemoryLeak.h ├── UIView+MemoryLeak.m ├── UIViewController+MemoryLeak.h └── UIViewController+MemoryLeak.m ├── README.md └── Screenshots └── 0.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | # CocoaPods 32 | # 33 | # We recommend against adding the Pods directory to your .gitignore. However 34 | # you should judge for yourself, the pros and cons are mentioned at: 35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 36 | # 37 | # Pods/ 38 | 39 | # Carthage 40 | # 41 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 42 | # Carthage/Checkouts 43 | 44 | Carthage/Build 45 | 46 | # fastlane 47 | # 48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 49 | # screenshots whenever they are needed. 50 | # For more information about the recommended setup visit: 51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 52 | 53 | fastlane/report.xml 54 | fastlane/Preview.html 55 | fastlane/screenshots 56 | fastlane/test_output 57 | 58 | # Code Injection 59 | # 60 | # After new code Injection tools there's a generated folder /iOSInjectionProject 61 | # https://github.com/johnno1962/injectionforxcode 62 | 63 | iOSInjectionProject/ 64 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 李龙 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | } 88 | ], 89 | "info" : { 90 | "version" : 1, 91 | "author" : "xcode" 92 | } 93 | } -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Assets.xcassets/navi_back_w.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "navi_back_w@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "navi_back_w@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Assets.xcassets/navi_back_w.imageset/navi_back_w@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/LLSearchViewController/LLSearchViewController/Assets.xcassets/navi_back_w.imageset/navi_back_w@2x.png -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Assets.xcassets/navi_back_w.imageset/navi_back_w@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/LLSearchViewController/LLSearchViewController/Assets.xcassets/navi_back_w.imageset/navi_back_w@3x.png -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Assets.xcassets/nearbyshop_showMap.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "nearbyshop_showMap@2x.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "filename" : "nearbyshop_showMap@3x.png", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Assets.xcassets/nearbyshop_showMap.imageset/nearbyshop_showMap@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/LLSearchViewController/LLSearchViewController/Assets.xcassets/nearbyshop_showMap.imageset/nearbyshop_showMap@2x.png -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Assets.xcassets/nearbyshop_showMap.imageset/nearbyshop_showMap@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/LLSearchViewController/LLSearchViewController/Assets.xcassets/nearbyshop_showMap.imageset/nearbyshop_showMap@3x.png -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/Base/BaseCommonSearchVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // BaseCommonSearchVC.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/9/3. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface BaseCommonSearchVC : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/Base/BaseCommonSearchVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // BaseCommonSearchVC.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/9/3. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "BaseCommonSearchVC.h" 10 | 11 | @interface BaseCommonSearchVC () 12 | 13 | @end 14 | 15 | @implementation BaseCommonSearchVC 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | // Do any additional setup after loading the view. 20 | } 21 | 22 | 23 | -(void)dealloc 24 | { 25 | NSLog(@"////////////////////////////// 父类也没了 //////////////////////////////////////////"); 26 | } 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/CategoryAndHistoryVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // CategoryAndHistoryVC.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "BaseCommonSearchVC.h" 10 | 11 | @interface CategoryAndHistoryVC : BaseCommonSearchVC 12 | 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/CategoryAndHistoryVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // CategoryAndHistoryVC.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "CategoryAndHistoryVC.h" 10 | #import "LLSearchNaviBarView.h" 11 | #import "LLSearchVCConst.h" 12 | #import "HistoryAndCategorySearchVC.h" 13 | #import "LLTestViewController.h" 14 | 15 | @interface CategoryAndHistoryVC () 16 | 17 | 18 | @end 19 | 20 | @implementation CategoryAndHistoryVC 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | self.view.backgroundColor = [UIColor whiteColor]; 26 | self.navigationController.navigationBar.hidden = YES; 27 | 28 | [self creatSearchNaviBar]; 29 | } 30 | 31 | - (void)creatSearchNaviBar{ 32 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 33 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 34 | 35 | @LLWeakObj(self); 36 | [searchNaviBarView showbackBtnWith:[UIImage imageNamed:@"navi_back_w"] onClick:^(UIButton *btn) { 37 | @LLStrongObj(self); 38 | [self.navigationController popViewControllerAnimated:YES]; 39 | }]; 40 | 41 | 42 | [searchNaviBarView setSearchBarBeignOnClickBlock:^{ 43 | @LLStrongObj(self); 44 | 45 | HistoryAndCategorySearchVC *searShopVC = [HistoryAndCategorySearchVC new]; 46 | 47 | //(1)点击分类 (2)用户点击键盘"搜索"按钮 (3)点击历史搜索记录 48 | [searShopVC beginSearch:^(NaviBarSearchType searchType,NBSSearchShopCategoryViewCellP *categorytagP,UILabel *historyTagLabel,LLSearchBar *searchBar) { 49 | // @LLStrongObj(self); 50 | 51 | NSLog(@"historyTagLabel:%@--->searchBar:%@--->categotyTitle:%@--->%@",historyTagLabel.text,searchBar.text,categorytagP.categotyTitle,categorytagP.categotyID); 52 | 53 | }]; 54 | //执行即时搜索匹配 55 | NSArray *tempArray = @[@"Java", @"Python", @"Objective-C", @"Swift", @"C", @"C++", @"PHP", @"C#", @"Perl", @"Go", @"JavaScript", @"R", @"Ruby", @"MATLAB"]; 56 | 57 | 58 | @LLWeakObj(searShopVC); 59 | [searShopVC searchbarDidChange:^(NaviBarSearchType searchType, LLSearchBar *searchBar, NSString *searchText) { 60 | @LLStrongObj(searShopVC); 61 | 62 | //FIXME:这里模拟网络请求数据!!! 63 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 64 | searShopVC.resultListArray = tempArray; 65 | }); 66 | }]; 67 | 68 | //点击了即时匹配选项 69 | [searShopVC resultListViewDidSelectedIndex:^(UITableView *tableView, NSInteger index) { 70 | // @LLStrongObj(self); 71 | NSLog(@"点击了即时搜索内容第%zd行的%@数据",index,tempArray[index]); 72 | }]; 73 | 74 | [self.navigationController presentViewController:searShopVC animated:NO completion:nil]; 75 | 76 | }]; 77 | 78 | [self.view addSubview:searchNaviBarView]; 79 | } 80 | 81 | -(void)dealloc{ 82 | NSLog(@"CategoryAndHistoryVC 页面销毁"); 83 | } 84 | 85 | 86 | 87 | 88 | @end 89 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/HistoryAnimationVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryAnimationVC.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "BaseCommonSearchVC.h" 10 | 11 | @interface HistoryAnimationVC : BaseCommonSearchVC 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/HistoryAnimationVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryAnimationVC.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "HistoryAnimationVC.h" 10 | #import "HistorySearchVC.h" 11 | #import "LLSearchVCConst.h" 12 | #import "LLSearchNaviBarView.h" 13 | 14 | @interface HistoryAnimationVC () 15 | 16 | @end 17 | 18 | @implementation HistoryAnimationVC 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | self.view.backgroundColor = [UIColor whiteColor]; 23 | self.navigationController.navigationBar.hidden = YES; 24 | 25 | [self creatSearchNaviBar]; 26 | } 27 | 28 | 29 | - (void)creatSearchNaviBar{ 30 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 31 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 32 | 33 | @LLWeakObj(self); 34 | [searchNaviBarView showbackBtnWith:[UIImage imageNamed:@"navi_back_w"] onClick:^(UIButton *btn) { 35 | @LLStrongObj(self); 36 | [self.navigationController popViewControllerAnimated:YES]; 37 | }]; 38 | 39 | [searchNaviBarView setSearchBarBeignOnClickBlock:^{ 40 | @LLStrongObj(self); 41 | HistorySearchVC *searShopVC = [HistorySearchVC new]; 42 | //在HistroySearchVC 中实现方法 43 | [searShopVC setSearchMethod]; 44 | [self.navigationController presentViewController:searShopVC animated:YES completion:nil]; 45 | }]; 46 | 47 | [self.view addSubview:searchNaviBarView]; 48 | } 49 | 50 | 51 | 52 | -(void)dealloc{ 53 | NSLog(@"HistoryAnimationVC 页面销毁"); 54 | } 55 | @end 56 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/HistoryVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryVC.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | //#import "BaseCommonSearchVC.h" 10 | #import 11 | 12 | @interface HistoryVC : UIViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/HistoryVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryVC.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "HistoryVC.h" 10 | #import "HistorySearchVC.h" 11 | #import "LLSearchVCConst.h" 12 | 13 | 14 | 15 | 16 | @interface HistoryVC () 17 | 18 | @end 19 | 20 | @implementation HistoryVC 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | self.view.backgroundColor = [UIColor whiteColor]; 26 | self.navigationController.navigationBar.hidden = YES; 27 | 28 | 29 | [self creatSearchNaviBar]; 30 | 31 | } 32 | 33 | 34 | - (void)creatSearchNaviBar{ 35 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 36 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 37 | 38 | 39 | @LLWeakObj(self); 40 | [searchNaviBarView showbackBtnWith:[UIImage imageNamed:@"navi_back_w"] onClick:^(UIButton *btn) { 41 | @LLStrongObj(self); 42 | [self.navigationController popViewControllerAnimated:YES]; 43 | }]; 44 | 45 | 46 | [searchNaviBarView setSearchBarBeignOnClickBlock:^{ 47 | @LLStrongObj(self); 48 | 49 | HistorySearchVC *searShopVC = [HistorySearchVC new]; 50 | 51 | 52 | @LLWeakObj(searShopVC); 53 | //(1)点击分类 (2)用户点击键盘"搜索"按钮 (3)点击历史搜索记录 54 | [searShopVC beginSearch:^(NaviBarSearchType searchType,NBSSearchShopCategoryViewCellP *categorytagP,UILabel *historyTagLabel,LLSearchBar *searchBar) { 55 | @LLStrongObj(searShopVC); 56 | 57 | NSLog(@"historyTagLabel:%@--->searchBar:%@--->categotyTitle:%@--->%@",historyTagLabel.text,searchBar.text,categorytagP.categotyTitle,categorytagP.categotyID); 58 | 59 | searShopVC.searchBarText = @"你选择的搜索内容显示到这里"; 60 | }]; 61 | 62 | 63 | //执行即时搜索匹配 64 | NSArray *tempArray = @[@"Java", @"Python"]; 65 | 66 | 67 | [searShopVC searchbarDidChange:^(NaviBarSearchType searchType, LLSearchBar *searchBar, NSString *searchText) { 68 | @LLStrongObj(searShopVC); 69 | 70 | //FIXME:这里模拟网络请求数据!!! 71 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 72 | searShopVC.resultListArray = tempArray; 73 | }); 74 | }]; 75 | 76 | [self.navigationController presentViewController:searShopVC animated:nil completion:nil]; 77 | }]; 78 | 79 | [self.view addSubview:searchNaviBarView]; 80 | } 81 | 82 | -(void)dealloc{ 83 | NSLog(@"HistoryVC 页面销毁"); 84 | } 85 | 86 | @end 87 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/LLTestViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLTestViewController.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/9/3. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LLTestViewController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/LLTestViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLTestViewController.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/9/3. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "LLTestViewController.h" 10 | 11 | @interface LLTestViewController () 12 | 13 | @end 14 | 15 | @implementation LLTestViewController 16 | 17 | - (void)viewDidLoad { 18 | [super viewDidLoad]; 19 | 20 | 21 | self.view.backgroundColor = [UIColor whiteColor]; 22 | 23 | UIButton *button = [[UIButton alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; 24 | [button setTitle:@"1000" forState:UIControlStateNormal]; 25 | [button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 26 | [button addTarget:self action:@selector(buttonOnClick) forControlEvents:UIControlEventTouchUpInside]; 27 | [self.view addSubview:button]; 28 | 29 | } 30 | 31 | - (void)buttonOnClick { 32 | 33 | [self dismissViewControllerAnimated:YES completion:nil]; 34 | } 35 | 36 | -(void)dealloc 37 | { 38 | NSLog(@"LLTestViewController 页面销毁"); 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/CommonVC/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "HistoryAndCategorySearchVC.h" 11 | #import "HistorySearchVC.h" 12 | #import "CategoryAndHistoryVC.h" 13 | #import "HistoryVC.h" 14 | 15 | #import 16 | #import "UIView+LLRect.h" 17 | #import "HistoryAnimationVC.h" 18 | 19 | 20 | @interface ViewController () 21 | @property (nonatomic,strong) UIScrollView *myBGScrollView; 22 | 23 | @end 24 | 25 | @implementation ViewController 26 | 27 | - (void)viewDidLoad { 28 | [super viewDidLoad]; 29 | // Do any additional setup after loading the view, typically from a nib. 30 | 31 | self.navigationController.navigationBar.hidden = YES; 32 | [self creatSearchNaviBarStyle1]; 33 | [self creatSearchNaviBarStyle2]; 34 | [self creatSearchNaviBarStyle3]; 35 | [self creatSearchNaviBarStyle4]; 36 | [self creatSearchNaviBarStyle5]; 37 | 38 | 39 | 40 | [self setButton:@"分类和历史记录搜索页面->" x:15 y:500 sel:@selector(buttonObClick1)]; 41 | [self setButton:@"历史记录搜索页面->" x:160 y:500 sel:@selector(buttonObClick2)]; 42 | [self setButton:@"历史记录搜索页面(动画)->" x:15 y:565 sel:@selector(buttonObClick3)]; 43 | // [self setButton:@"push界面->" x:160 y:565 sel:@selector(buttonObClick4)]; //暂时不实现 44 | } 45 | 46 | 47 | 48 | //--------------------------------------------------------------------------------------------------- 49 | #pragma mark ================================== LLSearchNaviBarView样式 ================================== 50 | //--------------------------------------------------------------------------------------------------- 51 | - (void)creatSearchNaviBarStyle1{ 52 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 53 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 54 | 55 | [searchNaviBarView setSearchBarBeignOnClickBlock:nil]; 56 | searchNaviBarView.y = -20; 57 | [self.myBGScrollView addSubview:searchNaviBarView]; 58 | } 59 | 60 | 61 | 62 | - (void)creatSearchNaviBarStyle2{ 63 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 64 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 65 | 66 | [searchNaviBarView showRightOneBtnWith:[UIImage imageNamed:@"nearbyshop_showMap"] onClick:nil]; 67 | 68 | [searchNaviBarView setSearchBarBeignOnClickBlock:nil]; 69 | 70 | searchNaviBarView.y = 100; 71 | [self.myBGScrollView addSubview:searchNaviBarView]; 72 | } 73 | 74 | 75 | - (void)creatSearchNaviBarStyle3{ 76 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 77 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 78 | 79 | [searchNaviBarView showbackBtnWith:[UIImage imageNamed:@"navi_back_w"] onClick:nil]; 80 | [searchNaviBarView showRightOneBtnWith:[UIImage imageNamed:@"nearbyshop_showMap"] onClick:nil]; 81 | 82 | [searchNaviBarView setSearchBarBeignOnClickBlock:nil]; 83 | 84 | searchNaviBarView.y = 200; 85 | [self.myBGScrollView addSubview:searchNaviBarView]; 86 | } 87 | 88 | 89 | - (void)creatSearchNaviBarStyle4{ 90 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 91 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 92 | 93 | [searchNaviBarView showbackBtnWith:[UIImage imageNamed:@"navi_back_w"] onClick:nil]; 94 | 95 | [searchNaviBarView setSearchBarBeignOnClickBlock:nil]; 96 | 97 | searchNaviBarView.y = 300; 98 | [self.myBGScrollView addSubview:searchNaviBarView]; 99 | } 100 | 101 | 102 | - (void)creatSearchNaviBarStyle5{ 103 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 104 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 105 | searchNaviBarView.backgroundColor = [UIColor redColor]; 106 | 107 | [searchNaviBarView showbackBtnWith:[UIImage imageNamed:@"navi_back_w"] onClick:nil]; 108 | 109 | [searchNaviBarView setSearchBarBeignOnClickBlock:nil]; 110 | 111 | searchNaviBarView.y = 400; 112 | [self.myBGScrollView addSubview:searchNaviBarView]; 113 | } 114 | 115 | 116 | 117 | //--------------------------------------------------------------------------------------------------- 118 | #pragma mark ================================== 跳转到搜索界面 ================================== 119 | //--------------------------------------------------------------------------------------------------- 120 | - (void)buttonObClick1 121 | { 122 | CategoryAndHistoryVC *chVC = [CategoryAndHistoryVC new]; 123 | [self.navigationController pushViewController:chVC animated:YES]; 124 | } 125 | 126 | - (void)buttonObClick2 127 | { 128 | HistoryVC *hVC = [HistoryVC new]; 129 | [self.navigationController pushViewController:hVC animated:YES]; 130 | } 131 | 132 | - (void)buttonObClick3 133 | { 134 | HistoryAnimationVC *haVC = [HistoryAnimationVC new]; 135 | [self.navigationController pushViewController:haVC animated:YES]; 136 | } 137 | 138 | - (void)buttonObClick4 139 | { 140 | HistorySearchVC *searShopVC = [HistorySearchVC new]; 141 | [self.navigationController pushViewController:searShopVC animated:YES]; 142 | } 143 | 144 | 145 | 146 | 147 | //--------------------------------------------------------------------------------------------------- 148 | #pragma mark ================================== 私有方法 ================================== 149 | //--------------------------------------------------------------------------------------------------- 150 | 151 | - (void)setButton:(NSString *)title x:(CGFloat)x y:(CGFloat)y sel:(SEL)method 152 | { 153 | UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(x, y, 130, 50)]; 154 | [button2 setTitle:title forState:UIControlStateNormal]; 155 | button2.backgroundColor = [UIColor cyanColor]; 156 | button2.titleLabel.adjustsFontSizeToFitWidth = YES; 157 | button2.titleLabel.translatesAutoresizingMaskIntoConstraints = YES; 158 | [button2 setTitleColor:[UIColor blackColor] forState:UIControlStateNormal]; 159 | [button2 addTarget:self action:method forControlEvents:UIControlEventTouchUpInside]; 160 | [self.myBGScrollView addSubview:button2]; 161 | } 162 | 163 | - (UIScrollView *)myBGScrollView 164 | { 165 | if (!_myBGScrollView) { 166 | _myBGScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,0, [UIScreen mainScreen].bounds.size.width,[UIScreen mainScreen].bounds.size.height)]; 167 | _myBGScrollView.contentSize = CGSizeMake([UIScreen mainScreen].bounds.size.width, 1000); 168 | _myBGScrollView.backgroundColor = [UIColor whiteColor]; 169 | UITapGestureRecognizer *tapGes = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(endEdit)]; 170 | [_myBGScrollView addGestureRecognizer:tapGes]; 171 | [self.view addSubview:_myBGScrollView]; 172 | } 173 | return _myBGScrollView; 174 | } 175 | 176 | 177 | - (void)endEdit 178 | { 179 | [self.myBGScrollView endEditing:YES]; 180 | } 181 | 182 | 183 | @end 184 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/Const/ZYHTFileNameConst.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | #import 4 | 5 | /*---------------------------------------------------------------------------------- 6 | * 项目缓存路径下的文件名称 * 7 | ----------------------------------------------------------------------------------*/ 8 | 9 | // 周边页面搜索商铺历史记录文件名 10 | UIKIT_EXTERN NSString *const NearByShopSearchShopNameHistoryCacheFileName; 11 | // 周边页面搜索地图地址 12 | UIKIT_EXTERN NSString *const NearByShopSearchMapAddressHistoryCacheFileName; 13 | //全部店铺搜索 14 | UIKIT_EXTERN NSString *const AllShopSearchHistoryCacheFileName; 15 | 16 | 17 | //UIKIT_EXTERN NSString *const CYPasswordViewEnabledUsen; 18 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/Const/ZYHTFileNameConst.m: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #import "ZYHTFileNameConst.h" 5 | 6 | NSString *const NearByShopSearchShopNameHistoryCacheFileName = @"NearByShopSearchShopNameHistoryCacheFileName"; 7 | NSString *const NearByShopSearchMapAddressHistoryCacheFileName = @"NearByShopSearchMapAddressHistoryCacheFileName"; 8 | NSString *const AllShopSearchHistoryCacheFileName = @"AllShopSearchHistoryCacheFileName"; 9 | 10 | //NSString *const CYPasswordViewEnabledUsen = @"SDDDDFDFDFDFDFDFDFFDFDF"; 11 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/MainVC/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/MainVC/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | 24 | - (void)applicationWillResignActive:(UIApplication *)application { 25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 27 | } 28 | 29 | 30 | - (void)applicationDidEnterBackground:(UIApplication *)application { 31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 33 | } 34 | 35 | 36 | - (void)applicationWillEnterForeground:(UIApplication *)application { 37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 38 | } 39 | 40 | 41 | - (void)applicationDidBecomeActive:(UIApplication *)application { 42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 43 | } 44 | 45 | 46 | - (void)applicationWillTerminate:(UIApplication *)application { 47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 48 | } 49 | 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/HistoryAndCategorySearchVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryAndCategorySearchVC.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "LLNaviSearchBaseVC.h" 10 | @class HistoryAndCategorySearchVC; 11 | 12 | 13 | @interface HistoryAndCategorySearchVC : LLNaviSearchBaseVC 14 | 15 | 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/HistoryAndCategorySearchVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryAndCategorySearchVC.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "HistoryAndCategorySearchVC.h" 10 | #import "HistoryAndCategorySearchHistroyViewP.h" 11 | #import "HistoryAndCategorySearchCategoryViewP.h" 12 | #import "LLSearchVCConst.h" 13 | 14 | @interface HistoryAndCategorySearchVC () 15 | 16 | @end 17 | 18 | @implementation HistoryAndCategorySearchVC 19 | 20 | - (void)viewDidLoad { 21 | 22 | //告诉父类你的prestenter是什么 23 | self.shopHistoryP = [HistoryAndCategorySearchHistroyViewP new]; 24 | 25 | self.shopCategoryP = [HistoryAndCategorySearchCategoryViewP new]; 26 | 27 | [super viewDidLoad]; 28 | 29 | } 30 | 31 | 32 | -(void)dealloc 33 | { 34 | NSLog(@"HistoryAndCategorySearchVC 页面销毁"); 35 | } 36 | 37 | 38 | @end 39 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/HistorySearchVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // HistorySearchVC.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "LLNaviSearchBaseVC.h" 10 | 11 | @interface HistorySearchVC : LLNaviSearchBaseVC 12 | 13 | 14 | //FIXME:也可以在这里实现搜索页面相关方法!!! 15 | - (void)setSearchMethod; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/HistorySearchVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // HistorySearchVC.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "HistorySearchVC.h" 10 | #import "HistorySearchHistroyViewP.h" 11 | #import "LLSearchVCConst.h" 12 | 13 | @interface HistorySearchVC () 14 | 15 | @end 16 | 17 | @implementation HistorySearchVC 18 | 19 | - (void)viewDidLoad { 20 | 21 | //告诉父类你的prestenter是什么 22 | self.shopHistoryP = [HistorySearchHistroyViewP new]; 23 | //告诉只显示历史搜索界面 24 | self.isOnlyShowHistoryView = YES; 25 | 26 | [super viewDidLoad]; 27 | } 28 | 29 | 30 | - (void)setSearchMethod 31 | { 32 | //FIXME:也可以在这里实现搜索页面相关方法!!! 33 | @LLWeakObj(self); 34 | [self searchbarDidChange:^(NaviBarSearchType searchType, LLSearchBar *searchBar, NSString *searchText) { 35 | @LLStrongObj(self); 36 | //FIXME:这里是用的模拟数据!!! 37 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 38 | self.resultListArray = @[@"春天", @"秋田", @"夏天-C", @"冬天"]; 39 | }); 40 | }]; 41 | } 42 | 43 | 44 | 45 | 46 | 47 | -(void)dealloc 48 | { 49 | NSLog(@"HistorySearchVC 页面销毁"); 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/Model/TagTypeModel.h: -------------------------------------------------------------------------------- 1 | // 2 | // TagTypeModel.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TagTypeModel : NSObject 12 | 13 | @property (nonatomic,copy) NSString *TypeID; 14 | @property (nonatomic,copy) NSString *TypeName; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/Model/TagTypeModel.m: -------------------------------------------------------------------------------- 1 | // 2 | // TagTypeModel.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "TagTypeModel.h" 10 | 11 | @implementation TagTypeModel 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/Presenter/HistoryAndCategorySearchCategoryViewP.h: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryAndCategorySearchCategoryViewP.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | /*---------------------------------------------------------------- 9 | * HistoryAndCategorySearchVC的分类页面的业务处理者 * 10 | -----------------------------------------------------------------*/ 11 | 12 | #import 13 | #import 14 | @class NBSSearchShopCategoryViewCellP; 15 | 16 | 17 | typedef void (^FetchNetDataCompleteHandlerBlock)(NSError *error,id result); 18 | 19 | 20 | @interface HistoryAndCategorySearchCategoryViewP : NSObject 21 | 22 | 23 | /** 24 | 获取商户分类 25 | */ 26 | - (NSArray *)allCategotyTypeData; 27 | 28 | /** 29 | 发送网络请求获取商户分类 30 | */ 31 | - (void)fetchCategotyTypeData:(FetchNetDataCompleteHandlerBlock)completeBlock; 32 | 33 | 34 | /** 35 | 获取商户分类的标题 36 | */ 37 | - (NSArray *)allCategotyTypeTitles; 38 | 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/Presenter/HistoryAndCategorySearchCategoryViewP.m: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryAndCategorySearchCategoryViewP.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "HistoryAndCategorySearchCategoryViewP.h" 10 | #import "NBSSearchShopCategoryViewCellP.h" 11 | #import "TagTypeModel.h" 12 | 13 | 14 | @interface HistoryAndCategorySearchCategoryViewP () 15 | 16 | @property (nonatomic,strong) NSMutableArray *collectionDataArray; 17 | 18 | @end 19 | 20 | 21 | @implementation HistoryAndCategorySearchCategoryViewP 22 | 23 | 24 | - (NSArray *)allCategotyTypeData 25 | { 26 | return self.collectionDataArray; 27 | } 28 | 29 | - (NSArray *)allCategotyTypeTitles{ 30 | 31 | return [self.collectionDataArray valueForKeyPath:@"categotyTitle"]; 32 | 33 | } 34 | 35 | - (void)fetchCategotyTypeData:(FetchNetDataCompleteHandlerBlock)completeBlock { 36 | 37 | //FIXME:模拟网络请求!!! 38 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 39 | 40 | NSArray *titleArray = @[@"全部",@"美女",@"烟酒",@"汽车",@"服装",@"超市",@"洗发水",@"电视机",@"洗衣用品",@"家具电器",@"家具用品",@"篮球",@"运动鞋",@"裤子",@"袜子",@"面包",@"水果"]; 41 | NSArray *tagArray = @[@(1),@(2),@(3),@(4),@(5),@(6),@(7),@(8),@(9),@(10),@(11),@(12),@(13),@(14),@(15),@(16),@(17),@(18),@(19),@(20),@(21)]; 42 | 43 | for (int i = 0; i < titleArray.count; i++) { 44 | TagTypeModel *shopM = [TagTypeModel new]; 45 | shopM.TypeName = titleArray[i]; 46 | shopM.TypeID = tagArray[i]; 47 | [self.collectionDataArray addObject:[NBSSearchShopCategoryViewCellP presenterWithModel:shopM]]; 48 | } 49 | 50 | 51 | 52 | //返回block 53 | completeBlock(nil,nil);//这里实际返回的是你真实网络请求数据 54 | }); 55 | 56 | } 57 | 58 | 59 | 60 | 61 | - (NSMutableArray *)collectionDataArray 62 | { 63 | if (!_collectionDataArray) { 64 | _collectionDataArray = [[NSMutableArray alloc] init]; 65 | } 66 | return _collectionDataArray; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/Presenter/HistoryAndCategorySearchHistroyViewP.h: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryAndCategorySearchHistroyViewP.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | /*---------------------------------------------------------------- 10 | * HistoryAndCategorySearchVC的历史搜索页面的业务处理者 * 11 | -----------------------------------------------------------------*/ 12 | 13 | #import "LLNaviSearchHistorySaveBasePresenter.h" 14 | 15 | @interface HistoryAndCategorySearchHistroyViewP : LLNaviSearchHistorySaveBasePresenter 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/Presenter/HistoryAndCategorySearchHistroyViewP.m: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryAndCategorySearchHistroyViewP.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "HistoryAndCategorySearchHistroyViewP.h" 10 | #import "LLSearchHistorySaveUtils.h" 11 | #import "ZYHTFileNameConst.h" 12 | 13 | @implementation HistoryAndCategorySearchHistroyViewP 14 | 15 | - (instancetype)init{ 16 | if (self = [super init]) { 17 | 18 | //赋值 19 | self.saveUtils = [[LLSearchHistorySaveUtils alloc] initWithSearchHistoriesCacheFileName:NearByShopSearchShopNameHistoryCacheFileName]; 20 | } 21 | return self; 22 | } 23 | 24 | 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/Presenter/HistorySearchHistroyViewP.h: -------------------------------------------------------------------------------- 1 | // 2 | // HistorySearchHistroyViewP.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | /*---------------------------------------------------------------- 10 | * HistorySearchVC的历史搜索页面的业务处理者 * 11 | -----------------------------------------------------------------*/ 12 | 13 | #import "LLNaviSearchHistorySaveBasePresenter.h" 14 | 15 | @interface HistorySearchHistroyViewP : LLNaviSearchHistorySaveBasePresenter 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Class/SearchVC/Presenter/HistorySearchHistroyViewP.m: -------------------------------------------------------------------------------- 1 | // 2 | // HistorySearchHistroyViewP.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "HistorySearchHistroyViewP.h" 10 | #import "LLSearchHistorySaveUtils.h" 11 | #import "ZYHTFileNameConst.h" 12 | 13 | @implementation HistorySearchHistroyViewP 14 | 15 | - (instancetype)init{ 16 | if (self = [super init]) { 17 | //code... 18 | self.saveUtils = [[LLSearchHistorySaveUtils alloc] initWithSearchHistoriesCacheFileName:NearByShopSearchMapAddressHistoryCacheFileName]; 19 | 20 | } 21 | return self; 22 | } 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/ExtensionPresenter/NBSSearchShopCategoryViewCellP.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBSSearchShopCategoryViewCellP.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/13. 6 | // 7 | // 8 | 9 | 10 | 11 | #import 12 | @class TagTypeModel; 13 | 14 | @interface NBSSearchShopCategoryViewCellP : NSObject 15 | 16 | +(instancetype)presenterWithModel:(TagTypeModel *)model; 17 | 18 | @property (nonatomic,copy,readonly) NSString *categotyTitle; 19 | @property (nonatomic,copy,readonly) NSString *categotyID; 20 | 21 | 22 | @end 23 | 24 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/ExtensionPresenter/NBSSearchShopCategoryViewCellP.m: -------------------------------------------------------------------------------- 1 | // 2 | // NBSSearchShopCategoryViewCellP.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/13. 6 | // 7 | // 8 | 9 | #import "NBSSearchShopCategoryViewCellP.h" 10 | #import "TagTypeModel.h" 11 | 12 | @interface NBSSearchShopCategoryViewCellP () 13 | @property (nonatomic,strong) TagTypeModel *myNearShopTypeModel; 14 | @end 15 | @implementation NBSSearchShopCategoryViewCellP 16 | 17 | 18 | +(instancetype)presenterWithModel:(TagTypeModel *)model 19 | { 20 | NBSSearchShopCategoryViewCellP *presenter = [NBSSearchShopCategoryViewCellP new]; 21 | presenter.myNearShopTypeModel = model; 22 | return presenter; 23 | } 24 | 25 | 26 | 27 | 28 | 29 | //--------------------------------------------------------------------------------------------------- 30 | #pragma mark ================================== cell所需参数 ================================== 31 | //--------------------------------------------------------------------------------------------------- 32 | -(NSString *)categotyTitle 33 | { 34 | return _myNearShopTypeModel.TypeName; 35 | } 36 | 37 | 38 | 39 | -(NSString *)categotyID 40 | { 41 | return _myNearShopTypeModel.TypeID; 42 | } 43 | 44 | 45 | 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/ExtensionView/LLSearchResultListView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchResultListView.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/28. 6 | // 7 | // 8 | 9 | #import 10 | 11 | typedef void (^resultListViewCellDidClickBlock)(UITableView *tableView,NSInteger index); 12 | 13 | @interface LLSearchResultListView : UIView 14 | 15 | @property (nonatomic,strong) NSArray *resultArray; 16 | 17 | 18 | /** 19 | 列表被选中 20 | */ 21 | - (void)resultListViewDidSelectedIndex:(resultListViewCellDidClickBlock)cellDidClickBlock; 22 | 23 | 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/ExtensionView/LLSearchResultListView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchResultListView.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/28. 6 | // 7 | // 8 | 9 | #import "LLSearchResultListView.h" 10 | #import "UIView+LLRect.h" 11 | #import "LLSearchVCConst.h" 12 | 13 | 14 | @interface LLSearchResultListView () 15 | @property (nonatomic,strong) UITableView *myTableView; 16 | @property (nonatomic,copy) resultListViewCellDidClickBlock myCellDidClickBlock; 17 | @end 18 | 19 | @implementation LLSearchResultListView 20 | static NSString *const flag = @"LLSearchResultListViewCell"; 21 | 22 | 23 | 24 | //不要xxx.frame = GRectmake()这样设置frame 25 | -(instancetype)initWithFrame:(CGRect)frame{ 26 | if (self = [super initWithFrame:frame]) { 27 | //初始化控件 28 | [self addSubview:self.myTableView]; 29 | } 30 | return self; 31 | } 32 | 33 | 34 | //--------------------------------------------------------------------------------------------------- 35 | #pragma mark ================================== UITableViewDataSource/UITableViewDataSource ================================== 36 | //--------------------------------------------------------------------------------------------------- 37 | static CGFloat const RowHeight = 44.f; 38 | 39 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{ 40 | return self.resultArray.count; 41 | } 42 | 43 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{ 44 | 45 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:flag forIndexPath:indexPath]; 46 | cell.textLabel.textColor = [UIColor darkGrayColor]; 47 | cell.textLabel.font = [UIFont systemFontOfSize:14]; 48 | cell.backgroundColor = [UIColor clearColor]; 49 | UIImageView *line = [[UIImageView alloc] initWithImage: [UIImage imageNamed:@"base_cell-content-line"]]; 50 | line.height = 0.5; 51 | line.alpha = 0.7; 52 | line.x = 10; 53 | line.y = 43; 54 | line.width = ZYHT_ScreenWidth; 55 | [cell.contentView addSubview:line]; 56 | 57 | cell.imageView.image = [UIImage imageNamed:@"base_search"]; 58 | cell.textLabel.text = self.resultArray[indexPath.row]; 59 | cell.accessoryType = UITableViewCellAccessoryNone; 60 | return cell; 61 | } 62 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 63 | return RowHeight; 64 | } 65 | 66 | -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{ 67 | //回调 68 | LLBLOCK_EXEC(_myCellDidClickBlock,tableView,indexPath.row); 69 | } 70 | 71 | 72 | 73 | - (UITableView *)myTableView 74 | { 75 | if (!_myTableView) { 76 | _myTableView = [[UITableView alloc] initWithFrame:CGRectZero]; 77 | _myTableView.backgroundColor = [UIColor colorWithRed:245/255.0 green:245/255.0 blue:245/255.0 alpha:1.0]; 78 | _myTableView.delegate = self; 79 | _myTableView.dataSource = self; 80 | _myTableView.tableFooterView = [UIView new]; 81 | 82 | _myTableView.separatorStyle = UITableViewCellSeparatorStyleNone; 83 | 84 | [self.myTableView registerClass:[UITableViewCell class] forCellReuseIdentifier:flag]; 85 | 86 | } 87 | return _myTableView; 88 | } 89 | 90 | 91 | -(void)layoutSubviews 92 | { 93 | [super layoutSubviews]; 94 | 95 | _myTableView.frame = self.bounds; 96 | } 97 | 98 | 99 | //--------------------------------------------------------------------------------------------------- 100 | #pragma mark ================================== 对外接口 ================================== 101 | //--------------------------------------------------------------------------------------------------- 102 | -(void)setResultArray:(NSArray *)resultArray 103 | { 104 | _resultArray = resultArray; 105 | [self.myTableView reloadData]; 106 | } 107 | 108 | - (void)resultListViewDidSelectedIndex:(resultListViewCellDidClickBlock)cellDidClickBlock 109 | { 110 | _myCellDidClickBlock = cellDidClickBlock; 111 | } 112 | 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/ExtensionView/NBSSearchShopCategoryView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBSSearchShopCategoryView.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/12. 6 | // 7 | // 8 | 9 | #import 10 | @class HistoryAndCategorySearchCategoryViewP; 11 | @class NBSSearchShopCategoryViewCellP; 12 | 13 | 14 | 15 | typedef void (^categoryTagonClickBlock)(NBSSearchShopCategoryViewCellP *cellP); 16 | 17 | @interface NBSSearchShopCategoryView : UIView 18 | 19 | 20 | 21 | + (instancetype)searchShopCategoryViewWithPresenter:(HistoryAndCategorySearchCategoryViewP *)presenter WithFrame:(CGRect)rect; 22 | 23 | 24 | - (void)reloadData; 25 | 26 | - (void)categoryTagonClick:(categoryTagonClickBlock)clickBlock; 27 | 28 | @property (nonatomic,copy) void(^modifyFrameBlock)(CGRect rect); 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/ExtensionView/NBSSearchShopCategoryView.m: -------------------------------------------------------------------------------- 1 | // 2 | // NBSSearchShopCategoryView.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/12. 6 | // 7 | // 8 | 9 | #import "NBSSearchShopCategoryView.h" 10 | #import "HistoryAndCategorySearchCategoryViewP.h" 11 | #import "NBSSearchShopCategoryViewCellP.h" 12 | #import "LLTagViewUtils.h" 13 | #import "UIView+LLRect.h" 14 | #import "LLSearchVCConst.h" 15 | #import "UIColor+LLHex.h" 16 | 17 | 18 | @interface NBSSearchShopCategoryView () 19 | 20 | @property (nonatomic,strong) UILabel *leftTitleLabel; 21 | @property (nonatomic,strong) UIButton *rightMoreBtn; 22 | @property (nonatomic,strong) UIView *coverView; 23 | @property (nonatomic,strong) HistoryAndCategorySearchCategoryViewP *shopCategoryViewP; 24 | @property (nonatomic,copy) categoryTagonClickBlock myOnCickBlock; 25 | 26 | @end 27 | 28 | @implementation NBSSearchShopCategoryView{ 29 | CGFloat leadPadding; 30 | CGFloat trailPadding; 31 | CGFloat topPadding; 32 | 33 | CGFloat leftTitleBtnHeight; 34 | 35 | CGFloat shopCategoryViewLTPadding; 36 | CGFloat shopCategoryCoverViewLTPadding; 37 | CGFloat shopCategoryCoverViewTopPadding; 38 | CGFloat shopCategoryCoverViewWidth; 39 | 40 | CGFloat categoryTagViewHeight; 41 | 42 | CGFloat categoryViewHeight; 43 | 44 | BOOL _isShowAllCategory; //是否展开显示全部分类 45 | 46 | LLTagViewUtils *tagViewUtils; 47 | } 48 | 49 | 50 | 51 | //初始化 52 | + (instancetype)searchShopCategoryViewWithPresenter:(HistoryAndCategorySearchCategoryViewP *)presenter WithFrame:(CGRect)rect{ 53 | NBSSearchShopCategoryView *categoryView = [[NBSSearchShopCategoryView alloc] initWithFrame:rect]; 54 | categoryView.shopCategoryViewP = presenter; 55 | return categoryView; 56 | } 57 | 58 | 59 | -(instancetype)initWithFrame:(CGRect)frame 60 | { 61 | if (self = [super initWithFrame:frame]) { 62 | 63 | //初始化设置参数 64 | [self initialization]; 65 | 66 | self.clipsToBounds = YES; 67 | 68 | //添加子控件 69 | [self addSubview:self.leftTitleLabel]; 70 | [self addSubview:self.rightMoreBtn]; 71 | [self addSubview:self.coverView]; 72 | 73 | } 74 | return self; 75 | } 76 | 77 | static CGFloat shopCategoryViewNotOpenHeight = 0;//分类模块未展开时的初始高度 78 | static CGFloat shopCategoryViewOpenHeight = 0;//展开时的高度 79 | 80 | - (void)initialization 81 | { 82 | //初始化计量值 83 | leadPadding = 13; 84 | trailPadding = 13; 85 | topPadding = 16; 86 | 87 | leftTitleBtnHeight = 15; 88 | 89 | categoryTagViewHeight = 33; 90 | 91 | // cover view of categoryView 92 | shopCategoryCoverViewLTPadding = leadPadding; 93 | shopCategoryViewLTPadding = 10; 94 | shopCategoryCoverViewTopPadding = 15; 95 | shopCategoryCoverViewWidth = ZYHT_ScreenWidth - shopCategoryCoverViewLTPadding*2; 96 | 97 | 98 | //not open 99 | shopCategoryViewNotOpenHeight = topPadding+leftTitleBtnHeight + shopCategoryCoverViewTopPadding + categoryTagViewHeight; 100 | 101 | 102 | } 103 | 104 | - (void)layoutSubviews { 105 | [super layoutSubviews]; 106 | 107 | self.leftTitleLabel.frame = CGRectMake(leadPadding, topPadding, 50, leftTitleBtnHeight); 108 | self.rightMoreBtn.frame = CGRectMake(self.width-50-trailPadding, topPadding, 50, 50); 109 | self.rightMoreBtn.centerY = self.leftTitleLabel.centerY; 110 | 111 | 112 | //open cayegotyView height 113 | shopCategoryViewOpenHeight = shopCategoryViewNotOpenHeight + categoryViewHeight - categoryTagViewHeight; 114 | 115 | //分类展示view 116 | self.coverView.frame = CGRectMake(leadPadding,self.leftTitleLabel.bottom+shopCategoryCoverViewTopPadding, shopCategoryCoverViewWidth, categoryViewHeight); 117 | 118 | if (!_isShowAllCategory) 119 | { 120 | self.height = shopCategoryViewNotOpenHeight; 121 | } 122 | else 123 | { 124 | self.height = shopCategoryViewOpenHeight; 125 | } 126 | 127 | 128 | //通知高度更新 129 | LLBLOCK_EXEC(self.modifyFrameBlock,self.frame); 130 | } 131 | 132 | 133 | - (UIView *)coverView 134 | { 135 | if (!_coverView) { 136 | UIView *view = [[UIView alloc] initWithFrame:(CGRect){0,0,shopCategoryCoverViewWidth,0}]; 137 | view.backgroundColor = [UIColor whiteColor]; 138 | view.clipsToBounds = YES; 139 | _coverView = view; 140 | } 141 | return _coverView; 142 | } 143 | 144 | 145 | - (UILabel *)leftTitleLabel 146 | { 147 | if (!_leftTitleLabel) { 148 | 149 | UILabel *labelName = [[UILabel alloc] initWithFrame:CGRectZero]; 150 | labelName.text = @"分类"; 151 | labelName.font = ZYHT_F_MediumFontOfSize(14); 152 | labelName.textColor = [UIColor colorWithHexString:@"111111"]; 153 | _leftTitleLabel = labelName; 154 | 155 | } 156 | return _leftTitleLabel; 157 | } 158 | 159 | - (UIButton *)rightMoreBtn 160 | { 161 | if (!_rightMoreBtn) { 162 | UIButton *button = [[UIButton alloc] initWithFrame:CGRectZero]; 163 | [button setTitle:@"更多" forState:UIControlStateNormal]; 164 | button.titleLabel.font = ZYHT_F_MediumFontOfSize(13); 165 | button.titleLabel.textAlignment = NSTextAlignmentRight; 166 | [button setTitleColor:[UIColor colorWithHexString:@"b2b2b2"] forState:UIControlStateNormal]; 167 | [button addTarget:self action:@selector(rightMoreBtnOnClick) forControlEvents:UIControlEventTouchUpInside]; 168 | 169 | _rightMoreBtn = button; 170 | } 171 | return _rightMoreBtn; 172 | } 173 | 174 | - (void)rightMoreBtnOnClick 175 | { 176 | //展开更多分类 177 | [self openShopCategoryView]; 178 | } 179 | 180 | //复制数据 181 | - (void)setupCategoryViewAndData 182 | { 183 | tagViewUtils = [LLTagViewUtils new]; 184 | [tagViewUtils setupRectangleTagsInView:self.coverView tagTexts:[self.shopCategoryViewP allCategotyTypeTitles] maxColumnNum:4 tagHeight:33]; 185 | 186 | categoryViewHeight = self.coverView.height; 187 | 188 | @LLWeakObj(self); 189 | [tagViewUtils tagLabelOnClick:^(UITapGestureRecognizer *tapGes, UILabel *tagLabel) { 190 | @LLStrongObj(self); 191 | // NSLog(@"%s-->%@--->%zd",__FUNCTION__,tagLabel.text,tagLabel.tag); 192 | if (tagLabel.tag <= self.shopCategoryViewP.allCategotyTypeData.count) { 193 | NBSSearchShopCategoryViewCellP *cellP = self.shopCategoryViewP.allCategotyTypeData[tagLabel.tag]; 194 | LLBLOCK_EXEC(_myOnCickBlock,cellP); 195 | } 196 | 197 | }]; 198 | } 199 | 200 | 201 | //--------------------------------------------------------------------------------------------------- 202 | #pragma mark ================================= 私有方法 ================================== 203 | //--------------------------------------------------------------------------------------------------- 204 | - (void)openShopCategoryView 205 | { 206 | _isShowAllCategory = !_isShowAllCategory; 207 | 208 | [self layoutSubviews]; 209 | } 210 | 211 | 212 | //----------------------------------------------------------------------------------------------------------- 213 | #pragma mark ================ 接口 ================ 214 | //----------------------------------------------------------------------------------------------------------- 215 | 216 | 217 | -(void)reloadData 218 | { 219 | [self setupCategoryViewAndData]; 220 | } 221 | 222 | - (void)categoryTagonClick:(categoryTagonClickBlock)clickBlock { 223 | _myOnCickBlock = clickBlock; 224 | } 225 | 226 | 227 | @end 228 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/ExtensionView/NBSSearchShopHistoryView.h: -------------------------------------------------------------------------------- 1 | // 2 | // NBSSearchShopHistoryView.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/14. 6 | // 7 | // 8 | 9 | #import 10 | @class HistorySearchHistroyViewP; 11 | 12 | typedef void (^historyTagonClickBlock)(UILabel *tagLabel); 13 | 14 | @interface NBSSearchShopHistoryView : UIView 15 | 16 | 17 | + (instancetype)searchShopCategoryViewWithPresenter:(HistorySearchHistroyViewP *)presenter WithFrame:(CGRect)rect; 18 | 19 | 20 | /** 21 | 刷新数据 22 | */ 23 | - (void)reloadData; 24 | 25 | 26 | /** 27 | 历史标签被点击 28 | 29 | @param clickBlock <#clickBlock description#> 30 | */ 31 | - (void)historyTagonClick:(historyTagonClickBlock)clickBlock; 32 | 33 | 34 | /** 35 | 消除所有按钮被点击 36 | */ 37 | @property (nonatomic,copy) void(^clearHistoryBtnOnClick)(); 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/ExtensionView/NBSSearchShopHistoryView.m: -------------------------------------------------------------------------------- 1 | // 2 | // NBSSearchShopHistoryView.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/14. 6 | // 7 | // 8 | 9 | #import "NBSSearchShopHistoryView.h" 10 | #import "NBSSearchShopCategoryViewCellP.h" 11 | #import "HistorySearchHistroyViewP.h" 12 | #import "LLTagViewUtils.h" 13 | #import "LLSearchVCConst.h" 14 | #import "UIView+LLRect.h" 15 | #import "UIColor+LLHex.h" 16 | 17 | 18 | 19 | @interface NBSSearchShopHistoryView () 20 | 21 | @property (nonatomic,strong) UILabel *leftTitleLabel; 22 | @property (nonatomic,strong) UIButton *rightMoreBtn; 23 | @property (nonatomic,strong) UIView *coverView; 24 | @property (nonatomic,strong) HistorySearchHistroyViewP *historyTagViewP; 25 | @property (nonatomic,copy) historyTagonClickBlock myOnCickBlock; 26 | 27 | @end 28 | 29 | @implementation NBSSearchShopHistoryView{ 30 | CGFloat leadPadding; 31 | CGFloat trailPadding; 32 | CGFloat topPadding; 33 | 34 | CGFloat leftTitleBtnHeight; 35 | 36 | CGFloat shopCategoryViewLTPadding; 37 | CGFloat shopCategoryCoverViewLTPadding; 38 | CGFloat shopCategoryCoverViewTopPadding; 39 | CGFloat shopCategoryCoverViewWidth; 40 | 41 | CGFloat categoryTagViewHeight; 42 | 43 | CGFloat categoryViewHeight; 44 | 45 | LLTagViewUtils *tagViewUtils; 46 | } 47 | 48 | 49 | 50 | //初始化 51 | + (instancetype)searchShopCategoryViewWithPresenter:(HistorySearchHistroyViewP *)presenter WithFrame:(CGRect)rect 52 | { 53 | NBSSearchShopHistoryView *categoryView = [[NBSSearchShopHistoryView alloc] initWithFrame:rect]; 54 | categoryView.historyTagViewP = presenter; 55 | return categoryView; 56 | } 57 | 58 | 59 | -(instancetype)initWithFrame:(CGRect)frame 60 | { 61 | if (self = [super initWithFrame:frame]) { 62 | 63 | //初始化设置参数 64 | [self initialization]; 65 | 66 | self.clipsToBounds = YES; 67 | 68 | //添加子控件 69 | [self addSubview:self.leftTitleLabel]; 70 | [self addSubview:self.rightMoreBtn]; 71 | [self addSubview:self.coverView]; 72 | 73 | } 74 | return self; 75 | } 76 | 77 | static CGFloat shopCategoryViewNotOpenHeight = 0;//分类模块未展开时的初始高度 78 | 79 | - (void)initialization 80 | { 81 | //初始化计量值 82 | leadPadding = 13; 83 | trailPadding = 13; 84 | topPadding = 20; 85 | 86 | leftTitleBtnHeight = 15; 87 | 88 | categoryTagViewHeight = 33; 89 | 90 | // cover view of categoryViewLLSearchVCConst 91 | shopCategoryCoverViewLTPadding = leadPadding; 92 | shopCategoryViewLTPadding = 10; 93 | shopCategoryCoverViewTopPadding = 15; 94 | shopCategoryCoverViewWidth = ZYHT_ScreenWidth - shopCategoryCoverViewLTPadding*2; 95 | 96 | 97 | //not open 98 | shopCategoryViewNotOpenHeight = topPadding+leftTitleBtnHeight + shopCategoryCoverViewTopPadding + categoryTagViewHeight; 99 | } 100 | 101 | - (void)layoutSubviews { 102 | [super layoutSubviews]; 103 | 104 | self.leftTitleLabel.frame = CGRectMake(leadPadding, topPadding, 70, leftTitleBtnHeight); 105 | self.rightMoreBtn.frame = CGRectMake(self.width-70-trailPadding, topPadding, 70, 50); 106 | self.rightMoreBtn.centerY = self.leftTitleLabel.centerY; 107 | 108 | 109 | self.coverView.frame = CGRectMake(leadPadding,self.leftTitleLabel.bottom+shopCategoryCoverViewTopPadding, shopCategoryCoverViewWidth, categoryViewHeight); 110 | 111 | self.height = shopCategoryViewNotOpenHeight + categoryViewHeight - categoryTagViewHeight; 112 | 113 | } 114 | 115 | 116 | - (UIView *)coverView 117 | { 118 | if (!_coverView) { 119 | UIView *view = [[UIView alloc] initWithFrame:(CGRect){0,0,shopCategoryCoverViewWidth,0}]; 120 | view.clipsToBounds = YES; 121 | _coverView = view; 122 | } 123 | return _coverView; 124 | } 125 | 126 | 127 | 128 | - (UILabel *)leftTitleLabel 129 | { 130 | if (!_leftTitleLabel) { 131 | 132 | UILabel *labelName = [[UILabel alloc] initWithFrame:CGRectZero]; 133 | labelName.text = @"历史搜索"; 134 | labelName.font = ZYHT_F_MediumFontOfSize(14); 135 | labelName.textColor = [UIColor colorWithHexString:@"111111"]; 136 | _leftTitleLabel = labelName; 137 | 138 | } 139 | return _leftTitleLabel; 140 | } 141 | 142 | - (UIButton *)rightMoreBtn 143 | { 144 | if (!_rightMoreBtn) { 145 | UIButton *button = [[UIButton alloc] initWithFrame:CGRectZero]; 146 | [button setTitle:@"清除历史" forState:UIControlStateNormal]; 147 | button.titleLabel.font = ZYHT_F_MediumFontOfSize(13); 148 | button.titleLabel.textAlignment = NSTextAlignmentRight; 149 | [button setTitleColor:[UIColor colorWithHexString:@"b2b2b2"] forState:UIControlStateNormal]; 150 | [button addTarget:self action:@selector(rightBtnOnClick) forControlEvents:UIControlEventTouchUpInside]; 151 | 152 | _rightMoreBtn = button; 153 | } 154 | return _rightMoreBtn; 155 | } 156 | 157 | 158 | - (void)rightBtnOnClick{ 159 | //展开更多分类 160 | [self clearAllHistoryData]; 161 | 162 | } 163 | 164 | //复制数据 165 | - (void)setuphistoryViewAndData 166 | { 167 | tagViewUtils = [LLTagViewUtils new]; 168 | [tagViewUtils setupCommonTagsInView:self.coverView tagTexts:[self.historyTagViewP getSearchCache] margin:10 tagHeight:29]; 169 | 170 | categoryViewHeight = self.coverView.height; 171 | tagViewUtils.commonTagStyle = ZYHTCommonTagStyleNormalWhiteTag; 172 | 173 | [tagViewUtils tagLabelOnClick:^(UITapGestureRecognizer *tapGes, UILabel *tagLabel) { 174 | LLBLOCK_EXEC(_myOnCickBlock,tagLabel); 175 | }]; 176 | } 177 | 178 | 179 | //--------------------------------------------------------------------------------------------------- 180 | #pragma mark ================================= 私有方法 ================================== 181 | //--------------------------------------------------------------------------------------------------- 182 | - (void)clearAllHistoryData 183 | { 184 | LLBLOCK_EXEC(self.clearHistoryBtnOnClick); 185 | } 186 | 187 | 188 | //----------------------------------------------------------------------------------------------------------- 189 | #pragma mark ================ 接口 ================ 190 | //----------------------------------------------------------------------------------------------------------- 191 | 192 | 193 | -(void)reloadData 194 | { 195 | [self setuphistoryViewAndData]; 196 | } 197 | 198 | -(void)historyTagonClick:(historyTagonClickBlock)clickBlock 199 | { 200 | _myOnCickBlock = clickBlock; 201 | } 202 | 203 | 204 | @end 205 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/SearchBar/LLSearchBar.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchBar.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/12. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface LLSearchBar : UISearchBar 12 | 13 | // 默认YES居中,通过设置NO,可居左 14 | @property (nonatomic, assign, setter = setHasCentredPlaceholder:) BOOL hasCentredPlaceholder; 15 | 16 | // searchField 左侧图片 17 | @property (nonatomic, strong) UIImage *leftImage; 18 | 19 | // placeholder颜色 20 | @property (nonatomic, strong) UIColor *placeholderColor; 21 | @property (nonatomic, strong) UIColor *textColor; 22 | 23 | @property (nonatomic,strong) UIFont *placeHolderFont; 24 | @property (nonatomic,strong) UIFont *textFont; 25 | 26 | 27 | - (instancetype)initWithFrame:(CGRect)frame leftImage:(UIImage *)leftImage placeholderColor:(UIColor *)placeholderColor; 28 | 29 | @property (nonatomic,assign) BOOL isHideClearButton; 30 | 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/SearchBar/LLSearchBar.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchBar.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/12. 6 | // 7 | // 8 | 9 | #import "LLSearchBar.h" 10 | 11 | @implementation LLSearchBar 12 | 13 | - (instancetype)initWithFrame:(CGRect)frame leftImage:(UIImage *)leftImage placeholderColor:(UIColor *)placeholderColor { 14 | self = [super initWithFrame:frame]; 15 | if (self) { 16 | self.hasCentredPlaceholder = YES; 17 | self.leftImage = leftImage; 18 | self.placeholderColor = placeholderColor; 19 | } 20 | return self; 21 | } 22 | 23 | - (void)layoutSubviews { 24 | [super layoutSubviews]; 25 | // 通过遍历self.subviews找到searchField 26 | UITextField *searchField; 27 | NSUInteger numViews = [self.subviews count]; 28 | for(int i = 0;i < numViews; i++) { 29 | if([[self.subviews objectAtIndex:i] isKindOfClass:[UITextField class]]) { 30 | searchField = [self.subviews objectAtIndex:i]; 31 | } 32 | } 33 | // 如果上述方法找不到searchField,试试下面的方法 34 | if (searchField == nil) { 35 | NSArray *arraySub = [self subviews]; 36 | UIView *viewSelf = [arraySub objectAtIndex:0]; 37 | NSArray *arrayView = [viewSelf subviews]; 38 | for(int i = 0;i < arrayView.count; i++) { 39 | if([[arrayView objectAtIndex:i] isKindOfClass:[UITextField class]]) { 40 | searchField = [arrayView objectAtIndex:i]; 41 | } 42 | } 43 | } 44 | if (searchField) { 45 | [searchField setBorderStyle:UITextBorderStyleNone]; 46 | //placeHolder颜色 47 | [searchField setValue:_placeholderColor forKeyPath:@"_placeholderLabel.textColor"]; 48 | searchField.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); 49 | searchField.textColor = _textColor; 50 | 51 | //字体大小 52 | [searchField setValue:_placeHolderFont forKeyPath:@"_placeholderLabel.font"]; 53 | searchField.font = _textFont; 54 | 55 | 56 | UIImage *image = _leftImage; 57 | UIImageView *leftImg = [[UIImageView alloc] initWithImage:image]; 58 | leftImg.frame = CGRectMake(0,0,image.size.width, image.size.height); 59 | searchField.leftView = leftImg; 60 | } 61 | 62 | //修改字体 63 | 64 | } 65 | 66 | 67 | #pragma mark - Methods 68 | 69 | - (void)setHasCentredPlaceholder:(BOOL)hasCentredPlaceholder { 70 | _hasCentredPlaceholder = hasCentredPlaceholder; 71 | SEL centerSelector = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"setCenter", @"Placeholder:"]); 72 | if ([self respondsToSelector:centerSelector]) { 73 | NSMethodSignature *signature = [[UISearchBar class] instanceMethodSignatureForSelector:centerSelector]; 74 | NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature]; 75 | [invocation setTarget:self]; 76 | [invocation setSelector:centerSelector]; 77 | [invocation setArgument:&_hasCentredPlaceholder atIndex:2]; 78 | [invocation invoke]; 79 | } 80 | } 81 | 82 | -(void)setIsHideClearButton:(BOOL)isHideClearButton 83 | { 84 | _isHideClearButton = isHideClearButton; 85 | if (_isHideClearButton) { 86 | for (UIView *view in self.subviews) { 87 | if ([view isKindOfClass:NSClassFromString(@"UIView")] && view.subviews.count > 1) { 88 | if ( [[view.subviews objectAtIndex:1] isKindOfClass:[UITextField class]]) { 89 | UITextField *textField = (UITextField *)[view.subviews objectAtIndex:1]; 90 | [textField setClearButtonMode:UITextFieldViewModeNever]; // 不需要出现clearButton 91 | } 92 | break; 93 | } 94 | } 95 | } 96 | } 97 | 98 | @end 99 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/SearchNaviBarView/LLSearchNaviBarView.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchNaviBarView.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/12. 6 | // 7 | // 8 | 9 | /*---------------------------------------------------------------------------------- 10 | * 自定义搜索导航条 * 11 | ----------------------------------------------------------------------------------*/ 12 | 13 | #import 14 | @class LLSearchBar; 15 | 16 | typedef NS_OPTIONS(NSUInteger, LLSearchNaviBarViewType) { 17 | searchNaviBarViewDefault = 0, 18 | searchNaviBarViewWhiteAndGray 19 | }; 20 | 21 | 22 | typedef void (^rightOneBtnOnClick) (UIButton *btn); 23 | typedef void (^backBtnOnClick) (UIButton *btn); 24 | typedef void (^keyBoardSearchBtnOnClickBlock) (LLSearchBar *searchBar); 25 | typedef void (^textofSearchBarDidChangeBlock) (LLSearchBar *searchBar,NSString *searchText); 26 | 27 | @interface LLSearchNaviBarView : UIView 28 | 29 | /** 30 | 实现该方法,则搜索框右边的按钮显示 31 | 32 | @param image 图片名称 33 | @param btnBlock 点击block 34 | */ 35 | - (void)showRightOneBtnWith:(UIImage *)image onClick:(rightOneBtnOnClick)btnBlock; 36 | 37 | /** 38 | 实现该方法,则搜索框右边的按钮显示 39 | 40 | @param title 按钮名称 41 | @param btnBlock 点击block 42 | */ 43 | - (void)showRightOneBtnWithTitle:(NSString *)title onClick:(rightOneBtnOnClick)btnBlock; 44 | 45 | 46 | /** 47 | 实现该方法,显示出导航条返回按钮,可以自定义返回按钮的图片,如果默认,则传入nil 48 | 49 | @param image 返回按钮图片,不需要则传Nil 50 | @param btnBlock 点击block 51 | */ 52 | - (void)showbackBtnWith:(UIImage *)image onClick:(backBtnOnClick)btnBlock; 53 | 54 | 55 | 56 | /** 57 | 导航条右边按钮图片 58 | */ 59 | @property (nonatomic,assign) UIImage *rightOneBtnIconImage; 60 | 61 | 62 | /** 63 | 导航条返回按钮图片 64 | */ 65 | @property (nonatomic,assign) UIImage *backBtnIconImage; 66 | 67 | /** 68 | 搜索框 69 | */ 70 | @property (nonatomic,strong,readonly) LLSearchBar *naviSearchBar; 71 | 72 | 73 | 74 | /** 75 | 搜索导航条样式 76 | */ 77 | @property (nonatomic,assign) LLSearchNaviBarViewType searchNaviBarViewType; 78 | 79 | 80 | /** 81 | 导航条搜索框中的searchbar的占位文字 82 | */ 83 | @property (nonatomic,copy) NSString *searbarPlaceHolder; 84 | 85 | 86 | 87 | /** 88 | 是否隐藏searchbar中的右边的图片 89 | */ 90 | @property (nonatomic,assign) BOOL isHideSearchBarRightIcon; 91 | 92 | /** 93 | 自定义searchbar中的右边的图片 94 | */ 95 | @property (nonatomic,assign) UIImage *searchBarRightIconImage; 96 | 97 | 98 | /** 99 | searchbar被点击 100 | */ 101 | @property (nonatomic,copy) void(^searchBarBeignOnClickBlock)(); 102 | 103 | 104 | /** 105 | 键盘上搜索按钮被点击 106 | */ 107 | - (void)keyBoardSearchBtnOnClick:(keyBoardSearchBtnOnClickBlock)searchBtnOnClickBlock; 108 | 109 | 110 | /** 111 | 搜索框框输入文字之后的即时变化 112 | */ 113 | - (void)textOfSearchBarDidChangeBlock:(textofSearchBarDidChangeBlock)textofSearchBarDidChangeBlock; 114 | 115 | @end 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/SearchNaviBarView/LLSearchNaviBarView.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchNaviBarView.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/12. 6 | // 7 | // 8 | 9 | #import "LLSearchNaviBarView.h" 10 | #import "LLSearchBar.h" 11 | #import "LLSearchVCConst.h" 12 | #import "UIView+LLRect.h" 13 | #import "UIColor+LLHex.h" 14 | 15 | @interface LLSearchNaviBarView () 16 | 17 | @property (nonatomic,strong) UIView *searchBgView; 18 | @property (nonatomic,strong) UIImageView *searLogoIconV; 19 | @property (nonatomic,strong) UIButton *backBtn; 20 | @property (nonatomic,strong) UIButton *rightOneBtn; 21 | 22 | @property (nonatomic,copy) rightOneBtnOnClick rightBtnBlock; 23 | @property (nonatomic,copy) backBtnOnClick backBtnBlock; 24 | @property (nonatomic,copy) keyBoardSearchBtnOnClickBlock keyBoardSearchBtnBlock; 25 | @property (nonatomic,copy) textofSearchBarDidChangeBlock textDidChangeBlock; 26 | @property (nonatomic,strong) LLSearchBar *searchBar; 27 | 28 | @end 29 | 30 | @implementation LLSearchNaviBarView 31 | { 32 | CGFloat searchBgViewH; 33 | CGFloat leftRightIconWH; 34 | CGFloat searchIconWH; 35 | CGFloat LeadMargin; 36 | CGFloat TrailMargin; 37 | } 38 | 39 | 40 | - (instancetype)init{ 41 | if (self = [super init]) { 42 | 43 | leftRightIconWH = 44.f; 44 | searchIconWH = 15.f; 45 | LeadMargin = 13.f; 46 | TrailMargin = 13.f; 47 | searchBgViewH = 29; 48 | 49 | self.frame = CGRectMake(0, 0, ZYHT_ScreenWidth, ZYHT_StatusBarAndNavigationBarHeight); 50 | self.backgroundColor = ZYHT_Q_RGBColor(56, 153, 229); 51 | 52 | [self addSubview:self.rightOneBtn]; 53 | [self addSubview:self.backBtn]; 54 | [self addSubview:[self setupSearView]]; 55 | } 56 | return self; 57 | } 58 | 59 | //--------------------------------------------------------------------------------------------------- 60 | #pragma mark ================================== 创建UI ================================== 61 | //--------------------------------------------------------------------------------------------------- 62 | 63 | - (UIButton *)backBtn 64 | { 65 | if (!_backBtn) { 66 | //左按钮 67 | _backBtn = ({ 68 | UIButton *backBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, ZYHT_StatusBarHeight, leftRightIconWH, leftRightIconWH)]; 69 | [backBtn setImage:[UIImage imageNamed:@"navi_back_w"] forState:UIControlStateNormal]; 70 | [backBtn addTarget:self action:@selector(backBtnOnCLick:) forControlEvents:UIControlEventTouchUpInside]; 71 | backBtn.hidden = YES; 72 | backBtn; 73 | }); 74 | } 75 | return _backBtn; 76 | } 77 | 78 | 79 | 80 | 81 | - (UIButton *)rightOneBtn 82 | { 83 | if (!_rightOneBtn) { 84 | 85 | _rightOneBtn = ({ 86 | UIButton *rightOneBtn = [[UIButton alloc] initWithFrame:CGRectMake(ZYHT_ScreenWidth-leftRightIconWH, ZYHT_StatusBarHeight, leftRightIconWH, leftRightIconWH)]; 87 | rightOneBtn.titleLabel.font = ZYHT_F_NormalFontOfSize(13); 88 | [rightOneBtn addTarget:self action:@selector(rightOneBtnOnCkick:) forControlEvents:UIControlEventTouchUpInside]; 89 | rightOneBtn.hidden = YES; 90 | rightOneBtn; 91 | }); 92 | } 93 | return _rightOneBtn; 94 | } 95 | 96 | 97 | - (UIView *)setupSearView 98 | { 99 | 100 | self.searchBgView = ({ 101 | UIView *searchBgView = [[UIView alloc] initWithFrame:CGRectMake(LeadMargin, ZYHT_StatusBarHeight+(ZYHT_NavigationBarHeight-searchBgViewH)*0.5, ZYHT_ScreenWidth-TrailMargin-LeadMargin, searchBgViewH)]; 102 | searchBgView.layer.cornerRadius = searchBgView.bounds.size.height*0.5; 103 | searchBgView.backgroundColor = ZYHT_Q_RGBAColor(255,255,255,0.3); 104 | searchBgView.clipsToBounds = YES; 105 | searchBgView; 106 | }); 107 | 108 | self.searLogoIconV = ({ 109 | UIImageView *searLogoIconV = [[UIImageView alloc] initWithFrame:(CGRect){CGRectGetWidth(self.searchBgView.frame)-searchBgViewH*0.5-searchIconWH, 0, searchIconWH, searchIconWH}]; 110 | searLogoIconV.image = [UIImage imageNamed:@"search"]; 111 | searLogoIconV.centerY = self.searchBgView.centerYInSelf; 112 | searLogoIconV.hidden = YES; 113 | searLogoIconV; 114 | }); 115 | 116 | 117 | self.searchBar = ({ 118 | LLSearchBar *searchBar = [[LLSearchBar alloc] initWithFrame:CGRectMake(5, 0, self.searchBgView.bounds.size.width-10, self.searchBgView.bounds.size.height)]; 119 | searchBar.backgroundImage = [UIImage imageNamed:@"clearImage"]; 120 | searchBar.delegate = self; 121 | // searchNaviBarViewDefault 情况下参数 122 | searchBar.placeholderColor = [UIColor whiteColor]; 123 | searchBar.textFont = ZYHT_F_NormalFontOfSize(12); 124 | searchBar.placeHolderFont = ZYHT_F_NormalFontOfSize(12); 125 | 126 | searchBar.hasCentredPlaceholder = NO; 127 | searchBar.isHideClearButton = YES; 128 | [searchBar setShowsCancelButton:NO]; 129 | searchBar; 130 | }); 131 | 132 | 133 | [self.searchBgView addSubview:self.searLogoIconV]; 134 | [self.searchBgView addSubview:self.searchBar]; 135 | 136 | return self.searchBgView; 137 | } 138 | 139 | 140 | //--------------------------------------------------------------------------------------------------- 141 | #pragma mark ================================== LLSearchBarDelegate ================================== 142 | //--------------------------------------------------------------------------------------------------- 143 | - (BOOL)searchBarShouldBeginEditing:(LLSearchBar *)searchBar 144 | { 145 | LLBLOCK_EXEC(_searchBarBeignOnClickBlock); 146 | return YES; 147 | } 148 | 149 | - (void)searchBarSearchButtonClicked:(LLSearchBar *)searchBar 150 | { 151 | LLBLOCK_EXEC(_keyBoardSearchBtnBlock,searchBar); 152 | } 153 | 154 | - (void)searchBar:(LLSearchBar *)searchBar textDidChange:(NSString *)searchText 155 | { 156 | LLBLOCK_EXEC(self.textDidChangeBlock,searchBar,searchText); 157 | } 158 | 159 | 160 | //--------------------------------------------------------------------------------------------------- 161 | #pragma mark ================================== 私有方法 ================================== 162 | //--------------------------------------------------------------------------------------------------- 163 | - (void)rightOneBtnOnCkick:(UIButton *)btn 164 | { 165 | LLBLOCK_EXEC(_rightBtnBlock,btn); 166 | } 167 | 168 | 169 | - (void)modifySearchBarViewFrame 170 | { 171 | if (!_backBtn.hidden && !_rightOneBtn.hidden) { 172 | self.searchBgView.x = self.backBtn.width; 173 | self.searchBgView.width = ZYHT_ScreenWidth-self.backBtn.width-self.rightOneBtn.width; 174 | } 175 | else if (_backBtn.hidden && !_rightOneBtn.hidden) 176 | { 177 | self.searchBgView.x = LeadMargin; 178 | self.searchBgView.width = ZYHT_ScreenWidth-LeadMargin-self.rightOneBtn.width; 179 | } 180 | else if (!_backBtn.hidden && _rightOneBtn.hidden) 181 | { 182 | self.searchBgView.x = self.backBtn.width; 183 | self.searchBgView.width = ZYHT_ScreenWidth-TrailMargin-self.backBtn.width; 184 | } 185 | 186 | 187 | self.searLogoIconV.x = self.searchBgView.width -searchBgViewH*0.5-searchIconWH; 188 | self.searchBar.width = self.searchBgView.bounds.size.width-10; 189 | } 190 | 191 | - (void)backBtnOnCLick:(UIButton *)btn 192 | { 193 | LLBLOCK_EXEC(_backBtnBlock,btn); 194 | } 195 | 196 | 197 | //--------------------------------------------------------------------------------------------------- 198 | #pragma mark ================================== 接口 ================================== 199 | //--------------------------------------------------------------------------------------------------- 200 | - (void)showRightOneBtnWith:(UIImage *)image onClick:(rightOneBtnOnClick)btnBlock 201 | { 202 | _rightBtnBlock = btnBlock; 203 | _rightOneBtn.hidden = NO; 204 | [_rightOneBtn setImage:image forState:UIControlStateNormal]; 205 | 206 | [self modifySearchBarViewFrame]; 207 | } 208 | 209 | -(void)showbackBtnWith:(UIImage *)image onClick:(backBtnOnClick)btnBlock 210 | { 211 | _backBtnBlock = btnBlock; 212 | _backBtn.hidden = NO; 213 | 214 | if (image) 215 | [_backBtn setImage:image forState:UIControlStateNormal]; 216 | 217 | [self modifySearchBarViewFrame]; 218 | } 219 | 220 | - (void)showRightOneBtnWithTitle:(NSString *)title onClick:(rightOneBtnOnClick)btnBlock { 221 | _rightBtnBlock = btnBlock; 222 | _rightOneBtn.hidden = NO; 223 | [_rightOneBtn setTitle:title forState:UIControlStateNormal]; 224 | 225 | [self modifySearchBarViewFrame]; 226 | } 227 | 228 | 229 | 230 | -(void)setRightOneBtnIconImage:(UIImage *)rightOneBtnIconImage 231 | { 232 | [_rightOneBtn setImage:rightOneBtnIconImage forState:UIControlStateNormal]; 233 | } 234 | 235 | 236 | -(void)setBackBtnIconImage:(UIImage *)backBtnIconImage 237 | { 238 | if (backBtnIconImage) 239 | [_backBtn setImage:backBtnIconImage forState:UIControlStateNormal]; 240 | } 241 | 242 | 243 | 244 | -(void)setSearbarPlaceHolder:(NSString *)searbarPlaceHolder 245 | { 246 | self.searchBar.placeholder = searbarPlaceHolder; 247 | } 248 | 249 | 250 | -(void)setIsHideSearchBarRightIcon:(BOOL)isHideSearchBarRightIcon 251 | { 252 | self.searLogoIconV.hidden = isHideSearchBarRightIcon; 253 | } 254 | 255 | 256 | -(void)setSearchBarRightIconImage:(UIImage *)searchBarRightIconImage 257 | { 258 | if (!self.searLogoIconV.hidden) { 259 | self.searLogoIconV.image = searchBarRightIconImage; 260 | } 261 | } 262 | 263 | -(LLSearchBar *)naviSearchBar{ 264 | return self.searchBar; 265 | } 266 | 267 | -(void)setSearchNaviBarViewType:(LLSearchNaviBarViewType)searchNaviBarViewType{ 268 | _searchNaviBarViewType = searchNaviBarViewType; 269 | 270 | switch (searchNaviBarViewType) { 271 | case searchNaviBarViewDefault: 272 | break; 273 | case searchNaviBarViewWhiteAndGray: 274 | { 275 | self.backgroundColor = [UIColor whiteColor]; 276 | self.searchBgView.backgroundColor = ZYHT_Q_RGBAColor(245, 245, 245, 1); 277 | self.searchBar.backgroundColor = ZYHT_Q_RGBAColor(245, 245, 245, 1); 278 | self.searchBar.placeholderColor = [UIColor colorWithHexString:@"686a6f"]; 279 | [_rightOneBtn setTitleColor:[UIColor colorWithHexString:@"333333"] forState:UIControlStateNormal]; 280 | 281 | //增加下划线 282 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, self.height-0.5, ZYHT_ScreenWidth, 0.5)]; 283 | view.backgroundColor = [UIColor colorWithHexString:@"d6d7dc"]; 284 | [self addSubview:view]; 285 | } 286 | break; 287 | default: 288 | break; 289 | } 290 | 291 | } 292 | 293 | - (void)keyBoardSearchBtnOnClick:(keyBoardSearchBtnOnClickBlock)searchBtnOnClickBlock { 294 | _keyBoardSearchBtnBlock = searchBtnOnClickBlock; 295 | } 296 | 297 | /** 298 | 搜索框框输入文字之后的即时变化 299 | */ 300 | - (void)textOfSearchBarDidChangeBlock:(textofSearchBarDidChangeBlock)textofSearchBarDidChangeBlock 301 | { 302 | _textDidChangeBlock = textofSearchBarDidChangeBlock; 303 | } 304 | 305 | @end 306 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/SearchSavePresenter/LLNaviSearchHistorySaveBasePresenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLNaviSearchHistorySaveBasePresenter.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/15. 6 | // 7 | // 8 | 9 | #import 10 | #import "LLSearchHistorySaveUtils.h" 11 | 12 | typedef void (^dealCompleteBlock) (BOOL isComplete); 13 | 14 | 15 | @interface LLNaviSearchHistorySaveBasePresenter : NSObject 16 | 17 | /*---------------------------------------------------------------- 18 | * 对子类抛出的属性 * 19 | -----------------------------------------------------------------*/ 20 | 21 | @property (nonatomic,strong) LLSearchHistorySaveUtils *saveUtils; 22 | 23 | 24 | /*---------------------------------------------------------------- 25 | * 接口方法 * 26 | -----------------------------------------------------------------*/ 27 | 28 | - (void)saveSearchCache:(NSString *)searchText result:(dealCompleteBlock)complete; 29 | 30 | - (void)clearSearchHistoryWithResult:(dealCompleteBlock)complete; 31 | 32 | - (NSArray *)getSearchCache; 33 | 34 | 35 | - (void)fetchAndHaveSearchCache:(dealCompleteBlock)complete; 36 | @end 37 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/SearchSavePresenter/LLNaviSearchHistorySaveBasePresenter.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLNaviSearchHistorySaveBasePresenter.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/15. 6 | // 7 | // 8 | 9 | #import "LLNaviSearchHistorySaveBasePresenter.h" 10 | #import "LLSearchVCConst.h" 11 | 12 | @implementation LLNaviSearchHistorySaveBasePresenter 13 | 14 | - (instancetype)init{ 15 | if (self = [super init]) { 16 | //code... 17 | _saveUtils = nil; 18 | } 19 | return self; 20 | } 21 | 22 | - (void)saveSearchCache:(NSString *)searchText result:(dealCompleteBlock)complete { 23 | [_saveUtils saveSearchCache:searchText result:complete]; 24 | } 25 | 26 | 27 | - (void)clearSearchHistoryWithResult:(dealCompleteBlock)complete { 28 | [self.saveUtils clearSearchHistoryWithResult:complete]; 29 | } 30 | 31 | - (NSArray *)getSearchCache{ 32 | // NSLog(@"%@",[self.saveUtils getSearchCache]); 33 | return [self.saveUtils getSearchCache]; 34 | } 35 | 36 | 37 | 38 | - (void)fetchAndHaveSearchCache:(dealCompleteBlock)complete { 39 | LLBLOCK_EXEC(complete,[self.saveUtils getSearchCache].count); 40 | } 41 | 42 | 43 | 44 | 45 | 46 | 47 | @end 48 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/SearchVC/LLNaviSearchBaseVC.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLNaviSearchBaseVC.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/15. 6 | // 7 | // 8 | 9 | 10 | #import 11 | #import "LLSearchNaviBarView.h" 12 | #import "LLSearchBar.h" 13 | #import "NBSSearchShopCategoryView.h" 14 | #import "NBSSearchShopHistoryView.h" 15 | 16 | #import "NBSSearchShopCategoryViewCellP.h" 17 | #import "LLSearchResultListView.h" 18 | 19 | 20 | typedef NS_OPTIONS(NSUInteger, NaviBarSearchType) { 21 | NaviBarSearchTypeDefault = 0, //导航条输入搜索 22 | NaviBarSearchTypeCategory, 23 | NaviBarSearchTypeHistory, 24 | NaviBarSearchTypesearchBarDidChange //搜索框即时搜索完成 25 | }; 26 | 27 | typedef void (^beginSearchBlock)(NaviBarSearchType searchType,NBSSearchShopCategoryViewCellP *categorytagP,UILabel *historyTagLabel,LLSearchBar *searchBar); 28 | 29 | typedef void (^searchBarDidChangeBlock)(NaviBarSearchType searchType, LLSearchBar *searchBar,NSString *searchText); 30 | 31 | 32 | @interface LLNaviSearchBaseVC : UIViewController 33 | 34 | /*---------------------------------------------------------------- 35 | * 接口方法 * 36 | -----------------------------------------------------------------*/ 37 | /** 38 | 搜索条的文字 39 | */ 40 | @property (nonatomic,copy) NSString *searchBarText; 41 | 42 | /** 43 | 即时搜索匹配框,匹配的数据列表 44 | */ 45 | @property (nonatomic,strong) NSArray *resultListArray; 46 | 47 | /** 48 | 搜索框:用户即时输入完毕 49 | 50 | @param didChangeBlock 更改后的回调 51 | */ 52 | - (void)searchbarDidChange:(searchBarDidChangeBlock)didChangeBlock; 53 | 54 | /** 55 | 即时匹配结果列表cell点击事件 56 | */ 57 | - (void)resultListViewDidSelectedIndex:(resultListViewCellDidClickBlock)cellDidClickBlock; 58 | 59 | /** 60 | 点击键盘"搜索"按钮或者历史标签 61 | 62 | @param beginSearchBlock 搜索数据 63 | */ 64 | - (void)beginSearch:(beginSearchBlock)beginSearchBlock; 65 | 66 | /** 67 | 是否只显示历史记录模 68 | ( 69 | 1. 其实在 OC 中是多此一举,因为已经为子类提供了[shopCategoryP],[shopHistoryP]处理类,如果任意一个初始化,为 nil,则其不会调用代码写出的方法. 70 | 这里为了更加安全,还是手动添加一个控制属性. 71 | 2. 当然,1中所说的仅限于使用默认本类默认布局情况下 72 | ) 73 | */ 74 | @property (nonatomic,assign) BOOL isOnlyShowHistoryView; 75 | 76 | 77 | 78 | /*---------------------------------------------------------------- 79 | * 对子类抛出的属性 * 80 | -----------------------------------------------------------------*/ 81 | 82 | @property (nonatomic,strong) UIScrollView *myBGScrollView; 83 | 84 | 85 | /** 86 | 分类模块的数据处理类,子类根据需要实现该属性,为界面提供数据 87 | */ 88 | @property (nonatomic,strong) id shopCategoryP; 89 | 90 | /** 91 | 历史记录模块的处理类,子类根据需要实现该属性,为界面提供数据 92 | */ 93 | @property (nonatomic,strong) id shopHistoryP; 94 | 95 | 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/SearchVC/LLNaviSearchBaseVC.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLNaviSearchBaseVC.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/15. 6 | // 7 | // 8 | 9 | #import "LLNaviSearchBaseVC.h" 10 | #import "LLSearchNaviBarView.h" 11 | #import "LLSearchBar.h" 12 | #import "NBSSearchShopCategoryView.h" 13 | #import "HistoryAndCategorySearchCategoryViewP.h" 14 | #import "NBSSearchShopCategoryViewCellP.h" 15 | #import "NBSSearchShopHistoryView.h" 16 | #import "HistoryAndCategorySearchHistroyViewP.h" 17 | #import "LLSearchVCConst.h" 18 | #import "UIView+LLRect.h" 19 | 20 | 21 | @interface LLNaviSearchBaseVC () 22 | 23 | @property (nonatomic,strong) LLSearchNaviBarView *searchNaviBarView; 24 | @property (nonatomic,strong) LLSearchBar *searchBar; 25 | 26 | @property (nonatomic,strong) NBSSearchShopCategoryView *shopCategoryView; 27 | @property (nonatomic,strong) NBSSearchShopHistoryView *shopHistoryView; 28 | 29 | 30 | @property (nonatomic,copy) beginSearchBlock beginSearchBlock; 31 | @property (nonatomic,copy) searchBarDidChangeBlock srdidChangeBlock; 32 | 33 | @property (nonatomic,copy) LLSearchResultListView *resultListView; 34 | 35 | @property (nonatomic,copy) resultListViewCellDidClickBlock myCellDidClickBlock; 36 | 37 | @end 38 | 39 | @implementation LLNaviSearchBaseVC{ 40 | CGFloat KeyboardHeightWhenShow; 41 | } 42 | 43 | 44 | - (void)viewDidAppear:(BOOL)animated 45 | { 46 | [super viewDidAppear:animated]; 47 | [self.searchBar becomeFirstResponder]; 48 | } 49 | 50 | - (void)viewDidLoad { 51 | [super viewDidLoad]; 52 | 53 | //导航条 54 | [self setupSearchNaviBar]; 55 | 56 | [self getData]; 57 | 58 | //监听键盘时间 59 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:UIKeyboardWillChangeFrameNotification object:nil]; 60 | 61 | 62 | } 63 | 64 | - (void)getData 65 | { 66 | @LLWeakObj(self); 67 | if (!_isOnlyShowHistoryView) { 68 | //开始获取数据 69 | [self.shopCategoryP fetchCategotyTypeData:^(NSError *error, id result) { 70 | @LLStrongObj(self); 71 | if(!error) 72 | [self setupShopCategory]; 73 | else 74 | [self myBGScrollView]; 75 | }]; 76 | } 77 | 78 | 79 | //开始获取数据 80 | [self.shopHistoryP getSearchCache]; 81 | [self.shopHistoryP fetchAndHaveSearchCache:^(BOOL isHave) { 82 | @LLStrongObj(self); 83 | if (isHave) 84 | [self setupShopHistory]; 85 | else 86 | [self myBGScrollView]; 87 | }]; 88 | } 89 | 90 | 91 | //创建分类界面 92 | - (void)setupShopCategory 93 | { 94 | self.shopCategoryView = [NBSSearchShopCategoryView searchShopCategoryViewWithPresenter:self.shopCategoryP WithFrame:(CGRect){0,0,ZYHT_ScreenWidth,0}]; 95 | 96 | @LLWeakObj(self); 97 | //分类搜索 98 | [self.shopCategoryView categoryTagonClick:^(NBSSearchShopCategoryViewCellP *cellP) { 99 | @LLStrongObj(self); 100 | [self beignToSearch:NaviBarSearchTypeCategory cellP:cellP tagLabel:nil searchBar:nil]; 101 | }]; 102 | 103 | 104 | [self.shopCategoryView setModifyFrameBlock:^(CGRect rect){ 105 | @LLStrongObj(self); 106 | [self modifyViewFrame]; 107 | }]; 108 | 109 | //刷新数据 110 | [self.shopCategoryView reloadData]; 111 | 112 | [self.myBGScrollView addSubview:self.shopCategoryView]; 113 | } 114 | 115 | 116 | //创建历史搜索栏 117 | - (void)setupShopHistory 118 | { 119 | 120 | self.shopHistoryView = [NBSSearchShopHistoryView searchShopCategoryViewWithPresenter:self.shopHistoryP WithFrame:(CGRect){0,self.shopCategoryView.bottom,ZYHT_ScreenWidth,0}]; 121 | 122 | @LLWeakObj(self); 123 | //开始搜索历史记录 124 | [self.shopHistoryView historyTagonClick:^(UILabel *tagLabel) { 125 | @LLStrongObj(self); 126 | [self beignToSearch:NaviBarSearchTypeHistory cellP:nil tagLabel:tagLabel searchBar:nil]; 127 | 128 | }]; 129 | 130 | //清空搜索历史 131 | [self.shopHistoryView setClearHistoryBtnOnClick:^{ 132 | @LLStrongObj(self); 133 | //清空 134 | [self.shopHistoryP clearSearchHistoryWithResult:nil]; 135 | 136 | [self.shopHistoryView removeFromSuperview]; 137 | }]; 138 | 139 | 140 | //刷新数据 141 | [self.shopHistoryView reloadData]; 142 | 143 | [self.myBGScrollView addSubview:self.shopHistoryView]; 144 | } 145 | 146 | 147 | //创建导航条 148 | - (void)setupSearchNaviBar 149 | { 150 | LLSearchNaviBarView *searchNaviBarView = [LLSearchNaviBarView new]; 151 | searchNaviBarView.searbarPlaceHolder = @"请输入搜索关键词"; 152 | searchNaviBarView.searchNaviBarViewType = searchNaviBarViewWhiteAndGray; 153 | self.searchBar = searchNaviBarView.naviSearchBar; 154 | 155 | @LLWeakObj(self); 156 | [searchNaviBarView showRightOneBtnWithTitle:@"取消" onClick:^(UIButton *btn) { 157 | @LLStrongObj(self); 158 | 159 | [searchNaviBarView.naviSearchBar resignFirstResponder]; 160 | [self dismissViewControllerAnimated:NO completion:nil]; 161 | }]; 162 | 163 | //开始搜索导航条输入 164 | [searchNaviBarView keyBoardSearchBtnOnClick:^(LLSearchBar *searchBar) { 165 | @LLStrongObj(self); 166 | //通知外界开始搜索 167 | [self beignToSearch:NaviBarSearchTypeDefault cellP:nil tagLabel:nil searchBar:searchBar]; 168 | //保存搜索历史记录 169 | [self.shopHistoryP saveSearchCache:searchBar.text result:nil]; 170 | }]; 171 | 172 | //搜索框即时输入捕捉 173 | [searchNaviBarView textOfSearchBarDidChangeBlock:^(LLSearchBar *searchBar, NSString *searchText) { 174 | @LLStrongObj(self); 175 | LLBLOCK_EXEC(self.srdidChangeBlock,NaviBarSearchTypesearchBarDidChange,searchBar,searchText) 176 | }]; 177 | 178 | 179 | 180 | [self.view addSubview:searchNaviBarView]; 181 | } 182 | 183 | 184 | 185 | #pragma mark ================ 更新界面 Frame ================ 186 | -(void)modifyViewFrame 187 | { 188 | self.shopHistoryView.y = self.shopCategoryView.bottom; 189 | } 190 | 191 | 192 | 193 | #pragma mark ================ UISCrollDelegate ================ 194 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView 195 | { 196 | [self.searchBar resignFirstResponder]; 197 | } 198 | 199 | 200 | //----------------------------------------------------------------------------------------------------------- 201 | #pragma mark ================ 私有方法 ================ 202 | //----------------------------------------------------------------------------------------------------------- 203 | - (UIScrollView *)myBGScrollView 204 | { 205 | if (!_myBGScrollView) { 206 | _myBGScrollView = ({ 207 | UIScrollView *bgScrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0,64, ZYHT_ScreenWidth,ZYHT_ScreenHeight-64)]; 208 | bgScrollView.backgroundColor = [UIColor colorWithRed:245/255.0 green:245/255.0 blue:245/255.0 alpha:1.0]; 209 | bgScrollView.contentSize = CGSizeMake(ZYHT_ScreenWidth, ZYHT_ScreenHeight-60); 210 | bgScrollView.showsVerticalScrollIndicator = NO; 211 | bgScrollView.delegate = self; 212 | [self.view addSubview:bgScrollView]; 213 | bgScrollView; 214 | }); 215 | } 216 | return _myBGScrollView; 217 | } 218 | 219 | 220 | - (void)beignToSearch:(NaviBarSearchType)searchType cellP:(NBSSearchShopCategoryViewCellP *)cellP tagLabel:(UILabel *)tagLabel searchBar:(LLSearchBar *)searchBar{ 221 | if (searchType == NaviBarSearchTypeDefault) 222 | { 223 | LLBLOCK_EXEC(self.beginSearchBlock,searchType,nil,nil,searchBar); 224 | } 225 | else if (searchType == NaviBarSearchTypeCategory) 226 | { 227 | LLBLOCK_EXEC(self.beginSearchBlock,searchType,cellP,nil,searchBar); 228 | } 229 | else if (searchType == NaviBarSearchTypeHistory) 230 | { 231 | LLBLOCK_EXEC(self.beginSearchBlock,searchType,nil,tagLabel,nil); 232 | } 233 | 234 | //退出 235 | [self dismissVC]; 236 | } 237 | 238 | - (void)dismissVC{ 239 | [[NSNotificationCenter defaultCenter] removeObserver:self]; 240 | [self dismissViewControllerAnimated:NO completion:nil]; 241 | } 242 | 243 | 244 | //创建即时匹配页面 245 | - (LLSearchResultListView *)resultListView 246 | { 247 | if (!_resultListView) { 248 | _resultListView = [[LLSearchResultListView alloc] init]; 249 | 250 | //列表被点击 251 | @LLWeakObj(self); 252 | [_resultListView resultListViewDidSelectedIndex:^(UITableView *tableView, NSInteger index) { 253 | @LLStrongObj(self); 254 | 255 | [self.shopHistoryP saveSearchCache:self.resultListArray[index] result:nil]; 256 | 257 | LLBLOCK_EXEC(self.myCellDidClickBlock,tableView,index); 258 | 259 | //退出搜索控制器 260 | [self dismissVC]; 261 | }]; 262 | 263 | 264 | [self.view addSubview:_resultListView]; 265 | } 266 | return _resultListView; 267 | } 268 | 269 | #pragma mark UIKeyboardWillChangeFrameNotification/当键盘的位置大小发生改变时触发 270 | - (void)keyboardWillChangeFrame:(NSNotification *)note 271 | { 272 | CGRect rect = [note.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; 273 | KeyboardHeightWhenShow = rect.size.height; 274 | } 275 | 276 | //----------------------------------------------------------------------------------------------------------- 277 | #pragma mark ================ 接口 ================ 278 | //----------------------------------------------------------------------------------------------------------- 279 | - (void)beginSearch:(beginSearchBlock)beginSearchBlock { 280 | _beginSearchBlock = beginSearchBlock; 281 | } 282 | 283 | -(void)setSearchBarText:(NSString *)searchBarText{ 284 | } 285 | 286 | -(void)setResultListArray:(NSArray *)resultListArray 287 | { 288 | _resultListArray = resultListArray; 289 | self.resultListView.frame = CGRectMake(0, ZYHT_StatusBarAndNavigationBarHeight, self.view.width, ZYHT_ScreenHeight-KeyboardHeightWhenShow-ZYHT_StatusBarAndNavigationBarHeight); 290 | self.resultListView.resultArray = resultListArray; 291 | } 292 | 293 | 294 | - (void)searchbarDidChange:(searchBarDidChangeBlock)didChangeBlock; 295 | { 296 | _srdidChangeBlock = didChangeBlock; 297 | } 298 | 299 | 300 | /** 301 | 即时匹配结果列表cell点击事件 302 | */ 303 | - (void)resultListViewDidSelectedIndex:(resultListViewCellDidClickBlock)cellDidClickBlock 304 | { 305 | _myCellDidClickBlock = cellDidClickBlock; 306 | } 307 | 308 | 309 | -(void)dealloc 310 | { 311 | NSLog(@"LLNaviSearchBaseVC 页面销毁"); 312 | } 313 | 314 | @end 315 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/Category/LLSearchVCConst.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchVCConst.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | /*---------------------------------------------------------------------------------- 11 | * 手机尺寸信息 * 12 | ----------------------------------------------------------------------------------*/ 13 | // UIScreen width. 14 | #define ZYHT_ScreenWidth [UIScreen mainScreen].bounds.size.width 15 | 16 | // UIScreen height. 17 | #define ZYHT_ScreenHeight [UIScreen mainScreen].bounds.size.height 18 | 19 | // Status bar height. 20 | #define ZYHT_StatusBarHeight 20.f 21 | 22 | // Navigation bar height. 23 | #define ZYHT_NavigationBarHeight 44.f 24 | 25 | // Tabbar height. 26 | #define ZYHT_TabbarHeight 49.f 27 | 28 | // Status bar & navigation bar height. 29 | #define ZYHT_StatusBarAndNavigationBarHeight (20.f + 44.f) 30 | 31 | 32 | /*---------------------------------------------------------------------------------- 33 | * 全局字体引用 * 34 | ----------------------------------------------------------------------------------*/ 35 | #define ZYHT_F_NormalFontOfSize(fontSize) [UIFont systemFontOfSize:fontSize] 36 | #define ZYHT_F_MediumFontOfSize(fontSize) [UIFont systemFontOfSize:fontSize weight:UIFontWeightMedium] 37 | 38 | 39 | /*---------------------------------------------------------------------------------- 40 | * Block/Block-weak-strong避免循环引用 * 41 | ----------------------------------------------------------------------------------*/ 42 | #define LLBLOCK_EXEC(block, ...) if (block) { block(__VA_ARGS__); } 43 | 44 | //#define LLWeakObj(o) autoreleasepool{} __weak typeof(o) o##Weak = o; 45 | //#define LLStrongObj(o) autoreleasepool{} __strong typeof(o) o = o##Weak; 46 | 47 | // 避免宏循环引用 48 | #ifndef LLWeakObj 49 | #if DEBUG 50 | #if __has_feature(objc_arc) 51 | #define LLWeakObj(object) autoreleasepool{} __weak __typeof__(object) weak##_##object = object; 52 | #else 53 | #define LLWeakObj(object) autoreleasepool{} __block __typeof__(object) block##_##object = object; 54 | #endif 55 | #else 56 | #if __has_feature(objc_arc) 57 | #define LLWeakObj(object) try{} @finally{} {} __weak __typeof__(object) weak##_##object = object; 58 | #else 59 | #define LLWeakObj(object) try{} @finally{} {} __block __typeof__(object) block##_##object = object; 60 | #endif 61 | #endif 62 | #endif 63 | 64 | #ifndef LLStrongObj 65 | #if DEBUG 66 | #if __has_feature(objc_arc) 67 | #define LLStrongObj(object) autoreleasepool{} __typeof__(object) object = weak##_##object; 68 | #else 69 | #define LLStrongObj(object) autoreleasepool{} __typeof__(object) object = block##_##object; 70 | #endif 71 | #else 72 | #if __has_feature(objc_arc) 73 | #define LLStrongObj(object) try{} @finally{} __typeof__(object) object = weak##_##object; 74 | #else 75 | #define LLStrongObj(object) try{} @finally{} __typeof__(object) object = block##_##object; 76 | #endif 77 | #endif 78 | #endif 79 | 80 | 81 | 82 | 83 | 84 | /*---------------------------------------------------------------------------------- 85 | * 全局快捷代码 * 86 | ----------------------------------------------------------------------------------*/ 87 | // 自定义颜色 88 | #define ZYHT_Q_RGBAColor(r, g, b, a) [UIColor colorWithRed:(r) / 255.0 green:(g) / 255.0 blue:(b) / 255.0 alpha:(a)] 89 | // 自定义颜色,alpha默认为1 90 | #define ZYHT_Q_RGBColor(r,g,b) [UIColor colorWithRed:r/255.0 green:g/255.0 blue:b/255.0 alpha:1.0] 91 | // 随机颜色 92 | #define ZYHT_Q_RandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:1.0]; 93 | 94 | 95 | 96 | @interface LLSearchVCConst : NSObject 97 | 98 | 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/Category/LLSearchVCConst.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchVCConst.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | 10 | 11 | 12 | #import "LLSearchVCConst.h" 13 | 14 | 15 | @implementation LLSearchVCConst 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/Category/UIColor+LLHex.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+LLHex.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIColor (LLHex) 12 | 13 | + (UIColor *)colorWithHexString:(NSString *)color; 14 | 15 | //从十六进制字符串获取颜色, 16 | //color:支持@“#123456”、 @“0X123456”、 @“123456”三种格式 17 | + (UIColor *)colorWithHexString:(NSString *)color alpha:(CGFloat)alpha; 18 | 19 | + (UIColor *)randomColor; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/Category/UIColor+LLHex.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIColor+LLHex.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/22. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "UIColor+LLHex.h" 10 | 11 | @implementation UIColor (LLHex) 12 | 13 | + (UIColor *)colorWithHexString:(NSString *)color{ 14 | return [self colorWithHexString:color alpha:1.0f]; 15 | } 16 | 17 | //从十六进制字符串获取颜色, 18 | //color:支持@“#123456”、 @“0X123456”、 @“123456”三种格式 19 | + (UIColor *)colorWithHexString:(NSString *)color alpha:(CGFloat)alpha{ 20 | //删除字符串中的空格 21 | NSString *cString = [[color stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString]; 22 | // String should be 6 or 8 characters 23 | if ([cString length] < 6) 24 | { 25 | return [UIColor clearColor]; 26 | } 27 | // strip 0X if it appears 28 | //如果是0x开头的,那么截取字符串,字符串从索引为2的位置开始,一直到末尾 29 | if ([cString hasPrefix:@"0X"]) 30 | { 31 | cString = [cString substringFromIndex:2]; 32 | } 33 | //如果是#开头的,那么截取字符串,字符串从索引为1的位置开始,一直到末尾 34 | if ([cString hasPrefix:@"#"]) 35 | { 36 | cString = [cString substringFromIndex:1]; 37 | } 38 | if ([cString length] != 6) 39 | { 40 | return [UIColor clearColor]; 41 | } 42 | 43 | // Separate into r, g, b substrings 44 | NSRange range; 45 | range.location = 0; 46 | range.length = 2; 47 | //r 48 | NSString *rString = [cString substringWithRange:range]; 49 | //g 50 | range.location = 2; 51 | NSString *gString = [cString substringWithRange:range]; 52 | //b 53 | range.location = 4; 54 | NSString *bString = [cString substringWithRange:range]; 55 | 56 | // Scan values 57 | unsigned int r, g, b; 58 | [[NSScanner scannerWithString:rString] scanHexInt:&r]; 59 | [[NSScanner scannerWithString:gString] scanHexInt:&g]; 60 | [[NSScanner scannerWithString:bString] scanHexInt:&b]; 61 | return [UIColor colorWithRed:((float)r / 255.0f) green:((float)g / 255.0f) blue:((float)b / 255.0f) alpha:alpha]; 62 | } 63 | 64 | 65 | + (UIColor *)randomColor { 66 | return [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:(1.0)]; 67 | } 68 | 69 | 70 | 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/Category/UIView+LLRect.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+LLRect.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/13. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | /** 12 | * UIScreen width. 13 | */ 14 | #define Width [UIScreen mainScreen].bounds.size.width 15 | 16 | /** 17 | * UIScreen height. 18 | */ 19 | #define Height [UIScreen mainScreen].bounds.size.height 20 | 21 | /** 22 | * Status bar height. 23 | */ 24 | #define StatusBarHeight 20.f 25 | 26 | /** 27 | * Navigation bar height. 28 | */ 29 | #define NavigationBarHeight 44.f 30 | 31 | /** 32 | * Tabbar height. 33 | */ 34 | #define TabbarHeight 49.f 35 | 36 | /** 37 | * Status bar & navigation bar height. 38 | */ 39 | #define StatusBarAndNavigationBarHeight (20.f + 44.f) 40 | 41 | /** 42 | * iPhone4 or iPhone4s 43 | */ 44 | #define iPhone4_4s (Width == 320.f && Height == 480.f ? YES : NO) 45 | 46 | /** 47 | * iPhone5 or iPhone5s 48 | */ 49 | #define iPhone5_5s (Width == 320.f && Height == 568.f ? YES : NO) 50 | 51 | /** 52 | * iPhone6 or iPhone6s 53 | */ 54 | #define iPhone6_6s (Width == 375.f && Height == 667.f ? YES : NO) 55 | 56 | /** 57 | * iPhone6Plus or iPhone6sPlus 58 | */ 59 | #define iPhone6_6sPlus (Width == 414.f && Height == 736.f ? YES : NO) 60 | 61 | @interface UIView (SetRect) 62 | 63 | /*---------------------- 64 | * Absolute coordinate * 65 | ----------------------*/ 66 | 67 | @property (nonatomic) CGPoint viewOrigin; 68 | @property (nonatomic) CGSize viewSize; 69 | 70 | @property (nonatomic) CGFloat x; 71 | @property (nonatomic) CGFloat y; 72 | @property (nonatomic) CGFloat width; 73 | @property (nonatomic) CGFloat height; 74 | 75 | @property (nonatomic) CGFloat top; 76 | @property (nonatomic) CGFloat bottom; 77 | @property (nonatomic) CGFloat left; 78 | @property (nonatomic) CGFloat right; 79 | 80 | @property (nonatomic) CGFloat centerX; 81 | @property (nonatomic) CGFloat centerY; 82 | 83 | @property(nonatomic,readonly) CGFloat centerYInSelf; 84 | 85 | /*---------------------- 86 | * Relative coordinate * 87 | ----------------------*/ 88 | 89 | @property (nonatomic, readonly) CGFloat middleX; 90 | @property (nonatomic, readonly) CGFloat middleY; 91 | @property (nonatomic, readonly) CGPoint middlePoint; 92 | 93 | @end 94 | 95 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/Category/UIView+LLRect.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+LLRect.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/13. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "UIView+LLRect.h" 10 | 11 | @implementation UIView (SetRect) 12 | 13 | - (CGPoint)viewOrigin { 14 | 15 | return self.frame.origin; 16 | } 17 | 18 | - (void)setViewOrigin:(CGPoint)viewOrigin { 19 | 20 | CGRect newFrame = self.frame; 21 | newFrame.origin = viewOrigin; 22 | self.frame = newFrame; 23 | } 24 | 25 | - (CGSize)viewSize { 26 | 27 | return self.frame.size; 28 | } 29 | 30 | - (void)setViewSize:(CGSize)viewSize { 31 | 32 | CGRect newFrame = self.frame; 33 | newFrame.size = viewSize; 34 | self.frame = newFrame; 35 | } 36 | 37 | - (CGFloat)x { 38 | 39 | return self.frame.origin.x; 40 | } 41 | 42 | - (void)setX:(CGFloat)x { 43 | 44 | CGRect newFrame = self.frame; 45 | newFrame.origin.x = x; 46 | self.frame = newFrame; 47 | } 48 | 49 | - (CGFloat)y { 50 | 51 | return self.frame.origin.y; 52 | } 53 | 54 | - (void)setY:(CGFloat)y { 55 | 56 | CGRect newFrame = self.frame; 57 | newFrame.origin.y = y; 58 | self.frame = newFrame; 59 | } 60 | 61 | - (CGFloat)width { 62 | 63 | return CGRectGetWidth(self.bounds); 64 | } 65 | 66 | - (void)setWidth:(CGFloat)width { 67 | 68 | CGRect newFrame = self.frame; 69 | newFrame.size.width = width; 70 | self.frame = newFrame; 71 | } 72 | 73 | - (CGFloat)height { 74 | 75 | return CGRectGetHeight(self.bounds); 76 | } 77 | 78 | - (void)setHeight:(CGFloat)height { 79 | 80 | CGRect newFrame = self.frame; 81 | newFrame.size.height = height; 82 | self.frame = newFrame; 83 | } 84 | 85 | - (CGFloat)top { 86 | 87 | return self.frame.origin.y; 88 | } 89 | 90 | - (void)setTop:(CGFloat)top { 91 | 92 | CGRect newFrame = self.frame; 93 | newFrame.origin.y = top; 94 | self.frame = newFrame; 95 | } 96 | 97 | - (CGFloat)bottom { 98 | 99 | return self.frame.origin.y + self.frame.size.height; 100 | } 101 | 102 | - (void)setBottom:(CGFloat)bottom { 103 | 104 | CGRect newFrame = self.frame; 105 | newFrame.origin.y = bottom - self.frame.size.height; 106 | self.frame = newFrame; 107 | } 108 | 109 | - (CGFloat)left { 110 | 111 | return self.frame.origin.x; 112 | } 113 | 114 | - (void)setLeft:(CGFloat)left { 115 | 116 | CGRect newFrame = self.frame; 117 | newFrame.origin.x = left; 118 | self.frame = newFrame; 119 | } 120 | 121 | - (CGFloat)right { 122 | 123 | return self.frame.origin.x + self.frame.size.width; 124 | } 125 | 126 | - (void)setRight:(CGFloat)right { 127 | 128 | CGRect newFrame = self.frame; 129 | newFrame.origin.x = right - self.frame.size.width; 130 | self.frame = newFrame; 131 | } 132 | 133 | - (CGFloat)centerX { 134 | 135 | return self.center.x; 136 | } 137 | 138 | - (void)setCenterX:(CGFloat)centerX { 139 | 140 | CGPoint newCenter = self.center; 141 | newCenter.x = centerX; 142 | self.center = newCenter; 143 | } 144 | 145 | - (CGFloat)centerY { 146 | 147 | return self.center.y; 148 | } 149 | 150 | - (void)setCenterY:(CGFloat)centerY { 151 | 152 | CGPoint newCenter = self.center; 153 | newCenter.y = centerY; 154 | self.center = newCenter; 155 | } 156 | 157 | 158 | -(CGFloat)centerYInSelf 159 | { 160 | return self.height*0.5; 161 | } 162 | 163 | 164 | 165 | - (CGFloat)middleX { 166 | 167 | return CGRectGetWidth(self.bounds) / 2.f; 168 | } 169 | 170 | - (CGFloat)middleY { 171 | 172 | return CGRectGetHeight(self.bounds) / 2.f; 173 | } 174 | 175 | - (CGPoint)middlePoint { 176 | 177 | return CGPointMake(CGRectGetWidth(self.bounds) / 2.f, CGRectGetHeight(self.bounds) / 2.f); 178 | } 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/LLSearchHistorySaveUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchHistorySaveUtils.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/14. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | typedef void (^dealCompleteBlock) (BOOL isComplete); 13 | 14 | @interface LLSearchHistorySaveUtils : NSObject 15 | 16 | 17 | /** 18 | The number of cache search record, default is 15. 19 | */ 20 | @property (nonatomic, assign) NSUInteger searchHistoriesCount; 21 | 22 | - (instancetype)initWithSearchHistoriesCacheFileName:(NSString *)fileName; 23 | - (void)saveSearchCache:(NSString *)searchText result:(dealCompleteBlock)complete; 24 | - (void)clearSearchHistoryWithResult:(dealCompleteBlock)complete; 25 | - (NSArray *)getSearchCache; 26 | 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/LLSearchHistorySaveUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchHistorySaveUtils.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/14. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "LLSearchHistorySaveUtils.h" 10 | #import "LLSearchVCConst.h" 11 | //#import "ZYHTHistoryDataSaveUtils.h" 12 | 13 | 14 | @interface LLSearchHistorySaveUtils () 15 | 16 | /** 17 | Whether remove the space of search string, default is YES. 18 | */ 19 | @property (nonatomic, assign) BOOL removeSpaceOnSearchString; 20 | 21 | 22 | 23 | /** 24 | The records of search 25 | */ 26 | @property (nonatomic, strong) NSMutableArray *searchHistories; 27 | 28 | 29 | /** 30 | The path of cache search record, default is `PYSEARCH_SEARCH_HISTORY_CACHE_PATH`. 31 | */ 32 | @property (nonatomic, copy) NSString *searchHistoriesCachePath; 33 | 34 | 35 | @end 36 | 37 | @implementation LLSearchHistorySaveUtils 38 | 39 | 40 | 41 | - (NSString *)getPathWithFileName:(NSString *)fileName 42 | { 43 | 44 | NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 45 | NSString *documentDir = [paths objectAtIndex:0]; 46 | NSString *dstPath = [documentDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.data",fileName]]; 47 | return dstPath; 48 | } 49 | 50 | 51 | 52 | 53 | - (instancetype)initWithSearchHistoriesCacheFileName:(NSString *)fileName 54 | { 55 | if (self = [super init]) { 56 | //code... 57 | _removeSpaceOnSearchString = YES; 58 | _searchHistoriesCachePath = [self getPathWithFileName:fileName]; 59 | _searchHistoriesCount = 15; 60 | } 61 | return self; 62 | } 63 | 64 | 65 | 66 | 67 | - (void)saveSearchCache:(NSString *)searchText result:(dealCompleteBlock)complete 68 | { 69 | BOOL saveFlag = NO; //存储是否成功,默认为不成功 70 | 71 | if (self.removeSpaceOnSearchString) { // remove sapce on search string 72 | searchText = [searchText stringByReplacingOccurrencesOfString:@" " withString:@""]; 73 | } 74 | if (searchText.length > 0) { 75 | 76 | //移除之前存储的相同的记录,重新储存到最前边 77 | [self.searchHistories removeObject:searchText]; 78 | [self.searchHistories insertObject:searchText atIndex:0]; 79 | 80 | //如果当前存储超过了规定存储的最大数量,则删除最开始的一个存储记录,再进行存储 81 | if (self.searchHistories.count > self.searchHistoriesCount) { 82 | [self.searchHistories removeLastObject]; 83 | } 84 | 85 | //存储消息记录,返回标识 86 | saveFlag = [NSKeyedArchiver archiveRootObject:self.searchHistories toFile:self.searchHistoriesCachePath]; 87 | } 88 | 89 | //返回结果 90 | LLBLOCK_EXEC(complete,saveFlag); 91 | } 92 | 93 | 94 | 95 | - (void)clearSearchHistoryWithResult:(dealCompleteBlock)complete 96 | { 97 | BOOL dealFlag = NO; //删除是否成功 98 | 99 | if (_searchHistoriesCachePath) { 100 | [self.searchHistories removeAllObjects]; 101 | dealFlag = [NSKeyedArchiver archiveRootObject:self.searchHistories toFile:self.searchHistoriesCachePath]; 102 | } 103 | 104 | //返回结果 105 | LLBLOCK_EXEC(complete,dealFlag); 106 | 107 | } 108 | 109 | 110 | 111 | - (NSArray *)getSearchCache{ 112 | return self.searchHistories; 113 | } 114 | 115 | 116 | 117 | - (NSMutableArray *)searchHistories 118 | { 119 | if (!_searchHistories) { 120 | _searchHistories = [NSMutableArray arrayWithArray:[NSKeyedUnarchiver unarchiveObjectWithFile:self.searchHistoriesCachePath]]; 121 | } 122 | return _searchHistories; 123 | } 124 | 125 | 126 | 127 | @end 128 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/LLTagViewUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // LLTagViewUtils.h 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/13. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | 13 | /** 14 | style of CommonTags 15 | */ 16 | typedef NS_ENUM(NSInteger, ZYHTCommonTagStyle) { 17 | ZYHTCommonTagStyleNormalTag, // normal tag without border 18 | ZYHTCommonTagStyleColorfulTag, // colorful tag without border, color of background is randrom and can be custom by `colorPol` 19 | ZYHTCommonTagStyleBorderTag, // border tag, color of background is `clearColor` 20 | ZYHTCommonTagStyleARCBorderTag, // broder tag with ARC, color of background is `clearColor` 21 | ZYHTCommonTagStyleNormalWhiteTag, 22 | ZYHTCommonTagStyleDefault = ZYHTCommonTagStyleNormalTag // default is `PYHotSearchStyleNormalTag` 23 | }; 24 | 25 | 26 | typedef void (^tagLabelOnClickBlock)(UITapGestureRecognizer *tapGes,UILabel *tagLabel); 27 | 28 | @interface LLTagViewUtils : NSObject 29 | 30 | 31 | /** 32 | 创建普通标签,可以通过ZYHTCommonTagStyle设置样式 33 | 34 | @param contentView 展示位置 35 | @param tagTexts 标签文字数组 36 | @param margin 标签间距 37 | @return 标签数组 38 | */ 39 | - (NSArray *)setupCommonTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts margin:(CGFloat)margin tagHeight:(CGFloat)tagHeight; 40 | 41 | /** 42 | The style of CommonTags, default is `ZYHTCommonTagStyleNormalTag`. 43 | */ 44 | @property (nonatomic, assign) ZYHTCommonTagStyle commonTagStyle; 45 | 46 | 47 | 48 | /** 49 | 设置矩形布局样式 50 | 51 | @param contentView 展示位置 52 | @param tagTexts 标签文字数组 53 | @param maxColumnNum 展示列数 54 | @param tagHeight 标签的高度 55 | */ 56 | - (void)setupRectangleTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts maxColumnNum:(int)maxColumnNum tagHeight:(CGFloat)tagHeight; 57 | 58 | 59 | /** 60 | 设置行样式标签布局 61 | 62 | @param contentView 展示位置 63 | @param tagTexts 标签文字数组 64 | @param padding 序号标签和文字标签的内间距 65 | @param tagViewMargin 标签控件的外间距 66 | */ 67 | - (void)setupRankTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts tagHeight:(CGFloat)tagHeight padding:(CGFloat)padding tagViewMargin:(CGFloat)tagViewMargin ; 68 | 69 | 70 | - (void)tagLabelOnClick:(tagLabelOnClickBlock)clickBlock; 71 | 72 | 73 | 74 | 75 | 76 | @end 77 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/Utils/LLTagViewUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLTagViewUtils.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/7/13. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import "LLTagViewUtils.h" 10 | #import "UIView+LLRect.h" 11 | 12 | 13 | 14 | #define LLTagViewUtils_COLORPolRandomColor [UIColor colorWithRed:arc4random_uniform(256)/255.0 green:arc4random_uniform(256)/255.0 blue:arc4random_uniform(256)/255.0 alpha:(1.0)] 15 | #define LLTagViewUtils_COLOR(r,g,b) [UIColor colorWithRed:(r/255.0) green:(g/255.0) blue:(b/255.0) alpha:1.0] 16 | #define PYSEARCH_REALY_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width 17 | 18 | 19 | 20 | @interface LLTagViewUtils () 21 | 22 | /** 23 | The element of popular search 24 | */ 25 | @property (nonatomic, strong) NSMutableArray *tagLabelArray; 26 | @property (nonatomic, strong) NSArray *tagLabelTitleArray; 27 | @property (nonatomic, strong) UIView *contentView; 28 | 29 | @property (nonatomic,copy) tagLabelOnClickBlock myOnCickBlock; 30 | 31 | @property (nonatomic, strong) NSArray *rankTextLabels; 32 | @property (nonatomic, strong) NSArray *rankTagIndexs; 33 | @property (nonatomic, strong) NSArray *rankViews; 34 | @end 35 | 36 | @implementation LLTagViewUtils 37 | 38 | 39 | 40 | //--------------------------------------------------------------------------------------------------- 41 | #pragma mark ================================== 接口 ================================== 42 | //--------------------------------------------------------------------------------------------------- 43 | 44 | - (void)tagLabelOnClick:(tagLabelOnClickBlock)clickBlock { 45 | _myOnCickBlock = clickBlock; 46 | } 47 | 48 | 49 | 50 | 51 | 52 | - (NSArray *)setupCommonTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts margin:(CGFloat)margin tagHeight:(CGFloat)tagHeight 53 | { 54 | return [self zyht_setupCommonTagsInView:contentView tagTexts:tagTexts margin:margin tagHeight:(CGFloat)tagHeight]; 55 | } 56 | 57 | - (void)setupRectangleTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts maxColumnNum:(int)maxColumnNum tagHeight:(CGFloat)tagHeight 58 | { 59 | return [self zyht_setupRectangleTagsInView:contentView tagTexts:tagTexts maxColumnNum:maxColumnNum tagHeight:tagHeight]; 60 | } 61 | 62 | - (void)setupRankTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts tagHeight:(CGFloat)tagHeight padding:(CGFloat)padding tagViewMargin:(CGFloat)tagViewMargin{ 63 | return [self zyht_setupRankTagsInView:contentView tagTexts:tagTexts tagHeight:tagHeight padding:padding tagViewMargin:tagViewMargin]; 64 | } 65 | 66 | 67 | 68 | //--------------------------------------------------------------------------------------------------- 69 | #pragma mark ================================== 绘制方法 ================================== 70 | //--------------------------------------------------------------------------------------------------- 71 | 72 | 73 | - (NSArray *)zyht_setupCommonTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts margin:(CGFloat)margin tagHeight:(CGFloat)tagHeight 74 | { 75 | 76 | self.contentView = contentView; 77 | self.tagLabelTitleArray = tagTexts; 78 | 79 | // [contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; 80 | 81 | for (int i = 0; i < tagTexts.count; i++) { 82 | UILabel *label = [self labelWithTitle:tagTexts[i]]; 83 | label.height = tagHeight; 84 | label.tag = i; //区分点击的重要标记 85 | [label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tagDidCLick:)]]; 86 | [contentView addSubview:label]; 87 | [self.tagLabelArray addObject:label]; 88 | } 89 | 90 | CGFloat currentX = 0; 91 | CGFloat currentY = 0; 92 | CGFloat countRow = 0; 93 | CGFloat countCol = 0; 94 | 95 | for (int i = 0; i < contentView.subviews.count; i++) { 96 | UILabel *subView = contentView.subviews[i]; 97 | // When the number of search words is too large, the width is width of the contentView 98 | if (subView.width > contentView.width) subView.width = contentView.width; 99 | if (currentX + subView.width + margin * countRow > contentView.width) { 100 | subView.x = 0; 101 | subView.y = (currentY += subView.height) + margin * ++countCol; 102 | currentX = subView.width; 103 | countRow = 1; 104 | } else { 105 | subView.x = (currentX += subView.width) - subView.width + margin * countRow; 106 | subView.y = currentY + margin * countCol; 107 | countRow ++; 108 | } 109 | } 110 | 111 | contentView.height = CGRectGetMaxY(contentView.subviews.lastObject.frame); 112 | 113 | return self.tagLabelArray; 114 | } 115 | 116 | 117 | -(void)setCommonTagStyle:(ZYHTCommonTagStyle)commonTagStyle{ 118 | 119 | _commonTagStyle = commonTagStyle; 120 | switch (commonTagStyle) { 121 | case ZYHTCommonTagStyleColorfulTag: 122 | for (UILabel *tag in self.tagLabelArray) { 123 | tag.textColor = [UIColor whiteColor]; 124 | tag.layer.borderColor = nil; 125 | tag.layer.borderWidth = 0.0; 126 | tag.backgroundColor = LLTagViewUtils_COLORPolRandomColor; 127 | } 128 | break; 129 | case ZYHTCommonTagStyleBorderTag: 130 | for (UILabel *tag in self.tagLabelArray) { 131 | tag.backgroundColor = [UIColor clearColor]; 132 | tag.layer.borderColor = LLTagViewUtils_COLOR(223, 223, 223).CGColor; 133 | tag.layer.borderWidth = 0.5; 134 | } 135 | break; 136 | case ZYHTCommonTagStyleARCBorderTag: 137 | for (UILabel *tag in self.tagLabelArray) { 138 | tag.backgroundColor = [UIColor clearColor]; 139 | tag.layer.borderColor = LLTagViewUtils_COLOR(223, 223, 223).CGColor; 140 | tag.layer.borderWidth = 0.5; 141 | tag.layer.cornerRadius = tag.height * 0.5; 142 | } 143 | break; 144 | case ZYHTCommonTagStyleNormalWhiteTag: 145 | for (UILabel *tag in self.tagLabelArray) { 146 | tag.backgroundColor = [UIColor whiteColor]; 147 | tag.textColor = LLTagViewUtils_COLOR(17, 17, 17); 148 | } 149 | break; 150 | // case PYHotSearchStyleRankTag: 151 | // self.rankTagBackgroundColorHexStrings = nil; 152 | // break; 153 | 154 | default: 155 | break; 156 | } 157 | } 158 | 159 | 160 | 161 | 162 | - (void)zyht_setupRectangleTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts maxColumnNum:(int)maxColumnNum tagHeight:(CGFloat)tagHeight 163 | { 164 | 165 | //设置tag标签 166 | CGFloat rectangleTagH = tagHeight; 167 | for (int i = 0; i < tagTexts.count; i++) { 168 | UILabel *rectangleTagLabel = [[UILabel alloc] init]; 169 | rectangleTagLabel.userInteractionEnabled = YES; 170 | rectangleTagLabel.font = [UIFont systemFontOfSize:14]; 171 | rectangleTagLabel.textColor = LLTagViewUtils_COLOR(18, 18, 18); 172 | // rectangleTagLabel.backgroundColor = [UIColor clearColor]; 173 | rectangleTagLabel.text = tagTexts[i]; 174 | rectangleTagLabel.width = contentView.width / maxColumnNum; 175 | rectangleTagLabel.height = rectangleTagH; 176 | rectangleTagLabel.textAlignment = NSTextAlignmentCenter; 177 | [rectangleTagLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tagDidCLick:)]]; 178 | rectangleTagLabel.x = rectangleTagLabel.width * (i % maxColumnNum); 179 | rectangleTagLabel.y = rectangleTagLabel.height * (i / maxColumnNum); 180 | rectangleTagLabel.tag = i; //区分点击的重要标记 181 | 182 | [contentView addSubview:rectangleTagLabel]; 183 | [self.tagLabelArray addObject:rectangleTagLabel]; 184 | } 185 | 186 | 187 | 188 | contentView.height = CGRectGetMaxY(contentView.subviews.lastObject.frame); 189 | 190 | //设置分割线 191 | int rowNumber = [self getRowNumberWithTotalCount:(int)tagTexts.count columnNumber:maxColumnNum]; 192 | CGFloat verticalLineHeight = rectangleTagH-10; 193 | CGFloat tbPadding = (rectangleTagH-verticalLineHeight)*0.5; 194 | for (int colIndex = 0; colIndex < maxColumnNum - 1; colIndex++) { 195 | 196 | for (int rowIndex = 0; rowIndex < rowNumber; rowIndex++) { 197 | UIImageView *verticalLine = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell-content-line-vertical"]]; 198 | verticalLine.height = verticalLineHeight; 199 | verticalLine.y = rectangleTagH*rowIndex + tbPadding; 200 | verticalLine.alpha = 0.7; 201 | verticalLine.x = contentView.width / maxColumnNum * (colIndex + 1); 202 | verticalLine.width = 0.5; 203 | [contentView addSubview:verticalLine]; 204 | } 205 | } 206 | 207 | for (int i = 0; i < ceil(((double)tagTexts.count / maxColumnNum)) - 1; i++) { 208 | UIImageView *verticalLine = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell-content-line"]]; 209 | verticalLine.height = 0.5; 210 | verticalLine.alpha = 0.7; 211 | verticalLine.y = rectangleTagH * (i + 1); 212 | verticalLine.width = contentView.width; 213 | [contentView addSubview:verticalLine]; 214 | } 215 | } 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | - (void)zyht_setupRankTagsInView:(UIView *)contentView tagTexts:(NSArray *)tagTexts tagHeight:(CGFloat)tagHeight padding:(CGFloat)padding tagViewMargin:(CGFloat)tagViewMargin 230 | { 231 | 232 | NSMutableArray *rankTextLabelsArr = [NSMutableArray array]; //文字数组 233 | NSMutableArray *rankTagIndexArr = [NSMutableArray array]; //序号数组 234 | NSMutableArray *rankViewArr = [NSMutableArray array]; 235 | for (int i = 0; i < tagTexts.count; i++) { 236 | UIView *rankView = [[UIView alloc] init]; 237 | rankView.height = tagHeight; 238 | rankView.width = (contentView.width-tagViewMargin) * 0.5; 239 | rankView.autoresizingMask = UIViewAutoresizingFlexibleWidth; 240 | [contentView addSubview:rankView]; 241 | 242 | // rank tag 243 | UILabel *rankIndexTag = [[UILabel alloc] init]; 244 | rankIndexTag.textAlignment = NSTextAlignmentCenter; 245 | rankIndexTag.font = [UIFont systemFontOfSize:10]; 246 | rankIndexTag.layer.cornerRadius = 3; 247 | rankIndexTag.clipsToBounds = YES; 248 | rankIndexTag.text = [NSString stringWithFormat:@"%d", i + 1]; 249 | [rankIndexTag sizeToFit]; 250 | rankIndexTag.width = rankIndexTag.height += padding * 0.5; 251 | rankIndexTag.y = (rankView.height - rankIndexTag.height) * 0.5; 252 | [rankView addSubview:rankIndexTag]; 253 | [rankTagIndexArr addObject:rankIndexTag]; 254 | 255 | // rank text 256 | UILabel *rankTextLabel = [[UILabel alloc] init]; 257 | rankTextLabel.text = tagTexts[i]; 258 | rankTextLabel.userInteractionEnabled = YES; 259 | [rankTextLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tagDidCLick:)]]; 260 | rankTextLabel.tag = i; 261 | rankTextLabel.textAlignment = NSTextAlignmentLeft; 262 | rankTextLabel.backgroundColor = [UIColor clearColor]; 263 | rankTextLabel.textColor = LLTagViewUtils_COLOR(113, 113, 113); 264 | rankTextLabel.font = [UIFont systemFontOfSize:14]; 265 | rankTextLabel.x = CGRectGetMaxX(rankIndexTag.frame) + padding; 266 | rankTextLabel.width = rankView.width - rankTextLabel.x; 267 | 268 | rankTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth; 269 | rankTextLabel.height = rankView.height; 270 | [rankTextLabelsArr addObject:rankTextLabel]; 271 | [rankView addSubview:rankTextLabel]; 272 | 273 | UIImageView *line = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"cell-content-line"]]; 274 | line.height = 0.5; 275 | line.alpha = 0.7; 276 | line.x = 0; 277 | line.y = rankView.height - 1; 278 | line.width = rankView.width; 279 | line.autoresizingMask = UIViewAutoresizingFlexibleWidth; 280 | 281 | [rankView addSubview:line];//分割线 282 | [rankViewArr addObject:rankView];// 283 | 284 | // set tag's background color and text color 285 | switch (i) { 286 | case 0: // NO.1 287 | rankIndexTag.backgroundColor = LLTagViewUtils_COLORPolRandomColor; 288 | rankIndexTag.textColor = [UIColor whiteColor]; 289 | break; 290 | case 1: // NO.2 291 | rankIndexTag.backgroundColor = LLTagViewUtils_COLORPolRandomColor; 292 | rankIndexTag.textColor = [UIColor whiteColor]; 293 | break; 294 | case 2: // NO.3 295 | rankIndexTag.backgroundColor = LLTagViewUtils_COLORPolRandomColor; 296 | rankIndexTag.textColor = [UIColor whiteColor]; 297 | break; 298 | default: // Other 299 | rankIndexTag.backgroundColor = LLTagViewUtils_COLOR(235, 235, 235); 300 | rankIndexTag.textColor = LLTagViewUtils_COLOR(18, 18, 18); 301 | break; 302 | } 303 | } 304 | 305 | 306 | self.rankTextLabels = [NSArray arrayWithArray:rankTextLabelsArr]; 307 | self.rankTagIndexs = [NSArray arrayWithArray:rankTagIndexArr]; 308 | self.rankViews = [NSArray arrayWithArray:rankViewArr]; 309 | 310 | for (int i = 0; i < rankViewArr.count; i++) { // default is two column 311 | UIView *rankView = rankViewArr[i]; 312 | rankView.x = (tagViewMargin + rankView.width) * (i % 2); 313 | rankView.y = rankView.height * (i / 2); 314 | } 315 | 316 | contentView.height = CGRectGetMaxY(rankViewArr.lastObject.frame); 317 | } 318 | 319 | 320 | //--------------------------------------------------------------------------------------------------- 321 | #pragma mark ================================== 私有方法 ================================== 322 | //--------------------------------------------------------------------------------------------------- 323 | - (NSMutableArray *)tagLabelArray 324 | { 325 | if (!_tagLabelArray) { 326 | _tagLabelArray = [[NSMutableArray alloc] init]; 327 | } 328 | return _tagLabelArray; 329 | } 330 | 331 | 332 | 333 | - (NSArray *)tagLabelTitleArray 334 | { 335 | if (!_tagLabelTitleArray) { 336 | _tagLabelTitleArray = [[NSArray alloc] init]; 337 | } 338 | return _tagLabelTitleArray; 339 | } 340 | 341 | - (int)getRowNumberWithTotalCount:(int)count columnNumber:(int)columnNumber { 342 | return count/columnNumber+(count%columnNumber==0?0:1); 343 | } 344 | 345 | - (void)tagDidCLick:(UITapGestureRecognizer *)tapGesture{ 346 | !_myOnCickBlock ? :_myOnCickBlock(tapGesture,(UILabel *)tapGesture.view); 347 | } 348 | 349 | - (UILabel *)labelWithTitle:(NSString *)title 350 | { 351 | UILabel *label = [[UILabel alloc] init]; 352 | label.userInteractionEnabled = YES; 353 | label.font = [UIFont systemFontOfSize:12]; 354 | label.text = title; 355 | label.textColor = [UIColor grayColor]; 356 | label.backgroundColor = LLTagViewUtils_COLOR(250, 250, 250); 357 | label.layer.cornerRadius = 3; 358 | label.clipsToBounds = YES; 359 | label.textAlignment = NSTextAlignmentCenter; 360 | [label sizeToFit]; 361 | label.width += 20; 362 | label.height += 14; 363 | return label; 364 | } 365 | 366 | 367 | 368 | @end 369 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/search_icon/clearImage@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/search_icon/clearImage@2x.png -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/search_icon/clearImage@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/search_icon/clearImage@3x.png -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/search_icon/search@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/search_icon/search@2x.png -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/search_icon/search@3x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/LLSearchViewController/LLSearchViewController/LLSearchViewControllerBase/search_icon/search@3x.png -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewController/Supporting Files/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // LLSearchViewController 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewControllerTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewControllerTests/LLSearchViewControllerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchViewControllerTests.m 3 | // LLSearchViewControllerTests 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LLSearchViewControllerTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation LLSearchViewControllerTests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | // Put setup code here. This method is called before the invocation of each test method in the class. 20 | } 21 | 22 | - (void)tearDown { 23 | // Put teardown code here. This method is called after the invocation of each test method in the class. 24 | [super tearDown]; 25 | } 26 | 27 | - (void)testExample { 28 | // This is an example of a functional test case. 29 | // Use XCTAssert and related functions to verify your tests produce the correct results. 30 | } 31 | 32 | - (void)testPerformanceExample { 33 | // This is an example of a performance test case. 34 | [self measureBlock:^{ 35 | // Put the code you want to measure the time of here. 36 | }]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewControllerUITests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /LLSearchViewController/LLSearchViewControllerUITests/LLSearchViewControllerUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // LLSearchViewControllerUITests.m 3 | // LLSearchViewControllerUITests 4 | // 5 | // Created by 李龙 on 2017/8/21. 6 | // Copyright © 2017年 李龙. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface LLSearchViewControllerUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation LLSearchViewControllerUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /MLeaksFinder/MLeakedObjectProxy.h: -------------------------------------------------------------------------------- 1 | // 2 | // MLeakedObjectProxy.h 3 | // MLeaksFinder 4 | // 5 | // Created by 佘泽坡 on 7/15/16. 6 | // Copyright © 2016 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface MLeakedObjectProxy : NSObject 12 | 13 | + (BOOL)isAnyObjectLeakedAtPtrs:(NSSet *)ptrs; 14 | + (void)addLeakedObject:(id)object; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /MLeaksFinder/MLeakedObjectProxy.m: -------------------------------------------------------------------------------- 1 | // 2 | // MLeakedObjectProxy.m 3 | // MLeaksFinder 4 | // 5 | // Created by 佘泽坡 on 7/15/16. 6 | // Copyright © 2016 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "MLeakedObjectProxy.h" 10 | #import "MLeaksFinder.h" 11 | #import "MLeaksMessenger.h" 12 | #import "NSObject+MemoryLeak.h" 13 | #import 14 | #import 15 | 16 | #if _INTERNAL_MLF_RC_ENABLED 17 | #import 18 | #endif 19 | 20 | static NSMutableSet *leakedObjectPtrs; 21 | 22 | @interface MLeakedObjectProxy () 23 | @property (nonatomic, weak) id object; 24 | @property (nonatomic, strong) NSNumber *objectPtr; 25 | @property (nonatomic, strong) NSArray *viewStack; 26 | @end 27 | 28 | @implementation MLeakedObjectProxy 29 | 30 | + (BOOL)isAnyObjectLeakedAtPtrs:(NSSet *)ptrs { 31 | NSAssert([NSThread isMainThread], @"Must be in main thread."); 32 | 33 | static dispatch_once_t onceToken; 34 | dispatch_once(&onceToken, ^{ 35 | leakedObjectPtrs = [[NSMutableSet alloc] init]; 36 | }); 37 | 38 | if (!ptrs.count) { 39 | return NO; 40 | } 41 | if ([leakedObjectPtrs intersectsSet:ptrs]) { 42 | return YES; 43 | } else { 44 | return NO; 45 | } 46 | } 47 | 48 | + (void)addLeakedObject:(id)object { 49 | NSAssert([NSThread isMainThread], @"Must be in main thread."); 50 | 51 | MLeakedObjectProxy *proxy = [[MLeakedObjectProxy alloc] init]; 52 | proxy.object = object; 53 | proxy.objectPtr = @((uintptr_t)object); 54 | proxy.viewStack = [object viewStack]; 55 | static const void *const kLeakedObjectProxyKey = &kLeakedObjectProxyKey; 56 | objc_setAssociatedObject(object, kLeakedObjectProxyKey, proxy, OBJC_ASSOCIATION_RETAIN); 57 | 58 | [leakedObjectPtrs addObject:proxy.objectPtr]; 59 | 60 | #if _INTERNAL_MLF_RC_ENABLED 61 | [MLeaksMessenger alertWithTitle:@"Memory Leak" 62 | message:[NSString stringWithFormat:@"%@", proxy.viewStack] 63 | delegate:proxy 64 | additionalButtonTitle:@"Retain Cycle"]; 65 | #else 66 | [MLeaksMessenger alertWithTitle:@"Memory Leak" 67 | message:[NSString stringWithFormat:@"%@", proxy.viewStack]]; 68 | #endif 69 | } 70 | 71 | - (void)dealloc { 72 | NSNumber *objectPtr = _objectPtr; 73 | NSArray *viewStack = _viewStack; 74 | dispatch_async(dispatch_get_main_queue(), ^{ 75 | [leakedObjectPtrs removeObject:objectPtr]; 76 | [MLeaksMessenger alertWithTitle:@"Object Deallocated" 77 | message:[NSString stringWithFormat:@"%@", viewStack]]; 78 | }); 79 | } 80 | 81 | #pragma mark - UIAlertViewDelegate 82 | 83 | - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex { 84 | if (!buttonIndex) { 85 | return; 86 | } 87 | 88 | id object = self.object; 89 | if (!object) { 90 | return; 91 | } 92 | 93 | #if _INTERNAL_MLF_RC_ENABLED 94 | dispatch_async(dispatch_get_global_queue(0, 0), ^{ 95 | FBRetainCycleDetector *detector = [FBRetainCycleDetector new]; 96 | [detector addCandidate:self.object]; 97 | NSSet *retainCycles = [detector findRetainCyclesWithMaxCycleLength:20]; 98 | 99 | BOOL hasFound = NO; 100 | for (NSArray *retainCycle in retainCycles) { 101 | NSInteger index = 0; 102 | for (FBObjectiveCGraphElement *element in retainCycle) { 103 | if (element.object == object) { 104 | NSArray *shiftedRetainCycle = [self shiftArray:retainCycle toIndex:index]; 105 | 106 | dispatch_async(dispatch_get_main_queue(), ^{ 107 | [MLeaksMessenger alertWithTitle:@"Retain Cycle" 108 | message:[NSString stringWithFormat:@"%@", shiftedRetainCycle]]; 109 | }); 110 | hasFound = YES; 111 | break; 112 | } 113 | 114 | ++index; 115 | } 116 | if (hasFound) { 117 | break; 118 | } 119 | } 120 | if (!hasFound) { 121 | dispatch_async(dispatch_get_main_queue(), ^{ 122 | [MLeaksMessenger alertWithTitle:@"Retain Cycle" 123 | message:@"Fail to find a retain cycle"]; 124 | }); 125 | } 126 | }); 127 | #endif 128 | } 129 | 130 | - (NSArray *)shiftArray:(NSArray *)array toIndex:(NSInteger)index { 131 | if (index == 0) { 132 | return array; 133 | } 134 | 135 | NSRange range = NSMakeRange(index, array.count - index); 136 | NSMutableArray *result = [[array subarrayWithRange:range] mutableCopy]; 137 | [result addObjectsFromArray:[array subarrayWithRange:NSMakeRange(0, index)]]; 138 | return result; 139 | } 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /MLeaksFinder/MLeaksFinder.h: -------------------------------------------------------------------------------- 1 | // 2 | // MLeaksFinder.h 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "NSObject+MemoryLeak.h" 10 | 11 | //#define MEMORY_LEAKS_FINDER_ENABLED 0 12 | 13 | #ifdef MEMORY_LEAKS_FINDER_ENABLED 14 | #define _INTERNAL_MLF_ENABLED MEMORY_LEAKS_FINDER_ENABLED 15 | #else 16 | #define _INTERNAL_MLF_ENABLED DEBUG 17 | #endif 18 | 19 | //#define MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED 1 20 | 21 | #ifdef MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED 22 | #define _INTERNAL_MLF_RC_ENABLED MEMORY_LEAKS_FINDER_RETAIN_CYCLE_ENABLED 23 | #elif COCOAPODS 24 | #define _INTERNAL_MLF_RC_ENABLED COCOAPODS 25 | #endif 26 | -------------------------------------------------------------------------------- /MLeaksFinder/MLeaksMessenger.h: -------------------------------------------------------------------------------- 1 | // 2 | // MLeaksMessenger.h 3 | // MLeaksFinder 4 | // 5 | // Created by 佘泽坡 on 7/17/16. 6 | // Copyright © 2016 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @interface MLeaksMessenger : NSObject 13 | 14 | + (void)alertWithTitle:(NSString *)title message:(NSString *)message; 15 | + (void)alertWithTitle:(NSString *)title 16 | message:(NSString *)message 17 | delegate:(id)delegate 18 | additionalButtonTitle:(NSString *)additionalButtonTitle; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /MLeaksFinder/MLeaksMessenger.m: -------------------------------------------------------------------------------- 1 | // 2 | // MLeaksMessenger.m 3 | // MLeaksFinder 4 | // 5 | // Created by 佘泽坡 on 7/17/16. 6 | // Copyright © 2016 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "MLeaksMessenger.h" 10 | 11 | static __weak UIAlertView *alertView; 12 | 13 | @implementation MLeaksMessenger 14 | 15 | + (void)alertWithTitle:(NSString *)title message:(NSString *)message { 16 | [self alertWithTitle:title message:message delegate:nil additionalButtonTitle:nil]; 17 | } 18 | 19 | + (void)alertWithTitle:(NSString *)title 20 | message:(NSString *)message 21 | delegate:(id)delegate 22 | additionalButtonTitle:(NSString *)additionalButtonTitle { 23 | [alertView dismissWithClickedButtonIndex:0 animated:NO]; 24 | UIAlertView *alertViewTemp = [[UIAlertView alloc] initWithTitle:title 25 | message:message 26 | delegate:delegate 27 | cancelButtonTitle:@"OK" 28 | otherButtonTitles:additionalButtonTitle, nil]; 29 | [alertViewTemp show]; 30 | alertView = alertViewTemp; 31 | 32 | NSLog(@"%@: %@", title, message); 33 | } 34 | 35 | @end 36 | -------------------------------------------------------------------------------- /MLeaksFinder/NSObject+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #define MLCheck(TARGET) [self willReleaseObject:(TARGET) relationship:@#TARGET]; 12 | 13 | @interface NSObject (MemoryLeak) 14 | 15 | - (BOOL)willDealloc; 16 | - (void)willReleaseObject:(id)object relationship:(NSString *)relationship; 17 | 18 | - (void)willReleaseChild:(id)child; 19 | - (void)willReleaseChildren:(NSArray *)children; 20 | 21 | - (NSArray *)viewStack; 22 | 23 | + (void)addClassNamesToWhitelist:(NSArray *)classNames; 24 | 25 | + (void)swizzleSEL:(SEL)originalSEL withSEL:(SEL)swizzledSEL; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /MLeaksFinder/NSObject+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSObject+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "NSObject+MemoryLeak.h" 10 | #import "MLeakedObjectProxy.h" 11 | #import "MLeaksFinder.h" 12 | #import 13 | #import 14 | 15 | #if _INTERNAL_MLF_RC_ENABLED 16 | #import 17 | #endif 18 | 19 | static const void *const kViewStackKey = &kViewStackKey; 20 | static const void *const kParentPtrsKey = &kParentPtrsKey; 21 | const void *const kLatestSenderKey = &kLatestSenderKey; 22 | 23 | @implementation NSObject (MemoryLeak) 24 | 25 | - (BOOL)willDealloc { 26 | NSString *className = NSStringFromClass([self class]); 27 | if ([[NSObject classNamesWhitelist] containsObject:className]) 28 | return NO; 29 | 30 | NSNumber *senderPtr = objc_getAssociatedObject([UIApplication sharedApplication], kLatestSenderKey); 31 | if ([senderPtr isEqualToNumber:@((uintptr_t)self)]) 32 | return NO; 33 | 34 | __weak id weakSelf = self; 35 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 36 | __strong id strongSelf = weakSelf; 37 | [strongSelf assertNotDealloc]; 38 | }); 39 | 40 | return YES; 41 | } 42 | 43 | - (void)assertNotDealloc { 44 | if ([MLeakedObjectProxy isAnyObjectLeakedAtPtrs:[self parentPtrs]]) { 45 | return; 46 | } 47 | [MLeakedObjectProxy addLeakedObject:self]; 48 | 49 | NSString *className = NSStringFromClass([self class]); 50 | NSLog(@"Possibly Memory Leak.\nIn case that %@ should not be dealloced, override -willDealloc in %@ by returning NO.\nView-ViewController stack: %@", className, className, [self viewStack]); 51 | } 52 | 53 | - (void)willReleaseObject:(id)object relationship:(NSString *)relationship { 54 | if ([relationship hasPrefix:@"self"]) { 55 | relationship = [relationship stringByReplacingCharactersInRange:NSMakeRange(0, 4) withString:@""]; 56 | } 57 | NSString *className = NSStringFromClass([object class]); 58 | className = [NSString stringWithFormat:@"%@(%@), ", relationship, className]; 59 | 60 | [object setViewStack:[[self viewStack] arrayByAddingObject:className]]; 61 | [object setParentPtrs:[[self parentPtrs] setByAddingObject:@((uintptr_t)object)]]; 62 | [object willDealloc]; 63 | } 64 | 65 | - (void)willReleaseChild:(id)child { 66 | if (!child) { 67 | return; 68 | } 69 | 70 | [self willReleaseChildren:@[ child ]]; 71 | } 72 | 73 | - (void)willReleaseChildren:(NSArray *)children { 74 | NSArray *viewStack = [self viewStack]; 75 | NSSet *parentPtrs = [self parentPtrs]; 76 | for (id child in children) { 77 | NSString *className = NSStringFromClass([child class]); 78 | [child setViewStack:[viewStack arrayByAddingObject:className]]; 79 | [child setParentPtrs:[parentPtrs setByAddingObject:@((uintptr_t)child)]]; 80 | [child willDealloc]; 81 | } 82 | } 83 | 84 | - (NSArray *)viewStack { 85 | NSArray *viewStack = objc_getAssociatedObject(self, kViewStackKey); 86 | if (viewStack) { 87 | return viewStack; 88 | } 89 | 90 | NSString *className = NSStringFromClass([self class]); 91 | return @[ className ]; 92 | } 93 | 94 | - (void)setViewStack:(NSArray *)viewStack { 95 | objc_setAssociatedObject(self, kViewStackKey, viewStack, OBJC_ASSOCIATION_RETAIN); 96 | } 97 | 98 | - (NSSet *)parentPtrs { 99 | NSSet *parentPtrs = objc_getAssociatedObject(self, kParentPtrsKey); 100 | if (!parentPtrs) { 101 | parentPtrs = [[NSSet alloc] initWithObjects:@((uintptr_t)self), nil]; 102 | } 103 | return parentPtrs; 104 | } 105 | 106 | - (void)setParentPtrs:(NSSet *)parentPtrs { 107 | objc_setAssociatedObject(self, kParentPtrsKey, parentPtrs, OBJC_ASSOCIATION_RETAIN); 108 | } 109 | 110 | + (void)swizzleSEL:(SEL)originalSEL withSEL:(SEL)swizzledSEL { 111 | #if _INTERNAL_MLF_ENABLED 112 | 113 | #if _INTERNAL_MLF_RC_ENABLED 114 | // Just find a place to set up FBRetainCycleDetector. 115 | static dispatch_once_t onceToken; 116 | dispatch_once(&onceToken, ^{ 117 | dispatch_async(dispatch_get_main_queue(), ^{ 118 | [FBAssociationManager hook]; 119 | }); 120 | }); 121 | #endif 122 | 123 | Class class = [self class]; 124 | 125 | Method originalMethod = class_getInstanceMethod(class, originalSEL); 126 | Method swizzledMethod = class_getInstanceMethod(class, swizzledSEL); 127 | 128 | BOOL didAddMethod = 129 | class_addMethod(class, 130 | originalSEL, 131 | method_getImplementation(swizzledMethod), 132 | method_getTypeEncoding(swizzledMethod)); 133 | 134 | if (didAddMethod) { 135 | class_replaceMethod(class, 136 | swizzledSEL, 137 | method_getImplementation(originalMethod), 138 | method_getTypeEncoding(originalMethod)); 139 | } else { 140 | method_exchangeImplementations(originalMethod, swizzledMethod); 141 | } 142 | #endif 143 | } 144 | 145 | + (NSMutableSet *)classNamesWhitelist 146 | { 147 | static NSMutableSet *whitelist = nil; 148 | 149 | if (!whitelist) { 150 | whitelist = [NSMutableSet setWithObjects: 151 | @"UIFieldEditor", // UIAlertControllerTextField 152 | @"UINavigationBar", 153 | @"_UIAlertControllerActionView", 154 | @"_UIVisualEffectBackdropView", 155 | nil]; 156 | 157 | // System's bug since iOS 10 and not fixed yet up to this ci. 158 | NSString *systemVersion = [UIDevice currentDevice].systemVersion; 159 | if ([systemVersion compare:@"10.0" options:NSNumericSearch] != NSOrderedAscending) { 160 | [whitelist addObject:@"UISwitch"]; 161 | } 162 | } 163 | 164 | return whitelist; 165 | } 166 | 167 | + (void)addClassNamesToWhitelist:(NSArray *)classNames 168 | { 169 | [[self classNamesWhitelist] addObjectsFromArray:classNames]; 170 | } 171 | 172 | @end 173 | -------------------------------------------------------------------------------- /MLeaksFinder/UIApplication+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIApplication+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by 佘泽坡 on 5/11/16. 6 | // Copyright © 2016 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MLeaksFinder.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @interface UIApplication (MemoryLeak) 15 | 16 | @end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /MLeaksFinder/UIApplication+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIApplication+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by 佘泽坡 on 5/11/16. 6 | // Copyright © 2016 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "UIApplication+MemoryLeak.h" 10 | #import "NSObject+MemoryLeak.h" 11 | #import 12 | 13 | #if _INTERNAL_MLF_ENABLED 14 | 15 | extern const void *const kLatestSenderKey; 16 | 17 | @implementation UIApplication (MemoryLeak) 18 | 19 | + (void)load { 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | [self swizzleSEL:@selector(sendAction:to:from:forEvent:) withSEL:@selector(swizzled_sendAction:to:from:forEvent:)]; 23 | }); 24 | } 25 | 26 | - (BOOL)swizzled_sendAction:(SEL)action to:(id)target from:(id)sender forEvent:(UIEvent *)event { 27 | objc_setAssociatedObject(self, kLatestSenderKey, @((uintptr_t)sender), OBJC_ASSOCIATION_RETAIN); 28 | 29 | return [self swizzled_sendAction:action to:target from:sender forEvent:event]; 30 | } 31 | 32 | @end 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /MLeaksFinder/UINavigationController+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationController+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MLeaksFinder.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @interface UINavigationController (MemoryLeak) 15 | 16 | @end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /MLeaksFinder/UINavigationController+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // UINavigationController+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "UINavigationController+MemoryLeak.h" 10 | #import "NSObject+MemoryLeak.h" 11 | #import 12 | 13 | #if _INTERNAL_MLF_ENABLED 14 | 15 | static const void *const kPoppedDetailVCKey = &kPoppedDetailVCKey; 16 | 17 | @implementation UINavigationController (MemoryLeak) 18 | 19 | + (void)load { 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | [self swizzleSEL:@selector(pushViewController:animated:) withSEL:@selector(swizzled_pushViewController:animated:)]; 23 | [self swizzleSEL:@selector(popViewControllerAnimated:) withSEL:@selector(swizzled_popViewControllerAnimated:)]; 24 | [self swizzleSEL:@selector(popToViewController:animated:) withSEL:@selector(swizzled_popToViewController:animated:)]; 25 | [self swizzleSEL:@selector(popToRootViewControllerAnimated:) withSEL:@selector(swizzled_popToRootViewControllerAnimated:)]; 26 | }); 27 | } 28 | 29 | - (void)swizzled_pushViewController:(UIViewController *)viewController animated:(BOOL)animated { 30 | if (self.splitViewController) { 31 | id detailViewController = objc_getAssociatedObject(self, kPoppedDetailVCKey); 32 | if ([detailViewController isKindOfClass:[UIViewController class]]) { 33 | [detailViewController willDealloc]; 34 | objc_setAssociatedObject(self, kPoppedDetailVCKey, nil, OBJC_ASSOCIATION_RETAIN); 35 | } 36 | } 37 | 38 | [self swizzled_pushViewController:viewController animated:animated]; 39 | } 40 | 41 | - (UIViewController *)swizzled_popViewControllerAnimated:(BOOL)animated { 42 | UIViewController *poppedViewController = [self swizzled_popViewControllerAnimated:animated]; 43 | 44 | if (!poppedViewController) { 45 | return nil; 46 | } 47 | 48 | // Detail VC in UISplitViewController is not dealloced until another detail VC is shown 49 | if (self.splitViewController && 50 | self.splitViewController.viewControllers.firstObject == self && 51 | self.splitViewController == poppedViewController.splitViewController) { 52 | objc_setAssociatedObject(self, kPoppedDetailVCKey, poppedViewController, OBJC_ASSOCIATION_RETAIN); 53 | return poppedViewController; 54 | } 55 | 56 | // VC is not dealloced until disappear when popped using a left-edge swipe gesture 57 | extern const void *const kHasBeenPoppedKey; 58 | objc_setAssociatedObject(poppedViewController, kHasBeenPoppedKey, @(YES), OBJC_ASSOCIATION_RETAIN); 59 | 60 | return poppedViewController; 61 | } 62 | 63 | - (NSArray *)swizzled_popToViewController:(UIViewController *)viewController animated:(BOOL)animated { 64 | NSArray *poppedViewControllers = [self swizzled_popToViewController:viewController animated:animated]; 65 | 66 | for (UIViewController *viewController in poppedViewControllers) { 67 | [viewController willDealloc]; 68 | } 69 | 70 | return poppedViewControllers; 71 | } 72 | 73 | - (NSArray *)swizzled_popToRootViewControllerAnimated:(BOOL)animated { 74 | NSArray *poppedViewControllers = [self swizzled_popToRootViewControllerAnimated:animated]; 75 | 76 | for (UIViewController *viewController in poppedViewControllers) { 77 | [viewController willDealloc]; 78 | } 79 | 80 | return poppedViewControllers; 81 | } 82 | 83 | - (BOOL)willDealloc { 84 | if (![super willDealloc]) { 85 | return NO; 86 | } 87 | 88 | [self willReleaseChildren:self.viewControllers]; 89 | 90 | return YES; 91 | } 92 | 93 | @end 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /MLeaksFinder/UIPageViewController+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIPageViewController+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MLeaksFinder.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @interface UIPageViewController (MemoryLeak) 15 | 16 | @end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /MLeaksFinder/UIPageViewController+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIPageViewController+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "UIPageViewController+MemoryLeak.h" 10 | #import "NSObject+MemoryLeak.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @implementation UIPageViewController (MemoryLeak) 15 | 16 | - (BOOL)willDealloc { 17 | if (![super willDealloc]) { 18 | return NO; 19 | } 20 | 21 | [self willReleaseChildren:self.viewControllers]; 22 | 23 | return YES; 24 | } 25 | 26 | @end 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /MLeaksFinder/UISplitViewController+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // UISplitViewController+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MLeaksFinder.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @interface UISplitViewController (MemoryLeak) 15 | 16 | @end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /MLeaksFinder/UISplitViewController+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // UISplitViewController+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "UISplitViewController+MemoryLeak.h" 10 | #import "NSObject+MemoryLeak.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @implementation UISplitViewController (MemoryLeak) 15 | 16 | - (BOOL)willDealloc { 17 | if (![super willDealloc]) { 18 | return NO; 19 | } 20 | 21 | [self willReleaseChildren:self.viewControllers]; 22 | 23 | return YES; 24 | } 25 | 26 | @end 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /MLeaksFinder/UITabBarController+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITabBarController+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MLeaksFinder.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @interface UITabBarController (MemoryLeak) 15 | 16 | @end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /MLeaksFinder/UITabBarController+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITabBarController+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "UITabBarController+MemoryLeak.h" 10 | #import "NSObject+MemoryLeak.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @implementation UITabBarController (MemoryLeak) 15 | 16 | - (BOOL)willDealloc { 17 | if (![super willDealloc]) { 18 | return NO; 19 | } 20 | 21 | [self willReleaseChildren:self.viewControllers]; 22 | 23 | return YES; 24 | } 25 | 26 | @end 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /MLeaksFinder/UITouch+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // UITouch+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by 佘泽坡 on 8/31/16. 6 | // Copyright © 2016 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MLeaksFinder.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @interface UITouch (MemoryLeak) 15 | 16 | @end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /MLeaksFinder/UITouch+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // UITouch+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by 佘泽坡 on 8/31/16. 6 | // Copyright © 2016 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "UITouch+MemoryLeak.h" 10 | #import 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | extern const void *const kLatestSenderKey; 15 | 16 | @implementation UITouch (MemoryLeak) 17 | 18 | + (void)load { 19 | static dispatch_once_t onceToken; 20 | dispatch_once(&onceToken, ^{ 21 | [self swizzleSEL:@selector(setView:) withSEL:@selector(swizzled_setView:)]; 22 | }); 23 | } 24 | 25 | - (void)swizzled_setView:(UIView *)view { 26 | [self swizzled_setView:view]; 27 | 28 | if (view) { 29 | objc_setAssociatedObject([UIApplication sharedApplication], 30 | kLatestSenderKey, 31 | @((uintptr_t)view), 32 | OBJC_ASSOCIATION_RETAIN); 33 | } 34 | } 35 | 36 | @end 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /MLeaksFinder/UIView+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MLeaksFinder.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @interface UIView (MemoryLeak) 15 | 16 | @end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /MLeaksFinder/UIView+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "UIView+MemoryLeak.h" 10 | #import "NSObject+MemoryLeak.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @implementation UIView (MemoryLeak) 15 | 16 | - (BOOL)willDealloc { 17 | if (![super willDealloc]) { 18 | return NO; 19 | } 20 | 21 | [self willReleaseChildren:self.subviews]; 22 | 23 | return YES; 24 | } 25 | 26 | @end 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /MLeaksFinder/UIViewController+MemoryLeak.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+MemoryLeak.h 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "MLeaksFinder.h" 11 | 12 | #if _INTERNAL_MLF_ENABLED 13 | 14 | @interface UIViewController (MemoryLeak) 15 | 16 | @end 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /MLeaksFinder/UIViewController+MemoryLeak.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+MemoryLeak.m 3 | // MLeaksFinder 4 | // 5 | // Created by zeposhe on 12/12/15. 6 | // Copyright © 2015 zeposhe. All rights reserved. 7 | // 8 | 9 | #import "UIViewController+MemoryLeak.h" 10 | #import "NSObject+MemoryLeak.h" 11 | #import 12 | 13 | #if _INTERNAL_MLF_ENABLED 14 | 15 | const void *const kHasBeenPoppedKey = &kHasBeenPoppedKey; 16 | 17 | @implementation UIViewController (MemoryLeak) 18 | 19 | + (void)load { 20 | static dispatch_once_t onceToken; 21 | dispatch_once(&onceToken, ^{ 22 | [self swizzleSEL:@selector(viewDidDisappear:) withSEL:@selector(swizzled_viewDidDisappear:)]; 23 | [self swizzleSEL:@selector(viewWillAppear:) withSEL:@selector(swizzled_viewWillAppear:)]; 24 | [self swizzleSEL:@selector(dismissViewControllerAnimated:completion:) withSEL:@selector(swizzled_dismissViewControllerAnimated:completion:)]; 25 | }); 26 | } 27 | 28 | - (void)swizzled_viewDidDisappear:(BOOL)animated { 29 | [self swizzled_viewDidDisappear:animated]; 30 | 31 | if ([objc_getAssociatedObject(self, kHasBeenPoppedKey) boolValue]) { 32 | [self willDealloc]; 33 | } 34 | } 35 | 36 | - (void)swizzled_viewWillAppear:(BOOL)animated { 37 | [self swizzled_viewWillAppear:animated]; 38 | 39 | objc_setAssociatedObject(self, kHasBeenPoppedKey, @(NO), OBJC_ASSOCIATION_RETAIN); 40 | } 41 | 42 | - (void)swizzled_dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion { 43 | [self swizzled_dismissViewControllerAnimated:flag completion:completion]; 44 | 45 | UIViewController *dismissedViewController = self.presentedViewController; 46 | if (!dismissedViewController && self.presentingViewController) { 47 | dismissedViewController = self; 48 | } 49 | 50 | if (!dismissedViewController) return; 51 | 52 | [dismissedViewController willDealloc]; 53 | } 54 | 55 | - (BOOL)willDealloc { 56 | if (![super willDealloc]) { 57 | return NO; 58 | } 59 | 60 | [self willReleaseChildren:self.childViewControllers]; 61 | [self willReleaseChild:self.presentedViewController]; 62 | 63 | if (self.isViewLoaded) { 64 | [self willReleaseChild:self.view]; 65 | } 66 | 67 | return YES; 68 | } 69 | 70 | @end 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 其实搜素界面的轮子很多,但是之所以再写,是因为发现市面上的很多框架,包括高分框架都是替我们制定了几种类型的搜素页面样式, 但是如果我们产品提出了另一种样式的要求,自定义页面很不方面. 基于能更方便的自定义搜索页面的目的, 写下这个轮子. 3 | 4 | ![LLSearchViewControllerBase结构说明](http://www.lilongcnc.cc/lauren_picture/20170822/0.gif) 5 | 6 | ### LLSearchViewControllerBase说明 7 | 8 | LLSearchViewControllerBase使用的是 `MVP` 模式.尾部有`Presenter`或者`P`的都是对应名称的业务逻辑主持人,可以理解为业务处理者. 把业务逻辑代码从`ViewController`中抽取出来,分配到每个 view模块对应的`Presenter`中. 在实际项目中,MVVM 太过于细化, 需要很多的桥接方法, 我并不是很喜欢, MVC 模式又很容易让新上手的人把`c`写的很臃肿, `MVP`模式是一种很折中的模式. 9 | 10 | 实现功能 11 | > - (1)自定义搜索页面View 12 | > - (2)历史搜索 13 | > - (3)分类标签 14 | > - (4)即时搜索结果匹配。 15 | 16 | 17 | ![LLSearchViewControllerBase结构说明](http://www.lilongcnc.cc/lauren_picture/20170822/1.png) 18 | 19 | 20 | 每个功能模块极其展示 view都尽可能的独立出来. 21 | 22 | ### 关于自定义搜索界面 23 | 24 | `ExtensionView`文件夹下边类,是搜索页面的[历史搜索模块,分类模块,即时匹配结果模块]的 view, `ExtensionPresenter`中是历史搜索页面的业务处理者. 而[历史搜索模块,分类模块]的业务处理者我则放到了`SSearchVC`目录下,这样做其实并不是特别好, 我这么做是为了 demo 的展现, 在实际项目中, 其实你可以完全放到`ExtensionPresenter`文件夹下. 25 | 26 | ![LLSearchViewControllerBase结构说明](http://www.lilongcnc.cc/lauren_picture/20170822/3.png) 27 | 28 | > - 我自定义了处理`历史搜索记录-LLNaviSearchHistorySaveBasePresenter`的基类和`搜索控制器-LLNaviSearchBaseVC`页面的基类,子类只需要继承这两个类就可以. 29 | > - `分类模块`和`即时匹配`模块没有基类,也不需要, 你如果不想要这两个功能,直接不实现其方法或者删掉相关代码即可. 30 | > - `LLSearchNaviBarView`是一个带有搜索框的模拟导航栏,你在任何地方都可以用它. 31 | 32 | 33 | 其中: 34 | 1. 历史搜索基类有保存,清理,获取保存记录方法. 子类继承之后,需要在实现下面代码(注意:指明存储文件名字) 35 | 36 | - (instancetype)init{ 37 | if (self = [super init]) { 38 | //code... 39 | self.saveUtils = [[LLSearchHistorySaveUtils alloc] initWithSearchHistoriesCacheFileName:NearByShopSearchMapAddressHistoryCacheFileName]; 40 | 41 | } 42 | return self; 43 | } 44 | 45 | 46 | 2. 控制器 ViewController需要在继承之后, 指定各模块的业务处理者是谁 47 | 48 | -(void)viewDidLoad { 49 | //告诉父类你的历史搜索prestenter是什么 50 | self.shopHistoryP = [HistoryAndCategorySearchHistroyViewP new]; 51 | //告诉父类你的分类prestenter是什么 52 | self.shopCategoryP = [HistoryAndCategorySearchCategoryViewP new]; 53 | [super viewDidLoad]; 54 | } 55 | 56 | 57 | 58 | 其他 59 | 60 | ### 进一步说明 61 | 62 | `历史搜索`和`分类`模块都是页面动态或者提前加载的, 为了显示动态还在的过程,我在`HistoryAndCategorySearchVC`这个搜索控制器调用的时候, 特意模拟网络数据延迟3s, 在实际操作中,为了保证体验,建议提前加载保存到本地最好, 我这里并没有针对分类提供本地持久化的方法. 63 | 64 | `即时结果匹配`这个功能, 只要实现下边这三个方法,即默认开启. 65 | 66 | /** 67 | 即时搜索匹配框,匹配的数据列表 68 | */ 69 | @property (nonatomic,strong) NSArray *resultListArray; 70 | /** 71 | 搜索框:用户即时输入完毕 72 | @param didChangeBlock 更改后的回调 73 | */ 74 | - (void)searchbarDidChange:(searchBarDidChangeBlock)didChangeBlock; 75 | 76 | /** 77 | 即时匹配结果列表cell点击事件 78 | */ 79 | - (void)resultListViewDidSelectedIndex:(resultListViewCellDidClickBlock)cellDidClickBlock; 80 | 81 | 82 | 83 | ### 内存泄露检测 84 | 85 | 因为我没有采用代理的方法,而是采用的bloc.开始第一版有些地方weakSelf并没有写全,导致了泄露问题,结合MLeaksFinder和Instruments进行了修复,但是使用MLeaksFinder 在 dealloc 方法已经执行了,还会报错内存泄露, 而Instruments 的 call tree 没有内容,有偶尔情况会全部报绿色对勾说没有泄露,不知道什么原因. 如果有朋友有好的检测内存泄露的方法,一定也告诉我下,我也学习下! 感谢提出内存泄露这个问题的朋友! 86 | 87 | 最后, 下面几个控制器调用的地方,提供了部分搜索页面接口展示: 88 | ![LLSearchViewControllerBase结构说明](http://www.lilongcnc.cc/lauren_picture/20170822/4.png) 89 | 90 | -------------------------------------------------------------------------------- /Screenshots/0.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/Screenshots/0.gif --------------------------------------------------------------------------------