The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .github
    ├── CODEOWNERS
    ├── ISSUE_TEMPLATE.md
    └── PULL_REQUEST_TEMPLATE.md
├── .gitignore
├── .travis.yml
├── LICENCE
├── PYSearch.podspec
├── PYSearch
    ├── NSBundle+PYSearchExtension.h
    ├── NSBundle+PYSearchExtension.m
    ├── PYSearch.bundle
    │   ├── back@2x.png
    │   ├── back@3x.png
    │   ├── cell-content-line-vertical@2x.png
    │   ├── cell-content-line-vertical@3x.png
    │   ├── cell-content-line@2x.png
    │   ├── cell-content-line@3x.png
    │   ├── clearImage@2x.png
    │   ├── clearImage@3x.png
    │   ├── close@2x.png
    │   ├── close@3x.png
    │   ├── empty@2x.png
    │   ├── empty@3x.png
    │   ├── en.lproj
    │   │   └── Localizable.strings
    │   ├── es.lproj
    │   │   └── Localizable.strings
    │   ├── fr.lproj
    │   │   └── Localizable.strings
    │   ├── search@2x.png
    │   ├── search@3x.png
    │   ├── search_history@2x.png
    │   ├── search_history@3x.png
    │   ├── zh-Hans.lproj
    │   │   └── Localizable.strings
    │   └── zh-Hant.lproj
    │   │   └── Localizable.strings
    ├── PYSearch.h
    ├── PYSearchConst.h
    ├── PYSearchConst.m
    ├── PYSearchSuggestionViewController.h
    ├── PYSearchSuggestionViewController.m
    ├── PYSearchViewController.h
    ├── PYSearchViewController.m
    ├── UIColor+PYSearchExtension.h
    ├── UIColor+PYSearchExtension.m
    ├── UIView+PYSearchExtension.h
    └── UIView+PYSearchExtension.m
├── PYSearchExample
    ├── PYSearchExample.xcodeproj
    │   ├── project.pbxproj
    │   ├── project.xcworkspace
    │   │   ├── contents.xcworkspacedata
    │   │   ├── xcshareddata
    │   │   │   └── IDEWorkspaceChecks.plist
    │   │   └── xcuserdata
    │   │   │   └── iphone5solo.xcuserdatad
    │   │   │       └── UserInterfaceState.xcuserstate
    │   └── xcuserdata
    │   │   └── iphone5solo.xcuserdatad
    │   │       ├── xcdebugger
    │   │           └── Breakpoints_v2.xcbkptlist
    │   │       └── xcschemes
    │   │           ├── PYSearchExample.xcscheme
    │   │           └── xcschememanagement.plist
    ├── PYSearchExample
    │   ├── AppDelegate.h
    │   ├── AppDelegate.m
    │   ├── Assets.xcassets
    │   │   └── AppIcon.appiconset
    │   │   │   └── Contents.json
    │   ├── Base.lproj
    │   │   └── LaunchScreen.storyboard
    │   ├── Info.plist
    │   ├── PYSearchExampleController.h
    │   ├── PYSearchExampleController.m
    │   ├── PYTempViewController.h
    │   ├── PYTempViewController.m
    │   ├── en.lproj
    │   │   └── Localizable.strings
    │   ├── es.lproj
    │   │   ├── LaunchScreen.strings
    │   │   └── Localizable.strings
    │   ├── fr.lproj
    │   │   ├── LaunchScreen.strings
    │   │   └── Localizable.strings
    │   ├── main.m
    │   ├── zh-Hans.lproj
    │   │   ├── LaunchScreen.strings
    │   │   └── Localizable.strings
    │   └── zh-Hant.lproj
    │   │   ├── LaunchScreen.strings
    │   │   └── Localizable.strings
    ├── PYSearchExampleTests
    │   ├── Info.plist
    │   └── PYSearchExampleTests.m
    └── PYSearchExampleUITests
    │   ├── Info.plist
    │   └── PYSearchExampleUITests.m
└── README.md


/.github/CODEOWNERS:
--------------------------------------------------------------------------------
1 | # Code owners for PYSearch
2 | * @ko1o
3 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
 1 | <!-- 
 2 | 您并不需要严格按照此模版提 ISSUE,只是为了方便提供相关信息,并不是为了设置障碍。
 3 | 如果你觉得麻烦,也可以直接按照自己的方式来提 ISSUE。
 4 | 这里非常希望您尽量多提供一些相关信息。
 5 | -->
 6 | ### 问题描述
 7 | <!--
 8 | 示例:
 9 | 搜索类型设置为 `PYHotSearchStyleRankTag` 或者 `PYHotSearchStyleRectangleTag`, 
