├── .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 | 
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 | 
18 |
19 |
20 | 每个功能模块极其展示 view都尽可能的独立出来.
21 |
22 | ### 关于自定义搜索界面
23 |
24 | `ExtensionView`文件夹下边类,是搜索页面的[历史搜索模块,分类模块,即时匹配结果模块]的 view, `ExtensionPresenter`中是历史搜索页面的业务处理者. 而[历史搜索模块,分类模块]的业务处理者我则放到了`SSearchVC`目录下,这样做其实并不是特别好, 我这么做是为了 demo 的展现, 在实际项目中, 其实你可以完全放到`ExtensionPresenter`文件夹下.
25 |
26 | 
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 | 
89 |
90 |
--------------------------------------------------------------------------------
/Screenshots/0.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/lilongcnc/LLSearchViewController/9535a2c059eecf35abf9f58aa5a930cad9374131/Screenshots/0.gif
--------------------------------------------------------------------------------