10 | 并在代理类中实现对应代理方法,点击热门搜索时无法执行代理方法。
11 | -->
12 | #### 重现步骤
13 | <!--
14 | 示例:
15 | 1、搜索类型设置为 `PYHotSearchStyleRankTag` 或者 `PYHotSearchStyleRectangleTag`
16 | 2、在代理类中实现如下代理方法:
17 | ```objective-c
18 | - (void)searchViewController:(PYSearchViewController *)searchViewController
19 |    didSelectHotSearchAtIndex:(NSInteger)index
20 |                   searchText:(NSString *)searchText
21 | {
22 |     NSLog(@"代理方法被调用");
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 | 请在列出受影响的设备,并添加对应 iOS 版本。
48 | 这里仅需要列出您测试过的设备,并不需要去测试所有的设备。
49 | 例如:
50 | - iPhone 8 (11.0.3)
51 | - iPhone 8 Plus (11.0.3, 12.0.1)
52 | -->
53 | 
54 | 
55 | 
56 | ### 版本信息
57 | <!-- 
58 | 这里除了PYSearch 版本都不是必须的,如果能提供最好,不能提供也没关系
59 | CocoaPods 版本:`pod  --version`
60 | Xcode 版本:菜单栏选择 Xcode 下的 About Xcode 或 执行 `xcodebuild -version`
61 | macOS 版本:从屏幕角落的苹果 () 菜单中选取 “关于本机” 
62 | -->
63 | 
64 | - PYSearch:vX.X.X
65 | - Xcode:vX.X.X
66 | - macOS:vX.X.X
67 | - CocoaPods:vX.X.X
68 | 
69 | 


--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | ### Reference Issue
2 | <!-- Example: Fixes #1234 -->
3 | 


--------------------------------------------------------------------------------
/.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 | *.xcuserstate
23 | 
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 | 
30 | # CocoaPods
31 | #
32 | # We recommend against adding the Pods directory to your .gitignore. However
33 | # you should judge for yourself, the pros and cons are mentioned at:
34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
35 | #
36 | # Pods/
37 | 
38 | # Carthage
39 | #
40 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
41 | # Carthage/Checkouts
42 | 
43 | Carthage/Build
44 | 
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
51 | 
52 | fastlane/report.xml
53 | fastlane/screenshots
54 | 
55 | #Code Injection
56 | #
57 | # After new code Injection tools there's a generated folder /iOSInjectionProject
58 | # https://github.com/johnno1962/injectionforxcode
59 | 
60 | iOSInjectionProject/
61 | .DS_Store
62 | 


--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | osx_image: xcode8
2 | language: objective-c
3 | xcode_workspace: PYSearchExample/PYSearchExample.xcodeproj
4 | xcode_schemes: PYSearchExample
5 | 


--------------------------------------------------------------------------------
/LICENCE:
--------------------------------------------------------------------------------
 1 | The MIT License (MIT)
 2 | 
 3 | Copyright (c) 2016 CoderKo1o
 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 | 


--------------------------------------------------------------------------------
/PYSearch.podspec:
--------------------------------------------------------------------------------
 1 | Pod::Spec.new do |s|
 2 |     s.name         = 'PYSearch'
 3 |     s.version      = '0.9.1'
 4 |     s.summary      = 'An elegant search controller which replaces the UISearchController for iOS.'
 5 |     s.homepage     = 'https://github.com/ko1o/PYSearch'
 6 |     s.license      = 'MIT'
 7 |     s.authors      = {'CoderKo1o' => '499491531@qq.com'}
 8 |     s.platform     = :ios, '7.0'
 9 |     s.source       = {:git => 'https://github.com/ko1o/PYSearch.git', :tag => s.version}
10 |     s.source_files = 'PYSearch/**/*.{h,m}'
11 |     s.resource     = 'PYSearch/PYSearch.bundle'
12 |     s.requires_arc = true
13 | end
14 | 
15 | 
16 | 


--------------------------------------------------------------------------------
/PYSearch/NSBundle+PYSearchExtension.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import <Foundation/Foundation.h>
 8 | #import <UIKit/UIKit.h>
 9 | 
10 | @interface NSBundle (PYSearchExtension)
11 | 
12 | /**
13 |  Get the localized string
14 | 
15 |  @param key     key for localized string
16 |  @return a localized string
17 |  */
18 | + (NSString *)py_localizedStringForKey:(NSString *)key;
19 | 
20 | /**
21 |  Get the path of `PYSearch.bundle`.
22 | 
23 |  @return path of the `PYSearch.bundle`
24 |  */
25 | + (NSBundle *)py_searchBundle;
26 | 
27 | /**
28 |  Get the image in the `PYSearch.bundle` path
29 | 
30 |  @param name name of image
31 |  @return a image
32 |  */
33 | + (UIImage *)py_imageNamed:(NSString *)name;
34 | 
35 | @end
36 | 


--------------------------------------------------------------------------------
/PYSearch/NSBundle+PYSearchExtension.m:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import "NSBundle+PYSearchExtension.h"
 8 | #import "PYSearchViewController.h"
 9 | 
10 | @implementation NSBundle (PYSearchExtension)
11 | 
12 | + (NSBundle *)py_searchBundle
13 | {
14 |     static NSBundle *searchBundle = nil;
15 |     if (nil == searchBundle) {
16 |         //Default use `[NSBundle mainBundle]`.
17 |         searchBundle = [NSBundle bundleWithPath:[[NSBundle mainBundle] pathForResource:@"PYSearch" ofType:@"bundle"]];
18 |         /**
19 |          If you use pod import and configure `use_frameworks` in Podfile, [NSBundle mainBundle] does not load the `PYSearch.fundle` resource file in `PYSearch.framework`. 
20 |          */
21 |         if (nil == searchBundle) { // Empty description resource file in `PYSearch.framework`.
22 |             searchBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[PYSearchViewController class]] pathForResource:@"PYSearch" ofType:@"bundle"]];
23 |         }
24 |     }
25 |     return searchBundle;
26 | }
27 | 
28 | + (NSString *)py_localizedStringForKey:(NSString *)key;
29 | {
30 |     return [self py_localizedStringForKey:key value:nil];
31 | }
32 | 
33 | + (NSString *)py_localizedStringForKey:(NSString *)key value:(NSString *)value
34 | {
35 |     static NSBundle *bundle = nil;
36 |     if (nil == bundle) {
37 |         NSString *language = [NSLocale preferredLanguages].firstObject;
38 |         if ([language hasPrefix:@"en"]) language = @"en";
39 |         else if ([language hasPrefix:@"es"]) language = @"es";
40 |         else if ([language hasPrefix:@"fr"]) language = @"fr";
41 |         else if ([language hasPrefix:@"zh"]) {
42 |             if ([language rangeOfString:@"Hans"].location != NSNotFound) {
43 |                 language = @"zh-Hans";
44 |             } else {
45 |                 language = @"zh-Hant";
46 |             }
47 |         } else {
48 |             language = @"en";
49 |         }
50 |         
51 |         // Find resources from `PYSearch.bundle`
52 |         bundle = [NSBundle bundleWithPath:[[NSBundle py_searchBundle] pathForResource:language ofType:@"lproj"]];
53 |     }
54 |     value = [bundle localizedStringForKey:key value:value table:nil];
55 |     return [[NSBundle mainBundle] localizedStringForKey:key value:value table:nil];
56 | }
57 |     
58 | + (UIImage *)py_imageNamed:(NSString *)name
59 | {
60 |     CGFloat scale = [[UIScreen mainScreen] scale];
61 |     name = 3.0 == scale ? [NSString stringWithFormat:@"%@@3x.png", name] : [NSString stringWithFormat:@"%@@2x.png", name];
62 |     UIImage *image = [UIImage imageWithContentsOfFile:[[[NSBundle py_searchBundle] resourcePath] stringByAppendingPathComponent:name]];
63 |     return image;
64 | }
65 | 
66 | @end
67 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/back@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/back@2x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/back@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/back@3x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/cell-content-line-vertical@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/cell-content-line-vertical@2x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/cell-content-line-vertical@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/cell-content-line-vertical@3x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/cell-content-line@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/cell-content-line@2x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/cell-content-line@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/cell-content-line@3x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/clearImage@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/clearImage@2x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/clearImage@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/clearImage@3x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/close@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/close@2x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/close@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/close@3x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/empty@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/empty@2x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/empty@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/empty@3x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | "PYSearchSearchPlaceholderText" = "Search content";
 2 | "PYSearchHotSearchText" = "Popular searches";
 3 | "PYSearchSearchHistoryText" = "Search history";
 4 | "PYSearchEmptySearchHistoryText" = "Clear the search history";
 5 | 
 6 | "PYSearchEmptyButtonText" = "Clear";
 7 | "PYSearchEmptySearchHistoryLogText" = "Clear the search history";
 8 | "PYSearchCancelButtonText" = "Cancel";
 9 | "PYSearchBackButtonText" = "Back";
10 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/es.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | "PYSearchSearchPlaceholderText" = "Buscar contenido";
 2 | "PYSearchHotSearchText" = "Búsquedas populares";
 3 | "PYSearchSearchHistoryText" = "Buscar Historia";
 4 | "PYSearchEmptySearchHistoryText" = "Borrar el historial de búsqueda";
 5 | 
 6 | "PYSearchEmptyButtonText" = "Borrar";
 7 | "PYSearchEmptySearchHistoryLogText" = "Borrar el historial de búsqueda";
 8 | "PYSearchCancelButtonText" = "Cancelar";
 9 | "PYSearchBackButtonText" = "Volver a";
10 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/fr.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | "PYSearchSearchPlaceholderText" = "Recherche de contenu";
 2 | "PYSearchHotSearchText" = "Recherches populaires";
 3 | "PYSearchSearchHistoryText" = "Historique des recherches";
 4 | "PYSearchEmptySearchHistoryText" = "Effacer l'historique des recherches";
 5 | 
 6 | "PYSearchEmptyButtonText" = "Effacer";
 7 | "PYSearchEmptySearchHistoryLogText" = "Effacer l'historique des recherches";
 8 | "PYSearchCancelButtonText" = "Annuler";
 9 | "PYSearchBackButtonText" = "Retour à";
10 | 
11 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/search@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/search@2x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/search@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/search@3x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/search_history@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/search_history@2x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/search_history@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/search_history@3x.png


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearch/PYSearch.bundle/zh-Hans.lproj/Localizable.strings


--------------------------------------------------------------------------------
/PYSearch/PYSearch.bundle/zh-Hant.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | "PYSearchSearchPlaceholderText" = "搜索內容";
 2 | "PYSearchHotSearchText" = "熱門搜索";
 3 | "PYSearchSearchHistoryText" = "搜索歷史";
 4 | "PYSearchEmptySearchHistoryText" = "清空搜索歷史";
 5 | 
 6 | "PYSearchEmptyButtonText" = "清空";
 7 | "PYSearchEmptySearchHistoryLogText" = "清空搜索歷史";
 8 | "PYSearchCancelButtonText" = "取消";
 9 | "PYSearchBackButtonText" = "返回";
10 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearch.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  代码地址: https://github.com/iphone5solo/PYSearch
 3 | //  代码地址: http://www.code4app.com/thread-11175-1-1.html
 4 | //  Created by CoderKo1o.
 5 | //  Copyright © 2016年 iphone5solo. All rights reserved.
 6 | //
 7 | 
 8 | #import <Foundation/Foundation.h>
 9 | 
10 | #import "PYSearchViewController.h"
11 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearchConst.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import <UIKit/UIKit.h>
 8 | #import "UIView+PYSearchExtension.h"
 9 | #import "UIColor+PYSearchExtension.h"
10 | #import "NSBundle+PYSearchExtension.h"
11 | 
12 | #define PYSEARCH_MARGIN 10
13 | #define PYSEARCH_BACKGROUND_COLOR PYSEARCH_COLOR(255, 255, 255)
14 | 
15 | #ifdef DEBUG
16 | #define PYSEARCH_LOG(...) NSLog(__VA_ARGS__)
17 | #else
18 | #define PYSEARCH_LOG(...)
19 | #endif
20 | 
21 | #define PYSEARCH_COLOR(r,g,b) [UIColor colorWithRed:(r/255.0) green:(g/255.0) blue:(b/255.0) alpha:1.0]
22 | #define PYSEARCH_RANDOM_COLOR  PYSEARCH_COLOR(arc4random_uniform(256),arc4random_uniform(256),arc4random_uniform(256))
23 | 
24 | #define PYSEARCH_DEPRECATED(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
25 | 
26 | #define PYSEARCH_REALY_SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
27 | #define PYSEARCH_REALY_SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
28 | #define PYScreenW (PYSEARCH_REALY_SCREEN_WIDTH < PYSEARCH_REALY_SCREEN_HEIGHT ? PYSEARCH_REALY_SCREEN_WIDTH : PYSEARCH_REALY_SCREEN_HEIGHT)
29 | #define PYScreenH (PYSEARCH_REALY_SCREEN_WIDTH > PYSEARCH_REALY_SCREEN_HEIGHT ? PYSEARCH_REALY_SCREEN_WIDTH : PYSEARCH_REALY_SCREEN_HEIGHT)
30 | #define PYSEARCH_SCREEN_SIZE CGSizeMake(PYScreenW, PYScreenH)
31 | 
32 | #define PYSEARCH_SEARCH_HISTORY_CACHE_PATH [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:@"PYSearchhistories.plist"] // the path of search record cached
33 | 
34 | UIKIT_EXTERN NSString *const PYSearchSearchPlaceholderText;
35 | UIKIT_EXTERN NSString *const PYSearchHotSearchText;
36 | UIKIT_EXTERN NSString *const PYSearchSearchHistoryText;
37 | UIKIT_EXTERN NSString *const PYSearchEmptySearchHistoryText;
38 | UIKIT_EXTERN NSString *const PYSearchEmptyButtonText;
39 | UIKIT_EXTERN NSString *const PYSearchEmptySearchHistoryLogText;
40 | UIKIT_EXTERN NSString *const PYSearchCancelButtonText;
41 | UIKIT_EXTERN NSString *const PYSearchBackButtonText;
42 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearchConst.m:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import <UIKit/UIKit.h>
 8 | 
 9 | NSString *const PYSearchSearchPlaceholderText = @"PYSearchSearchPlaceholderText";
10 | NSString *const PYSearchHotSearchText = @"PYSearchHotSearchText";
11 | NSString *const PYSearchSearchHistoryText = @"PYSearchSearchHistoryText";
12 | NSString *const PYSearchEmptySearchHistoryText = @"PYSearchEmptySearchHistoryText";
13 | 
14 | NSString *const PYSearchEmptyButtonText = @"PYSearchEmptyButtonText";
15 | NSString *const PYSearchEmptySearchHistoryLogText = @"PYSearchEmptySearchHistoryLogText";
16 | NSString *const PYSearchCancelButtonText = @"PYSearchCancelButtonText";
17 | NSString *const PYSearchBackButtonText = @"PYSearchBackButtonText";
18 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearchSuggestionViewController.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import <UIKit/UIKit.h>
 8 | 
 9 | typedef void(^PYSearchSuggestionDidSelectCellBlock)(UITableViewCell *selectedCell);
10 | 
11 | @protocol PYSearchSuggestionViewDataSource <NSObject, UITableViewDataSource>
12 | 
13 | @required
14 | - (UITableViewCell *)searchSuggestionView:(UITableView *)searchSuggestionView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
15 | - (NSInteger)searchSuggestionView:(UITableView *)searchSuggestionView numberOfRowsInSection:(NSInteger)section;
16 | @optional
17 | - (NSInteger)numberOfSectionsInSearchSuggestionView:(UITableView *)searchSuggestionView;
18 | - (CGFloat)searchSuggestionView:(UITableView *)searchSuggestionView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
19 | 
20 | @end
21 | 
22 | @interface PYSearchSuggestionViewController : UITableViewController
23 | 
24 | @property (nonatomic, weak) id<PYSearchSuggestionViewDataSource> dataSource;
25 | @property (nonatomic, copy) NSArray<NSString *> *searchSuggestions;
26 | @property (nonatomic, copy) PYSearchSuggestionDidSelectCellBlock didSelectCellBlock;
27 | 
28 | + (instancetype)searchSuggestionViewControllerWithDidSelectCellBlock:(PYSearchSuggestionDidSelectCellBlock)didSelectCellBlock;
29 | 
30 | @end
31 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearchSuggestionViewController.m:
--------------------------------------------------------------------------------
  1 | //
  2 | //  GitHub: https://github.com/iphone5solo/PYSearch
  3 | //  Created by CoderKo1o.
  4 | //  Copyright © 2016 iphone5solo. All rights reserved.
  5 | //
  6 | 
  7 | #import "PYSearchSuggestionViewController.h"
  8 | #import "PYSearchConst.h"
  9 | 
 10 | @interface PYSearchSuggestionViewController ()
 11 | 
 12 | @property (nonatomic, assign) UIEdgeInsets originalContentInsetWhenKeyboardShow;
 13 | @property (nonatomic, assign) UIEdgeInsets originalContentInsetWhenKeyboardHidden;
 14 | 
 15 | @property (nonatomic, assign) BOOL keyboardDidShow;
 16 | 
 17 | @end
 18 | 
 19 | @implementation PYSearchSuggestionViewController
 20 | 
 21 | + (instancetype)searchSuggestionViewControllerWithDidSelectCellBlock:(PYSearchSuggestionDidSelectCellBlock)didSelectCellBlock
 22 | {
 23 |     PYSearchSuggestionViewController *searchSuggestionVC = [[self alloc] init];
 24 |     searchSuggestionVC.didSelectCellBlock = didSelectCellBlock;
 25 |     searchSuggestionVC.automaticallyAdjustsScrollViewInsets = NO;
 26 |     return searchSuggestionVC;
 27 | }
 28 | 
 29 | - (void)viewDidLoad {
 30 |     [super viewDidLoad];
 31 |     
 32 |     self.tableView.separatorStyle = UITableViewCellSeparatorStyleNone;
 33 |     if ([self.tableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)]) { // For the adapter iPad
 34 |         self.tableView.cellLayoutMarginsFollowReadableWidth = NO;
 35 |     }
 36 |     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboradFrameDidShow:) name:UIKeyboardDidShowNotification object:nil];
 37 |     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboradFrameDidHidden:) name:UIKeyboardDidHideNotification object:nil];
 38 | }
 39 | 
 40 | - (void)dealloc
 41 | {
 42 |     [[NSNotificationCenter defaultCenter] removeObserver:self];
 43 | }
 44 | 
 45 | - (void)viewWillDisappear:(BOOL)animated
 46 | {
 47 |     [super viewWillDisappear:animated];
 48 |     
 49 |     if (self.keyboardDidShow) {
 50 |         self.originalContentInsetWhenKeyboardShow = self.tableView.contentInset;
 51 |     } else {
 52 |         self.originalContentInsetWhenKeyboardHidden = self.tableView.contentInset;
 53 |     }
 54 | }
 55 | 
 56 | - (void)keyboradFrameDidShow:(NSNotification *)notification
 57 | {
 58 |     self.keyboardDidShow = YES;
 59 |     [self setSearchSuggestions:_searchSuggestions];
 60 | }
 61 | 
 62 | - (void)keyboradFrameDidHidden:(NSNotification *)notification
 63 | {
 64 |     self.keyboardDidShow = NO;
 65 |     self.originalContentInsetWhenKeyboardHidden = UIEdgeInsetsMake(-30, 0, 30, 0);
 66 |     [self setSearchSuggestions:_searchSuggestions];
 67 | }
 68 | 
 69 | #pragma mark - setter
 70 | - (void)setSearchSuggestions:(NSArray<NSString *> *)searchSuggestions
 71 | {
 72 |     _searchSuggestions = [searchSuggestions copy];
 73 |     
 74 |     [self.tableView reloadData];
 75 |     
 76 |     /**
 77 |      * Adjust the searchSugesstionView when the keyboard changes.
 78 |      * more information can see : https://github.com/iphone5solo/PYSearch/issues/61
 79 |      */
 80 |     if (self.keyboardDidShow && !UIEdgeInsetsEqualToEdgeInsets(self.originalContentInsetWhenKeyboardShow, UIEdgeInsetsZero) && !UIEdgeInsetsEqualToEdgeInsets(self.originalContentInsetWhenKeyboardShow, UIEdgeInsetsMake(-30, 0, 30 - CGRectGetMaxY(self.navigationController.navigationBar.frame), 0))) {
 81 |         self.tableView.contentInset =  self.originalContentInsetWhenKeyboardShow;
 82 |     } else if (!self.keyboardDidShow && !UIEdgeInsetsEqualToEdgeInsets(self.originalContentInsetWhenKeyboardHidden, UIEdgeInsetsZero) && !UIEdgeInsetsEqualToEdgeInsets(self.originalContentInsetWhenKeyboardHidden, UIEdgeInsetsMake(-30, 0, 30 - CGRectGetMaxY(self.navigationController.navigationBar.frame), 0))) {
 83 |         self.tableView.contentInset =  self.originalContentInsetWhenKeyboardHidden;
 84 |     }
 85 |     self.tableView.contentOffset = CGPointMake(0, -self.tableView.contentInset.top);
 86 |     
 87 |     if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11.0) { // iOS 11
 88 |         self.tableView.contentInset = UIEdgeInsetsMake(-30, 0, 0, 0);
 89 |     }
 90 | }
 91 | 
 92 | #pragma mark - Table view data source
 93 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
 94 |     if ([self.dataSource respondsToSelector:@selector(numberOfSectionsInSearchSuggestionView:)]) {
 95 |         return [self.dataSource numberOfSectionsInSearchSuggestionView:tableView];
 96 |     }
 97 |     return 1;
 98 | }
 99 | 
100 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
101 |     if ([self.dataSource respondsToSelector:@selector(searchSuggestionView:numberOfRowsInSection:)]) {
102 |         return [self.dataSource searchSuggestionView:tableView numberOfRowsInSection:section];
103 |     }
104 |     return self.searchSuggestions.count;
105 | }
106 | 
107 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
108 |     if ([self.dataSource respondsToSelector:@selector(searchSuggestionView:cellForRowAtIndexPath:)]) {
109 |         UITableViewCell *cell= [self.dataSource searchSuggestionView:tableView cellForRowAtIndexPath:indexPath];
110 |         if (cell) return cell;
111 |     }
112 | 
113 |     static NSString *cellID = @"PYSearchSuggestionCellID";
114 |     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
115 |     if (!cell) {
116 |         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
117 |         cell.textLabel.textColor = [UIColor darkGrayColor];
118 |         cell.textLabel.font = [UIFont systemFontOfSize:14];
119 |         cell.backgroundColor = [UIColor clearColor];
120 |         UIImageView *line = [[UIImageView alloc] initWithImage: [NSBundle py_imageNamed:@"cell-content-line"]];
121 |         line.py_height = 0.5;
122 |         line.alpha = 0.7;
123 |         line.py_x = PYSEARCH_MARGIN;
124 |         line.py_y = 43;
125 |         line.py_width = PYScreenW;
126 |         [cell.contentView addSubview:line];
127 |     }
128 |     cell.imageView.image = [NSBundle py_imageNamed:@"search"];
129 |     cell.textLabel.text = self.searchSuggestions[indexPath.row];
130 |     return cell;
131 | }
132 | 
133 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
134 | {
135 |     if ([self.dataSource respondsToSelector:@selector(searchSuggestionView:heightForRowAtIndexPath:)]) {
136 |         return [self.dataSource searchSuggestionView:tableView heightForRowAtIndexPath:indexPath];
137 |     }
138 |     return 44.0;
139 | }
140 | 
141 | #pragma mark - UITableViewDelegate
142 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
143 | {
144 |     [tableView deselectRowAtIndexPath:indexPath animated:YES];
145 |     
146 |     if (self.didSelectCellBlock) self.didSelectCellBlock([tableView cellForRowAtIndexPath:indexPath]);
147 | }
148 | 
149 | @end
150 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearchViewController.h:
--------------------------------------------------------------------------------
  1 | //
  2 | //  GitHub: https://github.com/iphone5solo/PYSearch
  3 | //  Created by CoderKo1o.
  4 | //  Copyright © 2016 iphone5solo. All rights reserved.
  5 | //
  6 | 
  7 | #import <UIKit/UIKit.h>
  8 | #import "PYSearchConst.h"
  9 | 
 10 | @class PYSearchViewController, PYSearchSuggestionViewController;
 11 | 
 12 | typedef void(^PYDidSearchBlock)(PYSearchViewController *searchViewController, UISearchBar *searchBar, NSString *searchText);
 13 | 
 14 | /**
 15 |  style of popular search
 16 |  */
 17 | typedef NS_ENUM(NSInteger, PYHotSearchStyle)  {
 18 |     PYHotSearchStyleNormalTag,      // normal tag without border
 19 |     PYHotSearchStyleColorfulTag,    // colorful tag without border, color of background is randrom and can be custom by `colorPol`
 20 |     PYHotSearchStyleBorderTag,      // border tag, color of background is `clearColor`
 21 |     PYHotSearchStyleARCBorderTag,   // broder tag with ARC, color of background is `clearColor`
 22 |     PYHotSearchStyleRankTag,        // rank tag, color of background can be custom by `rankTagBackgroundColorHexStrings`
 23 |     PYHotSearchStyleRectangleTag,   // rectangle tag, color of background is `clearColor`
 24 |     PYHotSearchStyleDefault = PYHotSearchStyleNormalTag // default is `PYHotSearchStyleNormalTag`
 25 | };
 26 | 
 27 | /**
 28 |  style of search history
 29 |  */
 30 | typedef NS_ENUM(NSInteger, PYSearchHistoryStyle) {
 31 |     PYSearchHistoryStyleCell,           // style of UITableViewCell
 32 |     PYSearchHistoryStyleNormalTag,      // style of PYHotSearchStyleNormalTag
 33 |     PYSearchHistoryStyleColorfulTag,    // style of PYHotSearchStyleColorfulTag
 34 |     PYSearchHistoryStyleBorderTag,      // style of PYHotSearchStyleBorderTag
 35 |     PYSearchHistoryStyleARCBorderTag,   // style of PYHotSearchStyleARCBorderTag
 36 |     PYSearchHistoryStyleDefault = PYSearchHistoryStyleCell // default is `PYSearchHistoryStyleCell`
 37 | };
 38 | 
 39 | /**
 40 |  mode of search result view controller display
 41 |  */
 42 | typedef NS_ENUM(NSInteger, PYSearchResultShowMode) {
 43 |     PYSearchResultShowModeCustom,   // custom, can be push or pop and so on.
 44 |     PYSearchResultShowModePush,     // push, dispaly the view of search result by push
 45 |     PYSearchResultShowModeEmbed,    // embed, dispaly the view of search result by embed
 46 |     PYSearchResultShowModeDefault = PYSearchResultShowModeCustom // defualt is `PYSearchResultShowModeCustom`
 47 | };
 48 | /**
 49 |  mode of search view controller display
 50 |  */
 51 | typedef NS_ENUM(NSInteger, PYSearchViewControllerShowMode) {
 52 |     PYSearchViewControllerShowModeModal,    // modal, dispaly the view of searchViewController by modal
 53 |     PYSearchViewControllerShowModePush,   // push, dispaly the view of searchViewController by push
 54 |     PYSearchViewControllerShowDefault = PYSearchViewControllerShowModeModal // defualt is `PYSearchViewControllerShowModeModal`
 55 | };
 56 | 
 57 | 
 58 | /**
 59 |  The protocol of data source, you can custom the suggestion view by implement these methods the data scource.
 60 |  */
 61 | @protocol PYSearchViewControllerDataSource <NSObject>
 62 | 
 63 | @optional
 64 | 
 65 | /**
 66 |  Return a `UITableViewCell` object.
 67 | 
 68 |  @param searchSuggestionView    view which display search suggestions
 69 |  @param indexPath               indexPath of row
 70 |  @return a `UITableViewCell` object
 71 |  */
 72 | - (UITableViewCell *)searchSuggestionView:(UITableView *)searchSuggestionView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
 73 | 
 74 | /**
 75 |  Return number of rows in section.
 76 | 
 77 |  @param searchSuggestionView    view which display search suggestions
 78 |  @param section                 index of section
 79 |  @return number of rows in section
 80 |  */
 81 | - (NSInteger)searchSuggestionView:(UITableView *)searchSuggestionView numberOfRowsInSection:(NSInteger)section;
 82 | 
 83 | /**
 84 |  Return number of sections in search suggestion view.
 85 | 
 86 |  @param searchSuggestionView    view which display search suggestions
 87 |  @return number of sections
 88 |  */
 89 | - (NSInteger)numberOfSectionsInSearchSuggestionView:(UITableView *)searchSuggestionView;
 90 | 
 91 | /**
 92 |  Return height for row.
 93 | 
 94 |  @param searchSuggestionView    view which display search suggestions
 95 |  @param indexPath               indexPath of row
 96 |  @return height of row
 97 |  */
 98 | - (CGFloat)searchSuggestionView:(UITableView *)searchSuggestionView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
 99 | 
100 | @end
101 | 
102 | 
103 | /**
104 |  The protocol of delegate
105 |  */
106 | @protocol PYSearchViewControllerDelegate <NSObject, UITableViewDelegate>
107 | 
108 | @optional
109 | 
110 | /**
111 |  Called when search begain.
112 | 
113 |  @param searchViewController    search view controller
114 |  @param searchBar               search bar
115 |  @param searchText              text for search
116 |  */
117 | - (void)searchViewController:(PYSearchViewController *)searchViewController
118 |       didSearchWithSearchBar:(UISearchBar *)searchBar
119 |                   searchText:(NSString *)searchText;
120 | 
121 | /**
122 |  Called when popular search is selected.
123 | 
124 |  @param searchViewController    search view controller
125 |  @param index                   index of tag
126 |  @param searchText              text for search
127 |  
128 |  Note: `searchViewController:didSearchWithSearchBar:searchText:` will not be called when this method is implemented.
129 |  */
130 | - (void)searchViewController:(PYSearchViewController *)searchViewController
131 |    didSelectHotSearchAtIndex:(NSInteger)index
132 |                   searchText:(NSString *)searchText;
133 | 
134 | /**
135 |  Called when search history is selected.
136 | 
137 |  @param searchViewController    search view controller
138 |  @param index                   index of tag or row
139 |  @param searchText              text for search
140 |  
141 |  Note: `searchViewController:didSearchWithSearchBar:searchText:` will not be called when this method is implemented.
142 |  */
143 | - (void)searchViewController:(PYSearchViewController *)searchViewController
144 | didSelectSearchHistoryAtIndex:(NSInteger)index
145 |                   searchText:(NSString *)searchText;
146 | 
147 | /**
148 |  Called when search suggestion is selected.
149 | 
150 |  @param searchViewController    search view controller
151 |  @param index                   index of row
152 |  @param searchText              text for search
153 | 
154 |  Note: `searchViewController:didSearchWithSearchBar:searchText:` will not be called when this method is implemented.
155 |  */
156 | - (void)searchViewController:(PYSearchViewController *)searchViewController
157 | didSelectSearchSuggestionAtIndex:(NSInteger)index
158 |                   searchText:(NSString *)searchText PYSEARCH_DEPRECATED("Use searchViewController:didSelectSearchSuggestionAtIndexPath:searchText:");
159 | 
160 | /**
161 |  Called when search suggestion is selected, the method support more custom of search suggestion view.
162 | 
163 |  @param searchViewController    search view controller
164 |  @param indexPath               indexPath of row
165 |  @param searchBar               search bar
166 |  
167 |  Note: `searchViewController:didSearchWithSearchBar:searchText:` and `searchViewController:didSelectSearchSuggestionAtIndex:searchText:` will not be called when this method is implemented.
168 |  Suggestion: To ensure that can cache selected custom search suggestion records, you need to set `searchBar.text` = "custom search text".
169 |  */
170 | - (void)searchViewController:(PYSearchViewController *)searchViewController didSelectSearchSuggestionAtIndexPath:(NSIndexPath *)indexPath
171 |                    searchBar:(UISearchBar *)searchBar;
172 | 
173 | /**
174 |  Called when search text did change, you can reload data of suggestion view thought this method.
175 | 
176 |  @param searchViewController    search view controller
177 |  @param searchBar               search bar
178 |  @param searchText              text for search
179 |  */
180 | - (void)searchViewController:(PYSearchViewController *)searchViewController
181 |          searchTextDidChange:(UISearchBar *)searchBar
182 |                   searchText:(NSString *)searchText;
183 | 
184 | /**
185 |  Called when cancel item did press, default execute `[self dismissViewControllerAnimated:YES completion:nil]`.
186 | 
187 |  @param searchViewController search view controller
188 |  */
189 | - (void)didClickCancel:(PYSearchViewController *)searchViewController;
190 | 
191 | /**
192 |  Called when back item did press, default execute `[self.navigationController popViewControllerAnimated:YES]`.
193 |  
194 |  @param searchViewController search view controller
195 |  */
196 | - (void)didClickBack:(PYSearchViewController *)searchViewController;
197 | 
198 | @end
199 | 
200 | @interface PYSearchViewController : UIViewController
201 | 
202 | /**
203 |  The delegate
204 |  */
205 | @property (nonatomic, weak) id<PYSearchViewControllerDelegate> delegate;
206 | 
207 | /**
208 |  The data source
209 |  */
210 | @property (nonatomic, weak) id<PYSearchViewControllerDataSource> dataSource;
211 | 
212 | /**
213 |  Ranking the background color of the corresponding hexadecimal string (eg: @"#ffcc99") array (just four colors) when `hotSearchStyle` is `PYHotSearchStyleRankTag`.
214 |  */
215 | @property (nonatomic, strong) NSArray<NSString *> *rankTagBackgroundColorHexStrings;
216 | 
217 | /**
218 |  The pool of color which are use in colorful tag when `hotSearchStyle` is `PYHotSearchStyleColorfulTag`.
219 |  */
220 | @property (nonatomic, strong) NSMutableArray<UIColor *> *colorPol;
221 | 
222 | /**
223 |  Whether swap the popular search and search history location, default is NO.
224 |  
225 |  Note: It is‘t effective when `searchHistoryStyle` is `PYSearchHistoryStyleCell`.
226 |  */
227 | @property (nonatomic, assign) BOOL swapHotSeachWithSearchHistory;
228 | 
229 | /**
230 |  The element of popular search
231 |  */
232 | @property (nonatomic, copy) NSArray<NSString *> *hotSearches;
233 | 
234 | /**
235 |  The tags of popular search
236 |  */
237 | @property (nonatomic, copy) NSArray<UILabel *> *hotSearchTags;
238 | 
239 | /**
240 |  The label of popular search header
241 |  */
242 | @property (nonatomic, weak) UILabel *hotSearchHeader;
243 | 
244 | /**
245 |  Whether show popular search, default is YES.
246 |  */
247 | @property (nonatomic, assign) BOOL showHotSearch;
248 | 
249 | /**
250 |  The title of popular search
251 |  */
252 | @property (nonatomic, copy) NSString *hotSearchTitle;
253 | 
254 | /**
255 |  The tags of search history
256 |  */
257 | @property (nonatomic, copy) NSArray<UILabel *> *searchHistoryTags;
258 | 
259 | /**
260 |  The label of search history header
261 |  */
262 | @property (nonatomic, weak) UILabel *searchHistoryHeader;
263 | 
264 | /**
265 |  The title of search history
266 |  */
267 | @property (nonatomic, copy) NSString *searchHistoryTitle;
268 | 
269 | /**
270 |  Whether show search history, default is YES.
271 |  
272 |  Note: search record is not cache when it is NO.
273 |  */
274 | @property (nonatomic, assign) BOOL showSearchHistory;
275 | 
276 | /**
277 |  The path of cache search record, default is `PYSEARCH_SEARCH_HISTORY_CACHE_PATH`.
278 |  */
279 | @property (nonatomic, copy) NSString *searchHistoriesCachePath;
280 | 
281 | /**
282 |  The number of cache search record, default is 20.
283 |  */
284 | @property (nonatomic, assign) NSUInteger searchHistoriesCount;
285 | 
286 | /**
287 |  Whether remove the space of search string, default is YES.
288 |  */
289 | @property (nonatomic, assign) BOOL removeSpaceOnSearchString;
290 | 
291 | /**
292 |  The button of empty search record when `searchHistoryStyle` is’t `PYSearchHistoryStyleCell`.
293 |  */
294 | @property (nonatomic, weak) UIButton *emptyButton;
295 | 
296 | /**
297 |  The label od empty search record when `searchHistoryStyle` is `PYSearchHistoryStyleCell`.
298 |  */
299 | @property (nonatomic, weak) UILabel *emptySearchHistoryLabel;
300 | 
301 | /**
302 |  The style of popular search, default is `PYHotSearchStyleNormalTag`.
303 |  */
304 | @property (nonatomic, assign) PYHotSearchStyle hotSearchStyle;
305 | 
306 | /**
307 |  The style of search histrory, default is `PYSearchHistoryStyleCell`.
308 |  */
309 | @property (nonatomic, assign) PYSearchHistoryStyle searchHistoryStyle;
310 | 
311 | /**
312 |  The mode of display search result view controller, default is `PYSearchResultShowModeCustom`.
313 |  */
314 | @property (nonatomic, assign) PYSearchResultShowMode searchResultShowMode;
315 | 
316 | /**
317 |  The mode of display search view controller, default is `PYSearchViewControllerShowModeModal`.
318 |  */
319 | @property (nonatomic, assign) PYSearchViewControllerShowMode searchViewControllerShowMode;
320 | 
321 | /**
322 |  The search bar
323 |  */
324 | @property (nonatomic, weak) UISearchBar *searchBar;
325 | 
326 | /**
327 |  The text field of search bar
328 |  */
329 | @property (nonatomic, weak) UITextField *searchTextField;
330 | 
331 | /**
332 |  The background color of search bar.
333 |  */
334 | @property (nonatomic, strong) UIColor *searchBarBackgroundColor;
335 | 
336 | /**
337 |  The cornerRadius of `_UISearchBarSearchFieldBackgroundView` which from `self.searchTextField.subviews`, default is 0.0.
338 |  */
339 | @property (nonatomic, assign) CGFloat searchBarCornerRadius;
340 | 
341 | /**
342 |  The barButtonItem of cancel
343 |  */
344 | @property (nonatomic, strong) UIBarButtonItem *cancelBarButtonItem;
345 | 
346 | /**
347 |  The customView of cancelBarButtonItem
348 |  */
349 | @property (nonatomic, weak) UIButton *cancelButton;
350 | 
351 | /**
352 |  The barButtonItem of back
353 |  */
354 | @property (nonatomic, strong) UIBarButtonItem *backBarButtonItem;
355 | 
356 | /**
357 |  The customView of backBarButtonItem
358 |  */
359 | @property (nonatomic, weak) UIButton *backButton;
360 | 
361 | /**
362 |  The search suggestion view
363 |  */
364 | @property (nonatomic, weak, readonly) UITableView *searchSuggestionView;
365 | 
366 | /**
367 |  The block which invoked when search begain.
368 |  */
369 | @property (nonatomic, copy) PYDidSearchBlock didSearchBlock;
370 | 
371 | /**
372 |  The element of search suggestions
373 |  
374 |  Note: it is't effective when `searchSuggestionHidden` is NO or cell of suggestion view is custom.
375 |  */
376 | @property (nonatomic, copy) NSArray<NSString *> *searchSuggestions;
377 | 
378 | /**
379 |  Whether hidden search suggstion view, default is NO.
380 |  */
381 | @property (nonatomic, assign) BOOL searchSuggestionHidden;
382 | 
383 | /**
384 |  The view controller of search result.
385 |  */
386 | @property (nonatomic, strong) UIViewController *searchResultController;
387 | 
388 | /**
389 |  Whether show search result view when search text did change, default is NO.
390 |  
391 |  Note: it is effective only when `searchResultShowMode` is `PYSearchResultShowModeEmbed`.
392 |  */
393 | @property (nonatomic, assign) BOOL showSearchResultWhenSearchTextChanged;
394 | 
395 | /**
396 |  Whether show search result view when search bar become first responder again.
397 |  
398 |  Note: it is effective only when `searchResultShowMode` is `PYSearchResultShowModeEmbed`.
399 |  */
400 | @property (nonatomic, assign) BOOL showSearchResultWhenSearchBarRefocused;
401 | 
402 | /**
403 |  Whether show keyboard when return to search result, default is YES.
404 |  */
405 | @property (nonatomic, assign) BOOL showKeyboardWhenReturnSearchResult;
406 | 
407 | /**
408 |  Creates an instance of searchViewContoller with popular searches and search bar's placeholder.
409 | 
410 |  @param hotSearches     popular searchs
411 |  @param placeholder     placeholder of search bar
412 |  @return new instance of `PYSearchViewController` class
413 |  */
414 | + (instancetype)searchViewControllerWithHotSearches:(NSArray<NSString *> *)hotSearches
415 |                                searchBarPlaceholder:(NSString *)placeholder;
416 | 
417 | /**
418 |  Creates an instance of searchViewContoller with popular searches, search bar's placeholder and the block which invoked when search begain.
419 | 
420 |  @param hotSearches     popular searchs
421 |  @param placeholder     placeholder of search bar
422 |  @param block           block which invoked when search begain
423 |  @return new instance of `PYSearchViewController` class
424 |  
425 |  Note: The `delegate` has a priority greater than the `block`, `block` is't effective when `searchViewController:didSearchWithSearchBar:searchText:` is implemented.
426 |  */
427 | + (instancetype)searchViewControllerWithHotSearches:(NSArray<NSString *> *)hotSearches
428 |                                searchBarPlaceholder:(NSString *)placeholder
429 |                                      didSearchBlock:(PYDidSearchBlock)block;
430 | 
431 | @end
432 | 


--------------------------------------------------------------------------------
/PYSearch/PYSearchViewController.m:
--------------------------------------------------------------------------------
   1 | //
   2 | //  GitHub: https://github.com/iphone5solo/PYSearch
   3 | //  Created by CoderKo1o.
   4 | //  Copyright © 2016 iphone5solo. All rights reserved.
   5 | //
   6 | 
   7 | #import "PYSearchViewController.h"
   8 | #import "PYSearchConst.h"
   9 | #import "PYSearchSuggestionViewController.h"
  10 | 
  11 | #define PYRectangleTagMaxCol 3
  12 | #define PYTextColor PYSEARCH_COLOR(113, 113, 113)
  13 | #define PYSEARCH_COLORPolRandomColor self.colorPol[arc4random_uniform((uint32_t)self.colorPol.count)]
  14 | 
  15 | @interface PYSearchViewController () <UISearchBarDelegate, UITableViewDelegate, UITableViewDataSource, PYSearchSuggestionViewDataSource, UIGestureRecognizerDelegate> {
  16 |     id <UIGestureRecognizerDelegate> _previousInteractivePopGestureRecognizerDelegate;
  17 | }
  18 | 
  19 | /**
  20 |  The header view of search view
  21 |  */
  22 | @property (nonatomic, weak) UIView *headerView;
  23 | 
  24 | /**
  25 |  The view of popular search
  26 |  */
  27 | @property (nonatomic, weak) UIView *hotSearchView;
  28 | 
  29 | /**
  30 |  The view of search history
  31 |  */
  32 | @property (nonatomic, weak) UIView *searchHistoryView;
  33 | 
  34 | /**
  35 |  The records of search
  36 |  */
  37 | @property (nonatomic, strong) NSMutableArray *searchHistories;
  38 | 
  39 | /**
  40 |  Whether keyboard is showing.
  41 |  */
  42 | @property (nonatomic, assign) BOOL keyboardShowing;
  43 | 
  44 | /**
  45 |  The height of keyborad
  46 |  */
  47 | @property (nonatomic, assign) CGFloat keyboardHeight;
  48 | 
  49 | /**
  50 |  The search suggestion view contoller
  51 |  */
  52 | @property (nonatomic, weak) PYSearchSuggestionViewController *searchSuggestionVC;
  53 | 
  54 | /**
  55 |  The content view of popular search tags
  56 |  */
  57 | @property (nonatomic, weak) UIView *hotSearchTagsContentView;
  58 | 
  59 | /**
  60 |  The tags of rank
  61 |  */
  62 | @property (nonatomic, copy) NSArray<UILabel *> *rankTags;
  63 | 
  64 | /**
  65 |  The text labels of rank
  66 |  */
  67 | @property (nonatomic, copy) NSArray<UILabel *> *rankTextLabels;
  68 | 
  69 | /**
  70 |  The view of rank which contain tag and text label.
  71 |  */
  72 | @property (nonatomic, copy) NSArray<UIView *> *rankViews;
  73 | 
  74 | /**
  75 |  The content view of search history tags.
  76 |  */
  77 | @property (nonatomic, weak) UIView *searchHistoryTagsContentView;
  78 | 
  79 | /**
  80 |  The base table view  of search view controller
  81 |  */
  82 | @property (nonatomic, strong) UITableView *baseSearchTableView;
  83 | 
  84 | /**
  85 |  Whether did press suggestion cell
  86 |  */
  87 | @property (nonatomic, assign) BOOL didClickSuggestionCell;
  88 | 
  89 | /**
  90 |  The current orientation of device
  91 |  */
  92 | @property (nonatomic, assign) UIDeviceOrientation currentOrientation;
  93 | 
  94 | /**
  95 |  The width of cancel button
  96 |  */
  97 | @property (nonatomic, assign) CGFloat cancelButtonWidth;
  98 | 
  99 | @end
 100 | 
 101 | @implementation PYSearchViewController
 102 | 
 103 | - (instancetype)init
 104 | {
 105 |     if (self = [super init]) {
 106 |         [self setup];
 107 |     }
 108 |     return self;
 109 | }
 110 | 
 111 | - (void)awakeFromNib
 112 | {
 113 |     [super awakeFromNib];
 114 |     
 115 |     [self setup];
 116 | }
 117 | 
 118 | - (void)viewDidLayoutSubviews
 119 | {
 120 |     [super viewDidLayoutSubviews];
 121 |     
 122 |     if (self.currentOrientation != [[UIDevice currentDevice] orientation]) { // orientation changed, reload layout
 123 |         self.hotSearches = self.hotSearches;
 124 |         self.searchHistories = self.searchHistories;
 125 |         self.currentOrientation = [[UIDevice currentDevice] orientation];
 126 |     }
 127 |     
 128 |     CGFloat adaptWidth = 0.0;
 129 |     UISearchBar *searchBar = self.searchBar;
 130 |     UITextField *searchField = self.searchTextField;
 131 |     UIView *titleView = self.navigationItem.titleView;
 132 |     UIButton *backButton = self.navigationItem.leftBarButtonItem.customView;
 133 |     UIButton *cancelButton = self.navigationItem.rightBarButtonItem.customView;
 134 |     UIEdgeInsets backButtonLayoutMargins = UIEdgeInsetsZero;
 135 |     UIEdgeInsets cancelButtonLayoutMargins = UIEdgeInsetsZero;
 136 |     UIEdgeInsets navigationBarLayoutMargins = UIEdgeInsetsZero;
 137 |     UINavigationBar *navigationBar = self.navigationController.navigationBar;
 138 |     
 139 |     if (@available(iOS 8.0, *)) {
 140 |         backButton.layoutMargins = UIEdgeInsetsMake(8, 0, 8, 8);
 141 |         backButtonLayoutMargins = backButton.layoutMargins;
 142 |         cancelButton.layoutMargins = UIEdgeInsetsMake(8, 8, 8, 0);
 143 |         cancelButtonLayoutMargins = cancelButton.layoutMargins;
 144 |         navigationBarLayoutMargins = navigationBar.layoutMargins;
 145 |     }
 146 |     
 147 |     if (self.searchViewControllerShowMode == PYSearchViewControllerShowModePush) {
 148 |         UIButton *backButton = self.navigationItem.leftBarButtonItem.customView;
 149 |         UIImageView *imageView = backButton.imageView;
 150 |         UIView *titleLabel = backButton.titleLabel;
 151 |         
 152 |         [backButton sizeToFit];
 153 |         [imageView sizeToFit];
 154 |         [titleLabel sizeToFit];
 155 |         
 156 |         backButton.py_height = navigationBar.py_height;
 157 |         backButton.py_width = titleLabel.py_width + imageView.py_width / 2.0 + backButtonLayoutMargins.left + backButtonLayoutMargins.right;
 158 |         adaptWidth = backButton.py_width + 8;
 159 |     } else { // Default is PYSearchViewControllerShowModeModal
 160 |         [cancelButton sizeToFit];
 161 |         [cancelButton.titleLabel sizeToFit];
 162 |         self.cancelButtonWidth = cancelButton.py_width + cancelButtonLayoutMargins.left + cancelButtonLayoutMargins.right;
 163 |         adaptWidth = self.cancelButtonWidth + 8;
 164 |     }
 165 |     
 166 |     adaptWidth = adaptWidth + navigationBarLayoutMargins.left + navigationBarLayoutMargins.right;
 167 |     // Adapt the search bar layout problem in the navigation bar on iOS 11
 168 |     // More details : https://github.com/iphone5solo/PYSearch/issues/108
 169 |     if (@available(iOS 11.0, *)) { // iOS 11
 170 |         if (self.searchViewControllerShowMode == PYSearchViewControllerShowModeModal) {
 171 |             NSLayoutConstraint *leftLayoutConstraint = [searchBar.leftAnchor constraintEqualToAnchor:titleView.leftAnchor];
 172 |             if (navigationBarLayoutMargins.left > PYSEARCH_MARGIN) {
 173 |                 [leftLayoutConstraint setConstant:0];
 174 |             } else {
 175 |                 [leftLayoutConstraint setConstant:PYSEARCH_MARGIN - navigationBarLayoutMargins.left];
 176 |             }
 177 |         }
 178 |         searchBar.py_height = self.view.py_width > self.view.py_height ? 24 : 30;
 179 |         searchBar.py_width = self.view.py_width - adaptWidth - PYSEARCH_MARGIN;
 180 |         searchField.frame = searchBar.bounds;
 181 |         cancelButton.py_width = self.cancelButtonWidth;
 182 |     } else {
 183 |         titleView.py_y = self.view.py_width > self.view.py_height ? 4 : 7;
 184 |         titleView.py_height = self.view.py_width > self.view.py_height ? 24 : 30;
 185 |         if (self.searchViewControllerShowMode == PYSearchViewControllerShowModePush) {
 186 |             titleView.py_width = self.view.py_width - adaptWidth - PYSEARCH_MARGIN;
 187 |         } else {
 188 |             titleView.py_x = PYSEARCH_MARGIN * 1.5;
 189 |             titleView.py_width = self.view.py_width - self.cancelButtonWidth - titleView.py_x * 2 - 3;
 190 |         }
 191 |     }
 192 | }
 193 | 
 194 | - (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
 195 |     [self viewDidLayoutSubviews];
 196 | }
 197 | 
 198 | - (BOOL)prefersStatusBarHidden
 199 | {
 200 |     return NO;
 201 | }
 202 | 
 203 | - (void)viewWillAppear:(BOOL)animated
 204 | {
 205 |     [super viewWillAppear:animated];
 206 |     
 207 |     // Fixed search history view may not be displayed or other problem at the first time.
 208 |     [self setSearchHistoryStyle:self.searchHistoryStyle];  // in method viewDidAppear,the view flashes when searchHistory count > 0
 209 |     
 210 |     if (self.cancelButtonWidth == 0) { // Just adapt iOS 11.2
 211 |         [self viewDidLayoutSubviews];
 212 |     }
 213 |     
 214 |     // Adjust the view according to the `navigationBar.translucent`
 215 |     if (NO == self.navigationController.navigationBar.translucent) {
 216 |         self.baseSearchTableView.contentInset = UIEdgeInsetsMake(0, 0, self.view.py_y, 0);
 217 |         self.searchSuggestionVC.view.frame = CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame) - self.view.py_y, self.view.py_width, self.view.py_height + self.view.py_y);
 218 |         if (!self.navigationController.navigationBar.barTintColor) {
 219 |             self.navigationController.navigationBar.barTintColor = PYSEARCH_COLOR(249, 249, 249);
 220 |         }
 221 |     }
 222 |     
 223 |     if (NULL == self.searchResultController.parentViewController) {
 224 |         [self.searchBar becomeFirstResponder];
 225 |     } else if (YES == self.showKeyboardWhenReturnSearchResult) {
 226 |         [self.searchBar becomeFirstResponder];
 227 |     }
 228 |     if (_searchViewControllerShowMode == PYSearchViewControllerShowModePush) {
 229 |         if (self.navigationController.viewControllers.count > 1) {
 230 |             _previousInteractivePopGestureRecognizerDelegate = self.navigationController.interactivePopGestureRecognizer.delegate;
 231 |             self.navigationController.interactivePopGestureRecognizer.delegate = self;
 232 |         }
 233 |     }
 234 | }
 235 | 
 236 | - (void)viewDidAppear:(BOOL)animated
 237 | {
 238 |     [super viewDidAppear:animated];
 239 |     
 240 |     // Fixed search history view may not be displayed or other problem at the first time.
 241 |     [self setSearchHistoryStyle:self.searchHistoryStyle];
 242 | }
 243 | 
 244 | - (void)viewWillDisappear:(BOOL)animated
 245 | {
 246 |     [super viewWillDisappear:animated];
 247 |     
 248 |     [self.searchBar resignFirstResponder];
 249 |     
 250 |     if (_searchViewControllerShowMode == PYSearchViewControllerShowModePush) {
 251 |         self.navigationController.interactivePopGestureRecognizer.delegate = _previousInteractivePopGestureRecognizerDelegate;
 252 |     }
 253 | }
 254 | 
 255 | - (void)dealloc
 256 | {
 257 |     [[NSNotificationCenter defaultCenter] removeObserver:self];
 258 | }
 259 | 
 260 | + (instancetype)searchViewControllerWithHotSearches:(NSArray<NSString *> *)hotSearches searchBarPlaceholder:(NSString *)placeholder
 261 | {
 262 |     PYSearchViewController *searchVC = [[self alloc] init];
 263 |     searchVC.hotSearches = hotSearches;
 264 |     searchVC.searchBar.placeholder = placeholder;
 265 |     return searchVC;
 266 | }
 267 | 
 268 | + (instancetype)searchViewControllerWithHotSearches:(NSArray<NSString *> *)hotSearches searchBarPlaceholder:(NSString *)placeholder didSearchBlock:(PYDidSearchBlock)block
 269 | {
 270 |     PYSearchViewController *searchVC = [self searchViewControllerWithHotSearches:hotSearches searchBarPlaceholder:placeholder];
 271 |     searchVC.didSearchBlock = [block copy];
 272 |     return searchVC;
 273 | }
 274 | 
 275 | #pragma mark - Lazy
 276 | - (UITableView *)baseSearchTableView
 277 | {
 278 |     if (!_baseSearchTableView) {
 279 |         UITableView *baseSearchTableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
 280 |         baseSearchTableView.backgroundColor = [UIColor clearColor];
 281 |         baseSearchTableView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
 282 |         if ([baseSearchTableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)]) { // For the adapter iPad
 283 |             baseSearchTableView.cellLayoutMarginsFollowReadableWidth = NO;
 284 |         }
 285 |         baseSearchTableView.delegate = self;
 286 |         baseSearchTableView.dataSource = self;
 287 |         [self.view addSubview:baseSearchTableView];
 288 |         _baseSearchTableView = baseSearchTableView;
 289 |     }
 290 |     return _baseSearchTableView;
 291 | }
 292 | 
 293 | - (PYSearchSuggestionViewController *)searchSuggestionVC
 294 | {
 295 |     if (!_searchSuggestionVC) {
 296 |         PYSearchSuggestionViewController *searchSuggestionVC = [[PYSearchSuggestionViewController alloc] initWithStyle:UITableViewStyleGrouped];
 297 |         __weak typeof(self) _weakSelf = self;
 298 |         searchSuggestionVC.didSelectCellBlock = ^(UITableViewCell *didSelectCell) {
 299 |             __strong typeof(_weakSelf) _swSelf = _weakSelf;
 300 |             _swSelf.searchBar.text = didSelectCell.textLabel.text;
 301 |             NSIndexPath *indexPath = [_swSelf.searchSuggestionVC.tableView indexPathForCell:didSelectCell];
 302 |             
 303 |             if ([_swSelf.delegate respondsToSelector:@selector(searchViewController:didSelectSearchSuggestionAtIndexPath:searchBar:)]) {
 304 |                 [_swSelf.delegate searchViewController:_swSelf didSelectSearchSuggestionAtIndexPath:indexPath searchBar:_swSelf.searchBar];
 305 |                 [_swSelf saveSearchCacheAndRefreshView];
 306 |             } else if ([_swSelf.delegate respondsToSelector:@selector(searchViewController:didSelectSearchSuggestionAtIndex:searchText:)]) {
 307 | #pragma clang diagnostic push
 308 | #pragma clang diagnostic ignored "-Wdeprecated-declarations"
 309 |                 [_swSelf.delegate searchViewController:_swSelf didSelectSearchSuggestionAtIndex:indexPath.row searchText:_swSelf.searchBar.text];
 310 | #pragma clang diagnostic pop
 311 |                 [_swSelf saveSearchCacheAndRefreshView];
 312 |             } else {
 313 |                 [_swSelf searchBarSearchButtonClicked:_swSelf.searchBar];
 314 |             }
 315 |         };
 316 |         searchSuggestionVC.view.frame = CGRectMake(0, CGRectGetMaxY(self.navigationController.navigationBar.frame), PYScreenW, PYScreenH);
 317 |         searchSuggestionVC.view.backgroundColor = self.baseSearchTableView.backgroundColor;
 318 |         searchSuggestionVC.view.hidden = YES;
 319 |         _searchSuggestionView = (UITableView *)searchSuggestionVC.view;
 320 |         searchSuggestionVC.dataSource = self;
 321 |         [self.view addSubview:searchSuggestionVC.view];
 322 |         [self addChildViewController:searchSuggestionVC];
 323 |         _searchSuggestionVC = searchSuggestionVC;
 324 |     }
 325 |     return _searchSuggestionVC;
 326 | }
 327 | 
 328 | - (UIButton *)emptyButton
 329 | {
 330 |     if (!_emptyButton) {
 331 |         UIButton *emptyButton = [[UIButton alloc] init];
 332 |         emptyButton.titleLabel.font = self.searchHistoryHeader.font;
 333 |         [emptyButton setTitleColor:PYTextColor forState:UIControlStateNormal];
 334 |         [emptyButton setTitle:[NSBundle py_localizedStringForKey:PYSearchEmptyButtonText] forState:UIControlStateNormal];
 335 |         [emptyButton setImage:[NSBundle py_imageNamed:@"empty"] forState:UIControlStateNormal];
 336 |         [emptyButton addTarget:self action:@selector(emptySearchHistoryDidClick) forControlEvents:UIControlEventTouchUpInside];
 337 |         [emptyButton sizeToFit];
 338 |         emptyButton.py_width += PYSEARCH_MARGIN;
 339 |         emptyButton.py_height += PYSEARCH_MARGIN;
 340 |         emptyButton.py_centerY = self.searchHistoryHeader.py_centerY;
 341 |         emptyButton.py_x = self.searchHistoryView.py_width - emptyButton.py_width;
 342 |         emptyButton.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
 343 |         [self.searchHistoryView addSubview:emptyButton];
 344 |         _emptyButton = emptyButton;
 345 |     }
 346 |     return _emptyButton;
 347 | }
 348 | 
 349 | - (UIView *)searchHistoryTagsContentView
 350 | {
 351 |     if (!_searchHistoryTagsContentView) {
 352 |         UIView *searchHistoryTagsContentView = [[UIView alloc] init];
 353 |         searchHistoryTagsContentView.py_width = self.searchHistoryView.py_width;
 354 |         searchHistoryTagsContentView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 355 |         searchHistoryTagsContentView.py_y = CGRectGetMaxY(self.hotSearchTagsContentView.frame) + PYSEARCH_MARGIN;
 356 |         [self.searchHistoryView addSubview:searchHistoryTagsContentView];
 357 |         _searchHistoryTagsContentView = searchHistoryTagsContentView;
 358 |     }
 359 |     return _searchHistoryTagsContentView;
 360 | }
 361 | 
 362 | - (UILabel *)searchHistoryHeader
 363 | {
 364 |     if (!_searchHistoryHeader) {
 365 |         UILabel *titleLabel = [self setupTitleLabel:[NSBundle py_localizedStringForKey:PYSearchSearchHistoryText]];
 366 |         [self.searchHistoryView addSubview:titleLabel];
 367 |         _searchHistoryHeader = titleLabel;
 368 |     }
 369 |     return _searchHistoryHeader;
 370 | }
 371 | 
 372 | - (UIView *)searchHistoryView
 373 | {
 374 |     if (!_searchHistoryView) {
 375 |         UIView *searchHistoryView = [[UIView alloc] init];
 376 |         searchHistoryView.py_x = self.hotSearchView.py_x;
 377 |         searchHistoryView.py_y = self.hotSearchView.py_y;
 378 |         searchHistoryView.py_width = self.headerView.py_width - searchHistoryView.py_x * 2;
 379 |         searchHistoryView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 380 |         [self.headerView addSubview:searchHistoryView];
 381 |         _searchHistoryView = searchHistoryView;
 382 |     }
 383 |     return _searchHistoryView;
 384 | }
 385 | 
 386 | - (NSMutableArray *)searchHistories
 387 | {
 388 |     if (!_searchHistories) {
 389 |         _searchHistories = [NSMutableArray arrayWithArray:[NSKeyedUnarchiver unarchiveObjectWithFile:self.searchHistoriesCachePath]];
 390 |     }
 391 |     return _searchHistories;
 392 | }
 393 | 
 394 | - (NSMutableArray *)colorPol
 395 | {
 396 |     if (!_colorPol) {
 397 |         NSArray *colorStrPol = @[@"009999", @"0099cc", @"0099ff", @"00cc99", @"00cccc", @"336699", @"3366cc", @"3366ff", @"339966", @"666666", @"666699", @"6666cc", @"6666ff", @"996666", @"996699", @"999900", @"999933", @"99cc00", @"99cc33", @"660066", @"669933", @"990066", @"cc9900", @"cc6600" , @"cc3300", @"cc3366", @"cc6666", @"cc6699", @"cc0066", @"cc0033", @"ffcc00", @"ffcc33", @"ff9900", @"ff9933", @"ff6600", @"ff6633", @"ff6666", @"ff6699", @"ff3366", @"ff3333"];
 398 |         NSMutableArray *colorPolM = [NSMutableArray array];
 399 |         for (NSString *colorStr in colorStrPol) {
 400 |             UIColor *color = [UIColor py_colorWithHexString:colorStr];
 401 |             [colorPolM addObject:color];
 402 |         }
 403 |         _colorPol = colorPolM;
 404 |     }
 405 |     return _colorPol;
 406 | }
 407 | 
 408 | - (void)setup
 409 | {
 410 |     self.view.backgroundColor = [UIColor whiteColor];
 411 |     self.baseSearchTableView.separatorStyle = UITableViewCellSeparatorStyleNone;
 412 |     self.navigationController.navigationBar.backIndicatorImage = nil;
 413 |     [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardDidShow:) name:UIKeyboardDidShowNotification object:nil];
 414 |     UIButton *cancleButton = [UIButton buttonWithType:UIButtonTypeSystem];
 415 |     cancleButton.titleLabel.font = [UIFont systemFontOfSize:17];
 416 |     [cancleButton setTitle:[NSBundle py_localizedStringForKey:PYSearchCancelButtonText] forState:UIControlStateNormal];
 417 |     [cancleButton addTarget:self action:@selector(cancelDidClick)  forControlEvents:UIControlEventTouchUpInside];
 418 |     cancleButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
 419 |     cancleButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
 420 |     [cancleButton sizeToFit];
 421 |     cancleButton.py_width += PYSEARCH_MARGIN;
 422 |     self.cancelButton = cancleButton;
 423 |     self.cancelBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:cancleButton];
 424 |     UIButton *backButton = [UIButton buttonWithType:UIButtonTypeSystem];
 425 |     UIImage *backImage = [NSBundle py_imageNamed:@"back"];
 426 |     backButton.titleLabel.font = [UIFont systemFontOfSize:17];
 427 |     [backButton setTitle:[NSBundle py_localizedStringForKey:PYSearchBackButtonText] forState:UIControlStateNormal];
 428 |     [backButton setImage:backImage forState:UIControlStateNormal];
 429 |     [backButton addTarget:self action:@selector(backDidClick)  forControlEvents:UIControlEventTouchUpInside];
 430 |     backButton.contentVerticalAlignment = UIControlContentVerticalAlignmentCenter;
 431 |     backButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentLeft;
 432 |     [backButton.imageView sizeToFit];
 433 |     backButton.contentEdgeInsets = UIEdgeInsetsMake(0, -ceil(backImage.size.width / 2.0), 0, 0);
 434 |     backButton.imageEdgeInsets = UIEdgeInsetsMake(0, 0, 0, 0);
 435 |     [backButton sizeToFit];
 436 |     backButton.py_width += 3;
 437 |     self.backButton = backButton;
 438 |     self.backBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:backButton];
 439 |     
 440 |     /**
 441 |      * Initialize settings
 442 |      */
 443 |     self.hotSearchStyle = PYHotSearchStyleDefault;
 444 |     self.searchHistoryStyle = PYHotSearchStyleDefault;
 445 |     self.searchResultShowMode = PYSearchResultShowModeDefault;
 446 |     self.searchViewControllerShowMode = PYSearchViewControllerShowDefault;
 447 |     self.searchSuggestionHidden = NO;
 448 |     self.searchHistoriesCachePath = PYSEARCH_SEARCH_HISTORY_CACHE_PATH;
 449 |     self.searchHistoriesCount = 20;
 450 |     self.showSearchHistory = YES;
 451 |     self.showHotSearch = YES;
 452 |     self.showSearchResultWhenSearchTextChanged = NO;
 453 |     self.showSearchResultWhenSearchBarRefocused = NO;
 454 |     self.showKeyboardWhenReturnSearchResult = YES;
 455 |     self.removeSpaceOnSearchString = YES;
 456 |     self.searchBarCornerRadius = 0.0;
 457 |     
 458 |     UIView *titleView = [[UIView alloc] init];
 459 |     UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:titleView.bounds];
 460 |     [titleView addSubview:searchBar];
 461 |     if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 11.0) { // iOS 11
 462 |         [NSLayoutConstraint activateConstraints:@[
 463 |                                                   [searchBar.topAnchor constraintEqualToAnchor:titleView.topAnchor],
 464 |                                                   [searchBar.leftAnchor constraintEqualToAnchor:titleView.leftAnchor],
 465 |                                                   [searchBar.rightAnchor constraintEqualToAnchor:titleView.rightAnchor],
 466 |                                                   [searchBar.bottomAnchor constraintEqualToAnchor:titleView.bottomAnchor]
 467 |                                                   ]];
 468 |     } else {
 469 |         searchBar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
 470 |     }
 471 |     self.navigationItem.titleView = titleView;
 472 |     searchBar.placeholder = [NSBundle py_localizedStringForKey:PYSearchSearchPlaceholderText];
 473 |     searchBar.backgroundImage = [NSBundle py_imageNamed:@"clearImage"];
 474 |     searchBar.delegate = self;
 475 |     for (UIView *subView in [[searchBar.subviews lastObject] subviews]) {
 476 |         if ([[subView class] isSubclassOfClass:[UITextField class]]) {
 477 |             UITextField *textField = (UITextField *)subView;
 478 |             textField.font = [UIFont systemFontOfSize:16];
 479 |             _searchTextField = textField;
 480 |             break;
 481 |         }
 482 |     }
 483 |     self.searchBar = searchBar;
 484 |     
 485 |     UIView *headerView = [[UIView alloc] init];
 486 |     headerView.py_width = PYScreenW;
 487 |     headerView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 488 |     UIView *hotSearchView = [[UIView alloc] init];
 489 |     hotSearchView.py_x = PYSEARCH_MARGIN * 1.5;
 490 |     hotSearchView.py_width = headerView.py_width - hotSearchView.py_x * 2;
 491 |     hotSearchView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 492 |     UILabel *titleLabel = [self setupTitleLabel:[NSBundle py_localizedStringForKey:PYSearchHotSearchText]];
 493 |     self.hotSearchHeader = titleLabel;
 494 |     [hotSearchView addSubview:titleLabel];
 495 |     UIView *hotSearchTagsContentView = [[UIView alloc] init];
 496 |     hotSearchTagsContentView.py_width = hotSearchView.py_width;
 497 |     hotSearchTagsContentView.py_y = CGRectGetMaxY(titleLabel.frame) + PYSEARCH_MARGIN;
 498 |     hotSearchTagsContentView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 499 |     [hotSearchView addSubview:hotSearchTagsContentView];
 500 |     [headerView addSubview:hotSearchView];
 501 |     self.hotSearchTagsContentView = hotSearchTagsContentView;
 502 |     self.hotSearchView = hotSearchView;
 503 |     self.headerView = headerView;
 504 |     self.baseSearchTableView.tableHeaderView = headerView;
 505 |     
 506 |     UIView *footerView = [[UIView alloc] init];
 507 |     footerView.py_width = PYScreenW;
 508 |     UILabel *emptySearchHistoryLabel = [[UILabel alloc] init];
 509 |     emptySearchHistoryLabel.textColor = [UIColor darkGrayColor];
 510 |     emptySearchHistoryLabel.font = [UIFont systemFontOfSize:13];
 511 |     emptySearchHistoryLabel.userInteractionEnabled = YES;
 512 |     emptySearchHistoryLabel.text = [NSBundle py_localizedStringForKey:PYSearchEmptySearchHistoryText];
 513 |     emptySearchHistoryLabel.textAlignment = NSTextAlignmentCenter;
 514 |     emptySearchHistoryLabel.py_height = 49;
 515 |     [emptySearchHistoryLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(emptySearchHistoryDidClick)]];
 516 |     emptySearchHistoryLabel.py_width = footerView.py_width;
 517 |     emptySearchHistoryLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 518 |     self.emptySearchHistoryLabel = emptySearchHistoryLabel;
 519 |     [footerView addSubview:emptySearchHistoryLabel];
 520 |     footerView.py_height = emptySearchHistoryLabel.py_height;
 521 |     self.baseSearchTableView.tableFooterView = footerView;
 522 |     
 523 |     self.hotSearches = nil;
 524 | }
 525 | 
 526 | - (UILabel *)setupTitleLabel:(NSString *)title
 527 | {
 528 |     UILabel *titleLabel = [[UILabel alloc] init];
 529 |     titleLabel.text = title;
 530 |     titleLabel.font = [UIFont systemFontOfSize:13];
 531 |     titleLabel.tag = 1;
 532 |     titleLabel.textColor = PYTextColor;
 533 |     [titleLabel sizeToFit];
 534 |     titleLabel.py_x = 0;
 535 |     titleLabel.py_y = 0;
 536 |     return titleLabel;
 537 | }
 538 | 
 539 | - (void)setupHotSearchRectangleTags
 540 | {
 541 |     UIView *contentView = self.hotSearchTagsContentView;
 542 |     contentView.py_width = PYSEARCH_REALY_SCREEN_WIDTH;
 543 |     contentView.py_x = -PYSEARCH_MARGIN * 1.5;
 544 |     contentView.py_y += 2;
 545 |     contentView.backgroundColor = [UIColor whiteColor];
 546 |     self.baseSearchTableView.backgroundColor = [UIColor py_colorWithHexString:@"#efefef"];
 547 |     // remove all subviews in hotSearchTagsContentView
 548 |     [self.hotSearchTagsContentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
 549 |     
 550 |     CGFloat rectangleTagH = 40;
 551 |     NSMutableArray *rectangleTagLabelsM = [NSMutableArray array];
 552 |     for (int i = 0; i < self.hotSearches.count; i++) {
 553 |         UILabel *rectangleTagLabel = [[UILabel alloc] init];
 554 |         rectangleTagLabel.userInteractionEnabled = YES;
 555 |         rectangleTagLabel.font = [UIFont systemFontOfSize:14];
 556 |         rectangleTagLabel.textColor = PYTextColor;
 557 |         rectangleTagLabel.backgroundColor = [UIColor clearColor];
 558 |         rectangleTagLabel.text = self.hotSearches[i];
 559 |         rectangleTagLabel.py_width = contentView.py_width / PYRectangleTagMaxCol;
 560 |         rectangleTagLabel.py_height = rectangleTagH;
 561 |         rectangleTagLabel.textAlignment = NSTextAlignmentCenter;
 562 |         [rectangleTagLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tagDidCLick:)]];
 563 |         rectangleTagLabel.py_x = rectangleTagLabel.py_width * (i % PYRectangleTagMaxCol);
 564 |         rectangleTagLabel.py_y = rectangleTagLabel.py_height * (i / PYRectangleTagMaxCol);
 565 |         [contentView addSubview:rectangleTagLabel];
 566 |         [rectangleTagLabelsM addObject:rectangleTagLabel];
 567 |     }
 568 |     self.hotSearchTags = [rectangleTagLabelsM copy];
 569 |     contentView.py_height = CGRectGetMaxY(contentView.subviews.lastObject.frame);
 570 |     
 571 |     self.hotSearchView.py_height = CGRectGetMaxY(contentView.frame) + PYSEARCH_MARGIN * 2;
 572 |     self.baseSearchTableView.tableHeaderView.py_height = self.headerView.py_height = MAX(CGRectGetMaxY(self.hotSearchView.frame), CGRectGetMaxY(self.searchHistoryView.frame));
 573 |     
 574 |     for (int i = 0; i < PYRectangleTagMaxCol - 1; i++) {
 575 |         UIImageView *verticalLine = [[UIImageView alloc] initWithImage:[NSBundle py_imageNamed:@"cell-content-line-vertical"]];
 576 |         verticalLine.py_height = contentView.py_height;
 577 |         verticalLine.alpha = 0.7;
 578 |         verticalLine.py_x = contentView.py_width / PYRectangleTagMaxCol * (i + 1);
 579 |         verticalLine.py_width = 0.5;
 580 |         [contentView addSubview:verticalLine];
 581 |     }
 582 |     
 583 |     for (int i = 0; i < ceil(((double)self.hotSearches.count / PYRectangleTagMaxCol)) - 1; i++) {
 584 |         UIImageView *verticalLine = [[UIImageView alloc] initWithImage:[NSBundle py_imageNamed:@"cell-content-line"]];
 585 |         verticalLine.py_height = 0.5;
 586 |         verticalLine.alpha = 0.7;
 587 |         verticalLine.py_y = rectangleTagH * (i + 1);
 588 |         verticalLine.py_width = contentView.py_width;
 589 |         [contentView addSubview:verticalLine];
 590 |     }
 591 |     [self layoutForDemand];
 592 |     // Note:When the operating system for the iOS 9.x series tableHeaderView height settings are invalid, you need to reset the tableHeaderView
 593 |     [self.baseSearchTableView setTableHeaderView:self.baseSearchTableView.tableHeaderView];
 594 | }
 595 | 
 596 | - (void)setupHotSearchRankTags
 597 | {
 598 |     UIView *contentView = self.hotSearchTagsContentView;
 599 |     [self.hotSearchTagsContentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
 600 |     
 601 |     NSMutableArray *rankTextLabelsM = [NSMutableArray array];
 602 |     NSMutableArray *rankTagM = [NSMutableArray array];
 603 |     NSMutableArray *rankViewM = [NSMutableArray array];
 604 |     for (int i = 0; i < self.hotSearches.count; i++) {
 605 |         UIView *rankView = [[UIView alloc] init];
 606 |         rankView.py_height = 40;
 607 |         rankView.py_width = (self.baseSearchTableView.py_width - PYSEARCH_MARGIN * 3) * 0.5;
 608 |         rankView.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 609 |         [contentView addSubview:rankView];
 610 |         // rank tag
 611 |         UILabel *rankTag = [[UILabel alloc] init];
 612 |         rankTag.textAlignment = NSTextAlignmentCenter;
 613 |         rankTag.font = [UIFont systemFontOfSize:10];
 614 |         rankTag.layer.cornerRadius = 3;
 615 |         rankTag.clipsToBounds = YES;
 616 |         rankTag.text = [NSString stringWithFormat:@"%d", i + 1];
 617 |         [rankTag sizeToFit];
 618 |         rankTag.py_width = rankTag.py_height += PYSEARCH_MARGIN * 0.5;
 619 |         rankTag.py_y = (rankView.py_height - rankTag.py_height) * 0.5;
 620 |         [rankView addSubview:rankTag];
 621 |         [rankTagM addObject:rankTag];
 622 |         // rank text
 623 |         UILabel *rankTextLabel = [[UILabel alloc] init];
 624 |         rankTextLabel.text = self.hotSearches[i];
 625 |         rankTextLabel.userInteractionEnabled = YES;
 626 |         [rankTextLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tagDidCLick:)]];
 627 |         rankTextLabel.textAlignment = NSTextAlignmentLeft;
 628 |         rankTextLabel.backgroundColor = [UIColor clearColor];
 629 |         rankTextLabel.textColor = PYTextColor;
 630 |         rankTextLabel.font = [UIFont systemFontOfSize:14];
 631 |         rankTextLabel.py_x = CGRectGetMaxX(rankTag.frame) + PYSEARCH_MARGIN;
 632 |         rankTextLabel.py_width = (self.baseSearchTableView.py_width - PYSEARCH_MARGIN * 3) * 0.5 - rankTextLabel.py_x;
 633 |         rankTextLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 634 |         rankTextLabel.py_height = rankView.py_height;
 635 |         [rankTextLabelsM addObject:rankTextLabel];
 636 |         [rankView addSubview:rankTextLabel];
 637 |         
 638 |         UIImageView *line = [[UIImageView alloc] initWithImage:[NSBundle py_imageNamed:@"cell-content-line"]];
 639 |         line.py_height = 0.5;
 640 |         line.alpha = 0.7;
 641 |         line.py_x = -PYScreenW * 0.5;
 642 |         line.py_y = rankView.py_height - 1;
 643 |         line.py_width = self.baseSearchTableView.py_width;
 644 |         line.autoresizingMask = UIViewAutoresizingFlexibleWidth;
 645 |         [rankView addSubview:line];
 646 |         [rankViewM addObject:rankView];
 647 |         
 648 |         // set tag's background color and text color
 649 |         switch (i) {
 650 |             case 0: // NO.1
 651 |                 rankTag.backgroundColor = [UIColor py_colorWithHexString:self.rankTagBackgroundColorHexStrings[0]];
 652 |                 rankTag.textColor = [UIColor whiteColor];
 653 |                 break;
 654 |             case 1: // NO.2
 655 |                 rankTag.backgroundColor = [UIColor py_colorWithHexString:self.rankTagBackgroundColorHexStrings[1]];
 656 |                 rankTag.textColor = [UIColor whiteColor];
 657 |                 break;
 658 |             case 2: // NO.3
 659 |                 rankTag.backgroundColor = [UIColor py_colorWithHexString:self.rankTagBackgroundColorHexStrings[2]];
 660 |                 rankTag.textColor = [UIColor whiteColor];
 661 |                 break;
 662 |             default: // Other
 663 |                 rankTag.backgroundColor = [UIColor py_colorWithHexString:self.rankTagBackgroundColorHexStrings[3]];
 664 |                 rankTag.textColor = PYTextColor;
 665 |                 break;
 666 |         }
 667 |     }
 668 |     self.rankTextLabels = rankTextLabelsM;
 669 |     self.rankTags = rankTagM;
 670 |     self.rankViews = rankViewM;
 671 |     
 672 |     for (int i = 0; i < self.rankViews.count; i++) { // default is two column
 673 |         UIView *rankView = self.rankViews[i];
 674 |         rankView.py_x = (PYSEARCH_MARGIN + rankView.py_width) * (i % 2);
 675 |         rankView.py_y = rankView.py_height * (i / 2);
 676 |     }
 677 |     
 678 |     contentView.py_height = CGRectGetMaxY(self.rankViews.lastObject.frame);
 679 |     self.hotSearchView.py_height = CGRectGetMaxY(contentView.frame) + PYSEARCH_MARGIN * 2;
 680 |     self.baseSearchTableView.tableHeaderView.py_height = self.headerView.py_height = MAX(CGRectGetMaxY(self.hotSearchView.frame), CGRectGetMaxY(self.searchHistoryView.frame));
 681 |     [self layoutForDemand];
 682 |     
 683 |     // Note:When the operating system for the iOS 9.x series tableHeaderView height settings are invalid, you need to reset the tableHeaderView
 684 |     [self.baseSearchTableView setTableHeaderView:self.baseSearchTableView.tableHeaderView];
 685 | }
 686 | 
 687 | - (void)setupHotSearchNormalTags
 688 | {
 689 |     self.hotSearchTags = [self addAndLayoutTagsWithTagsContentView:self.hotSearchTagsContentView tagTexts:self.hotSearches];
 690 |     [self setHotSearchStyle:self.hotSearchStyle];
 691 | }
 692 | 
 693 | - (void)setupSearchHistoryTags
 694 | {
 695 |     self.baseSearchTableView.tableFooterView = nil;
 696 |     self.searchHistoryTagsContentView.py_y = PYSEARCH_MARGIN;
 697 |     self.emptyButton.py_y = self.searchHistoryHeader.py_y - PYSEARCH_MARGIN * 0.5;
 698 |     self.searchHistoryTagsContentView.py_y = CGRectGetMaxY(self.emptyButton.frame) + PYSEARCH_MARGIN;
 699 |     self.searchHistoryTags = [self addAndLayoutTagsWithTagsContentView:self.searchHistoryTagsContentView tagTexts:[self.searchHistories copy]];
 700 | }
 701 | 
 702 | - (NSArray *)addAndLayoutTagsWithTagsContentView:(UIView *)contentView tagTexts:(NSArray<NSString *> *)tagTexts;
 703 | {
 704 |     [contentView.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)];
 705 |     NSMutableArray *tagsM = [NSMutableArray array];
 706 |     for (int i = 0; i < tagTexts.count; i++) {
 707 |         UILabel *label = [self labelWithTitle:tagTexts[i]];
 708 |         [label addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tagDidCLick:)]];
 709 |         [contentView addSubview:label];
 710 |         [tagsM addObject:label];
 711 |     }
 712 |     
 713 |     CGFloat currentX = 0;
 714 |     CGFloat currentY = 0;
 715 |     CGFloat countRow = 0;
 716 |     CGFloat countCol = 0;
 717 |     
 718 |     for (int i = 0; i < contentView.subviews.count; i++) {
 719 |         UILabel *subView = contentView.subviews[i];
 720 |         // When the number of search words is too large, the width is width of the contentView
 721 |         if (subView.py_width > contentView.py_width) subView.py_width = contentView.py_width;
 722 |         if (currentX + subView.py_width + PYSEARCH_MARGIN * countRow > contentView.py_width) {
 723 |             subView.py_x = 0;
 724 |             subView.py_y = (currentY += subView.py_height) + PYSEARCH_MARGIN * ++countCol;
 725 |             currentX = subView.py_width;
 726 |             countRow = 1;
 727 |         } else {
 728 |             subView.py_x = (currentX += subView.py_width) - subView.py_width + PYSEARCH_MARGIN * countRow;
 729 |             subView.py_y = currentY + PYSEARCH_MARGIN * countCol;
 730 |             countRow ++;
 731 |         }
 732 |     }
 733 |     
 734 |     contentView.py_height = CGRectGetMaxY(contentView.subviews.lastObject.frame);
 735 |     if (self.hotSearchTagsContentView == contentView) { // popular search tag
 736 |         self.hotSearchView.py_height = CGRectGetMaxY(contentView.frame) + PYSEARCH_MARGIN * 2;
 737 |     } else if (self.searchHistoryTagsContentView == contentView) { // search history tag
 738 |         self.searchHistoryView.py_height = CGRectGetMaxY(contentView.frame) + PYSEARCH_MARGIN * 2;
 739 |     }
 740 |     
 741 |     [self layoutForDemand];
 742 |     self.baseSearchTableView.tableHeaderView.py_height = self.headerView.py_height = MAX(CGRectGetMaxY(self.hotSearchView.frame), CGRectGetMaxY(self.searchHistoryView.frame));
 743 |     self.baseSearchTableView.tableHeaderView.hidden = NO;
 744 |     
 745 |     // Note:When the operating system for the iOS 9.x series tableHeaderView height settings are invalid, you need to reset the tableHeaderView
 746 |     [self.baseSearchTableView setTableHeaderView:self.baseSearchTableView.tableHeaderView];
 747 |     return [tagsM copy];
 748 | }
 749 | 
 750 | - (void)layoutForDemand {
 751 |     if (NO == self.swapHotSeachWithSearchHistory) {
 752 |         self.hotSearchView.py_y = PYSEARCH_MARGIN * 2;
 753 |         self.searchHistoryView.py_y = self.hotSearches.count > 0 && self.showHotSearch ? CGRectGetMaxY(self.hotSearchView.frame) : PYSEARCH_MARGIN * 1.5;
 754 |     } else { // swap popular search whith search history
 755 |         self.searchHistoryView.py_y = PYSEARCH_MARGIN * 1.5;
 756 |         self.hotSearchView.py_y = self.searchHistories.count > 0 && self.showSearchHistory ? CGRectGetMaxY(self.searchHistoryView.frame) : PYSEARCH_MARGIN * 2;
 757 |     }
 758 | }
 759 | 
 760 | #pragma mark - setter
 761 | - (void)setRankTextLabels:(NSArray<UILabel *> *)rankTextLabels
 762 | {
 763 |     // popular search tagLabel's tag is 1, search history tagLabel's tag is 0.
 764 |     for (UILabel *rankLabel in rankTextLabels) {
 765 |         rankLabel.tag = 1;
 766 |     }
 767 |     _rankTextLabels= rankTextLabels;
 768 | }
 769 | 
 770 | - (void)setSearchBarCornerRadius:(CGFloat)searchBarCornerRadius
 771 | {
 772 |     _searchBarCornerRadius = searchBarCornerRadius;
 773 |     
 774 |     for (UIView *subView in self.searchTextField.subviews) {
 775 |         if ([NSStringFromClass([subView class]) isEqualToString:@"_UISearchBarSearchFieldBackgroundView"]) {
 776 |             subView.layer.cornerRadius = searchBarCornerRadius;
 777 |             subView.clipsToBounds = YES;
 778 |             break;
 779 |         }
 780 |     }
 781 | }
 782 | 
 783 | - (void)setSwapHotSeachWithSearchHistory:(BOOL)swapHotSeachWithSearchHistory
 784 | {
 785 |     _swapHotSeachWithSearchHistory = swapHotSeachWithSearchHistory;
 786 |     
 787 |     self.hotSearches = self.hotSearches;
 788 |     self.searchHistories = self.searchHistories;
 789 | }
 790 | 
 791 | - (void)setHotSearchTitle:(NSString *)hotSearchTitle
 792 | {
 793 |     _hotSearchTitle = [hotSearchTitle copy];
 794 |     
 795 |     self.hotSearchHeader.text = _hotSearchTitle;
 796 | }
 797 | 
 798 | - (void)setSearchHistoryTitle:(NSString *)searchHistoryTitle
 799 | {
 800 |     _searchHistoryTitle = [searchHistoryTitle copy];
 801 |     
 802 |     if (PYSearchHistoryStyleCell == self.searchHistoryStyle) {
 803 |         [self.baseSearchTableView reloadData];
 804 |     } else {
 805 |         self.searchHistoryHeader.text = _searchHistoryTitle;
 806 |     }
 807 | }
 808 | 
 809 | - (void)setShowSearchResultWhenSearchTextChanged:(BOOL)showSearchResultWhenSearchTextChanged
 810 | {
 811 |     _showSearchResultWhenSearchTextChanged = showSearchResultWhenSearchTextChanged;
 812 |     
 813 |     if (YES == _showSearchResultWhenSearchTextChanged) {
 814 |         self.searchSuggestionHidden = YES;
 815 |     }
 816 | }
 817 | 
 818 | - (void)setShowHotSearch:(BOOL)showHotSearch
 819 | {
 820 |     _showHotSearch = showHotSearch;
 821 |     
 822 |     [self setHotSearches:self.hotSearches];
 823 |     [self setSearchHistoryStyle:self.searchHistoryStyle];
 824 | }
 825 | 
 826 | - (void)setShowSearchHistory:(BOOL)showSearchHistory
 827 | {
 828 |     _showSearchHistory = showSearchHistory;
 829 |     
 830 |     [self setHotSearches:self.hotSearches];
 831 |     [self setSearchHistoryStyle:self.searchHistoryStyle];
 832 | }
 833 | 
 834 | - (void)setCancelBarButtonItem:(UIBarButtonItem *)cancelBarButtonItem
 835 | {
 836 |     _cancelBarButtonItem = cancelBarButtonItem;
 837 |     self.navigationItem.rightBarButtonItem = cancelBarButtonItem;
 838 | }
 839 | 
 840 | - (void)setCancelButton:(UIButton *)cancelButton
 841 | {
 842 |     _cancelButton = cancelButton;
 843 |     self.navigationItem.rightBarButtonItem.customView = cancelButton;
 844 | }
 845 | 
 846 | - (void)setSearchHistoriesCachePath:(NSString *)searchHistoriesCachePath
 847 | {
 848 |     _searchHistoriesCachePath = [searchHistoriesCachePath copy];
 849 |     
 850 |     self.searchHistories = nil;
 851 |     if (PYSearchHistoryStyleCell == self.searchHistoryStyle) {
 852 |         [self.baseSearchTableView reloadData];
 853 |     } else {
 854 |         [self setSearchHistoryStyle:self.searchHistoryStyle];
 855 |     }
 856 | }
 857 | 
 858 | - (void)setHotSearchTags:(NSArray<UILabel *> *)hotSearchTags
 859 | {
 860 |     // popular search tagLabel's tag is 1, search history tagLabel's tag is 0.
 861 |     for (UILabel *tagLabel in hotSearchTags) {
 862 |         tagLabel.tag = 1;
 863 |     }
 864 |     _hotSearchTags = hotSearchTags;
 865 | }
 866 | 
 867 | - (void)setSearchBarBackgroundColor:(UIColor *)searchBarBackgroundColor
 868 | {
 869 |     _searchBarBackgroundColor = searchBarBackgroundColor;
 870 |     _searchTextField.backgroundColor = searchBarBackgroundColor;
 871 | }
 872 | 
 873 | - (void)setSearchSuggestions:(NSArray<NSString *> *)searchSuggestions
 874 | {
 875 |     if ([self.dataSource respondsToSelector:@selector(searchSuggestionView:cellForRowAtIndexPath:)]) {
 876 |         // set searchSuggestion is nil when cell of suggestion view is custom.
 877 |         _searchSuggestions = nil;
 878 |         return;
 879 |     }
 880 |     
 881 |     _searchSuggestions = [searchSuggestions copy];
 882 |     self.searchSuggestionVC.searchSuggestions = [searchSuggestions copy];
 883 |     
 884 |     self.baseSearchTableView.hidden = !self.searchSuggestionHidden && [self.searchSuggestionVC.tableView numberOfRowsInSection:0];
 885 |     self.searchSuggestionVC.view.hidden = self.searchSuggestionHidden || ![self.searchSuggestionVC.tableView numberOfRowsInSection:0];
 886 | }
 887 | 
 888 | - (void)setRankTagBackgroundColorHexStrings:(NSArray<NSString *> *)rankTagBackgroundColorHexStrings
 889 | {
 890 |     if (rankTagBackgroundColorHexStrings.count < 4) {
 891 |         NSArray *colorStrings = @[@"#f14230", @"#ff8000", @"#ffcc01", @"#ebebeb"];
 892 |         _rankTagBackgroundColorHexStrings = colorStrings;
 893 |     } else {
 894 |         _rankTagBackgroundColorHexStrings = @[rankTagBackgroundColorHexStrings[0], rankTagBackgroundColorHexStrings[1], rankTagBackgroundColorHexStrings[2], rankTagBackgroundColorHexStrings[3]];
 895 |     }
 896 |     
 897 |     self.hotSearches = self.hotSearches;
 898 | }
 899 | 
 900 | - (void)setHotSearches:(NSArray *)hotSearches
 901 | {
 902 |     _hotSearches = hotSearches;
 903 |     if (0 == hotSearches.count || !self.showHotSearch) {
 904 |         self.hotSearchHeader.hidden = YES;
 905 |         self.hotSearchTagsContentView.hidden = YES;
 906 |         if (PYSearchHistoryStyleCell == self.searchHistoryStyle) {
 907 |             UIView *tableHeaderView = self.baseSearchTableView.tableHeaderView;
 908 |             tableHeaderView.py_height = PYSEARCH_MARGIN * 1.5;
 909 |             [self.baseSearchTableView setTableHeaderView:tableHeaderView];
 910 |         }
 911 |         return;
 912 |     };
 913 |     
 914 |     self.baseSearchTableView.tableHeaderView.hidden = NO;
 915 |     self.hotSearchHeader.hidden = NO;
 916 |     self.hotSearchTagsContentView.hidden = NO;
 917 |     if (PYHotSearchStyleDefault == self.hotSearchStyle
 918 |         || PYHotSearchStyleColorfulTag == self.hotSearchStyle
 919 |         || PYHotSearchStyleBorderTag == self.hotSearchStyle
 920 |         || PYHotSearchStyleARCBorderTag == self.hotSearchStyle) {
 921 |         [self setupHotSearchNormalTags];
 922 |     } else if (PYHotSearchStyleRankTag == self.hotSearchStyle) {
 923 |         [self setupHotSearchRankTags];
 924 |     } else if (PYHotSearchStyleRectangleTag == self.hotSearchStyle) {
 925 |         [self setupHotSearchRectangleTags];
 926 |     }
 927 |     [self setSearchHistoryStyle:self.searchHistoryStyle];
 928 | }
 929 | 
 930 | - (void)setSearchHistoryStyle:(PYSearchHistoryStyle)searchHistoryStyle
 931 | {
 932 |     _searchHistoryStyle = searchHistoryStyle;
 933 |     
 934 |     if (!self.searchHistories.count || !self.showSearchHistory || UISearchBarStyleDefault == searchHistoryStyle) {
 935 |         self.searchHistoryHeader.hidden = YES;
 936 |         self.searchHistoryTagsContentView.hidden = YES;
 937 |         self.searchHistoryView.hidden = YES;
 938 |         self.emptyButton.hidden = YES;
 939 |         return;
 940 |     };
 941 |     
 942 |     self.searchHistoryHeader.hidden = NO;
 943 |     self.searchHistoryTagsContentView.hidden = NO;
 944 |     self.searchHistoryView.hidden = NO;
 945 |     self.emptyButton.hidden = NO;
 946 |     [self setupSearchHistoryTags];
 947 |     
 948 |     switch (searchHistoryStyle) {
 949 |         case PYSearchHistoryStyleColorfulTag:
 950 |             for (UILabel *tag in self.searchHistoryTags) {
 951 |                 tag.textColor = [UIColor whiteColor];
 952 |                 tag.layer.borderColor = nil;
 953 |                 tag.layer.borderWidth = 0.0;
 954 |                 tag.backgroundColor = PYSEARCH_COLORPolRandomColor;
 955 |             }
 956 |             break;
 957 |         case PYSearchHistoryStyleBorderTag:
 958 |             for (UILabel *tag in self.searchHistoryTags) {
 959 |                 tag.backgroundColor = [UIColor clearColor];
 960 |                 tag.layer.borderColor = PYSEARCH_COLOR(223, 223, 223).CGColor;
 961 |                 tag.layer.borderWidth = 0.5;
 962 |             }
 963 |             break;
 964 |         case PYSearchHistoryStyleARCBorderTag:
 965 |             for (UILabel *tag in self.searchHistoryTags) {
 966 |                 tag.backgroundColor = [UIColor clearColor];
 967 |                 tag.layer.borderColor = PYSEARCH_COLOR(223, 223, 223).CGColor;
 968 |                 tag.layer.borderWidth = 0.5;
 969 |                 tag.layer.cornerRadius = tag.py_height * 0.5;
 970 |             }
 971 |             break;
 972 |         default:
 973 |             break;
 974 |     }
 975 | }
 976 | 
 977 | - (void)setHotSearchStyle:(PYHotSearchStyle)hotSearchStyle
 978 | {
 979 |     _hotSearchStyle = hotSearchStyle;
 980 |     
 981 |     switch (hotSearchStyle) {
 982 |         case PYHotSearchStyleColorfulTag:
 983 |             for (UILabel *tag in self.hotSearchTags) {
 984 |                 tag.textColor = [UIColor whiteColor];
 985 |                 tag.layer.borderColor = nil;
 986 |                 tag.layer.borderWidth = 0.0;
 987 |                 tag.backgroundColor = PYSEARCH_COLORPolRandomColor;
 988 |             }
 989 |             break;
 990 |         case PYHotSearchStyleBorderTag:
 991 |             for (UILabel *tag in self.hotSearchTags) {
 992 |                 tag.backgroundColor = [UIColor clearColor];
 993 |                 tag.layer.borderColor = PYSEARCH_COLOR(223, 223, 223).CGColor;
 994 |                 tag.layer.borderWidth = 0.5;
 995 |             }
 996 |             break;
 997 |         case PYHotSearchStyleARCBorderTag:
 998 |             for (UILabel *tag in self.hotSearchTags) {
 999 |                 tag.backgroundColor = [UIColor clearColor];
1000 |                 tag.layer.borderColor = PYSEARCH_COLOR(223, 223, 223).CGColor;
1001 |                 tag.layer.borderWidth = 0.5;
1002 |                 tag.layer.cornerRadius = tag.py_height * 0.5;
1003 |             }
1004 |             break;
1005 |         case PYHotSearchStyleRectangleTag:
1006 |             self.hotSearches = self.hotSearches;
1007 |             break;
1008 |         case PYHotSearchStyleRankTag:
1009 |             self.rankTagBackgroundColorHexStrings = nil;
1010 |             break;
1011 |             
1012 |         default:
1013 |             break;
1014 |     }
1015 | }
1016 | 
1017 | - (void)setSearchViewControllerShowMode:(PYSearchViewControllerShowMode)searchViewControllerShowMode
1018 | {
1019 |     _searchViewControllerShowMode = searchViewControllerShowMode;
1020 |     if (_searchViewControllerShowMode == PYSearchViewControllerShowModeModal) { // modal
1021 |         self.navigationItem.hidesBackButton = YES;
1022 |         self.navigationItem.rightBarButtonItem = _cancelBarButtonItem;
1023 |         self.navigationItem.leftBarButtonItem = nil;
1024 |     } else if (_searchViewControllerShowMode == PYSearchViewControllerShowModePush) { // push
1025 |         self.navigationItem.hidesBackButton = YES;
1026 |         self.navigationItem.leftBarButtonItem = _backBarButtonItem;
1027 |         self.navigationItem.rightBarButtonItem = nil;
1028 |     }
1029 | }
1030 | 
1031 | - (void)cancelDidClick
1032 | {
1033 |     [self.searchBar resignFirstResponder];
1034 |     
1035 |     if ([self.delegate respondsToSelector:@selector(didClickCancel:)]) {
1036 |         [self.delegate didClickCancel:self];
1037 |         return;
1038 |     }
1039 |     
1040 |     [self dismissViewControllerAnimated:YES completion:nil];
1041 | }
1042 | 
1043 | - (void)backDidClick
1044 | {
1045 |     [self.searchBar resignFirstResponder];
1046 |     
1047 |     if ([self.delegate respondsToSelector:@selector(didClickBack:)]) {
1048 |         [self.delegate didClickBack:self];
1049 |         return;
1050 |     }
1051 |     
1052 |     [self.navigationController popViewControllerAnimated:YES];
1053 | }
1054 | 
1055 | - (void)keyboardDidShow:(NSNotification *)noti
1056 | {
1057 |     NSDictionary *info = noti.userInfo;
1058 |     self.keyboardHeight = [info[UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
1059 |     self.keyboardShowing = YES;
1060 |     // Adjust the content inset of suggestion view
1061 |     self.searchSuggestionVC.tableView.contentInset = UIEdgeInsetsMake(-30, 0, self.keyboardHeight + 30, 0);
1062 | }
1063 | 
1064 | 
1065 | - (void)emptySearchHistoryDidClick
1066 | {
1067 |     [self.searchHistories removeAllObjects];
1068 |     [NSKeyedArchiver archiveRootObject:self.searchHistories toFile:self.searchHistoriesCachePath];
1069 |     if (PYSearchHistoryStyleCell == self.searchHistoryStyle) {
1070 |         [self.baseSearchTableView reloadData];
1071 |     } else {
1072 |         self.searchHistoryStyle = self.searchHistoryStyle;
1073 |     }
1074 |     if (YES == self.swapHotSeachWithSearchHistory) {
1075 |         self.hotSearches = self.hotSearches;
1076 |     }
1077 |     PYSEARCH_LOG(@"%@", [NSBundle py_localizedStringForKey:PYSearchEmptySearchHistoryLogText]);
1078 | }
1079 | 
1080 | - (void)tagDidCLick:(UITapGestureRecognizer *)gr
1081 | {
1082 |     UILabel *label = (UILabel *)gr.view;
1083 |     self.searchBar.text = label.text;
1084 |     // popular search tagLabel's tag is 1, search history tagLabel's tag is 0.
1085 |     if (1 == label.tag) {
1086 |         if ([self.delegate respondsToSelector:@selector(searchViewController:didSelectHotSearchAtIndex:searchText:)]) {
1087 |             [self.delegate searchViewController:self didSelectHotSearchAtIndex:[self.hotSearchTags indexOfObject:label] searchText:label.text];
1088 |             [self saveSearchCacheAndRefreshView];
1089 |         } else {
1090 |             [self searchBarSearchButtonClicked:self.searchBar];
1091 |         }
1092 |     } else {
1093 |         if ([self.delegate respondsToSelector:@selector(searchViewController:didSelectSearchHistoryAtIndex:searchText:)]) {
1094 |             [self.delegate searchViewController:self didSelectSearchHistoryAtIndex:[self.searchHistoryTags indexOfObject:label] searchText:label.text];
1095 |             [self saveSearchCacheAndRefreshView];
1096 |         } else {
1097 |             [self searchBarSearchButtonClicked:self.searchBar];
1098 |         }
1099 |     }
1100 |     PYSEARCH_LOG(@"Search %@", label.text);
1101 | }
1102 | 
1103 | - (UILabel *)labelWithTitle:(NSString *)title
1104 | {
1105 |     UILabel *label = [[UILabel alloc] init];
1106 |     label.userInteractionEnabled = YES;
1107 |     label.font = [UIFont systemFontOfSize:12];
1108 |     label.text = title;
1109 |     label.textColor = [UIColor grayColor];
1110 |     label.backgroundColor = [UIColor py_colorWithHexString:@"#fafafa"];
1111 |     label.layer.cornerRadius = 3;
1112 |     label.clipsToBounds = YES;
1113 |     label.textAlignment = NSTextAlignmentCenter;
1114 |     [label sizeToFit];
1115 |     label.py_width += 20;
1116 |     label.py_height += 14;
1117 |     return label;
1118 | }
1119 | 
1120 | - (void)saveSearchCacheAndRefreshView
1121 | {
1122 |     UISearchBar *searchBar = self.searchBar;
1123 |     [searchBar resignFirstResponder];
1124 |     NSString *searchText = searchBar.text;
1125 |     if (self.removeSpaceOnSearchString) { // remove sapce on search string
1126 |         searchText = [searchBar.text stringByReplacingOccurrencesOfString:@" " withString:@""];
1127 |     }
1128 |     if (self.showSearchHistory && searchText.length > 0) {
1129 |         [self.searchHistories removeObject:searchText];
1130 |         [self.searchHistories insertObject:searchText atIndex:0];
1131 |         
1132 |         if (self.searchHistories.count > self.searchHistoriesCount) {
1133 |             [self.searchHistories removeLastObject];
1134 |         }
1135 |         [NSKeyedArchiver archiveRootObject:self.searchHistories toFile:self.searchHistoriesCachePath];
1136 |         
1137 |         if (PYSearchHistoryStyleCell == self.searchHistoryStyle) {
1138 |             [self.baseSearchTableView reloadData];
1139 |         } else {
1140 |             self.searchHistoryStyle = self.searchHistoryStyle;
1141 |         }
1142 |     }
1143 |     
1144 |     [self handleSearchResultShow];
1145 | }
1146 | 
1147 | - (void)handleSearchResultShow
1148 | {
1149 |     switch (self.searchResultShowMode) {
1150 |         case PYSearchResultShowModePush:
1151 |             self.searchResultController.view.hidden = NO;
1152 |             [self.navigationController pushViewController:self.searchResultController animated:YES];
1153 |             break;
1154 |         case PYSearchResultShowModeEmbed:
1155 |             if (self.searchResultController) {
1156 |                 [self.view addSubview:self.searchResultController.view];
1157 |                 [self addChildViewController:self.searchResultController];
1158 |                 self.searchResultController.view.hidden = NO;
1159 |                 self.searchResultController.view.py_y = NO == self.navigationController.navigationBar.translucent ? 0 : CGRectGetMaxY(self.navigationController.navigationBar.frame);
1160 |                 self.searchResultController.view.py_height = self.view.py_height - self.searchResultController.view.py_y;
1161 |                 self.searchSuggestionVC.view.hidden = YES;
1162 |             } else {
1163 |                 PYSEARCH_LOG(@"PYSearchDebug: searchResultController cannot be nil when searchResultShowMode is PYSearchResultShowModeEmbed.");
1164 |             }
1165 |             break;
1166 |         case PYSearchResultShowModeCustom:
1167 |             
1168 |             break;
1169 |         default:
1170 |             break;
1171 |     }
1172 | }
1173 | 
1174 | #pragma mark - PYSearchSuggestionViewDataSource
1175 | - (NSInteger)numberOfSectionsInSearchSuggestionView:(UITableView *)searchSuggestionView
1176 | {
1177 |     if ([self.dataSource respondsToSelector:@selector(numberOfSectionsInSearchSuggestionView:)]) {
1178 |         return [self.dataSource numberOfSectionsInSearchSuggestionView:searchSuggestionView];
1179 |     }
1180 |     return 1;
1181 | }
1182 | 
1183 | - (NSInteger)searchSuggestionView:(UITableView *)searchSuggestionView numberOfRowsInSection:(NSInteger)section
1184 | {
1185 |     if ([self.dataSource respondsToSelector:@selector(searchSuggestionView:numberOfRowsInSection:)]) {
1186 |         NSInteger numberOfRow = [self.dataSource searchSuggestionView:searchSuggestionView numberOfRowsInSection:section];
1187 |         searchSuggestionView.hidden = self.searchSuggestionHidden || !self.searchBar.text.length || 0 == numberOfRow;
1188 |         self.baseSearchTableView.hidden = !searchSuggestionView.hidden;
1189 |         return numberOfRow;
1190 |     }
1191 |     return self.searchSuggestions.count;
1192 | }
1193 | 
1194 | - (UITableViewCell *)searchSuggestionView:(UITableView *)searchSuggestionView cellForRowAtIndexPath:(NSIndexPath *)indexPath
1195 | {
1196 |     if ([self.dataSource respondsToSelector:@selector(searchSuggestionView:cellForRowAtIndexPath:)]) {
1197 |         return [self.dataSource searchSuggestionView:searchSuggestionView cellForRowAtIndexPath:indexPath];
1198 |     }
1199 |     return nil;
1200 | }
1201 | 
1202 | - (CGFloat)searchSuggestionView:(UITableView *)searchSuggestionView heightForRowAtIndexPath:(NSIndexPath *)indexPath
1203 | {
1204 |     if ([self.dataSource respondsToSelector:@selector(searchSuggestionView:heightForRowAtIndexPath:)]) {
1205 |         return [self.dataSource searchSuggestionView:searchSuggestionView heightForRowAtIndexPath:indexPath];
1206 |     }
1207 |     return 44.0;
1208 | }
1209 | 
1210 | #pragma mark - UISearchBarDelegate
1211 | - (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
1212 | {
1213 |     if ([self.delegate respondsToSelector:@selector(searchViewController:didSearchWithSearchBar:searchText:)]) {
1214 |         [self.delegate searchViewController:self didSearchWithSearchBar:searchBar searchText:searchBar.text];
1215 |         [self saveSearchCacheAndRefreshView];
1216 |         return;
1217 |     }
1218 |     if (self.didSearchBlock) self.didSearchBlock(self, searchBar, searchBar.text);
1219 |     [self saveSearchCacheAndRefreshView];
1220 | }
1221 | 
1222 | - (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
1223 | {
1224 |     if (PYSearchResultShowModeEmbed == self.searchResultShowMode && self.showSearchResultWhenSearchTextChanged) {
1225 |         [self handleSearchResultShow];
1226 |         self.searchResultController.view.hidden = 0 == searchText.length;
1227 |     } else if (self.searchResultController) {
1228 |         self.searchResultController.view.hidden = YES;
1229 |     }
1230 |     self.baseSearchTableView.hidden = searchText.length && !self.searchSuggestionHidden && [self.searchSuggestionVC.tableView numberOfRowsInSection:0];
1231 |     self.searchSuggestionVC.view.hidden = self.searchSuggestionHidden || !searchText.length || ![self.searchSuggestionVC.tableView numberOfRowsInSection:0];
1232 |     if (self.searchSuggestionVC.view.hidden) {
1233 |         self.searchSuggestions = nil;
1234 |     }
1235 |     [self.view bringSubviewToFront:self.searchSuggestionVC.view];
1236 |     if ([self.delegate respondsToSelector:@selector(searchViewController:searchTextDidChange:searchText:)]) {
1237 |         [self.delegate searchViewController:self searchTextDidChange:searchBar searchText:searchText];
1238 |     }
1239 | }
1240 | 
1241 | - (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
1242 | {
1243 |     if (PYSearchResultShowModeEmbed == self.searchResultShowMode) {
1244 |         self.searchResultController.view.hidden = 0 == searchBar.text.length || !self.showSearchResultWhenSearchBarRefocused;
1245 |         self.searchSuggestionVC.view.hidden = self.searchSuggestionHidden || !searchBar.text.length || ![self.searchSuggestionVC.tableView numberOfRowsInSection:0];
1246 |         if (self.searchSuggestionVC.view.hidden) {
1247 |             self.searchSuggestions = nil;
1248 |         }
1249 |         self.baseSearchTableView.hidden = searchBar.text.length && !self.searchSuggestionHidden && ![self.searchSuggestionVC.tableView numberOfRowsInSection:0];
1250 |     }
1251 |     [self setSearchSuggestions:self.searchSuggestions];
1252 |     return YES;
1253 | }
1254 | 
1255 | - (void)closeDidClick:(UIButton *)sender
1256 | {
1257 |     UITableViewCell *cell = (UITableViewCell *)sender.superview;
1258 |     [self.searchHistories removeObject:cell.textLabel.text];
1259 |     [NSKeyedArchiver archiveRootObject:self.searchHistories toFile:self.searchHistoriesCachePath];
1260 |     [self.baseSearchTableView reloadData];
1261 | }
1262 | 
1263 | #pragma mark - Table view data source
1264 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
1265 |     return  1;
1266 | }
1267 | 
1268 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
1269 |     self.baseSearchTableView.tableFooterView.hidden = 0 == self.searchHistories.count || !self.showSearchHistory;
1270 |     return self.showSearchHistory && PYSearchHistoryStyleCell == self.searchHistoryStyle ? self.searchHistories.count : 0;
1271 | }
1272 | 
1273 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
1274 | {
1275 |     static NSString *cellID = @"PYSearchHistoryCellID";
1276 |     
1277 |     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
1278 |     if (!cell) {
1279 |         cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID];
1280 |         cell.textLabel.textColor = PYTextColor;
1281 |         cell.textLabel.font = [UIFont systemFontOfSize:14];
1282 |         cell.backgroundColor = [UIColor clearColor];
1283 |         
1284 |         UIButton *closetButton = [[UIButton alloc] init];
1285 |         closetButton.py_size = CGSizeMake(cell.py_height, cell.py_height);
1286 |         [closetButton setImage:[NSBundle py_imageNamed:@"close"] forState:UIControlStateNormal];
1287 |         UIImageView *closeView = [[UIImageView alloc] initWithImage:[NSBundle py_imageNamed:@"close"]];
1288 |         [closetButton addTarget:self action:@selector(closeDidClick:) forControlEvents:UIControlEventTouchUpInside];
1289 |         closeView.contentMode = UIViewContentModeCenter;
1290 |         cell.accessoryView = closetButton;
1291 |         UIImageView *line = [[UIImageView alloc] initWithImage:[NSBundle py_imageNamed:@"cell-content-line"]];
1292 |         line.py_height = 0.5;
1293 |         line.alpha = 0.7;
1294 |         line.py_x = PYSEARCH_MARGIN;
1295 |         line.py_y = 43;
1296 |         line.py_width = tableView.py_width;
1297 |         line.autoresizingMask = UIViewAutoresizingFlexibleWidth;
1298 |         [cell.contentView addSubview:line];
1299 |     }
1300 |     
1301 |     cell.imageView.image = [NSBundle py_imageNamed:@"search_history"];
1302 |     cell.textLabel.text = self.searchHistories[indexPath.row];
1303 |     
1304 |     return cell;
1305 | }
1306 | 
1307 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
1308 | {
1309 |     return self.showSearchHistory && self.searchHistories.count && PYSearchHistoryStyleCell == self.searchHistoryStyle ? (self.searchHistoryTitle.length ? self.searchHistoryTitle : [NSBundle py_localizedStringForKey:PYSearchSearchHistoryText]) : nil;
1310 | }
1311 | 
1312 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
1313 | {
1314 |     return self.searchHistories.count && self.showSearchHistory && PYSearchHistoryStyleCell == self.searchHistoryStyle ? 25 : 0.01;
1315 | }
1316 | 
1317 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section
1318 | {
1319 |     return 0.01;
1320 | }
1321 | 
1322 | #pragma mark - UITableViewDelegate
1323 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
1324 | {
1325 |     UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
1326 |     [tableView deselectRowAtIndexPath:indexPath animated:YES];
1327 |     self.searchBar.text = cell.textLabel.text;
1328 |     
1329 |     if ([self.delegate respondsToSelector:@selector(searchViewController:didSelectSearchHistoryAtIndex:searchText:)]) {
1330 |         [self.delegate searchViewController:self didSelectSearchHistoryAtIndex:indexPath.row searchText:cell.textLabel.text];
1331 |         [self saveSearchCacheAndRefreshView];
1332 |     } else {
1333 |         [self searchBarSearchButtonClicked:self.searchBar];
1334 |     }
1335 | }
1336 | 
1337 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView
1338 | {
1339 |     if (self.keyboardShowing) {
1340 |         // Adjust the content inset of suggestion view
1341 |         self.searchSuggestionVC.tableView.contentInset = UIEdgeInsetsMake(-30, 0, 30, 0);
1342 |         [self.searchBar resignFirstResponder];
1343 |     }
1344 | }
1345 | 
1346 | #pragma mark - UIGestureRecognizerDelegate
1347 | 
1348 | - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer*)gestureRecognizer
1349 | {
1350 |     return self.navigationController.childViewControllers.count > 1;
1351 | }
1352 | 
1353 | - (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
1354 | {
1355 |     return self.navigationController.viewControllers.count > 1;
1356 | }
1357 | 
1358 | @end
1359 | 


--------------------------------------------------------------------------------
/PYSearch/UIColor+PYSearchExtension.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import <UIKit/UIKit.h>
 8 | 
 9 | @interface UIColor (PYSearchExtension)
10 | 
11 | /**
12 |  Returns the corresponding color according to the hexadecimal string.
13 | 
14 |  @param hexString   hexadecimal string(eg:@"#ccff88")
15 |  @return new instance of `UIColor` class
16 |  */
17 | + (instancetype)py_colorWithHexString:(NSString *)hexString;
18 | 
19 | /**
20 |   Returns the corresponding color according to the hexadecimal string and alpha.
21 | 
22 |  @param hexString   hexadecimal string(eg:@"#ccff88")
23 |  @param alpha       alpha
24 |  @return new instance of `UIColor` class
25 |  */
26 | + (instancetype)py_colorWithHexString:(NSString *)hexString alpha:(CGFloat)alpha;
27 | 
28 | @end
29 | 


--------------------------------------------------------------------------------
/PYSearch/UIColor+PYSearchExtension.m:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import "UIColor+PYSearchExtension.h"
 8 | 
 9 | @implementation UIColor (PYSearchExtension)
10 | 
11 | + (instancetype)py_colorWithHexString:(NSString *)hexString
12 | {
13 |     NSString *colorString = [[hexString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] uppercaseString];
14 |     
15 |     if (colorString.length < 6) {
16 |         return [UIColor clearColor];
17 |     }
18 |     
19 |     if ([colorString hasPrefix:@"0X"]) {
20 |         colorString = [colorString substringFromIndex:2];
21 |     }
22 |     
23 |     if ([colorString hasPrefix:@"#"]) {
24 |         colorString = [colorString substringFromIndex:1];
25 |     }
26 |     
27 |     if (colorString.length != 6) {
28 |         return [UIColor clearColor];
29 |     }
30 |     
31 |     NSRange range;
32 |     range.location = 0;
33 |     range.length = 2;
34 |     // r
35 |     NSString *rString = [colorString substringWithRange:range];
36 |     
37 |     // g
38 |     range.location = 2;
39 |     NSString *gString = [colorString substringWithRange:range];
40 |     
41 |     // b
42 |     range.location = 4;
43 |     NSString *bString = [colorString substringWithRange:range];
44 |     
45 |     unsigned int r, g, b;
46 |     [[NSScanner scannerWithString:rString] scanHexInt:&r];
47 |     [[NSScanner scannerWithString:gString] scanHexInt:&g];
48 |     [[NSScanner scannerWithString:bString] scanHexInt:&b];
49 | 
50 |     return [UIColor colorWithRed:(float)r / 255.0 green:(float)g / 255.0 blue:(float)b / 255.0 alpha:1.0];
51 | }
52 | 
53 | + (instancetype)py_colorWithHexString:(NSString *)hexString alpha:(CGFloat)alpha
54 | {
55 |     return [[self py_colorWithHexString:hexString] colorWithAlphaComponent:alpha];
56 | }
57 | 
58 | @end
59 | 


--------------------------------------------------------------------------------
/PYSearch/UIView+PYSearchExtension.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import <UIKit/UIKit.h>
 8 | 
 9 | @interface UIView (PYSearchExtension)
10 | 
11 | @property (nonatomic, assign) CGFloat py_x;
12 | @property (nonatomic, assign) CGFloat py_y;
13 | @property (nonatomic, assign) CGFloat py_centerX;
14 | @property (nonatomic, assign) CGFloat py_centerY;
15 | @property (nonatomic, assign) CGFloat py_width;
16 | @property (nonatomic, assign) CGFloat py_height;
17 | @property (nonatomic, assign) CGSize  py_size;
18 | @property (nonatomic, assign) CGPoint py_origin;
19 | 
20 | @end
21 | 


--------------------------------------------------------------------------------
/PYSearch/UIView+PYSearchExtension.m:
--------------------------------------------------------------------------------
  1 | //
  2 | //  GitHub: https://github.com/iphone5solo/PYSearch
  3 | //  Created by CoderKo1o.
  4 | //  Copyright © 2016 iphone5solo. All rights reserved.
  5 | //
  6 | 
  7 | #import "UIView+PYSearchExtension.h"
  8 | 
  9 | @implementation UIView (PYSearchExtension)
 10 | 
 11 | - (void)setPy_x:(CGFloat)py_x
 12 | {
 13 |     CGRect frame = self.frame;
 14 |     frame.origin.x = py_x;
 15 |     self.frame = frame;
 16 | }
 17 | 
 18 | - (CGFloat)py_x
 19 | {
 20 |     return self.py_origin.x;
 21 | }
 22 | 
 23 | - (void)setPy_centerX:(CGFloat)py_centerX
 24 | {
 25 |     CGPoint center = self.center;
 26 |     center.x = py_centerX;
 27 |     self.center = center;
 28 | }
 29 | 
 30 | - (CGFloat)py_centerX
 31 | {
 32 |     return self.center.x;
 33 | }
 34 | 
 35 | -(void)setPy_centerY:(CGFloat)py_centerY
 36 | {
 37 |     CGPoint center = self.center;
 38 |     center.y = py_centerY;
 39 |     self.center = center;
 40 | }
 41 | 
 42 | - (CGFloat)py_centerY
 43 | {
 44 |     return self.center.y;
 45 | }
 46 | 
 47 | - (void)setPy_y:(CGFloat)py_y
 48 | {
 49 |     CGRect frame = self.frame;
 50 |     frame.origin.y = py_y;
 51 |     self.frame = frame;
 52 | }
 53 | 
 54 | - (CGFloat)py_y
 55 | {
 56 |     return self.frame.origin.y;
 57 | }
 58 | 
 59 | - (void)setPy_size:(CGSize)py_size
 60 | {
 61 |     CGRect frame = self.frame;
 62 |     frame.size = py_size;
 63 |     self.frame = frame;
 64 | 
 65 | }
 66 | 
 67 | - (CGSize)py_size
 68 | {
 69 |     return self.frame.size;
 70 | }
 71 | 
 72 | - (void)setPy_height:(CGFloat)py_height
 73 | {
 74 |     CGRect frame = self.frame;
 75 |     frame.size.height = py_height;
 76 |     self.frame = frame;
 77 | }
 78 | 
 79 | - (CGFloat)py_height
 80 | {
 81 |     return self.frame.size.height;
 82 | }
 83 | 
 84 | - (void)setPy_width:(CGFloat)py_width
 85 | {
 86 |     CGRect frame = self.frame;
 87 |     frame.size.width = py_width;
 88 |     self.frame = frame;
 89 | 
 90 | }
 91 | 
 92 | -(CGFloat)py_width
 93 | {
 94 |     return self.frame.size.width;
 95 | }
 96 | 
 97 | - (void)setPy_origin:(CGPoint)py_origin
 98 | {
 99 |     CGRect frame = self.frame;
100 |     frame.origin = py_origin;
101 |     self.frame = frame;
102 | }
103 | 
104 | - (CGPoint)py_origin
105 | {
106 |     return self.frame.origin;
107 | }
108 | 
109 | @end
110 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
  1 | // !$*UTF8*$!
  2 | {
  3 | 	archiveVersion = 1;
  4 | 	classes = {
  5 | 	};
  6 | 	objectVersion = 46;
  7 | 	objects = {
  8 | 
  9 | /* Begin PBXBuildFile section */
 10 | 		6B3EB2111DC498370080DF86 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B3EB2101DC498370080DF86 /* AppDelegate.m */; };
 11 | 		6B3EB21F1DC498410080DF86 /* PYSearch.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6B3EB2131DC498410080DF86 /* PYSearch.bundle */; };
 12 | 		6B3EB2201DC498410080DF86 /* PYSearchConst.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B3EB2161DC498410080DF86 /* PYSearchConst.m */; };
 13 | 		6B3EB2211DC498410080DF86 /* PYSearchSuggestionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B3EB2181DC498410080DF86 /* PYSearchSuggestionViewController.m */; };
 14 | 		6B3EB2221DC498410080DF86 /* PYSearchViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B3EB21A1DC498410080DF86 /* PYSearchViewController.m */; };
 15 | 		6B3EB2231DC498410080DF86 /* UIColor+PYSearchExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B3EB21C1DC498410080DF86 /* UIColor+PYSearchExtension.m */; };
 16 | 		6B3EB2241DC498410080DF86 /* UIView+PYSearchExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B3EB21E1DC498410080DF86 /* UIView+PYSearchExtension.m */; };
 17 | 		6B8FA3851E1B781F00DFD42A /* NSBundle+PYSearchExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B8FA3841E1B781F00DFD42A /* NSBundle+PYSearchExtension.m */; };
 18 | 		6B9717681DC48FA800B2DAA1 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B9717671DC48FA800B2DAA1 /* main.m */; };
 19 | 		6B9717761DC48FA800B2DAA1 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6B9717751DC48FA800B2DAA1 /* Assets.xcassets */; };
 20 | 		6B9717791DC48FA800B2DAA1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6B9717771DC48FA800B2DAA1 /* LaunchScreen.storyboard */; };
 21 | 		6B9717841DC48FA800B2DAA1 /* PYSearchExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B9717831DC48FA800B2DAA1 /* PYSearchExampleTests.m */; };
 22 | 		6B97178F1DC48FA800B2DAA1 /* PYSearchExampleUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B97178E1DC48FA800B2DAA1 /* PYSearchExampleUITests.m */; };
 23 | 		6B97179E1DC48FE800B2DAA1 /* PYSearchExampleController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B97179D1DC48FE800B2DAA1 /* PYSearchExampleController.m */; };
 24 | 		6B9DA6011DC8415700D07A16 /* PYTempViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6B9DA6001DC8415700D07A16 /* PYTempViewController.m */; };
 25 | 		A6324EC11E3130FB00BAA226 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = A6324EC31E3130FB00BAA226 /* Localizable.strings */; };
 26 | /* End PBXBuildFile section */
 27 | 
 28 | /* Begin PBXContainerItemProxy section */
 29 | 		6B9717801DC48FA800B2DAA1 /* PBXContainerItemProxy */ = {
 30 | 			isa = PBXContainerItemProxy;
 31 | 			containerPortal = 6B97175B1DC48FA700B2DAA1 /* Project object */;
 32 | 			proxyType = 1;
 33 | 			remoteGlobalIDString = 6B9717621DC48FA800B2DAA1;
 34 | 			remoteInfo = PYSearchExample;
 35 | 		};
 36 | 		6B97178B1DC48FA800B2DAA1 /* PBXContainerItemProxy */ = {
 37 | 			isa = PBXContainerItemProxy;
 38 | 			containerPortal = 6B97175B1DC48FA700B2DAA1 /* Project object */;
 39 | 			proxyType = 1;
 40 | 			remoteGlobalIDString = 6B9717621DC48FA800B2DAA1;
 41 | 			remoteInfo = PYSearchExample;
 42 | 		};
 43 | /* End PBXContainerItemProxy section */
 44 | 
 45 | /* Begin PBXFileReference section */
 46 | 		6B3EB20F1DC498370080DF86 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
 47 | 		6B3EB2101DC498370080DF86 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
 48 | 		6B3EB2131DC498410080DF86 /* PYSearch.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = PYSearch.bundle; sourceTree = "<group>"; };
 49 | 		6B3EB2141DC498410080DF86 /* PYSearch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYSearch.h; sourceTree = "<group>"; };
 50 | 		6B3EB2151DC498410080DF86 /* PYSearchConst.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYSearchConst.h; sourceTree = "<group>"; };
 51 | 		6B3EB2161DC498410080DF86 /* PYSearchConst.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PYSearchConst.m; sourceTree = "<group>"; };
 52 | 		6B3EB2171DC498410080DF86 /* PYSearchSuggestionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYSearchSuggestionViewController.h; sourceTree = "<group>"; };
 53 | 		6B3EB2181DC498410080DF86 /* PYSearchSuggestionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PYSearchSuggestionViewController.m; sourceTree = "<group>"; };
 54 | 		6B3EB2191DC498410080DF86 /* PYSearchViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYSearchViewController.h; sourceTree = "<group>"; };
 55 | 		6B3EB21A1DC498410080DF86 /* PYSearchViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PYSearchViewController.m; sourceTree = "<group>"; };
 56 | 		6B3EB21B1DC498410080DF86 /* UIColor+PYSearchExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+PYSearchExtension.h"; sourceTree = "<group>"; };
 57 | 		6B3EB21C1DC498410080DF86 /* UIColor+PYSearchExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+PYSearchExtension.m"; sourceTree = "<group>"; };
 58 | 		6B3EB21D1DC498410080DF86 /* UIView+PYSearchExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIView+PYSearchExtension.h"; sourceTree = "<group>"; };
 59 | 		6B3EB21E1DC498410080DF86 /* UIView+PYSearchExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIView+PYSearchExtension.m"; sourceTree = "<group>"; };
 60 | 		6B8FA3831E1B781F00DFD42A /* NSBundle+PYSearchExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBundle+PYSearchExtension.h"; sourceTree = "<group>"; };
 61 | 		6B8FA3841E1B781F00DFD42A /* NSBundle+PYSearchExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBundle+PYSearchExtension.m"; sourceTree = "<group>"; };
 62 | 		6B9717631DC48FA800B2DAA1 /* PYSearchExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PYSearchExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
 63 | 		6B9717671DC48FA800B2DAA1 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
 64 | 		6B9717751DC48FA800B2DAA1 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 65 | 		6B9717781DC48FA800B2DAA1 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
 66 | 		6B97177A1DC48FA800B2DAA1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 67 | 		6B97177F1DC48FA800B2DAA1 /* PYSearchExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PYSearchExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 68 | 		6B9717831DC48FA800B2DAA1 /* PYSearchExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PYSearchExampleTests.m; sourceTree = "<group>"; };
 69 | 		6B9717851DC48FA800B2DAA1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 70 | 		6B97178A1DC48FA800B2DAA1 /* PYSearchExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PYSearchExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
 71 | 		6B97178E1DC48FA800B2DAA1 /* PYSearchExampleUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PYSearchExampleUITests.m; sourceTree = "<group>"; };
 72 | 		6B9717901DC48FA800B2DAA1 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 73 | 		6B97179C1DC48FE800B2DAA1 /* PYSearchExampleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYSearchExampleController.h; sourceTree = "<group>"; };
 74 | 		6B97179D1DC48FE800B2DAA1 /* PYSearchExampleController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PYSearchExampleController.m; sourceTree = "<group>"; };
 75 | 		6B9DA5FF1DC8415700D07A16 /* PYTempViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PYTempViewController.h; sourceTree = "<group>"; };
 76 | 		6B9DA6001DC8415700D07A16 /* PYTempViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PYTempViewController.m; sourceTree = "<group>"; };
 77 | 		A6324EBB1E312F1100BAA226 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
 78 | 		A6324EBC1E312F1600BAA226 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/LaunchScreen.strings; sourceTree = "<group>"; };
 79 | 		A6324EBD1E312F1C00BAA226 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/LaunchScreen.strings"; sourceTree = "<group>"; };
 80 | 		A6324EBE1E312F2000BAA226 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/LaunchScreen.strings"; sourceTree = "<group>"; };
 81 | 		A6324EC21E3130FB00BAA226 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
 82 | 		A6324EC41E3130FE00BAA226 /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
 83 | 		A6324EC51E3130FE00BAA226 /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
 84 | 		A6324EC61E3130FF00BAA226 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
 85 | 		A6324EC71E31310000BAA226 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
 86 | /* End PBXFileReference section */
 87 | 
 88 | /* Begin PBXFrameworksBuildPhase section */
 89 | 		6B9717601DC48FA800B2DAA1 /* Frameworks */ = {
 90 | 			isa = PBXFrameworksBuildPhase;
 91 | 			buildActionMask = 2147483647;
 92 | 			files = (
 93 | 			);
 94 | 			runOnlyForDeploymentPostprocessing = 0;
 95 | 		};
 96 | 		6B97177C1DC48FA800B2DAA1 /* Frameworks */ = {
 97 | 			isa = PBXFrameworksBuildPhase;
 98 | 			buildActionMask = 2147483647;
 99 | 			files = (
100 | 			);
101 | 			runOnlyForDeploymentPostprocessing = 0;
102 | 		};
103 | 		6B9717871DC48FA800B2DAA1 /* Frameworks */ = {
104 | 			isa = PBXFrameworksBuildPhase;
105 | 			buildActionMask = 2147483647;
106 | 			files = (
107 | 			);
108 | 			runOnlyForDeploymentPostprocessing = 0;
109 | 		};
110 | /* End PBXFrameworksBuildPhase section */
111 | 
112 | /* Begin PBXGroup section */
113 | 		6B3EB2121DC498410080DF86 /* PYSearch */ = {
114 | 			isa = PBXGroup;
115 | 			children = (
116 | 				6B3EB2131DC498410080DF86 /* PYSearch.bundle */,
117 | 				6B3EB2141DC498410080DF86 /* PYSearch.h */,
118 | 				6B3EB2151DC498410080DF86 /* PYSearchConst.h */,
119 | 				6B3EB2161DC498410080DF86 /* PYSearchConst.m */,
120 | 				6B3EB2171DC498410080DF86 /* PYSearchSuggestionViewController.h */,
121 | 				6B3EB2181DC498410080DF86 /* PYSearchSuggestionViewController.m */,
122 | 				6B3EB2191DC498410080DF86 /* PYSearchViewController.h */,
123 | 				6B3EB21A1DC498410080DF86 /* PYSearchViewController.m */,
124 | 				6B3EB21B1DC498410080DF86 /* UIColor+PYSearchExtension.h */,
125 | 				6B3EB21C1DC498410080DF86 /* UIColor+PYSearchExtension.m */,
126 | 				6B3EB21D1DC498410080DF86 /* UIView+PYSearchExtension.h */,
127 | 				6B3EB21E1DC498410080DF86 /* UIView+PYSearchExtension.m */,
128 | 				6B8FA3831E1B781F00DFD42A /* NSBundle+PYSearchExtension.h */,
129 | 				6B8FA3841E1B781F00DFD42A /* NSBundle+PYSearchExtension.m */,
130 | 			);
131 | 			name = PYSearch;
132 | 			path = ../../PYSearch;
133 | 			sourceTree = "<group>";
134 | 		};
135 | 		6B97175A1DC48FA700B2DAA1 = {
136 | 			isa = PBXGroup;
137 | 			children = (
138 | 				6B9717651DC48FA800B2DAA1 /* PYSearchExample */,
139 | 				6B9717821DC48FA800B2DAA1 /* PYSearchExampleTests */,
140 | 				6B97178D1DC48FA800B2DAA1 /* PYSearchExampleUITests */,
141 | 				6B9717641DC48FA800B2DAA1 /* Products */,
142 | 			);
143 | 			sourceTree = "<group>";
144 | 		};
145 | 		6B9717641DC48FA800B2DAA1 /* Products */ = {
146 | 			isa = PBXGroup;
147 | 			children = (
148 | 				6B9717631DC48FA800B2DAA1 /* PYSearchExample.app */,
149 | 				6B97177F1DC48FA800B2DAA1 /* PYSearchExampleTests.xctest */,
150 | 				6B97178A1DC48FA800B2DAA1 /* PYSearchExampleUITests.xctest */,
151 | 			);
152 | 			name = Products;
153 | 			sourceTree = "<group>";
154 | 		};
155 | 		6B9717651DC48FA800B2DAA1 /* PYSearchExample */ = {
156 | 			isa = PBXGroup;
157 | 			children = (
158 | 				6B3EB2121DC498410080DF86 /* PYSearch */,
159 | 				6B3EB20F1DC498370080DF86 /* AppDelegate.h */,
160 | 				6B3EB2101DC498370080DF86 /* AppDelegate.m */,
161 | 				6B97179C1DC48FE800B2DAA1 /* PYSearchExampleController.h */,
162 | 				6B97179D1DC48FE800B2DAA1 /* PYSearchExampleController.m */,
163 | 				6B9DA5FF1DC8415700D07A16 /* PYTempViewController.h */,
164 | 				6B9DA6001DC8415700D07A16 /* PYTempViewController.m */,
165 | 				6B9717751DC48FA800B2DAA1 /* Assets.xcassets */,
166 | 				6B9717661DC48FA800B2DAA1 /* Supporting Files */,
167 | 			);
168 | 			path = PYSearchExample;
169 | 			sourceTree = "<group>";
170 | 		};
171 | 		6B9717661DC48FA800B2DAA1 /* Supporting Files */ = {
172 | 			isa = PBXGroup;
173 | 			children = (
174 | 				6B9717771DC48FA800B2DAA1 /* LaunchScreen.storyboard */,
175 | 				6B97177A1DC48FA800B2DAA1 /* Info.plist */,
176 | 				A6324EC31E3130FB00BAA226 /* Localizable.strings */,
177 | 				6B9717671DC48FA800B2DAA1 /* main.m */,
178 | 			);
179 | 			name = "Supporting Files";
180 | 			sourceTree = "<group>";
181 | 		};
182 | 		6B9717821DC48FA800B2DAA1 /* PYSearchExampleTests */ = {
183 | 			isa = PBXGroup;
184 | 			children = (
185 | 				6B9717831DC48FA800B2DAA1 /* PYSearchExampleTests.m */,
186 | 				6B9717851DC48FA800B2DAA1 /* Info.plist */,
187 | 			);
188 | 			path = PYSearchExampleTests;
189 | 			sourceTree = "<group>";
190 | 		};
191 | 		6B97178D1DC48FA800B2DAA1 /* PYSearchExampleUITests */ = {
192 | 			isa = PBXGroup;
193 | 			children = (
194 | 				6B97178E1DC48FA800B2DAA1 /* PYSearchExampleUITests.m */,
195 | 				6B9717901DC48FA800B2DAA1 /* Info.plist */,
196 | 			);
197 | 			path = PYSearchExampleUITests;
198 | 			sourceTree = "<group>";
199 | 		};
200 | /* End PBXGroup section */
201 | 
202 | /* Begin PBXNativeTarget section */
203 | 		6B9717621DC48FA800B2DAA1 /* PYSearchExample */ = {
204 | 			isa = PBXNativeTarget;
205 | 			buildConfigurationList = 6B9717931DC48FA800B2DAA1 /* Build configuration list for PBXNativeTarget "PYSearchExample" */;
206 | 			buildPhases = (
207 | 				6B97175F1DC48FA800B2DAA1 /* Sources */,
208 | 				6B9717601DC48FA800B2DAA1 /* Frameworks */,
209 | 				6B9717611DC48FA800B2DAA1 /* Resources */,
210 | 			);
211 | 			buildRules = (
212 | 			);
213 | 			dependencies = (
214 | 			);
215 | 			name = PYSearchExample;
216 | 			productName = PYSearchExample;
217 | 			productReference = 6B9717631DC48FA800B2DAA1 /* PYSearchExample.app */;
218 | 			productType = "com.apple.product-type.application";
219 | 		};
220 | 		6B97177E1DC48FA800B2DAA1 /* PYSearchExampleTests */ = {
221 | 			isa = PBXNativeTarget;
222 | 			buildConfigurationList = 6B9717961DC48FA800B2DAA1 /* Build configuration list for PBXNativeTarget "PYSearchExampleTests" */;
223 | 			buildPhases = (
224 | 				6B97177B1DC48FA800B2DAA1 /* Sources */,
225 | 				6B97177C1DC48FA800B2DAA1 /* Frameworks */,
226 | 				6B97177D1DC48FA800B2DAA1 /* Resources */,
227 | 			);
228 | 			buildRules = (
229 | 			);
230 | 			dependencies = (
231 | 				6B9717811DC48FA800B2DAA1 /* PBXTargetDependency */,
232 | 			);
233 | 			name = PYSearchExampleTests;
234 | 			productName = PYSearchExampleTests;
235 | 			productReference = 6B97177F1DC48FA800B2DAA1 /* PYSearchExampleTests.xctest */;
236 | 			productType = "com.apple.product-type.bundle.unit-test";
237 | 		};
238 | 		6B9717891DC48FA800B2DAA1 /* PYSearchExampleUITests */ = {
239 | 			isa = PBXNativeTarget;
240 | 			buildConfigurationList = 6B9717991DC48FA800B2DAA1 /* Build configuration list for PBXNativeTarget "PYSearchExampleUITests" */;
241 | 			buildPhases = (
242 | 				6B9717861DC48FA800B2DAA1 /* Sources */,
243 | 				6B9717871DC48FA800B2DAA1 /* Frameworks */,
244 | 				6B9717881DC48FA800B2DAA1 /* Resources */,
245 | 			);
246 | 			buildRules = (
247 | 			);
248 | 			dependencies = (
249 | 				6B97178C1DC48FA800B2DAA1 /* PBXTargetDependency */,
250 | 			);
251 | 			name = PYSearchExampleUITests;
252 | 			productName = PYSearchExampleUITests;
253 | 			productReference = 6B97178A1DC48FA800B2DAA1 /* PYSearchExampleUITests.xctest */;
254 | 			productType = "com.apple.product-type.bundle.ui-testing";
255 | 		};
256 | /* End PBXNativeTarget section */
257 | 
258 | /* Begin PBXProject section */
259 | 		6B97175B1DC48FA700B2DAA1 /* Project object */ = {
260 | 			isa = PBXProject;
261 | 			attributes = {
262 | 				LastUpgradeCheck = 0730;
263 | 				ORGANIZATIONNAME = CoderKo1o;
264 | 				TargetAttributes = {
265 | 					6B9717621DC48FA800B2DAA1 = {
266 | 						CreatedOnToolsVersion = 7.3;
267 | 					};
268 | 					6B97177E1DC48FA800B2DAA1 = {
269 | 						CreatedOnToolsVersion = 7.3;
270 | 						TestTargetID = 6B9717621DC48FA800B2DAA1;
271 | 					};
272 | 					6B9717891DC48FA800B2DAA1 = {
273 | 						CreatedOnToolsVersion = 7.3;
274 | 						TestTargetID = 6B9717621DC48FA800B2DAA1;
275 | 					};
276 | 				};
277 | 			};
278 | 			buildConfigurationList = 6B97175E1DC48FA700B2DAA1 /* Build configuration list for PBXProject "PYSearchExample" */;
279 | 			compatibilityVersion = "Xcode 3.2";
280 | 			developmentRegion = English;
281 | 			hasScannedForEncodings = 0;
282 | 			knownRegions = (
283 | 				en,
284 | 				Base,
285 | 				fr,
286 | 				es,
287 | 				"zh-Hans",
288 | 				"zh-Hant",
289 | 			);
290 | 			mainGroup = 6B97175A1DC48FA700B2DAA1;
291 | 			productRefGroup = 6B9717641DC48FA800B2DAA1 /* Products */;
292 | 			projectDirPath = "";
293 | 			projectRoot = "";
294 | 			targets = (
295 | 				6B9717621DC48FA800B2DAA1 /* PYSearchExample */,
296 | 				6B97177E1DC48FA800B2DAA1 /* PYSearchExampleTests */,
297 | 				6B9717891DC48FA800B2DAA1 /* PYSearchExampleUITests */,
298 | 			);
299 | 		};
300 | /* End PBXProject section */
301 | 
302 | /* Begin PBXResourcesBuildPhase section */
303 | 		6B9717611DC48FA800B2DAA1 /* Resources */ = {
304 | 			isa = PBXResourcesBuildPhase;
305 | 			buildActionMask = 2147483647;
306 | 			files = (
307 | 				6B9717791DC48FA800B2DAA1 /* LaunchScreen.storyboard in Resources */,
308 | 				A6324EC11E3130FB00BAA226 /* Localizable.strings in Resources */,
309 | 				6B3EB21F1DC498410080DF86 /* PYSearch.bundle in Resources */,
310 | 				6B9717761DC48FA800B2DAA1 /* Assets.xcassets in Resources */,
311 | 			);
312 | 			runOnlyForDeploymentPostprocessing = 0;
313 | 		};
314 | 		6B97177D1DC48FA800B2DAA1 /* Resources */ = {
315 | 			isa = PBXResourcesBuildPhase;
316 | 			buildActionMask = 2147483647;
317 | 			files = (
318 | 			);
319 | 			runOnlyForDeploymentPostprocessing = 0;
320 | 		};
321 | 		6B9717881DC48FA800B2DAA1 /* Resources */ = {
322 | 			isa = PBXResourcesBuildPhase;
323 | 			buildActionMask = 2147483647;
324 | 			files = (
325 | 			);
326 | 			runOnlyForDeploymentPostprocessing = 0;
327 | 		};
328 | /* End PBXResourcesBuildPhase section */
329 | 
330 | /* Begin PBXSourcesBuildPhase section */
331 | 		6B97175F1DC48FA800B2DAA1 /* Sources */ = {
332 | 			isa = PBXSourcesBuildPhase;
333 | 			buildActionMask = 2147483647;
334 | 			files = (
335 | 				6B3EB2201DC498410080DF86 /* PYSearchConst.m in Sources */,
336 | 				6B3EB2241DC498410080DF86 /* UIView+PYSearchExtension.m in Sources */,
337 | 				6B97179E1DC48FE800B2DAA1 /* PYSearchExampleController.m in Sources */,
338 | 				6B3EB2211DC498410080DF86 /* PYSearchSuggestionViewController.m in Sources */,
339 | 				6B3EB2221DC498410080DF86 /* PYSearchViewController.m in Sources */,
340 | 				6B9DA6011DC8415700D07A16 /* PYTempViewController.m in Sources */,
341 | 				6B9717681DC48FA800B2DAA1 /* main.m in Sources */,
342 | 				6B3EB2231DC498410080DF86 /* UIColor+PYSearchExtension.m in Sources */,
343 | 				6B8FA3851E1B781F00DFD42A /* NSBundle+PYSearchExtension.m in Sources */,
344 | 				6B3EB2111DC498370080DF86 /* AppDelegate.m in Sources */,
345 | 			);
346 | 			runOnlyForDeploymentPostprocessing = 0;
347 | 		};
348 | 		6B97177B1DC48FA800B2DAA1 /* Sources */ = {
349 | 			isa = PBXSourcesBuildPhase;
350 | 			buildActionMask = 2147483647;
351 | 			files = (
352 | 				6B9717841DC48FA800B2DAA1 /* PYSearchExampleTests.m in Sources */,
353 | 			);
354 | 			runOnlyForDeploymentPostprocessing = 0;
355 | 		};
356 | 		6B9717861DC48FA800B2DAA1 /* Sources */ = {
357 | 			isa = PBXSourcesBuildPhase;
358 | 			buildActionMask = 2147483647;
359 | 			files = (
360 | 				6B97178F1DC48FA800B2DAA1 /* PYSearchExampleUITests.m in Sources */,
361 | 			);
362 | 			runOnlyForDeploymentPostprocessing = 0;
363 | 		};
364 | /* End PBXSourcesBuildPhase section */
365 | 
366 | /* Begin PBXTargetDependency section */
367 | 		6B9717811DC48FA800B2DAA1 /* PBXTargetDependency */ = {
368 | 			isa = PBXTargetDependency;
369 | 			target = 6B9717621DC48FA800B2DAA1 /* PYSearchExample */;
370 | 			targetProxy = 6B9717801DC48FA800B2DAA1 /* PBXContainerItemProxy */;
371 | 		};
372 | 		6B97178C1DC48FA800B2DAA1 /* PBXTargetDependency */ = {
373 | 			isa = PBXTargetDependency;
374 | 			target = 6B9717621DC48FA800B2DAA1 /* PYSearchExample */;
375 | 			targetProxy = 6B97178B1DC48FA800B2DAA1 /* PBXContainerItemProxy */;
376 | 		};
377 | /* End PBXTargetDependency section */
378 | 
379 | /* Begin PBXVariantGroup section */
380 | 		6B9717771DC48FA800B2DAA1 /* LaunchScreen.storyboard */ = {
381 | 			isa = PBXVariantGroup;
382 | 			children = (
383 | 				6B9717781DC48FA800B2DAA1 /* Base */,
384 | 				A6324EBB1E312F1100BAA226 /* fr */,
385 | 				A6324EBC1E312F1600BAA226 /* es */,
386 | 				A6324EBD1E312F1C00BAA226 /* zh-Hans */,
387 | 				A6324EBE1E312F2000BAA226 /* zh-Hant */,
388 | 			);
389 | 			name = LaunchScreen.storyboard;
390 | 			sourceTree = "<group>";
391 | 		};
392 | 		A6324EC31E3130FB00BAA226 /* Localizable.strings */ = {
393 | 			isa = PBXVariantGroup;
394 | 			children = (
395 | 				A6324EC21E3130FB00BAA226 /* en */,
396 | 				A6324EC41E3130FE00BAA226 /* fr */,
397 | 				A6324EC51E3130FE00BAA226 /* es */,
398 | 				A6324EC61E3130FF00BAA226 /* zh-Hans */,
399 | 				A6324EC71E31310000BAA226 /* zh-Hant */,
400 | 			);
401 | 			name = Localizable.strings;
402 | 			sourceTree = "<group>";
403 | 		};
404 | /* End PBXVariantGroup section */
405 | 
406 | /* Begin XCBuildConfiguration section */
407 | 		6B9717911DC48FA800B2DAA1 /* Debug */ = {
408 | 			isa = XCBuildConfiguration;
409 | 			buildSettings = {
410 | 				ALWAYS_SEARCH_USER_PATHS = NO;
411 | 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
412 | 				CLANG_ANALYZER_NONNULL = YES;
413 | 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
414 | 				CLANG_CXX_LIBRARY = "libc++";
415 | 				CLANG_ENABLE_MODULES = YES;
416 | 				CLANG_ENABLE_OBJC_ARC = YES;
417 | 				CLANG_WARN_BOOL_CONVERSION = YES;
418 | 				CLANG_WARN_CONSTANT_CONVERSION = YES;
419 | 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
420 | 				CLANG_WARN_EMPTY_BODY = YES;
421 | 				CLANG_WARN_ENUM_CONVERSION = YES;
422 | 				CLANG_WARN_INT_CONVERSION = YES;
423 | 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
424 | 				CLANG_WARN_UNREACHABLE_CODE = YES;
425 | 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
426 | 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
427 | 				COPY_PHASE_STRIP = NO;
428 | 				DEBUG_INFORMATION_FORMAT = dwarf;
429 | 				ENABLE_STRICT_OBJC_MSGSEND = YES;
430 | 				ENABLE_TESTABILITY = YES;
431 | 				GCC_C_LANGUAGE_STANDARD = gnu99;
432 | 				GCC_DYNAMIC_NO_PIC = NO;
433 | 				GCC_NO_COMMON_BLOCKS = YES;
434 | 				GCC_OPTIMIZATION_LEVEL = 0;
435 | 				GCC_PREPROCESSOR_DEFINITIONS = (
436 | 					"DEBUG=1",
437 | 					"$(inherited)",
438 | 				);
439 | 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
440 | 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
441 | 				GCC_WARN_UNDECLARED_SELECTOR = YES;
442 | 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
443 | 				GCC_WARN_UNUSED_FUNCTION = YES;
444 | 				GCC_WARN_UNUSED_VARIABLE = YES;
445 | 				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
446 | 				MTL_ENABLE_DEBUG_INFO = YES;
447 | 				ONLY_ACTIVE_ARCH = YES;
448 | 				SDKROOT = iphoneos;
449 | 			};
450 | 			name = Debug;
451 | 		};
452 | 		6B9717921DC48FA800B2DAA1 /* Release */ = {
453 | 			isa = XCBuildConfiguration;
454 | 			buildSettings = {
455 | 				ALWAYS_SEARCH_USER_PATHS = NO;
456 | 				CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
457 | 				CLANG_ANALYZER_NONNULL = YES;
458 | 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
459 | 				CLANG_CXX_LIBRARY = "libc++";
460 | 				CLANG_ENABLE_MODULES = YES;
461 | 				CLANG_ENABLE_OBJC_ARC = YES;
462 | 				CLANG_WARN_BOOL_CONVERSION = YES;
463 | 				CLANG_WARN_CONSTANT_CONVERSION = YES;
464 | 				CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
465 | 				CLANG_WARN_EMPTY_BODY = YES;
466 | 				CLANG_WARN_ENUM_CONVERSION = YES;
467 | 				CLANG_WARN_INT_CONVERSION = YES;
468 | 				CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
469 | 				CLANG_WARN_UNREACHABLE_CODE = YES;
470 | 				CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
471 | 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
472 | 				COPY_PHASE_STRIP = NO;
473 | 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
474 | 				ENABLE_NS_ASSERTIONS = NO;
475 | 				ENABLE_STRICT_OBJC_MSGSEND = YES;
476 | 				GCC_C_LANGUAGE_STANDARD = gnu99;
477 | 				GCC_NO_COMMON_BLOCKS = YES;
478 | 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
479 | 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
480 | 				GCC_WARN_UNDECLARED_SELECTOR = YES;
481 | 				GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
482 | 				GCC_WARN_UNUSED_FUNCTION = YES;
483 | 				GCC_WARN_UNUSED_VARIABLE = YES;
484 | 				IPHONEOS_DEPLOYMENT_TARGET = 9.3;
485 | 				MTL_ENABLE_DEBUG_INFO = NO;
486 | 				SDKROOT = iphoneos;
487 | 				VALIDATE_PRODUCT = YES;
488 | 			};
489 | 			name = Release;
490 | 		};
491 | 		6B9717941DC48FA800B2DAA1 /* Debug */ = {
492 | 			isa = XCBuildConfiguration;
493 | 			buildSettings = {
494 | 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
495 | 				DEVELOPMENT_TEAM = "";
496 | 				INFOPLIST_FILE = PYSearchExample/Info.plist;
497 | 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
498 | 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
499 | 				PRODUCT_BUNDLE_IDENTIFIER = com.iphone5solo.PYSearchExample;
500 | 				PRODUCT_NAME = "$(TARGET_NAME)";
501 | 				TARGETED_DEVICE_FAMILY = "1,2";
502 | 			};
503 | 			name = Debug;
504 | 		};
505 | 		6B9717951DC48FA800B2DAA1 /* Release */ = {
506 | 			isa = XCBuildConfiguration;
507 | 			buildSettings = {
508 | 				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
509 | 				DEVELOPMENT_TEAM = "";
510 | 				INFOPLIST_FILE = PYSearchExample/Info.plist;
511 | 				IPHONEOS_DEPLOYMENT_TARGET = 7.0;
512 | 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
513 | 				PRODUCT_BUNDLE_IDENTIFIER = com.iphone5solo.PYSearchExample;
514 | 				PRODUCT_NAME = "$(TARGET_NAME)";
515 | 				TARGETED_DEVICE_FAMILY = "1,2";
516 | 			};
517 | 			name = Release;
518 | 		};
519 | 		6B9717971DC48FA800B2DAA1 /* Debug */ = {
520 | 			isa = XCBuildConfiguration;
521 | 			buildSettings = {
522 | 				BUNDLE_LOADER = "$(TEST_HOST)";
523 | 				INFOPLIST_FILE = PYSearchExampleTests/Info.plist;
524 | 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
525 | 				PRODUCT_BUNDLE_IDENTIFIER = com.iphone5solo.PYSearchExampleTests;
526 | 				PRODUCT_NAME = "$(TARGET_NAME)";
527 | 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PYSearchExample.app/PYSearchExample";
528 | 			};
529 | 			name = Debug;
530 | 		};
531 | 		6B9717981DC48FA800B2DAA1 /* Release */ = {
532 | 			isa = XCBuildConfiguration;
533 | 			buildSettings = {
534 | 				BUNDLE_LOADER = "$(TEST_HOST)";
535 | 				INFOPLIST_FILE = PYSearchExampleTests/Info.plist;
536 | 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
537 | 				PRODUCT_BUNDLE_IDENTIFIER = com.iphone5solo.PYSearchExampleTests;
538 | 				PRODUCT_NAME = "$(TARGET_NAME)";
539 | 				TEST_HOST = "$(BUILT_PRODUCTS_DIR)/PYSearchExample.app/PYSearchExample";
540 | 			};
541 | 			name = Release;
542 | 		};
543 | 		6B97179A1DC48FA800B2DAA1 /* Debug */ = {
544 | 			isa = XCBuildConfiguration;
545 | 			buildSettings = {
546 | 				INFOPLIST_FILE = PYSearchExampleUITests/Info.plist;
547 | 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
548 | 				PRODUCT_BUNDLE_IDENTIFIER = com.iphone5solo.PYSearchExampleUITests;
549 | 				PRODUCT_NAME = "$(TARGET_NAME)";
550 | 				TEST_TARGET_NAME = PYSearchExample;
551 | 			};
552 | 			name = Debug;
553 | 		};
554 | 		6B97179B1DC48FA800B2DAA1 /* Release */ = {
555 | 			isa = XCBuildConfiguration;
556 | 			buildSettings = {
557 | 				INFOPLIST_FILE = PYSearchExampleUITests/Info.plist;
558 | 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
559 | 				PRODUCT_BUNDLE_IDENTIFIER = com.iphone5solo.PYSearchExampleUITests;
560 | 				PRODUCT_NAME = "$(TARGET_NAME)";
561 | 				TEST_TARGET_NAME = PYSearchExample;
562 | 			};
563 | 			name = Release;
564 | 		};
565 | /* End XCBuildConfiguration section */
566 | 
567 | /* Begin XCConfigurationList section */
568 | 		6B97175E1DC48FA700B2DAA1 /* Build configuration list for PBXProject "PYSearchExample" */ = {
569 | 			isa = XCConfigurationList;
570 | 			buildConfigurations = (
571 | 				6B9717911DC48FA800B2DAA1 /* Debug */,
572 | 				6B9717921DC48FA800B2DAA1 /* Release */,
573 | 			);
574 | 			defaultConfigurationIsVisible = 0;
575 | 			defaultConfigurationName = Release;
576 | 		};
577 | 		6B9717931DC48FA800B2DAA1 /* Build configuration list for PBXNativeTarget "PYSearchExample" */ = {
578 | 			isa = XCConfigurationList;
579 | 			buildConfigurations = (
580 | 				6B9717941DC48FA800B2DAA1 /* Debug */,
581 | 				6B9717951DC48FA800B2DAA1 /* Release */,
582 | 			);
583 | 			defaultConfigurationIsVisible = 0;
584 | 			defaultConfigurationName = Release;
585 | 		};
586 | 		6B9717961DC48FA800B2DAA1 /* Build configuration list for PBXNativeTarget "PYSearchExampleTests" */ = {
587 | 			isa = XCConfigurationList;
588 | 			buildConfigurations = (
589 | 				6B9717971DC48FA800B2DAA1 /* Debug */,
590 | 				6B9717981DC48FA800B2DAA1 /* Release */,
591 | 			);
592 | 			defaultConfigurationIsVisible = 0;
593 | 			defaultConfigurationName = Release;
594 | 		};
595 | 		6B9717991DC48FA800B2DAA1 /* Build configuration list for PBXNativeTarget "PYSearchExampleUITests" */ = {
596 | 			isa = XCConfigurationList;
597 | 			buildConfigurations = (
598 | 				6B97179A1DC48FA800B2DAA1 /* Debug */,
599 | 				6B97179B1DC48FA800B2DAA1 /* Release */,
600 | 			);
601 | 			defaultConfigurationIsVisible = 0;
602 | 			defaultConfigurationName = Release;
603 | 		};
604 | /* End XCConfigurationList section */
605 | 	};
606 | 	rootObject = 6B97175B1DC48FA700B2DAA1 /* Project object */;
607 | }
608 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <Workspace
3 |    version = "1.0">
4 |    <FileRef
5 |       location = "self:PYSearchExample.xcodeproj">
6 |    </FileRef>
7 | </Workspace>
8 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3 | <plist version="1.0">
4 | <dict>
5 | 	<key>IDEDidComputeMac32BitWarning</key>
6 | 	<true/>
7 | </dict>
8 | </plist>
9 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample.xcodeproj/project.xcworkspace/xcuserdata/iphone5solo.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ko1o/PYSearch/b62360587dae1e7aa7545d427de49916407f2a94/PYSearchExample/PYSearchExample.xcodeproj/project.xcworkspace/xcuserdata/iphone5solo.xcuserdatad/UserInterfaceState.xcuserstate


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample.xcodeproj/xcuserdata/iphone5solo.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 | <?xml version="1.0" encoding="UTF-8"?>
2 | <Bucket
3 |    type = "1"
4 |    version = "2.0">
5 | </Bucket>
6 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample.xcodeproj/xcuserdata/iphone5solo.xcuserdatad/xcschemes/PYSearchExample.xcscheme:
--------------------------------------------------------------------------------
  1 | <?xml version="1.0" encoding="UTF-8"?>
  2 | <Scheme
  3 |    LastUpgradeVersion = "0730"
  4 |    version = "1.3">
  5 |    <BuildAction
  6 |       parallelizeBuildables = "YES"
  7 |       buildImplicitDependencies = "YES">
  8 |       <BuildActionEntries>
  9 |          <BuildActionEntry
 10 |             buildForTesting = "YES"
 11 |             buildForRunning = "YES"
 12 |             buildForProfiling = "YES"
 13 |             buildForArchiving = "YES"
 14 |             buildForAnalyzing = "YES">
 15 |             <BuildableReference
 16 |                BuildableIdentifier = "primary"
 17 |                BlueprintIdentifier = "6B9717621DC48FA800B2DAA1"
 18 |                BuildableName = "PYSearchExample.app"
 19 |                BlueprintName = "PYSearchExample"
 20 |                ReferencedContainer = "container:PYSearchExample.xcodeproj">
 21 |             </BuildableReference>
 22 |          </BuildActionEntry>
 23 |       </BuildActionEntries>
 24 |    </BuildAction>
 25 |    <TestAction
 26 |       buildConfiguration = "Debug"
 27 |       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
 28 |       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
 29 |       shouldUseLaunchSchemeArgsEnv = "YES">
 30 |       <Testables>
 31 |          <TestableReference
 32 |             skipped = "NO">
 33 |             <BuildableReference
 34 |                BuildableIdentifier = "primary"
 35 |                BlueprintIdentifier = "6B97177E1DC48FA800B2DAA1"
 36 |                BuildableName = "PYSearchExampleTests.xctest"
 37 |                BlueprintName = "PYSearchExampleTests"
 38 |                ReferencedContainer = "container:PYSearchExample.xcodeproj">
 39 |             </BuildableReference>
 40 |          </TestableReference>
 41 |          <TestableReference
 42 |             skipped = "NO">
 43 |             <BuildableReference
 44 |                BuildableIdentifier = "primary"
 45 |                BlueprintIdentifier = "6B9717891DC48FA800B2DAA1"
 46 |                BuildableName = "PYSearchExampleUITests.xctest"
 47 |                BlueprintName = "PYSearchExampleUITests"
 48 |                ReferencedContainer = "container:PYSearchExample.xcodeproj">
 49 |             </BuildableReference>
 50 |          </TestableReference>
 51 |       </Testables>
 52 |       <MacroExpansion>
 53 |          <BuildableReference
 54 |             BuildableIdentifier = "primary"
 55 |             BlueprintIdentifier = "6B9717621DC48FA800B2DAA1"
 56 |             BuildableName = "PYSearchExample.app"
 57 |             BlueprintName = "PYSearchExample"
 58 |             ReferencedContainer = "container:PYSearchExample.xcodeproj">
 59 |          </BuildableReference>
 60 |       </MacroExpansion>
 61 |       <AdditionalOptions>
 62 |       </AdditionalOptions>
 63 |    </TestAction>
 64 |    <LaunchAction
 65 |       buildConfiguration = "Debug"
 66 |       selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
 67 |       selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
 68 |       launchStyle = "0"
 69 |       useCustomWorkingDirectory = "NO"
 70 |       ignoresPersistentStateOnLaunch = "NO"
 71 |       debugDocumentVersioning = "YES"
 72 |       debugServiceExtension = "internal"
 73 |       allowLocationSimulation = "YES">
 74 |       <BuildableProductRunnable
 75 |          runnableDebuggingMode = "0">
 76 |          <BuildableReference
 77 |             BuildableIdentifier = "primary"
 78 |             BlueprintIdentifier = "6B9717621DC48FA800B2DAA1"
 79 |             BuildableName = "PYSearchExample.app"
 80 |             BlueprintName = "PYSearchExample"
 81 |             ReferencedContainer = "container:PYSearchExample.xcodeproj">
 82 |          </BuildableReference>
 83 |       </BuildableProductRunnable>
 84 |       <AdditionalOptions>
 85 |       </AdditionalOptions>
 86 |    </LaunchAction>
 87 |    <ProfileAction
 88 |       buildConfiguration = "Release"
 89 |       shouldUseLaunchSchemeArgsEnv = "YES"
 90 |       savedToolIdentifier = ""
 91 |       useCustomWorkingDirectory = "NO"
 92 |       debugDocumentVersioning = "YES">
 93 |       <BuildableProductRunnable
 94 |          runnableDebuggingMode = "0">
 95 |          <BuildableReference
 96 |             BuildableIdentifier = "primary"
 97 |             BlueprintIdentifier = "6B9717621DC48FA800B2DAA1"
 98 |             BuildableName = "PYSearchExample.app"
 99 |             BlueprintName = "PYSearchExample"
100 |             ReferencedContainer = "container:PYSearchExample.xcodeproj">
101 |          </BuildableReference>
102 |       </BuildableProductRunnable>
103 |    </ProfileAction>
104 |    <AnalyzeAction
105 |       buildConfiguration = "Debug">
106 |    </AnalyzeAction>
107 |    <ArchiveAction
108 |       buildConfiguration = "Release"
109 |       revealArchiveInOrganizer = "YES">
110 |    </ArchiveAction>
111 | </Scheme>
112 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample.xcodeproj/xcuserdata/iphone5solo.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>SchemeUserState</key>
 6 | 	<dict>
 7 | 		<key>PYSearchExample.xcscheme</key>
 8 | 		<dict>
 9 | 			<key>orderHint</key>
10 | 			<integer>0</integer>
11 | 		</dict>
12 | 	</dict>
13 | 	<key>SuppressBuildableAutocreation</key>
14 | 	<dict>
15 | 		<key>6B9717621DC48FA800B2DAA1</key>
16 | 		<dict>
17 | 			<key>primary</key>
18 | 			<true/>
19 | 		</dict>
20 | 		<key>6B97177E1DC48FA800B2DAA1</key>
21 | 		<dict>
22 | 			<key>primary</key>
23 | 			<true/>
24 | 		</dict>
25 | 		<key>6B9717891DC48FA800B2DAA1</key>
26 | 		<dict>
27 | 			<key>primary</key>
28 | 			<true/>
29 | 		</dict>
30 | 	</dict>
31 | </dict>
32 | </plist>
33 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/AppDelegate.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | #import <UIKit/UIKit.h>
 7 | 
 8 | @interface AppDelegate : UIResponder <UIApplicationDelegate>
 9 | 
10 | @property (strong, nonatomic) UIWindow *window;
11 | 
12 | @end
13 | 
14 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/AppDelegate.m:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import "AppDelegate.h"
 8 | #import "PYSearchExampleController.h"
 9 | 
10 | @interface AppDelegate ()
11 | 
12 | @end
13 | 
14 | @implementation AppDelegate
15 | 
16 | 
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
18 |     if (!self.window) {
19 |         UIWindow *keyWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
20 |         keyWindow.rootViewController = [[UINavigationController alloc] initWithRootViewController:[[PYSearchExampleController alloc] init]];
21 |         [keyWindow makeKeyAndVisible];
22 |         self.window = keyWindow;
23 |     }
24 |     return YES;
25 | }
26 | 
27 | 
28 | - (void)applicationWillResignActive:(UIApplication *)application {
29 |     // 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.
30 |     // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
31 | }
32 | 
33 | 
34 | - (void)applicationDidEnterBackground:(UIApplication *)application {
35 |     // 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.
36 |     // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
37 | }
38 | 
39 | 
40 | - (void)applicationWillEnterForeground:(UIApplication *)application {
41 |     // 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.
42 | }
43 | 
44 | 
45 | - (void)applicationDidBecomeActive:(UIApplication *)application {
46 |     // 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.
47 | }
48 | 
49 | 
50 | - (void)applicationWillTerminate:(UIApplication *)application {
51 |     // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
52 | }
53 | 
54 | 
55 | @end
56 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/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 |   "info" : {
45 |     "version" : 1,
46 |     "author" : "xcode"
47 |   }
48 | }


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11762" systemVersion="16C67" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
 3 |     <device id="retina4_7" orientation="portrait">
 4 |         <adaptation id="fullscreen"/>
 5 |     </device>
 6 |     <dependencies>
 7 |         <deployment identifier="iOS"/>
 8 |         <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11757"/>
 9 |         <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
10 |     </dependencies>
11 |     <scenes>
12 |         <!--View Controller-->
13 |         <scene sceneID="EHf-IW-A2E">
14 |             <objects>
15 |                 <viewController id="01J-lp-oVM" sceneMemberID="viewController">
16 |                     <layoutGuides>
17 |                         <viewControllerLayoutGuide type="top" id="Llm-lL-Icb"/>
18 |                         <viewControllerLayoutGuide type="bottom" id="xb3-aO-Qok"/>
19 |                     </layoutGuides>
20 |                     <view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
21 |                         <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
22 |                         <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
23 |                         <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
24 |                     </view>
25 |                 </viewController>
26 |                 <placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
27 |             </objects>
28 |             <point key="canvasLocation" x="53" y="375"/>
29 |         </scene>
30 |     </scenes>
31 | </document>
32 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>CFBundleDevelopmentRegion</key>
 6 | 	<string>en</string>
 7 | 	<key>CFBundleDisplayName</key>
 8 | 	<string>PYSearch</string>
 9 | 	<key>CFBundleExecutable</key>
10 | 	<string>$(EXECUTABLE_NAME)</string>
11 | 	<key>CFBundleIdentifier</key>
12 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
13 | 	<key>CFBundleInfoDictionaryVersion</key>
14 | 	<string>6.0</string>
15 | 	<key>CFBundleName</key>
16 | 	<string>$(PRODUCT_NAME)</string>
17 | 	<key>CFBundlePackageType</key>
18 | 	<string>APPL</string>
19 | 	<key>CFBundleShortVersionString</key>
20 | 	<string>1.0</string>
21 | 	<key>CFBundleSignature</key>
22 | 	<string>????</string>
23 | 	<key>CFBundleVersion</key>
24 | 	<string>1</string>
25 | 	<key>LSRequiresIPhoneOS</key>
26 | 	<true/>
27 | 	<key>UILaunchStoryboardName</key>
28 | 	<string>LaunchScreen</string>
29 | 	<key>UIRequiredDeviceCapabilities</key>
30 | 	<array>
31 | 		<string>armv7</string>
32 | 	</array>
33 | 	<key>UIStatusBarTintParameters</key>
34 | 	<dict>
35 | 		<key>UINavigationBar</key>
36 | 		<dict>
37 | 			<key>Style</key>
38 | 			<string>UIBarStyleDefault</string>
39 | 			<key>Translucent</key>
40 | 			<false/>
41 | 		</dict>
42 | 	</dict>
43 | 	<key>UISupportedInterfaceOrientations</key>
44 | 	<array>
45 | 		<string>UIInterfaceOrientationPortrait</string>
46 | 		<string>UIInterfaceOrientationLandscapeLeft</string>
47 | 		<string>UIInterfaceOrientationLandscapeRight</string>
48 | 		<string>UIInterfaceOrientationPortraitUpsideDown</string>
49 | 	</array>
50 | </dict>
51 | </plist>
52 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/PYSearchExampleController.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import <UIKit/UIKit.h>
 8 | 
 9 | @interface PYSearchExampleController : UITableViewController
10 | 
11 | @end
12 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/PYSearchExampleController.m:
--------------------------------------------------------------------------------
  1 | //
  2 | //  GitHub: https://github.com/iphone5solo/PYSearch
  3 | //  Created by CoderKo1o.
  4 | //  Copyright © 2016 iphone5solo. All rights reserved.
  5 | //
  6 | 
  7 | #import "PYSearchExampleController.h"
  8 | #import "PYSearch.h"
  9 | #import "PYTempViewController.h"
 10 | 
 11 | @interface PYSearchExampleController () <PYSearchViewControllerDelegate>
 12 | 
 13 | @end
 14 | 
 15 | @implementation PYSearchExampleController
 16 | 
 17 | - (void)viewDidLoad {
 18 |     [super viewDidLoad];
 19 |     
 20 |     // set title
 21 |     self.title = @"PYSearch Example";
 22 |     self.tableView = [[UITableView alloc] initWithFrame:self.view.bounds style:UITableViewStyleGrouped];
 23 |     if ([self.tableView respondsToSelector:@selector(setCellLayoutMarginsFollowReadableWidth:)]) { // Adjust for iPad
 24 |         self.tableView.cellLayoutMarginsFollowReadableWidth = NO;
 25 |     }
 26 | }
 27 | 
 28 | - (void)didReceiveMemoryWarning {
 29 |     [super didReceiveMemoryWarning];
 30 |     // Dispose of any resources that can be recreated.
 31 | }
 32 | 
 33 | #pragma mark - Table view data source
 34 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
 35 | {
 36 |     return 2;
 37 | }
 38 | 
 39 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
 40 |     return section ? 5 : 6;
 41 | }
 42 | 
 43 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 44 |     UITableViewCell *cell = [[UITableViewCell alloc] init];
 45 |     if (0 == indexPath.section) {
 46 |         cell.textLabel.text = @[@"PYHotSearchStyleDefault", @"PYHotSearchStyleColorfulTag", @"PYHotSearchStyleBorderTag", @"PYHotSearchStyleARCBorderTag", @"PYHotSearchStyleRankTag", @"PYHotSearchStyleRectangleTag"][indexPath.row];
 47 |     } else {
 48 |         cell.textLabel.text = @[@"PYSearchHistoryStyleDefault", @"PYSearchHistoryStyleNormalTag", @"PYSearchHistoryStyleColorfulTag", @"PYSearchHistoryStyleBorderTag", @"PYSearchHistoryStyleARCBorderTag"][indexPath.row];
 49 |     }
 50 |     return cell;
 51 | }
 52 | 
 53 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
 54 | {
 55 |     // 1. Create an Array of popular search
 56 |     NSArray *hotSeaches = @[@"Java", @"Python", @"Objective-C", @"Swift", @"C", @"C++", @"PHP", @"C#", @"Perl", @"Go", @"JavaScript", @"R", @"Ruby", @"MATLAB"];
 57 |     // 2. Create a search view controller
 58 |     PYSearchViewController *searchViewController = [PYSearchViewController searchViewControllerWithHotSearches:hotSeaches searchBarPlaceholder:NSLocalizedString(@"PYExampleSearchPlaceholderText", @"搜索编程语言") didSearchBlock:^(PYSearchViewController *searchViewController, UISearchBar *searchBar, NSString *searchText) {
 59 |         // Called when search begain.
 60 |         // eg:Push to a temp view controller
 61 |         [searchViewController.navigationController pushViewController:[[PYTempViewController alloc] init] animated:YES];
 62 |     }];
 63 |     // 3. Set style for popular search and search history
 64 |     if (0 == indexPath.section) {
 65 |         searchViewController.hotSearchStyle = (NSInteger)indexPath.row;
 66 |         searchViewController.searchHistoryStyle = PYHotSearchStyleDefault;
 67 |     } else {
 68 |         searchViewController.hotSearchStyle = PYHotSearchStyleDefault;
 69 |         searchViewController.searchHistoryStyle = (NSInteger)indexPath.row; 
 70 |     }
 71 |     // 4. Set delegate
 72 |     searchViewController.delegate = self;
 73 |     // 5. Present(Modal) or push search view controller
 74 |     // Present(Modal)
 75 | //    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:searchViewController];
 76 | //    [self presentViewController:nav animated:YES completion:nil];
 77 |     // Push
 78 |     // Set mode of show search view controller, default is `PYSearchViewControllerShowModeModal`
 79 |     searchViewController.searchViewControllerShowMode = PYSearchViewControllerShowModePush;
 80 | //    // Push search view controller
 81 |     [self.navigationController pushViewController:searchViewController animated:YES];
 82 | }
 83 | 
 84 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
 85 | {
 86 |     return section ? NSLocalizedString(@"PYExampleTableSectionZeroTitle", @"选择搜索历史风格(热门搜索为默认风格)") : NSLocalizedString(@"PYExampleTableSectionZeroTitle", @"选择热门搜索风格(搜索历史为默认风格)");
 87 | }
 88 | 
 89 | #pragma mark - PYSearchViewControllerDelegate
 90 | - (void)searchViewController:(PYSearchViewController *)searchViewController searchTextDidChange:(UISearchBar *)seachBar searchText:(NSString *)searchText
 91 | {
 92 |     if (searchText.length) {
 93 |         // Simulate a send request to get a search suggestions
 94 |         dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.25 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
 95 |             NSMutableArray *searchSuggestionsM = [NSMutableArray array];
 96 |             for (int i = 0; i < arc4random_uniform(5) + 10; i++) {
 97 |                 NSString *searchSuggestion = [NSString stringWithFormat:@"Search suggestion %d", i];
 98 |                 [searchSuggestionsM addObject:searchSuggestion];
 99 |             }
100 |             // Refresh and display the search suggustions
101 |             searchViewController.searchSuggestions = searchSuggestionsM;
102 |         });
103 |     }
104 | }
105 | @end
106 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/PYTempViewController.h:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import <UIKit/UIKit.h>
 8 | 
 9 | @interface PYTempViewController : UIViewController
10 | 
11 | @end
12 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/PYTempViewController.m:
--------------------------------------------------------------------------------
 1 | //
 2 | //  GitHub: https://github.com/iphone5solo/PYSearch
 3 | //  Created by CoderKo1o.
 4 | //  Copyright © 2016 iphone5solo. All rights reserved.
 5 | //
 6 | 
 7 | #import "PYTempViewController.h"
 8 | #import "PYSearchConst.h"
 9 | 
10 | @interface PYTempViewController ()
11 | 
12 | @end
13 | 
14 | @implementation PYTempViewController
15 | 
16 | - (void)viewDidLoad {
17 |     [super viewDidLoad];
18 |     
19 |     self.title = @"SearchResultViewController";
20 |     self.view.backgroundColor = PYSEARCH_RANDOM_COLOR;
21 | }
22 | 
23 | - (void)didReceiveMemoryWarning {
24 |     [super didReceiveMemoryWarning];
25 |     // Dispose of any resources that can be recreated.
26 | }
27 | 
28 | @end
29 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | /* 
 2 |   Localizable.strings
 3 |   PYSearchExample
 4 | 
 5 |   Created by Sam Spencer on 1/19/17.
 6 |   Copyright © 2017 CoderKo1o. All rights reserved.
 7 | */
 8 | 
 9 | "PYExampleSearchPlaceholderText" = "Search programming language";
10 | "PYExampleTableSectionZeroTitle" = "Select a Search History Style (Popular Search is default)";
11 | "PYExampleTableSectionOneTitle" = "Select Top Search Style (Search History is default)";
12 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/es.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 | 
2 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/es.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | /* 
 2 |   Localizable.strings
 3 |   PYSearchExample
 4 | 
 5 |   Created by Sam Spencer on 1/19/17.
 6 |   Copyright © 2017 CoderKo1o. All rights reserved.
 7 | */
 8 | 
 9 | "PYExampleSearchPlaceholderText" = "Buscar lenguaje de programación";
10 | "PYExampleTableSectionZeroTitle" = "Elija el estilo Historial de Búsqueda";
11 | "PYExampleTableSectionOneTitle" = "Elija el estilo Popular de Búsquedas";
12 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/fr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 | 
2 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/fr.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | /* 
 2 |   Localizable.strings
 3 |   PYSearchExample
 4 | 
 5 |   Created by Sam Spencer on 1/19/17.
 6 |   Copyright © 2017 CoderKo1o. All rights reserved.
 7 | */
 8 | 
 9 | "PYExampleSearchPlaceholderText" = "Rechercher un langage de programmation";
10 | "PYExampleTableSectionZeroTitle" = "Choisissez le style de Historique de la Recherche";
11 | "PYExampleTableSectionOneTitle" = "Choisissez le style de Recherches Populaires";
12 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/main.m:
--------------------------------------------------------------------------------
 1 | //
 2 | //  main.m
 3 | //  PYSearchExample
 4 | //
 5 | //  Created by 谢培艺 on 2016/10/29.
 6 | //  Copyright © 2016年 CoderKo1o. All rights reserved.
 7 | //
 8 | 
 9 | #import <UIKit/UIKit.h>
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 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/zh-Hans.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 | 
2 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/zh-Hans.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | /* 
 2 |   Localizable.strings
 3 |   PYSearchExample
 4 | 
 5 |   Created by Sam Spencer on 1/19/17.
 6 |   Copyright © 2017 CoderKo1o. All rights reserved.
 7 | */
 8 | 
 9 | "PYExampleSearchPlaceholderText" = "搜索编程语言";
10 | "PYExampleTableSectionZeroTitle" = "选择搜索历史风格(热门搜索为默认风格)";
11 | "PYExampleTableSectionOneTitle" = "";
12 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/zh-Hant.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 | 
2 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExample/zh-Hant.lproj/Localizable.strings:
--------------------------------------------------------------------------------
 1 | /* 
 2 |   Localizable.strings
 3 |   PYSearchExample
 4 | 
 5 |   Created by Sam Spencer on 1/19/17.
 6 |   Copyright © 2017 CoderKo1o. All rights reserved.
 7 | */
 8 | 
 9 | "PYExampleSearchPlaceholderText" = "搜索编程语言";
10 | "PYExampleTableSectionZeroTitle" = "选择搜索历史风格(热门搜索为默认风格)";
11 | "PYExampleTableSectionOneTitle" = "";
12 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExampleTests/Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>CFBundleDevelopmentRegion</key>
 6 | 	<string>en</string>
 7 | 	<key>CFBundleExecutable</key>
 8 | 	<string>$(EXECUTABLE_NAME)</string>
 9 | 	<key>CFBundleIdentifier</key>
10 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11 | 	<key>CFBundleInfoDictionaryVersion</key>
12 | 	<string>6.0</string>
13 | 	<key>CFBundleName</key>
14 | 	<string>$(PRODUCT_NAME)</string>
15 | 	<key>CFBundlePackageType</key>
16 | 	<string>BNDL</string>
17 | 	<key>CFBundleShortVersionString</key>
18 | 	<string>1.0</string>
19 | 	<key>CFBundleSignature</key>
20 | 	<string>????</string>
21 | 	<key>CFBundleVersion</key>
22 | 	<string>1</string>
23 | </dict>
24 | </plist>
25 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExampleTests/PYSearchExampleTests.m:
--------------------------------------------------------------------------------
 1 | //
 2 | //  PYSearchExampleTests.m
 3 | //  PYSearchExampleTests
 4 | //
 5 | //  Created by 谢培艺 on 2016/10/29.
 6 | //  Copyright © 2016年 CoderKo1o. All rights reserved.
 7 | //
 8 | 
 9 | #import <XCTest/XCTest.h>
10 | 
11 | @interface PYSearchExampleTests : XCTestCase
12 | 
13 | @end
14 | 
15 | @implementation PYSearchExampleTests
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 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExampleUITests/Info.plist:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="UTF-8"?>
 2 | <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
 3 | <plist version="1.0">
 4 | <dict>
 5 | 	<key>CFBundleDevelopmentRegion</key>
 6 | 	<string>en</string>
 7 | 	<key>CFBundleExecutable</key>
 8 | 	<string>$(EXECUTABLE_NAME)</string>
 9 | 	<key>CFBundleIdentifier</key>
10 | 	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
11 | 	<key>CFBundleInfoDictionaryVersion</key>
12 | 	<string>6.0</string>
13 | 	<key>CFBundleName</key>
14 | 	<string>$(PRODUCT_NAME)</string>
15 | 	<key>CFBundlePackageType</key>
16 | 	<string>BNDL</string>
17 | 	<key>CFBundleShortVersionString</key>
18 | 	<string>1.0</string>
19 | 	<key>CFBundleSignature</key>
20 | 	<string>????</string>
21 | 	<key>CFBundleVersion</key>
22 | 	<string>1</string>
23 | </dict>
24 | </plist>
25 | 


--------------------------------------------------------------------------------
/PYSearchExample/PYSearchExampleUITests/PYSearchExampleUITests.m:
--------------------------------------------------------------------------------
 1 | //
 2 | //  PYSearchExampleUITests.m
 3 | //  PYSearchExampleUITests
 4 | //
 5 | //  Created by 谢培艺 on 2016/10/29.
 6 | //  Copyright © 2016年 CoderKo1o. All rights reserved.
 7 | //
 8 | 
 9 | #import <XCTest/XCTest.h>
10 | 
11 | @interface PYSearchExampleUITests : XCTestCase
12 | 
13 | @end
14 | 
15 | @implementation PYSearchExampleUITests
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 | 


--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
  1 | <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/logo.png" height="200">
  2 | 
  3 | <br/><br/>
  4 | [![Apps Using](https://img.shields.io/badge/Apps%20Using-%3E%203,000-00BFFF.svg?style=plastic)](https://cocoapods.org/pods/PYSearch)
  5 | [![Total Downloads](https://img.shields.io/badge/Total%20Downloads-%3E%2060,000-00BFFF.svg?style=plastic)](https://cocoapods.org/pods/PYSearch)
  6 | <br>
  7 | [![Build Status](https://travis-ci.org/ko1o/PYSearch.svg?branch=master)](https://travis-ci.org/ko1o/PYSearch)
  8 | [![Pod Version](http://img.shields.io/cocoapods/v/PYSearch.svg?style=flat)](http://cocoadocs.org/docsets/PYSearch/)
  9 | [![Pod Platform](https://img.shields.io/badge/platform-iOS%207%2B-blue.svg?style=flat)](http://cocoadocs.org/docsets/PYSearch/)
 10 | [![Pod License](http://img.shields.io/cocoapods/l/PYSearch.svg?style=flat)](https://opensource.org/licenses/MIT)
 11 | 
 12 | - 🔍 An elegant search controller for iOS.
 13 | 
 14 | ## QQ chat room
 15 |  <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/QQChatRoomForPYSearch.jpg" width="200">
 16 | 
 17 | ## Features
 18 | - [x] Support a variety of hot search style
 19 | - [x] Support a variety of search history style
 20 | - [x] Support a variety of search results display mode
 21 | - [x] Support a variety of search view controller display mode
 22 | - [x] Support search suggestions
 23 | - [x] Support search history (record) cache
 24 | - [x] Support callback using delegate or block completion search
 25 | - [x] Support CocoaPods
 26 | - [x] Support localization
 27 | - [x] Support vertical and horizontal screen on iPhone and iPad
 28 | 
 29 | ## Requirements
 30 | * iOS 7.0 or later
 31 | * Xcode 7.0 or later
 32 | 
 33 | ## Architecture
 34 | ### Main
 35 | - `PYSearch`
 36 | - `PYSearchConst`
 37 | - `PYSearchViewController`
 38 | - `PYSearchSuggestionViewController`
 39 | 
 40 | ### Category
 41 | - `UIColor+PYSearchExtension`
 42 | - `UIView+PYSearchExtension`
 43 | - `NSBundle+PYSearchExtension`
 44 | 
 45 | ## Contents
 46 | * Getting Started
 47 |   * [Renderings](#Renderings)
 48 |   * [Styles](#Styles)
 49 |   
 50 | * Usage
 51 |   * [How to use](#Howtouse)
 52 |   * [Details (See the example program PYSearchExample for details)](#Details)
 53 |   * [Custom](#Custom)
 54 |   
 55 | * [Hope](#Hope)
 56 | 
 57 | ## <a id="Renderings"></a>Renderings
 58 | 
 59 | <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/PYSearchDemo.gif" width="375"> 
 60 | 
 61 | ## <a id="Styles"></a>Styles
 62 | 
 63 | #### Hot search style
 64 | <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/hotSearchStyle01.png" width="375"> <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/hotSearchStyle02.png" width="375"><br><img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/hotSearchStyle03.png" width="375"> <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/hotSearchStyle04.png" width="375"><br><img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/hotSearchStyle05.png" width="375"> <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/hotSearchStyle06.png" width="375"> 
 65 | 
 66 | #### Search history style
 67 | <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/searchHistoryStyle01.png" width="375"> <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/searchHistoryStyle02.png" width="375"><br><img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/searchHistoryStyle03.png" width="375"> <img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/searchHistoryStyle04.png" width="375"><br><img src="https://github.com/iphone5solo/learngit/raw/master/imagesForPYSearch/searchHistoryStyle05.png" width="375">
 68 | 
 69 | ## <a id="Howtouse"></a>How to use
 70 | * Use CocoaPods:
 71 |   - `pod "PYSearch"`
 72 |   - Import the main file:`#import <PYSearch.h>`
 73 | * Manual import:
 74 |   - Drag All files in the `PYSearch` folder to project
 75 |   - Import the main file:`#import "PYSearch.h"`
 76 |   
 77 |   
 78 | ## <a id="Details"></a>Details (See the example program PYSearchExample for details)
 79 | ```objc
 80 |     // 1. Create hotSearches array
 81 |     NSArray *hotSeaches = @[@"Java", @"Python", @"Objective-C", @"Swift", @"C", @"C++", @"PHP", @"C#", @"Perl", @"Go", @"JavaScript", @"R", @"Ruby", @"MATLAB"];
 82 |     // 2. Create searchViewController
 83 |     PYSearchViewController *searchViewController = [PYSearchViewController searchViewControllerWithHotSearches:hotSeaches searchBarPlaceholder:@"Search programming language" didSearchBlock:^(PYSearchViewController *searchViewController, UISearchBar *searchBar, NSString *searchText) {
 84 |         // Call this Block when completion search automatically
 85 |         // Such as: Push to a view controller
 86 |         [searchViewController.navigationController pushViewController:[[UIViewController alloc] init] animated:YES];
 87 |         
 88 |     }];
 89 |     // 3. present the searchViewController
 90 |     UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:searchViewController];
 91 |     [self presentViewController:nav  animated:NO completion:nil];
 92 | 
 93 | ```
 94 | 
 95 | ## <a id="Custom"></a>Custom
 96 | 
 97 | * Custom search suggestions display
 98 | ```objc
 99 | // 1. Set dataSource
100 | searchViewController.dataSource = self;
101 | // 2. Implement dataSource method
102 | ```
103 | 
104 | * Custom search result dispaly
105 | ```objc
106 | // 1. Set searchResultShowMode
107 | searchViewController.searchResultShowMode = PYSearchResultShowModeEmbed;
108 | // 2. Set searchResultController 
109 | searchViewController.searchResultController = [[UIViewController alloc] init];
110 | ```
111 | 
112 | * Set hotSearchStyle(default is PYHotSearchStyleNormalTag)
113 | ```objc
114 | // Set hotSearchStyle
115 | searchViewController.hotSearchStyle = PYHotSearchStyleColorfulTag;
116 | ```
117 | 
118 | * Set searchHistoryStyle(default is PYSearchHistoryStyleCell)
119 | ```objc
120 | // Set searchHistoryStyle
121 | searchViewController.searchHistoryStyle = PYSearchHistoryStyleBorderTag;
122 | ```
123 | 
124 | * Set searchHistoriesCachePath(default is PYSEARCH_SEARCH_HISTORY_CACHE_PATH)
125 | ```objc
126 | // Set searchHistoriesCachePath
127 | searchViewController.searchHistoriesCachePath = @"The cache path";
128 | ```
129 | 
130 | * Set searchHistoriesCount(default is 20)
131 | ```objc
132 | // Set searchHistoriesCount
133 | searchViewController. searchHistoriesCount = 6;
134 | ```
135 | 
136 | * Set searchResultShowMode(default is PYSearchResultShowModeCustom)
137 | ```objc
138 | // Set searchResultShowMode
139 | searchViewController.searchResultShowMode = PYSearchResultShowModeEmbed;
140 | ```
141 | 
142 | * Set searchSuggestionHidden(deafult is NO)
143 | ```objc
144 | // Set searchSuggestionHidden
145 | searchViewController.searchSuggestionHidden = YES;
146 | ```
147 | 
148 | ## <a id="Hope"></a>Hope
149 | 
150 | - If you have any questions during the process or want more interfaces to customize,you can [issues me](https://github.com/iphone5solo/PYSearch/issues/new)! 
151 | - Instead of giving me star, it is better to throw a bug to me!
152 | - If you want to participate in the maintenance of this project or have a good design style, welcome to pull request!
153 | - If you feel slightly discomfort in use, please contact me QQ:499491531 or Email:499491531@qq.com.
154 | - Hope to improve this project together, let it become more powerful, able to meet the needs of most users!
155 | 
156 | ## Licenses
157 | All source code is licensed under the MIT License.
158 | 


--------------------------------------------------------------------------------