├── HXTechnologyBlogCrawler.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcuserdata
│ └── huangxuan518.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── HXTechnologyBlogCrawler.xcscheme
│ └── xcschememanagement.plist
├── HXTechnologyBlogCrawler.xcworkspace
├── contents.xcworkspacedata
└── xcuserdata
│ └── huangxuan518.xcuserdatad
│ ├── UserInterfaceState.xcuserstate
│ └── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
├── HXTechnologyBlogCrawler
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── LaunchImage.launchimage
│ │ ├── Contents.json
│ │ ├── Default-568h@2x.png
│ │ └── Default-667h@2x.png
│ └── logo.imageset
│ │ ├── Contents.json
│ │ ├── logo.png
│ │ ├── logo@2x.png
│ │ └── logo@3x.png
├── CoreData
│ └── DatasourceModel.xcdatamodeld
│ │ └── DatasourceModel.xcdatamodel
│ │ └── contents
├── Hpple
│ ├── TFHpple.h
│ ├── TFHpple.m
│ ├── TFHppleElement.h
│ ├── TFHppleElement.m
│ ├── XPathQuery.h
│ └── XPathQuery.m
├── Info.plist
├── Main
│ ├── Model
│ │ ├── HXArticle.h
│ │ └── HXArticle.m
│ ├── View
│ │ ├── HXArticleListCell.h
│ │ ├── HXArticleListCell.m
│ │ ├── HXArticleListCell.xib
│ │ ├── HXHistoryCell.h
│ │ ├── HXHistoryCell.m
│ │ ├── HXHistoryCell.xib
│ │ ├── HXHistoryLastCell.h
│ │ ├── HXHistoryLastCell.m
│ │ └── HXHistoryLastCell.xib
│ └── ViewController
│ │ ├── Detail
│ │ ├── HXDetailWebViewController.h
│ │ ├── HXDetailWebViewController.m
│ │ └── HXDetailWebViewController.xib
│ │ ├── Home
│ │ ├── HXHomeViewController.h
│ │ ├── HXHomeViewController.m
│ │ └── HXHomeViewController.xib
│ │ └── List
│ │ ├── HXArticleListViewController.h
│ │ ├── HXArticleListViewController.m
│ │ ├── HXHistoryListViewController.h
│ │ ├── HXHistoryListViewController.m
│ │ ├── HXSearchResultViewController.h
│ │ └── HXSearchResultViewController.m
├── Request
│ ├── HXRequestManager.h
│ └── HXRequestManager.m
├── main.m
└── xiaoguo.gif
├── Podfile
├── Podfile.lock
├── Pods
├── Headers
│ ├── Private
│ │ └── MJRefresh
│ │ │ ├── MJRefresh.h
│ │ │ ├── MJRefreshAutoFooter.h
│ │ │ ├── MJRefreshAutoGifFooter.h
│ │ │ ├── MJRefreshAutoNormalFooter.h
│ │ │ ├── MJRefreshAutoStateFooter.h
│ │ │ ├── MJRefreshBackFooter.h
│ │ │ ├── MJRefreshBackGifFooter.h
│ │ │ ├── MJRefreshBackNormalFooter.h
│ │ │ ├── MJRefreshBackStateFooter.h
│ │ │ ├── MJRefreshComponent.h
│ │ │ ├── MJRefreshConst.h
│ │ │ ├── MJRefreshFooter.h
│ │ │ ├── MJRefreshGifHeader.h
│ │ │ ├── MJRefreshHeader.h
│ │ │ ├── MJRefreshNormalHeader.h
│ │ │ ├── MJRefreshStateHeader.h
│ │ │ ├── UIScrollView+MJExtension.h
│ │ │ ├── UIScrollView+MJRefresh.h
│ │ │ └── UIView+MJExtension.h
│ └── Public
│ │ └── MJRefresh
│ │ ├── MJRefresh.h
│ │ ├── MJRefreshAutoFooter.h
│ │ ├── MJRefreshAutoGifFooter.h
│ │ ├── MJRefreshAutoNormalFooter.h
│ │ ├── MJRefreshAutoStateFooter.h
│ │ ├── MJRefreshBackFooter.h
│ │ ├── MJRefreshBackGifFooter.h
│ │ ├── MJRefreshBackNormalFooter.h
│ │ ├── MJRefreshBackStateFooter.h
│ │ ├── MJRefreshComponent.h
│ │ ├── MJRefreshConst.h
│ │ ├── MJRefreshFooter.h
│ │ ├── MJRefreshGifHeader.h
│ │ ├── MJRefreshHeader.h
│ │ ├── MJRefreshNormalHeader.h
│ │ ├── MJRefreshStateHeader.h
│ │ ├── UIScrollView+MJExtension.h
│ │ ├── UIScrollView+MJRefresh.h
│ │ └── UIView+MJExtension.h
├── MJRefresh
│ ├── LICENSE
│ ├── MJRefresh
│ │ ├── Base
│ │ │ ├── MJRefreshAutoFooter.h
│ │ │ ├── MJRefreshAutoFooter.m
│ │ │ ├── MJRefreshBackFooter.h
│ │ │ ├── MJRefreshBackFooter.m
│ │ │ ├── MJRefreshComponent.h
│ │ │ ├── MJRefreshComponent.m
│ │ │ ├── MJRefreshFooter.h
│ │ │ ├── MJRefreshFooter.m
│ │ │ ├── MJRefreshHeader.h
│ │ │ └── MJRefreshHeader.m
│ │ ├── Custom
│ │ │ ├── Footer
│ │ │ │ ├── Auto
│ │ │ │ │ ├── MJRefreshAutoGifFooter.h
│ │ │ │ │ ├── MJRefreshAutoGifFooter.m
│ │ │ │ │ ├── MJRefreshAutoNormalFooter.h
│ │ │ │ │ ├── MJRefreshAutoNormalFooter.m
│ │ │ │ │ ├── MJRefreshAutoStateFooter.h
│ │ │ │ │ └── MJRefreshAutoStateFooter.m
│ │ │ │ └── Back
│ │ │ │ │ ├── MJRefreshBackGifFooter.h
│ │ │ │ │ ├── MJRefreshBackGifFooter.m
│ │ │ │ │ ├── MJRefreshBackNormalFooter.h
│ │ │ │ │ ├── MJRefreshBackNormalFooter.m
│ │ │ │ │ ├── MJRefreshBackStateFooter.h
│ │ │ │ │ └── MJRefreshBackStateFooter.m
│ │ │ └── Header
│ │ │ │ ├── MJRefreshGifHeader.h
│ │ │ │ ├── MJRefreshGifHeader.m
│ │ │ │ ├── MJRefreshNormalHeader.h
│ │ │ │ ├── MJRefreshNormalHeader.m
│ │ │ │ ├── MJRefreshStateHeader.h
│ │ │ │ └── MJRefreshStateHeader.m
│ │ ├── MJRefresh.bundle
│ │ │ └── arrow@2x.png
│ │ ├── MJRefresh.h
│ │ ├── MJRefreshConst.h
│ │ ├── MJRefreshConst.m
│ │ ├── UIScrollView+MJExtension.h
│ │ ├── UIScrollView+MJExtension.m
│ │ ├── UIScrollView+MJRefresh.h
│ │ ├── UIScrollView+MJRefresh.m
│ │ ├── UIView+MJExtension.h
│ │ └── UIView+MJExtension.m
│ └── README.md
├── Manifest.lock
├── Pods.xcodeproj
│ ├── project.pbxproj
│ └── xcuserdata
│ │ └── huangxuan518.xcuserdatad
│ │ └── xcschemes
│ │ ├── MJRefresh.xcscheme
│ │ ├── Pods-HXTechnologyBlogCrawler.xcscheme
│ │ └── xcschememanagement.plist
└── Target Support Files
│ ├── MJRefresh
│ ├── MJRefresh-dummy.m
│ ├── MJRefresh-prefix.pch
│ └── MJRefresh.xcconfig
│ └── Pods-HXTechnologyBlogCrawler
│ ├── Pods-HXTechnologyBlogCrawler-acknowledgements.markdown
│ ├── Pods-HXTechnologyBlogCrawler-acknowledgements.plist
│ ├── Pods-HXTechnologyBlogCrawler-dummy.m
│ ├── Pods-HXTechnologyBlogCrawler-frameworks.sh
│ ├── Pods-HXTechnologyBlogCrawler-resources.sh
│ ├── Pods-HXTechnologyBlogCrawler.debug.xcconfig
│ └── Pods-HXTechnologyBlogCrawler.release.xcconfig
└── README.md
/HXTechnologyBlogCrawler.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler.xcodeproj/xcuserdata/huangxuan518.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler.xcodeproj/xcuserdata/huangxuan518.xcuserdatad/xcschemes/HXTechnologyBlogCrawler.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler.xcodeproj/xcuserdata/huangxuan518.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | HXTechnologyBlogCrawler.xcscheme
8 |
9 | orderHint
10 | 1
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | E49D47361D65670C004FE1E6
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler.xcworkspace/xcuserdata/huangxuan518.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangxuan518/HXTechnologyBlogCrawler/0a2b6b0224ac0117877ef724c8fca5ec515d0bff/HXTechnologyBlogCrawler.xcworkspace/xcuserdata/huangxuan518.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler.xcworkspace/xcuserdata/huangxuan518.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // HXHtmlParser
4 | //
5 | // Created by 黄轩 on 16/8/18.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // HXHtmlParser
4 | //
5 | // Created by 黄轩 on 16/8/18.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 | #import "HXHomeViewController.h"
11 |
12 | @interface AppDelegate ()
13 |
14 | @end
15 |
16 | @implementation AppDelegate
17 |
18 |
19 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
20 | // Override point for customization after application launch.
21 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
22 | self.window.backgroundColor = [UIColor whiteColor];
23 |
24 | HXHomeViewController *vc = [HXHomeViewController new];
25 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
26 | self.window.rootViewController = nav;
27 |
28 | [self.window makeKeyAndVisible];
29 |
30 | return YES;
31 | }
32 |
33 | - (void)applicationWillResignActive:(UIApplication *)application {
34 | // 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.
35 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
36 | }
37 |
38 | - (void)applicationDidEnterBackground:(UIApplication *)application {
39 | // 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.
40 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
41 | }
42 |
43 | - (void)applicationWillEnterForeground:(UIApplication *)application {
44 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
45 | }
46 |
47 | - (void)applicationDidBecomeActive:(UIApplication *)application {
48 | // 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.
49 | }
50 |
51 | - (void)applicationWillTerminate:(UIApplication *)application {
52 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "8.0",
8 | "subtype" : "736h",
9 | "scale" : "3x"
10 | },
11 | {
12 | "orientation" : "landscape",
13 | "idiom" : "iphone",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "8.0",
16 | "subtype" : "736h",
17 | "scale" : "3x"
18 | },
19 | {
20 | "extent" : "full-screen",
21 | "idiom" : "iphone",
22 | "subtype" : "667h",
23 | "filename" : "Default-667h@2x.png",
24 | "minimum-system-version" : "8.0",
25 | "orientation" : "portrait",
26 | "scale" : "2x"
27 | },
28 | {
29 | "orientation" : "portrait",
30 | "idiom" : "iphone",
31 | "extent" : "full-screen",
32 | "minimum-system-version" : "7.0",
33 | "scale" : "2x"
34 | },
35 | {
36 | "extent" : "full-screen",
37 | "idiom" : "iphone",
38 | "subtype" : "retina4",
39 | "filename" : "Default-568h@2x.png",
40 | "minimum-system-version" : "7.0",
41 | "orientation" : "portrait",
42 | "scale" : "2x"
43 | },
44 | {
45 | "orientation" : "portrait",
46 | "idiom" : "iphone",
47 | "extent" : "full-screen",
48 | "scale" : "1x"
49 | },
50 | {
51 | "orientation" : "portrait",
52 | "idiom" : "iphone",
53 | "extent" : "full-screen",
54 | "scale" : "2x"
55 | },
56 | {
57 | "orientation" : "portrait",
58 | "idiom" : "iphone",
59 | "extent" : "full-screen",
60 | "subtype" : "retina4",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangxuan518/HXTechnologyBlogCrawler/0a2b6b0224ac0117877ef724c8fca5ec515d0bff/HXTechnologyBlogCrawler/Assets.xcassets/LaunchImage.launchimage/Default-568h@2x.png
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangxuan518/HXTechnologyBlogCrawler/0a2b6b0224ac0117877ef724c8fca5ec515d0bff/HXTechnologyBlogCrawler/Assets.xcassets/LaunchImage.launchimage/Default-667h@2x.png
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/logo.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "filename" : "logo.png",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "filename" : "logo@2x.png",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "universal",
15 | "filename" : "logo@3x.png",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "version" : 1,
21 | "author" : "xcode"
22 | }
23 | }
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/logo.imageset/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangxuan518/HXTechnologyBlogCrawler/0a2b6b0224ac0117877ef724c8fca5ec515d0bff/HXTechnologyBlogCrawler/Assets.xcassets/logo.imageset/logo.png
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/logo.imageset/logo@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangxuan518/HXTechnologyBlogCrawler/0a2b6b0224ac0117877ef724c8fca5ec515d0bff/HXTechnologyBlogCrawler/Assets.xcassets/logo.imageset/logo@2x.png
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Assets.xcassets/logo.imageset/logo@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangxuan518/HXTechnologyBlogCrawler/0a2b6b0224ac0117877ef724c8fca5ec515d0bff/HXTechnologyBlogCrawler/Assets.xcassets/logo.imageset/logo@3x.png
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/CoreData/DatasourceModel.xcdatamodeld/DatasourceModel.xcdatamodel/contents:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Hpple/TFHpple.h:
--------------------------------------------------------------------------------
1 | //
2 | // TFHpple.h
3 | // Hpple
4 | //
5 | // Created by Geoffrey Grosenbach on 1/31/09.
6 | //
7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
8 | //
9 | // MIT LICENSE
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining
12 | // a copy of this software and associated documentation files (the
13 | // "Software"), to deal in the Software without restriction, including
14 | // without limitation the rights to use, copy, modify, merge, publish,
15 | // distribute, sublicense, and/or sell copies of the Software, and to
16 | // permit persons to whom the Software is furnished to do so, subject to
17 | // the following conditions:
18 | //
19 | // The above copyright notice and this permission notice shall be
20 | // included in all copies or substantial portions of the Software.
21 | //
22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 |
30 |
31 | #import
32 |
33 | #import "TFHppleElement.h"
34 |
35 | @interface TFHpple : NSObject
36 |
37 | - (id) initWithData:(NSData *)theData encoding:(NSString *)encoding isXML:(BOOL)isDataXML;
38 | - (id) initWithData:(NSData *)theData isXML:(BOOL)isDataXML;
39 | - (id) initWithXMLData:(NSData *)theData encoding:(NSString *)encoding;
40 | - (id) initWithXMLData:(NSData *)theData;
41 | - (id) initWithHTMLData:(NSData *)theData encoding:(NSString *)encoding;
42 | - (id) initWithHTMLData:(NSData *)theData;
43 |
44 | + (TFHpple *) hppleWithData:(NSData *)theData encoding:(NSString *)encoding isXML:(BOOL)isDataXML;
45 | + (TFHpple *) hppleWithData:(NSData *)theData isXML:(BOOL)isDataXML;
46 | + (TFHpple *) hppleWithXMLData:(NSData *)theData encoding:(NSString *)encoding;
47 | + (TFHpple *) hppleWithXMLData:(NSData *)theData;
48 | + (TFHpple *) hppleWithHTMLData:(NSData *)theData encoding:(NSString *)encoding;
49 | + (TFHpple *) hppleWithHTMLData:(NSData *)theData;
50 |
51 | - (NSArray *) searchWithXPathQuery:(NSString *)xPathOrCSS;
52 | - (TFHppleElement *) peekAtSearchWithXPathQuery:(NSString *)xPathOrCSS;
53 |
54 | @property (nonatomic, readonly) NSData * data;
55 | @property (nonatomic, readonly) NSString * encoding;
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Hpple/TFHpple.m:
--------------------------------------------------------------------------------
1 | //
2 | // TFHpple.m
3 | // Hpple
4 | //
5 | // Created by Geoffrey Grosenbach on 1/31/09.
6 | //
7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
8 | //
9 | // MIT LICENSE
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining
12 | // a copy of this software and associated documentation files (the
13 | // "Software"), to deal in the Software without restriction, including
14 | // without limitation the rights to use, copy, modify, merge, publish,
15 | // distribute, sublicense, and/or sell copies of the Software, and to
16 | // permit persons to whom the Software is furnished to do so, subject to
17 | // the following conditions:
18 | //
19 | // The above copyright notice and this permission notice shall be
20 | // included in all copies or substantial portions of the Software.
21 | //
22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 |
30 | #import "TFHpple.h"
31 | #import "XPathQuery.h"
32 |
33 | @interface TFHpple ()
34 | {
35 | NSData * data;
36 | NSString * encoding;
37 | BOOL isXML;
38 | }
39 |
40 | @end
41 |
42 |
43 | @implementation TFHpple
44 |
45 | @synthesize data;
46 | @synthesize encoding;
47 |
48 |
49 | - (id) initWithData:(NSData *)theData encoding:(NSString *)theEncoding isXML:(BOOL)isDataXML
50 | {
51 | if (!(self = [super init])) {
52 | return nil;
53 | }
54 |
55 | data = theData;
56 | encoding = theEncoding;
57 | isXML = isDataXML;
58 |
59 | return self;
60 | }
61 |
62 | - (id) initWithData:(NSData *)theData isXML:(BOOL)isDataXML
63 | {
64 | return [self initWithData:theData encoding:nil isXML:isDataXML];
65 | }
66 |
67 | - (id) initWithXMLData:(NSData *)theData encoding:(NSString *)theEncoding
68 | {
69 | return [self initWithData:theData encoding:theEncoding isXML:YES];
70 | }
71 |
72 | - (id) initWithXMLData:(NSData *)theData
73 | {
74 | return [self initWithData:theData encoding:nil isXML:YES];
75 | }
76 |
77 | - (id) initWithHTMLData:(NSData *)theData encoding:(NSString *)theEncoding
78 | {
79 | return [self initWithData:theData encoding:theEncoding isXML:NO];
80 | }
81 |
82 | - (id) initWithHTMLData:(NSData *)theData
83 | {
84 | return [self initWithData:theData encoding:nil isXML:NO];
85 | }
86 |
87 | + (TFHpple *) hppleWithData:(NSData *)theData encoding:(NSString *)theEncoding isXML:(BOOL)isDataXML {
88 | return [[[self class] alloc] initWithData:theData encoding:theEncoding isXML:isDataXML];
89 | }
90 |
91 | + (TFHpple *) hppleWithData:(NSData *)theData isXML:(BOOL)isDataXML {
92 | return [[self class] hppleWithData:theData encoding:nil isXML:isDataXML];
93 | }
94 |
95 | + (TFHpple *) hppleWithHTMLData:(NSData *)theData encoding:(NSString *)theEncoding {
96 | return [[self class] hppleWithData:theData encoding:theEncoding isXML:NO];
97 | }
98 |
99 | + (TFHpple *) hppleWithHTMLData:(NSData *)theData {
100 | return [[self class] hppleWithData:theData encoding:nil isXML:NO];
101 | }
102 |
103 | + (TFHpple *) hppleWithXMLData:(NSData *)theData encoding:(NSString *)theEncoding {
104 | return [[self class] hppleWithData:theData encoding:theEncoding isXML:YES];
105 | }
106 |
107 | + (TFHpple *) hppleWithXMLData:(NSData *)theData {
108 | return [[self class] hppleWithData:theData encoding:nil isXML:YES];
109 | }
110 |
111 | #pragma mark -
112 |
113 | // Returns all elements at xPath.
114 | - (NSArray *) searchWithXPathQuery:(NSString *)xPathOrCSS
115 | {
116 | NSArray * detailNodes = nil;
117 | if (isXML) {
118 | detailNodes = PerformXMLXPathQueryWithEncoding(data, xPathOrCSS, encoding);
119 | } else {
120 | detailNodes = PerformHTMLXPathQueryWithEncoding(data, xPathOrCSS, encoding);
121 | }
122 |
123 | NSMutableArray * hppleElements = [NSMutableArray array];
124 | for (id node in detailNodes) {
125 | [hppleElements addObject:[TFHppleElement hppleElementWithNode:node isXML:isXML withEncoding:encoding]];
126 | }
127 | return hppleElements;
128 | }
129 |
130 | // Returns first element at xPath
131 | - (TFHppleElement *) peekAtSearchWithXPathQuery:(NSString *)xPathOrCSS
132 | {
133 | NSArray * elements = [self searchWithXPathQuery:xPathOrCSS];
134 | if ([elements count] >= 1) {
135 | return [elements objectAtIndex:0];
136 | }
137 |
138 | return nil;
139 | }
140 |
141 | @end
142 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Hpple/TFHppleElement.h:
--------------------------------------------------------------------------------
1 | //
2 | // TFHppleElement.h
3 | // Hpple
4 | //
5 | // Created by Geoffrey Grosenbach on 1/31/09.
6 | //
7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
8 | //
9 | // MIT LICENSE
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining
12 | // a copy of this software and associated documentation files (the
13 | // "Software"), to deal in the Software without restriction, including
14 | // without limitation the rights to use, copy, modify, merge, publish,
15 | // distribute, sublicense, and/or sell copies of the Software, and to
16 | // permit persons to whom the Software is furnished to do so, subject to
17 | // the following conditions:
18 | //
19 | // The above copyright notice and this permission notice shall be
20 | // included in all copies or substantial portions of the Software.
21 | //
22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 |
30 | #import
31 |
32 |
33 | @interface TFHppleElement : NSObject
34 |
35 | - (id) initWithNode:(NSDictionary *) theNode isXML:(BOOL)isDataXML withEncoding:(NSString *)theEncoding;
36 |
37 | + (TFHppleElement *) hppleElementWithNode:(NSDictionary *) theNode isXML:(BOOL)isDataXML withEncoding:(NSString *)theEncoding;
38 |
39 | @property (nonatomic, copy, readonly) NSString *raw;
40 | // Returns this tag's innerHTML content.
41 | @property (nonatomic, copy, readonly) NSString *content;
42 |
43 | // Returns the name of the current tag, such as "h3".
44 | @property (nonatomic, copy, readonly) NSString *tagName;
45 |
46 | // Returns tag attributes with name as key and content as value.
47 | // href = 'http://peepcode.com'
48 | // class = 'highlight'
49 | @property (nonatomic, strong, readonly) NSDictionary *attributes;
50 |
51 | // Returns the children of a given node
52 | @property (nonatomic, strong, readonly) NSArray *children;
53 |
54 | // Returns the first child of a given node
55 | @property (nonatomic, strong, readonly) TFHppleElement *firstChild;
56 |
57 | // the parent of a node
58 | @property (nonatomic, unsafe_unretained, readonly) TFHppleElement *parent;
59 |
60 | // Returns YES if the node has any child
61 | // This is more efficient than using the children property since no NSArray is constructed
62 | - (BOOL)hasChildren;
63 |
64 | // Returns YES if this is a text node
65 | - (BOOL)isTextNode;
66 |
67 | // Provides easy access to the content of a specific attribute,
68 | // such as 'href' or 'class'.
69 | - (NSString *) objectForKey:(NSString *) theKey;
70 |
71 | // Returns the children whose tag name equals the given string
72 | // (comparison is performed with NSString's isEqualToString)
73 | // Returns an empty array if no matching child is found
74 | - (NSArray *) childrenWithTagName:(NSString *)tagName;
75 |
76 | // Returns the first child node whose tag name equals the given string
77 | // (comparison is performed with NSString's isEqualToString)
78 | // Returns nil if no matching child is found
79 | - (TFHppleElement *) firstChildWithTagName:(NSString *)tagName;
80 |
81 | // Returns the children whose class equals the given string
82 | // (comparison is performed with NSString's isEqualToString)
83 | // Returns an empty array if no matching child is found
84 | - (NSArray *) childrenWithClassName:(NSString *)className;
85 |
86 | // Returns the first child whose class requals the given string
87 | // (comparison is performed with NSString's isEqualToString)
88 | // Returns nil if no matching child is found
89 | - (TFHppleElement *) firstChildWithClassName:(NSString*)className;
90 |
91 | // Returns the first text node from this element's children
92 | // Returns nil if there is no text node among the children
93 | - (TFHppleElement *) firstTextChild;
94 |
95 | // Returns the string contained by the first text node from this element's children
96 | // Convenience method which can be used instead of firstTextChild.content
97 | - (NSString *) text;
98 |
99 | // Returns elements searched with xpath
100 | - (NSArray *) searchWithXPathQuery:(NSString *)xPathOrCSS;
101 |
102 | // Custom keyed subscripting
103 | - (id)objectForKeyedSubscript:(id)key;
104 |
105 |
106 | @end
107 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Hpple/TFHppleElement.m:
--------------------------------------------------------------------------------
1 | //
2 | // TFHppleElement.m
3 | // Hpple
4 | //
5 | // Created by Geoffrey Grosenbach on 1/31/09.
6 | //
7 | // Copyright (c) 2009 Topfunky Corporation, http://topfunky.com
8 | //
9 | // MIT LICENSE
10 | //
11 | // Permission is hereby granted, free of charge, to any person obtaining
12 | // a copy of this software and associated documentation files (the
13 | // "Software"), to deal in the Software without restriction, including
14 | // without limitation the rights to use, copy, modify, merge, publish,
15 | // distribute, sublicense, and/or sell copies of the Software, and to
16 | // permit persons to whom the Software is furnished to do so, subject to
17 | // the following conditions:
18 | //
19 | // The above copyright notice and this permission notice shall be
20 | // included in all copies or substantial portions of the Software.
21 | //
22 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 |
30 |
31 | #import "TFHppleElement.h"
32 | #import "XPathQuery.h"
33 |
34 | static NSString * const TFHppleNodeContentKey = @"nodeContent";
35 | static NSString * const TFHppleNodeNameKey = @"nodeName";
36 | static NSString * const TFHppleNodeChildrenKey = @"nodeChildArray";
37 | static NSString * const TFHppleNodeAttributeArrayKey = @"nodeAttributeArray";
38 | static NSString * const TFHppleNodeAttributeNameKey = @"attributeName";
39 |
40 | static NSString * const TFHppleTextNodeName = @"text";
41 |
42 | @interface TFHppleElement ()
43 | {
44 | NSDictionary * node;
45 | BOOL isXML;
46 | NSString *encoding;
47 | __unsafe_unretained TFHppleElement *parent;
48 | }
49 |
50 | @property (nonatomic, unsafe_unretained, readwrite) TFHppleElement *parent;
51 |
52 | @end
53 |
54 | @implementation TFHppleElement
55 | @synthesize parent;
56 |
57 |
58 | - (id) initWithNode:(NSDictionary *) theNode isXML:(BOOL)isDataXML withEncoding:(NSString *)theEncoding
59 | {
60 | if (!(self = [super init]))
61 | return nil;
62 |
63 | isXML = isDataXML;
64 | node = theNode;
65 | encoding = theEncoding;
66 |
67 | return self;
68 | }
69 |
70 | + (TFHppleElement *) hppleElementWithNode:(NSDictionary *) theNode isXML:(BOOL)isDataXML withEncoding:(NSString *)theEncoding
71 | {
72 | return [[[self class] alloc] initWithNode:theNode isXML:isDataXML withEncoding:theEncoding];
73 | }
74 |
75 | #pragma mark -
76 |
77 | - (NSString *)raw
78 | {
79 | return [node objectForKey:@"raw"];
80 | }
81 |
82 | - (NSString *) content
83 | {
84 | return [node objectForKey:TFHppleNodeContentKey];
85 | }
86 |
87 |
88 | - (NSString *) tagName
89 | {
90 | return [node objectForKey:TFHppleNodeNameKey];
91 | }
92 |
93 | - (NSArray *) children
94 | {
95 | NSMutableArray *children = [NSMutableArray array];
96 | for (NSDictionary *child in [node objectForKey:TFHppleNodeChildrenKey]) {
97 | TFHppleElement *element = [TFHppleElement hppleElementWithNode:child isXML:isXML withEncoding:encoding];
98 | element.parent = self;
99 | [children addObject:element];
100 | }
101 | return children;
102 | }
103 |
104 | - (TFHppleElement *) firstChild
105 | {
106 | NSArray * children = self.children;
107 | if (children.count)
108 | return [children objectAtIndex:0];
109 | return nil;
110 | }
111 |
112 |
113 | - (NSDictionary *) attributes
114 | {
115 | NSMutableDictionary * translatedAttributes = [NSMutableDictionary dictionary];
116 | for (NSDictionary * attributeDict in [node objectForKey:TFHppleNodeAttributeArrayKey]) {
117 | if ([attributeDict objectForKey:TFHppleNodeContentKey] && [attributeDict objectForKey:TFHppleNodeAttributeNameKey]) {
118 | [translatedAttributes setObject:[attributeDict objectForKey:TFHppleNodeContentKey]
119 | forKey:[attributeDict objectForKey:TFHppleNodeAttributeNameKey]];
120 | }
121 | }
122 | return translatedAttributes;
123 | }
124 |
125 | - (NSString *) objectForKey:(NSString *) theKey
126 | {
127 | return [[self attributes] objectForKey:theKey];
128 | }
129 |
130 | - (id) description
131 | {
132 | return [node description];
133 | }
134 |
135 | - (BOOL)hasChildren
136 | {
137 | if ([node objectForKey:TFHppleNodeChildrenKey])
138 | return YES;
139 | else
140 | return NO;
141 | }
142 |
143 | - (BOOL)isTextNode
144 | {
145 | // we must distinguish between real text nodes and standard nodes with tha name "text" ()
146 | // real text nodes must have content
147 | if ([self.tagName isEqualToString:TFHppleTextNodeName] && (self.content))
148 | return YES;
149 | else
150 | return NO;
151 | }
152 |
153 | - (NSArray*) childrenWithTagName:(NSString*)tagName
154 | {
155 | NSMutableArray* matches = [NSMutableArray array];
156 |
157 | for (TFHppleElement* child in self.children)
158 | {
159 | if ([child.tagName isEqualToString:tagName])
160 | [matches addObject:child];
161 | }
162 |
163 | return matches;
164 | }
165 |
166 | - (TFHppleElement *) firstChildWithTagName:(NSString*)tagName
167 | {
168 | for (TFHppleElement* child in self.children)
169 | {
170 | if ([child.tagName isEqualToString:tagName])
171 | return child;
172 | }
173 |
174 | return nil;
175 | }
176 |
177 | - (NSArray*) childrenWithClassName:(NSString*)className
178 | {
179 | NSMutableArray* matches = [NSMutableArray array];
180 |
181 | for (TFHppleElement* child in self.children)
182 | {
183 | if ([[child objectForKey:@"class"] isEqualToString:className])
184 | [matches addObject:child];
185 | }
186 |
187 | return matches;
188 | }
189 |
190 | - (TFHppleElement *) firstChildWithClassName:(NSString*)className
191 | {
192 | for (TFHppleElement* child in self.children)
193 | {
194 | if ([[child objectForKey:@"class"] isEqualToString:className])
195 | return child;
196 | }
197 |
198 | return nil;
199 | }
200 |
201 | - (TFHppleElement *) firstTextChild
202 | {
203 | for (TFHppleElement* child in self.children)
204 | {
205 | if ([child isTextNode])
206 | return child;
207 | }
208 |
209 | return [self firstChildWithTagName:TFHppleTextNodeName];
210 | }
211 |
212 | - (NSString *) text
213 | {
214 | return self.firstTextChild.content;
215 | }
216 |
217 | // Returns all elements at xPath.
218 | - (NSArray *) searchWithXPathQuery:(NSString *)xPathOrCSS
219 | {
220 |
221 | NSData *data = [self.raw dataUsingEncoding:NSUTF8StringEncoding];
222 |
223 | NSArray * detailNodes = nil;
224 | if (isXML) {
225 | detailNodes = PerformXMLXPathQueryWithEncoding(data, xPathOrCSS, encoding);
226 | } else {
227 | detailNodes = PerformHTMLXPathQueryWithEncoding(data, xPathOrCSS, encoding);
228 | }
229 |
230 | NSMutableArray * hppleElements = [NSMutableArray array];
231 | for (id newNode in detailNodes) {
232 | [hppleElements addObject:[TFHppleElement hppleElementWithNode:newNode isXML:isXML withEncoding:encoding]];
233 | }
234 | return hppleElements;
235 | }
236 |
237 | // Custom keyed subscripting
238 | - (id)objectForKeyedSubscript:(id)key
239 | {
240 | return [self objectForKey:key];
241 | }
242 |
243 | @end
244 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Hpple/XPathQuery.h:
--------------------------------------------------------------------------------
1 | //
2 | // XPathQuery.h
3 | // FuelFinder
4 | //
5 | // Created by Matt Gallagher on 4/08/08.
6 | // Copyright 2008 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query);
12 | NSArray *PerformHTMLXPathQueryWithEncoding(NSData *document, NSString *query,NSString *encoding);
13 | NSArray *PerformXMLXPathQuery(NSData *document, NSString *query);
14 | NSArray *PerformXMLXPathQueryWithEncoding(NSData *document, NSString *query,NSString *encoding);
15 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Hpple/XPathQuery.m:
--------------------------------------------------------------------------------
1 | //
2 | // XPathQuery.m
3 | // FuelFinder
4 | //
5 | // Created by Matt Gallagher on 4/08/08.
6 | // Copyright 2008 __MyCompanyName__. All rights reserved.
7 | //
8 |
9 | #import "XPathQuery.h"
10 |
11 | #import
12 | #import
13 | #import
14 | #import
15 | #import
16 |
17 | NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult,BOOL parentContent);
18 | NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query);
19 |
20 | NSDictionary *DictionaryForNode(xmlNodePtr currentNode, NSMutableDictionary *parentResult,BOOL parentContent)
21 | {
22 | NSMutableDictionary *resultForNode = [NSMutableDictionary dictionary];
23 | if (currentNode->name) {
24 | NSString *currentNodeContent = [NSString stringWithCString:(const char *)currentNode->name
25 | encoding:NSUTF8StringEncoding];
26 | resultForNode[@"nodeName"] = currentNodeContent;
27 | }
28 |
29 | xmlChar *nodeContent = xmlNodeGetContent(currentNode);
30 | if (nodeContent != NULL) {
31 | NSString *currentNodeContent = [NSString stringWithCString:(const char *)nodeContent
32 | encoding:NSUTF8StringEncoding];
33 | if ([resultForNode[@"nodeName"] isEqual:@"text"] && parentResult) {
34 | if (parentContent) {
35 | NSCharacterSet *charactersToTrim = [NSCharacterSet whitespaceAndNewlineCharacterSet];
36 | parentResult[@"nodeContent"] = [currentNodeContent stringByTrimmingCharactersInSet:charactersToTrim];
37 | return nil;
38 | }
39 | if (currentNodeContent != nil) {
40 | resultForNode[@"nodeContent"] = currentNodeContent;
41 | }
42 | return resultForNode;
43 | } else {
44 | resultForNode[@"nodeContent"] = currentNodeContent;
45 | }
46 | xmlFree(nodeContent);
47 | }
48 |
49 | xmlAttr *attribute = currentNode->properties;
50 | if (attribute) {
51 | NSMutableArray *attributeArray = [NSMutableArray array];
52 | while (attribute) {
53 | NSMutableDictionary *attributeDictionary = [NSMutableDictionary dictionary];
54 | NSString *attributeName = [NSString stringWithCString:(const char *)attribute->name
55 | encoding:NSUTF8StringEncoding];
56 | if (attributeName) {
57 | attributeDictionary[@"attributeName"] = attributeName;
58 | }
59 |
60 | if (attribute->children) {
61 | NSDictionary *childDictionary = DictionaryForNode(attribute->children, attributeDictionary, true);
62 | if (childDictionary) {
63 | attributeDictionary[@"attributeContent"] = childDictionary;
64 | }
65 | }
66 |
67 | if ([attributeDictionary count] > 0) {
68 | [attributeArray addObject:attributeDictionary];
69 | }
70 | attribute = attribute->next;
71 | }
72 |
73 | if ([attributeArray count] > 0) {
74 | resultForNode[@"nodeAttributeArray"] = attributeArray;
75 | }
76 | }
77 |
78 | xmlNodePtr childNode = currentNode->children;
79 | if (childNode) {
80 | NSMutableArray *childContentArray = [NSMutableArray array];
81 | while (childNode) {
82 | NSDictionary *childDictionary = DictionaryForNode(childNode, resultForNode,false);
83 | if (childDictionary) {
84 | [childContentArray addObject:childDictionary];
85 | }
86 | childNode = childNode->next;
87 | }
88 | if ([childContentArray count] > 0) {
89 | resultForNode[@"nodeChildArray"] = childContentArray;
90 | }
91 | }
92 |
93 | xmlBufferPtr buffer = xmlBufferCreate();
94 | xmlNodeDump(buffer, currentNode->doc, currentNode, 0, 0);
95 | NSString *rawContent = [NSString stringWithCString:(const char *)buffer->content encoding:NSUTF8StringEncoding];
96 | if (rawContent != nil) {
97 | resultForNode[@"raw"] = rawContent;
98 | }
99 | xmlBufferFree(buffer);
100 | return resultForNode;
101 | }
102 |
103 | NSArray *PerformXPathQuery(xmlDocPtr doc, NSString *query)
104 | {
105 | xmlXPathContextPtr xpathCtx;
106 | xmlXPathObjectPtr xpathObj;
107 |
108 | /* Make sure that passed query is non-nil and is NSString object */
109 | if (query == nil || ![query isKindOfClass:[NSString class]]) {
110 | return nil;
111 | }
112 |
113 | /* Create xpath evaluation context */
114 | xpathCtx = xmlXPathNewContext(doc);
115 | if(xpathCtx == NULL) {
116 | NSLog(@"Unable to create XPath context.");
117 | return nil;
118 | }
119 |
120 | /* Evaluate xpath expression */
121 | xpathObj = xmlXPathEvalExpression((xmlChar *)[query cStringUsingEncoding:NSUTF8StringEncoding], xpathCtx);
122 | if(xpathObj == NULL) {
123 | NSLog(@"Unable to evaluate XPath.");
124 | xmlXPathFreeContext(xpathCtx);
125 | return nil;
126 | }
127 |
128 | xmlNodeSetPtr nodes = xpathObj->nodesetval;
129 | if (!nodes) {
130 | NSLog(@"Nodes was nil.");
131 | xmlXPathFreeObject(xpathObj);
132 | xmlXPathFreeContext(xpathCtx);
133 | return nil;
134 | }
135 |
136 | NSMutableArray *resultNodes = [NSMutableArray array];
137 | for (NSInteger i = 0; i < nodes->nodeNr; i++) {
138 | NSDictionary *nodeDictionary = DictionaryForNode(nodes->nodeTab[i], nil,false);
139 | if (nodeDictionary) {
140 | [resultNodes addObject:nodeDictionary];
141 | }
142 | }
143 |
144 | /* Cleanup */
145 | xmlXPathFreeObject(xpathObj);
146 | xmlXPathFreeContext(xpathCtx);
147 |
148 | return resultNodes;
149 | }
150 |
151 | NSArray *PerformHTMLXPathQuery(NSData *document, NSString *query) {
152 | return PerformHTMLXPathQueryWithEncoding(document, query, nil);
153 | }
154 |
155 | NSArray *PerformHTMLXPathQueryWithEncoding(NSData *document, NSString *query,NSString *encoding)
156 | {
157 | xmlDocPtr doc;
158 |
159 | /* Load XML document */
160 | const char *encoded = encoding ? [encoding cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
161 |
162 | doc = htmlReadMemory([document bytes], (int)[document length], "", encoded, HTML_PARSE_NOWARNING | HTML_PARSE_NOERROR);
163 | if (doc == NULL) {
164 | NSLog(@"Unable to parse.");
165 | return nil;
166 | }
167 |
168 | NSArray *result = PerformXPathQuery(doc, query);
169 | xmlFreeDoc(doc);
170 |
171 | return result;
172 | }
173 |
174 | NSArray *PerformXMLXPathQuery(NSData *document, NSString *query) {
175 | return PerformXMLXPathQueryWithEncoding(document, query, nil);
176 | }
177 |
178 | NSArray *PerformXMLXPathQueryWithEncoding(NSData *document, NSString *query,NSString *encoding)
179 | {
180 | xmlDocPtr doc;
181 |
182 | /* Load XML document */
183 | const char *encoded = encoding ? [encoding cStringUsingEncoding:NSUTF8StringEncoding] : NULL;
184 |
185 | doc = xmlReadMemory([document bytes], (int)[document length], "", encoded, XML_PARSE_RECOVER);
186 |
187 | if (doc == NULL) {
188 | NSLog(@"Unable to parse.");
189 | return nil;
190 | }
191 |
192 | NSArray *result = PerformXPathQuery(doc, query);
193 | xmlFreeDoc(doc);
194 |
195 | return result;
196 | }
197 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | NSAppTransportSecurity
26 |
27 | NSAllowsArbitraryLoads
28 |
29 |
30 | UIRequiredDeviceCapabilities
31 |
32 | armv7
33 |
34 | UISupportedInterfaceOrientations
35 |
36 | UIInterfaceOrientationPortrait
37 | UIInterfaceOrientationLandscapeLeft
38 | UIInterfaceOrientationLandscapeRight
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/Model/HXArticle.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXArticle.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/22.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HXArticle : NSObject
12 |
13 | @property (nonatomic,copy) NSString *title;
14 | @property (nonatomic,copy) NSString *sketch;
15 | @property (nonatomic,copy) NSString *url;
16 | @property (nonatomic,copy) NSString *time;
17 | @property (nonatomic,copy) NSString *recommendcount;
18 | @property (nonatomic,copy) NSString *commentcount;
19 | @property (nonatomic,copy) NSString *readcount;
20 | @property (nonatomic,copy) NSString *homepage;
21 | @property (nonatomic,copy) NSString *name;
22 | @property (nonatomic,copy) NSString *findCount;
23 |
24 | @end
25 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/Model/HXArticle.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXArticle.m
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/22.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXArticle.h"
10 |
11 | @implementation HXArticle
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/View/HXArticleListCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXArticleListCell.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/20.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "HXArticle.h"
11 |
12 | @class HXArticleListCell;
13 |
14 | @protocol HXArticleListCellDelegate
15 |
16 | - (void)articleListCell:(HXArticleListCell *)cell titleButtonAction:(UIButton *)sender article:(HXArticle *)article;
17 | - (void)articleListCell:(HXArticleListCell *)cell nameButtonAction:(UIButton *)sender article:(HXArticle *)article;
18 |
19 | @end
20 |
21 | @interface HXArticleListCell : UITableViewCell
22 |
23 | @property (nonatomic,weak) id delegate;
24 | @property (weak, nonatomic) IBOutlet UIButton *titleButton;
25 | @property (weak, nonatomic) IBOutlet UILabel *sketchLabel;
26 | @property (weak, nonatomic) IBOutlet UIButton *nameButton;
27 | @property (weak, nonatomic) IBOutlet UILabel *timeLabel;
28 | @property (weak, nonatomic) IBOutlet UILabel *countLabel;
29 |
30 | - (void)setData:(id)data key:(NSString *)key delegate:(id)delegate;
31 |
32 | + (float)getCellFrame:(id)msg width:(float)width;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/View/HXArticleListCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXArticleListCell.m
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/20.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXArticleListCell.h"
10 |
11 | @interface HXArticleListCell ()
12 |
13 | @property (nonatomic,strong) HXArticle *article;
14 |
15 | @end
16 |
17 | @implementation HXArticleListCell
18 |
19 | - (void)awakeFromNib {
20 | // Initialization code
21 | [super awakeFromNib];
22 | }
23 |
24 | - (void)setData:(id)data key:(NSString *)key delegate:(id)delegate {
25 | if ([data isKindOfClass:[HXArticle class]]) {
26 | _delegate = delegate;
27 | _article = (HXArticle *)data;
28 | //标题
29 | [self.titleButton setAttributedTitle:[self getTitleAttributedString:_article.title key:key] forState:UIControlStateNormal];
30 | //简述
31 | self.sketchLabel.attributedText = [self getContentAttributedString:_article.sketch key:key];
32 | //作者
33 | [self.nameButton setTitle:_article.name forState:UIControlStateNormal];
34 | //时间
35 | self.timeLabel.text = [NSString stringWithFormat:@"发布于 %@",_article.time];
36 |
37 | NSMutableString *str = [NSMutableString stringWithString:@""];
38 |
39 | //推荐数
40 | if (_article.recommendcount.integerValue > 0) {
41 | [str appendFormat:@"推荐(%@)",_article.recommendcount];
42 | }
43 |
44 | //评论数
45 | if (_article.commentcount.integerValue > 0) {
46 | if (_article.recommendcount.integerValue > 0) {
47 | [str appendString:@" "];
48 | }
49 | [str appendFormat:@"评论(%@)",_article.commentcount];
50 | }
51 |
52 | //阅读数
53 | if (_article.readcount.integerValue > 0) {
54 | if (_article.commentcount.integerValue > 0) {
55 | [str appendString:@" "];
56 | }
57 | [str appendFormat:@"阅读(%@)",_article.readcount];
58 | }
59 |
60 | self.countLabel.text = str;
61 | }
62 | }
63 |
64 | #pragma mark - 文字样式处理
65 |
66 | //获取内容样式 关键字标亮
67 | - (NSMutableAttributedString *)getContentAttributedString:(NSString *)content key:(NSString *)key {
68 |
69 | NSMutableAttributedString *titleStr = [[NSMutableAttributedString alloc] initWithString:content];
70 |
71 | NSString *copyStr = content;
72 |
73 | NSMutableString *xxstr = [NSMutableString new];
74 | for (int i = 0; i < key.length; i++) {
75 | [xxstr appendString:@"*"];
76 | }
77 |
78 | while ([copyStr rangeOfString:key options:NSCaseInsensitiveSearch].location != NSNotFound) {
79 |
80 | NSRange range = [copyStr rangeOfString:key options:NSCaseInsensitiveSearch];
81 |
82 | //关键字颜色
83 | UIColor *keyColor = [UIColor redColor];
84 |
85 | [titleStr addAttribute:NSForegroundColorAttributeName value:keyColor range:range];
86 |
87 | copyStr = [copyStr stringByReplacingCharactersInRange:NSMakeRange(range.location, range.length) withString:xxstr];
88 | }
89 | return titleStr;
90 | }
91 |
92 | //获取标题样式 标题下划线 关键字标亮
93 | - (NSMutableAttributedString *)getTitleAttributedString:(NSString *)title key:(NSString *)key {
94 | //标题样式
95 | NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:title];
96 |
97 | //下划线颜色
98 | UIColor *undlineColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:204/255.0 alpha:1.0];
99 | //下划线颜色和位置
100 | [attributedString addAttribute:NSForegroundColorAttributeName value:undlineColor range:NSMakeRange(0,title.length)];
101 | //下划线样式
102 | [attributedString addAttribute:NSUnderlineStyleAttributeName value:[NSNumber numberWithInteger:NSUnderlineStyleSingle] range:NSMakeRange(0,title.length)];
103 |
104 | NSString *copyStr = title;
105 |
106 | NSMutableString *xxstr = [NSMutableString new];
107 | for (int i = 0; i < key.length; i++) {
108 | [xxstr appendString:@"*"];
109 | }
110 |
111 | while ([copyStr rangeOfString:key options:NSCaseInsensitiveSearch].location != NSNotFound) {
112 |
113 | NSRange range = [copyStr rangeOfString:key options:NSCaseInsensitiveSearch];
114 | //关键字颜色
115 | UIColor *keyColor = [UIColor redColor];
116 | [attributedString addAttribute:NSForegroundColorAttributeName value:keyColor range:range];
117 |
118 | copyStr = [copyStr stringByReplacingCharactersInRange:NSMakeRange(range.location, range.length) withString:xxstr];
119 | }
120 |
121 | return attributedString;
122 | }
123 |
124 | - (IBAction)titleButtonAction:(UIButton *)sender {
125 | if (_delegate && [_delegate respondsToSelector:@selector(articleListCell:titleButtonAction:article:)]) {
126 | [_delegate articleListCell:self titleButtonAction:sender article:_article];
127 | }
128 | }
129 |
130 | - (IBAction)nameButtonAction:(UIButton *)sender {
131 | if (_delegate && [_delegate respondsToSelector:@selector(articleListCell:nameButtonAction:article:)]) {
132 | [_delegate articleListCell:self nameButtonAction:sender article:_article];
133 | }
134 | }
135 |
136 | + (float)getCellFrame:(id)msg width:(float)width {
137 | if ([msg isKindOfClass:[HXArticle class]]) {
138 | HXArticle *article = (HXArticle *)msg;
139 | NSString *str = article.sketch;
140 | CGRect frame = [str boundingRectWithSize:CGSizeMake(width, MAXFLOAT) options:NSStringDrawingUsesFontLeading|NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName: [UIFont systemFontOfSize:12]} context:nil];
141 | return 77 + frame.size.height - 12;
142 | }
143 | return 77;
144 | }
145 |
146 | @end
147 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/View/HXHistoryCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXHistoryCell.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/25.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class HXHistoryCell;
12 |
13 | @protocol HXHistoryCellDelegate
14 |
15 | - (void)historyCell:(HXHistoryCell *)cell deleteButtonAction:(UIButton *)sender history:(NSString *)history;
16 |
17 | @end
18 |
19 | @interface HXHistoryCell : UITableViewCell
20 |
21 | @property (nonatomic,weak) id delegate;
22 | @property (weak, nonatomic) IBOutlet UILabel *historyLabel;
23 |
24 | - (void)setData:(id)data delegate:(id)delegate;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/View/HXHistoryCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXHistoryCell.m
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/25.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXHistoryCell.h"
10 |
11 | @interface HXHistoryCell ()
12 |
13 | @property (nonatomic,strong) NSString *history;
14 |
15 | @end
16 |
17 | @implementation HXHistoryCell
18 |
19 | - (void)awakeFromNib {
20 | // Initialization code
21 | [super awakeFromNib];
22 | }
23 |
24 | - (void)setData:(id)data delegate:(id)delegate {
25 | if ([data isKindOfClass:[NSString class]]) {
26 | _delegate = delegate;
27 | _history = (NSString *)data;
28 |
29 | self.historyLabel.text = _history;
30 | }
31 | }
32 |
33 | - (IBAction)deleteButtonAction:(UIButton *)sender {
34 | if (_delegate && [_delegate respondsToSelector:@selector(historyCell:deleteButtonAction:history:)]) {
35 | [_delegate historyCell:self deleteButtonAction:sender history:_history];
36 | }
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/View/HXHistoryCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
24 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/View/HXHistoryLastCell.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXHistoryLastCell.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/25.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @class HXHistoryLastCell;
12 |
13 | @protocol HXHistoryLastCellDelegate
14 |
15 | - (void)historyLastCell:(HXHistoryLastCell *)cell deleteButtonAction:(UIButton *)sender;
16 | - (void)historyLastCell:(HXHistoryLastCell *)cell moreButtonAction:(UIButton *)sender;
17 |
18 | @end
19 |
20 | @interface HXHistoryLastCell : UITableViewCell
21 |
22 | @property (nonatomic,weak) id delegate;
23 |
24 | - (void)setData:(id)data delegate:(id)delegate;
25 |
26 | @end
27 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/View/HXHistoryLastCell.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXHistoryLastCell.m
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/25.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXHistoryLastCell.h"
10 |
11 | @interface HXHistoryLastCell ()
12 |
13 | @property (nonatomic,strong) NSString *history;
14 |
15 | @end
16 |
17 | @implementation HXHistoryLastCell
18 |
19 | - (void)awakeFromNib {
20 | // Initialization code
21 | [super awakeFromNib];
22 | }
23 |
24 | - (void)setData:(id)data delegate:(id)delegate {
25 | _delegate = delegate;
26 | }
27 |
28 | - (IBAction)deleteButtonAction:(UIButton *)sender {
29 | if (_delegate && [_delegate respondsToSelector:@selector(historyLastCell:deleteButtonAction:)]) {
30 | [_delegate historyLastCell:self deleteButtonAction:sender];
31 | }
32 | }
33 |
34 | - (IBAction)moreButtonAction:(UIButton *)sender {
35 | if (_delegate && [_delegate respondsToSelector:@selector(historyLastCell:deleteButtonAction:)]) {
36 | [_delegate historyLastCell:self moreButtonAction:sender];
37 | }
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/View/HXHistoryLastCell.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
31 |
45 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/Detail/HXDetailWebViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXDetailWebViewController.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/20.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "HXArticle.h"
11 |
12 | @interface HXDetailWebViewController : UIViewController
13 |
14 | @property (strong, nonatomic) HXArticle *article;
15 | @property (copy, nonatomic) NSString *type;
16 |
17 | @end
18 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/Detail/HXDetailWebViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXDetailWebViewController.m
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/20.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXDetailWebViewController.h"
10 |
11 | @interface HXDetailWebViewController ()
12 |
13 | @property (weak, nonatomic) IBOutlet UIWebView *webView;
14 |
15 | @end
16 |
17 | @implementation HXDetailWebViewController
18 |
19 |
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | // Do any additional setup after loading the view from its nib.
24 | self.view.backgroundColor = [UIColor whiteColor];
25 |
26 | if ([_type isEqualToString:@"home"]) {
27 | self.title = _article.name;
28 |
29 | //1.创建并加载远程网页
30 | [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:_article.homepage]]];
31 | } else if ([_type isEqualToString:@"detail"]) {
32 | self.title = _article.title;
33 |
34 | //1.创建并加载远程网页
35 | [_webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:_article.url]]];
36 | }
37 | }
38 |
39 | - (void)didReceiveMemoryWarning {
40 | [super didReceiveMemoryWarning];
41 | // Dispose of any resources that can be recreated.
42 |
43 |
44 | }
45 |
46 | @end
47 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/Detail/HXDetailWebViewController.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/Home/HXHomeViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXHomeViewController.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/22.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HXHomeViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/Home/HXHomeViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXHomeViewController.m
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/22.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXHomeViewController.h"
10 | #import "HXSearchResultViewController.h"
11 | #import "HXHistoryListViewController.h"
12 | #import "HXHistoryCell.h"
13 | #import "HXHistoryLastCell.h"
14 |
15 | @interface HXHomeViewController ()
16 |
17 | @property (weak, nonatomic) IBOutlet UITextField *keyTextField;
18 | @property (weak, nonatomic) IBOutlet UIView *keyView;
19 | @property (weak, nonatomic) IBOutlet UIButton *searchButton;
20 | @property (weak, nonatomic) IBOutlet UITableView *tableView;
21 | @property (nonatomic,strong) NSMutableArray *tagAry;
22 | @property (nonatomic,assign) float maxHeight;
23 | @property (weak, nonatomic) IBOutlet NSLayoutConstraint *tableViewHeight;
24 |
25 | @end
26 |
27 | @implementation HXHomeViewController
28 |
29 | - (void)viewDidLoad {
30 | [super viewDidLoad];
31 | // Do any additional setup after loading the view from its nib.
32 | self.view.backgroundColor = [UIColor whiteColor];
33 |
34 | _keyView.layer.borderWidth = 1.0;
35 | _keyView.layer.borderColor = [UIColor colorWithRed:204/255.0 green:204/255.0 blue:204/255.0 alpha:1.0].CGColor;
36 | _tableView.layer.borderWidth = 1.0;
37 | _tableView.layer.borderColor = [UIColor colorWithRed:204/255.0 green:204/255.0 blue:204/255.0 alpha:1.0].CGColor;
38 | [_tableView registerNib:[UINib nibWithNibName:@"HXHistoryCell" bundle:nil] forCellReuseIdentifier:@"HXHistoryCell"];
39 | [_tableView registerNib:[UINib nibWithNibName:@"HXHistoryLastCell" bundle:nil] forCellReuseIdentifier:@"HXHistoryLastCell"];
40 |
41 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
42 | NSArray *ary = [userDefaults objectForKey:@"tagAry"];
43 | _tagAry = [NSMutableArray arrayWithArray:ary];
44 |
45 | _maxHeight = [UIScreen mainScreen].bounds.size.height - _tableView.frame.origin.y;
46 |
47 | [self changeTableViewHeight];
48 |
49 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasShown:) name:UIKeyboardDidShowNotification object:nil];
50 |
51 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWasHidden:) name:UIKeyboardDidHideNotification object:nil];
52 | }
53 |
54 | - (void)viewWillAppear:(BOOL)animated {
55 | [super viewWillAppear:animated];
56 | self.navigationController.navigationBarHidden = YES;
57 | }
58 |
59 | - (void)viewWillDisappear:(BOOL)animated {
60 | [super viewWillDisappear:animated];
61 | self.navigationController.navigationBarHidden = NO;
62 | }
63 |
64 | #pragma mark - data
65 |
66 | - (NSArray *)dataSource {
67 | return _tagAry;
68 | }
69 |
70 | #pragma mark UITableViewDataSource/UITableViewDelegate
71 |
72 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
73 | if (self.dataSource.count > 9) {
74 | return 9 + 1;
75 | }
76 | return self.dataSource.count + 1;
77 | }
78 |
79 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
80 |
81 | if (indexPath.row == self.dataSource.count || indexPath.row == 9) {
82 | //最后一行
83 | HXHistoryLastCell *cell = [tableView dequeueReusableCellWithIdentifier:@"HXHistoryLastCell"];
84 | if (!cell) {
85 | cell = [[HXHistoryLastCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"HXHistoryLastCell"];
86 | }
87 | [cell setData:nil delegate:self];
88 | return cell;
89 | } else {
90 | HXHistoryCell *cell = [tableView dequeueReusableCellWithIdentifier:@"HXHistoryCell"];
91 | if (!cell) {
92 | cell = [[HXHistoryCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"HXHistoryCell"];
93 | }
94 |
95 | NSString *str = _tagAry[self.dataSource.count - indexPath.row - 1];
96 | [cell setData:str delegate:self];
97 |
98 | return cell;
99 | }
100 | }
101 |
102 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
103 | return 20;
104 | }
105 |
106 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
107 | [tableView deselectRowAtIndexPath:indexPath animated:YES];
108 |
109 | _tableView.hidden = YES;
110 |
111 | NSString *str = _tagAry[self.dataSource.count - indexPath.row - 1];
112 |
113 | if (str.length > 0) {
114 |
115 | [self gotoSearchResultViewController:str];
116 | }
117 | }
118 |
119 | #pragma mark - HXHistoryCellDelegate
120 |
121 | - (void)historyCell:(HXHistoryCell *)cell deleteButtonAction:(UIButton *)sender history:(NSString *)history {
122 | [_tagAry removeObject:history];
123 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
124 | [userDefaults setObject:_tagAry forKey:@"tagAry"];
125 | [userDefaults synchronize];
126 | [self changeTableViewHeight];
127 | [_tableView reloadData];
128 | }
129 |
130 | #pragma mark - HXHistoryLastCellDelegate
131 |
132 | - (void)historyLastCell:(HXHistoryLastCell *)cell deleteButtonAction:(UIButton *)sender {
133 | [_tagAry removeAllObjects];
134 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
135 | [userDefaults setObject:_tagAry forKey:@"tagAry"];
136 | [userDefaults synchronize];
137 | _tableView.hidden = YES;
138 | }
139 |
140 | - (void)historyLastCell:(HXHistoryLastCell *)cell moreButtonAction:(UIButton *)sender {
141 | [self gotoHistoryListViewController];
142 | }
143 |
144 | #pragma mark - Text
145 |
146 | - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
147 | if (_tagAry.count > 0) {
148 | _tableView.hidden = NO;
149 | }
150 | return YES;
151 | }
152 |
153 | - (IBAction)tapButtonAction:(UITapGestureRecognizer *)sender {
154 | _tableView.hidden = YES;
155 | [self.view endEditing:YES];
156 | }
157 |
158 |
159 | - (void)keyboardWasShown:(NSNotification *)notif
160 | {
161 | NSDictionary *info = [notif userInfo];
162 | NSValue *value = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
163 | CGSize keyboardSize = [value CGRectValue].size;
164 | NSLog(@"keyBoard:%f", keyboardSize.height); //216
165 |
166 | _maxHeight = [value CGRectValue].origin.y - _tableView.frame.origin.y;
167 | [self changeTableViewHeight];
168 | }
169 |
170 | - (void)keyboardWasHidden:(NSNotification *)notif
171 | {
172 | NSDictionary *info = [notif userInfo];
173 |
174 | NSValue *value = [info objectForKey:UIKeyboardFrameBeginUserInfoKey];
175 | CGSize keyboardSize = [value CGRectValue].size;
176 | NSLog(@"keyboardWasHidden keyBoard:%f", keyboardSize.height);
177 |
178 | _maxHeight = [value CGRectValue].origin.y - _tableView.frame.origin.y;
179 | [self changeTableViewHeight];
180 | }
181 |
182 | - (void)changeTableViewHeight {
183 | if (_tagAry.count > 0 && _keyTextField.isFirstResponder) {
184 | _tableView.hidden = NO;
185 | }
186 |
187 | if (_tagAry.count >= 9) {
188 | if (_maxHeight > 20*10) {
189 | _tableViewHeight.constant = 200;
190 | } else {
191 | _tableViewHeight.constant = _maxHeight;
192 | }
193 | } else {
194 | if (_maxHeight > 20*_tagAry.count) {
195 | _tableViewHeight.constant = 20*(_tagAry.count + 1);
196 | } else {
197 | _tableViewHeight.constant = _maxHeight;
198 | }
199 | }
200 | }
201 |
202 | #pragma mark - Button Action
203 |
204 | - (IBAction)searchButtonAction:(UIButton *)sender {
205 | if (_keyTextField.text.length > 0) {
206 | if (![_tagAry containsObject:_keyTextField.text]) {
207 | [_tagAry addObject:_keyTextField.text];
208 |
209 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
210 | [userDefaults setObject:_tagAry forKey:@"tagAry"];
211 | [userDefaults synchronize];
212 |
213 | [self changeTableViewHeight];
214 |
215 | [_tableView reloadData];
216 | }
217 | [self gotoSearchResultViewController:_keyTextField.text];
218 | }
219 | }
220 |
221 | #pragma mark - goto
222 |
223 | - (void)gotoSearchResultViewController:(NSString *)key {
224 | HXSearchResultViewController *vc = [HXSearchResultViewController new];
225 | vc.key = key;
226 | [self.navigationController pushViewController:vc animated:YES];
227 | }
228 |
229 | /**
230 | * 去历史记录页面
231 | */
232 | - (void)gotoHistoryListViewController {
233 | HXHistoryListViewController *vc = [HXHistoryListViewController new];
234 | [self.navigationController pushViewController:vc animated:YES];
235 | }
236 |
237 | - (void)didReceiveMemoryWarning {
238 | [super didReceiveMemoryWarning];
239 | // Dispose of any resources that can be recreated.
240 | }
241 |
242 | - (void)dealloc {
243 | [[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:UIKeyboardDidShowNotification];
244 | [[NSNotificationCenter defaultCenter] removeObserver:self forKeyPath:UIKeyboardDidHideNotification];
245 | }
246 |
247 | @end
248 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/List/HXArticleListViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXArticleListViewController.h
3 | // https://github.com/huangxuan518/HXInternationalizationDemo
4 | //
5 | // Created by 黄轩 on 16/7/29.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HXArticleListViewController : UIViewController
12 |
13 | @property (nonatomic,copy) NSString *key; //搜索关键字
14 | @property (nonatomic,copy) NSString *blogType; //博客类型 1.@"csdn" CSDN博客 2.@"cnblogs" 博客园 3.@"51cto" 51CTO博客 4.@"oschina" 开源中国博客
15 |
16 | @end
17 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/List/HXArticleListViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXArticleListViewController.m
3 | // https://github.com/huangxuan518/HXInternationalizationDemo
4 | //
5 | // Created by 黄轩 on 16/7/29.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXArticleListViewController.h"
10 | #import "HXDetailWebViewController.h"
11 | #import "HXArticleListCell.h"
12 | #import "HXArticle.h"
13 | #import "HXRequestManager.h"
14 |
15 | #import
16 |
17 | @interface HXArticleListViewController ()
18 |
19 | @property (nonatomic,strong) UITableView *tableView;
20 | @property (nonatomic,copy) NSString *searchText;//搜索词
21 | @property (nonatomic,strong) UILabel *findCountLabel;
22 | @property (nonatomic,strong) NSMutableArray *dataAry;
23 | @property (nonatomic,strong) HXRequestManager *requestManager;
24 |
25 | @property (nonatomic,assign) NSInteger page;
26 |
27 | @end
28 |
29 | @implementation HXArticleListViewController
30 |
31 | - (void)viewDidLoad {
32 | [super viewDidLoad];
33 | // Do any additional setup after loading the view.
34 | self.view.backgroundColor = [UIColor clearColor];
35 |
36 | _page = 1;
37 | _dataAry = [NSMutableArray new];
38 |
39 | [self.view addSubview:self.tableView];
40 |
41 | __weak __typeof(self)weakSelf = self;
42 | self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
43 | __strong __typeof(self)self = weakSelf;
44 | //下拉刷新
45 | _page = 1;
46 | [self request:_page];
47 | }];
48 |
49 | self.tableView.mj_footer = [MJRefreshAutoNormalFooter footerWithRefreshingBlock:^{
50 | __strong __typeof(self)self = weakSelf;
51 | //加载更多
52 | _page++;
53 | [self request:_page];
54 | }];
55 |
56 | [self.tableView.mj_header beginRefreshing];
57 | }
58 |
59 | - (UILabel *)findCountLabel {
60 | if (!_findCountLabel) {
61 | _findCountLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, self.view.frame.size.height - 30, self.view.frame.size.width, 30)];
62 | _findCountLabel.backgroundColor = [UIColor grayColor];
63 | _findCountLabel.textAlignment = NSTextAlignmentCenter;
64 | _findCountLabel.font = [UIFont systemFontOfSize:12];
65 | _findCountLabel.textColor = [UIColor whiteColor];
66 | [self.view addSubview:_findCountLabel];
67 | }
68 | _findCountLabel.frame = CGRectMake(0, self.view.frame.size.height - 30, self.view.frame.size.width, 30);
69 | return _findCountLabel;
70 | }
71 |
72 | - (void)request:(NSInteger)page {
73 | __weak __typeof(self)weakSelf = self;
74 | [self.requestManager requestWithBlogType:_blogType key:_key page:page complete:^(NSArray *dataAry,NSString *findCount) {
75 | __strong __typeof(self)self = weakSelf;
76 |
77 | [self.tableView.mj_header endRefreshing];
78 | [self.tableView.mj_footer endRefreshing];
79 |
80 | if (page == 1) {
81 | self.findCountLabel.text = [NSString stringWithFormat:@"为您找到相关结果约%@个",findCount];
82 | [_dataAry removeAllObjects];
83 | }
84 |
85 | [_dataAry addObjectsFromArray:dataAry];
86 | [self.tableView reloadData];
87 | }];
88 | }
89 |
90 | #pragma mark - data
91 |
92 | - (NSArray *)dataSource {
93 | return _dataAry;
94 | }
95 |
96 | #pragma mark UITableViewDataSource/UITableViewDelegate
97 |
98 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
99 | return self.dataSource.count;
100 | }
101 |
102 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
103 |
104 | HXArticleListCell *cell = [tableView dequeueReusableCellWithIdentifier:@"HXArticleListCell"];
105 | if (!cell) {
106 | cell = [[HXArticleListCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"HXArticleListCell"];
107 | }
108 |
109 | [cell setData:self.dataSource[indexPath.row] key:_key delegate:self];
110 |
111 | return cell;
112 | }
113 |
114 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
115 | HXArticle *article = self.dataSource[indexPath.row];
116 | return [HXArticleListCell getCellFrame:article width:tableView.frame.size.width];
117 | }
118 |
119 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
120 | [tableView deselectRowAtIndexPath:indexPath animated:YES];
121 | }
122 |
123 | #pragma HXArticleListCellDelegate
124 |
125 | - (void)articleListCell:(HXArticleListCell *)cell titleButtonAction:(UIButton *)sender article:(HXArticle *)article {
126 | [self gotoDetailWebViewController:article type:@"detail"];
127 | }
128 |
129 | - (void)articleListCell:(HXArticleListCell *)cell nameButtonAction:(UIButton *)sender article:(HXArticle *)article {
130 | [self gotoDetailWebViewController:article type:@"home"];
131 | }
132 |
133 | #pragma mark - goto
134 |
135 | /**
136 | * 去文章详情界面
137 | */
138 | - (void)gotoDetailWebViewController:(HXArticle *)article type:(NSString *)type {
139 | HXDetailWebViewController *vc = [HXDetailWebViewController new];
140 | vc.article = article;
141 | vc.type = type;
142 | [self.navigationController pushViewController:vc animated:YES];
143 | }
144 |
145 | #pragma mark - 懒加载
146 |
147 | - (UITableView *)tableView {
148 | if (!_tableView) {
149 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - 30) style:UITableViewStylePlain];
150 | _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
151 | _tableView.dataSource = self;
152 | _tableView.delegate = self;
153 | _tableView.backgroundColor = [UIColor clearColor];
154 | [_tableView registerNib:[UINib nibWithNibName:@"HXArticleListCell" bundle:nil] forCellReuseIdentifier:@"HXArticleListCell"];
155 | }
156 | return _tableView;
157 | }
158 |
159 | - (HXRequestManager *)requestManager {
160 | if (!_requestManager) {
161 | _requestManager = [HXRequestManager new];
162 | }
163 | return _requestManager;
164 | }
165 |
166 | - (void)didReceiveMemoryWarning {
167 | [super didReceiveMemoryWarning];
168 | // Dispose of any resources that can be recreated.
169 | }
170 |
171 | @end
172 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/List/HXHistoryListViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXHistoryListViewController.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/25.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HXHistoryListViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/List/HXHistoryListViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXHistoryListViewController.m
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/25.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXHistoryListViewController.h"
10 | #import "HXSearchResultViewController.h"
11 |
12 | @interface HXHistoryListViewController ()
13 |
14 | @property (nonatomic,strong) UITableView *tableView;
15 | @property (nonatomic,strong) NSMutableArray *dataAry;
16 |
17 | @end
18 |
19 | @implementation HXHistoryListViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | // Do any additional setup after loading the view.
24 | self.view.backgroundColor = [UIColor whiteColor];
25 |
26 | self.title = @"搜索历史";
27 |
28 | [self.view addSubview:self.tableView];
29 | }
30 |
31 | #pragma mark - data
32 |
33 | - (NSArray *)dataSource {
34 | NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
35 | NSArray *ary = [userDefaults objectForKey:@"tagAry"];
36 | return ary;
37 | }
38 |
39 | #pragma mark UITableViewDataSource/UITableViewDelegate
40 |
41 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
42 | return self.dataSource.count;
43 | }
44 |
45 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
46 |
47 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellID"];
48 | if (!cell) {
49 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"CellID"];
50 | }
51 |
52 | NSString *str = self.dataSource[self.dataSource.count - indexPath.row - 1];
53 |
54 | cell.textLabel.text = str;
55 |
56 | return cell;
57 | }
58 |
59 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
60 | return 44;
61 | }
62 |
63 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
64 | [tableView deselectRowAtIndexPath:indexPath animated:YES];
65 |
66 | NSString *str = self.dataSource[self.dataSource.count - indexPath.row - 1];
67 | [self gotoSearchResultViewController:str];
68 | }
69 |
70 | #pragma mark - goto
71 |
72 | - (void)gotoSearchResultViewController:(NSString *)key {
73 | HXSearchResultViewController *vc = [HXSearchResultViewController new];
74 | vc.key = key;
75 | [self.navigationController pushViewController:vc animated:YES];
76 | }
77 |
78 | #pragma mark - 懒加载
79 |
80 | - (UITableView *)tableView {
81 | if (!_tableView) {
82 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - 30) style:UITableViewStylePlain];
83 | _tableView.autoresizingMask = UIViewAutoresizingFlexibleHeight;
84 | _tableView.dataSource = self;
85 | _tableView.delegate = self;
86 | _tableView.backgroundColor = [UIColor clearColor];
87 | [_tableView registerNib:[UINib nibWithNibName:@"HXArticleListCell" bundle:nil] forCellReuseIdentifier:@"HXArticleListCell"];
88 | }
89 | return _tableView;
90 | }
91 |
92 | - (void)didReceiveMemoryWarning {
93 | [super didReceiveMemoryWarning];
94 | // Dispose of any resources that can be recreated.
95 | }
96 |
97 | @end
98 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/List/HXSearchResultViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXSearchResultViewController.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/24.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HXSearchResultViewController : UIViewController
12 |
13 | @property (nonatomic,copy) NSString *key;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Main/ViewController/List/HXSearchResultViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // HXSearchResultViewController.m
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/24.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import "HXSearchResultViewController.h"
10 | #import "HXArticleListViewController.h"
11 |
12 | @interface HXSearchResultViewController ()
13 |
14 | @property (nonatomic,strong) HXArticleListViewController *csdnVc; //CSDN
15 | @property (nonatomic,strong) HXArticleListViewController *cnblogsVc; //博客园
16 | @property (nonatomic,strong) HXArticleListViewController *ctoVc; //51CTO
17 | @property (nonatomic,strong) HXArticleListViewController *oschinaVc; //开源中国
18 |
19 | @property (nonatomic ,strong) UIViewController *currentVC; //当前Vc
20 |
21 | @end
22 |
23 | @implementation HXSearchResultViewController
24 |
25 | - (void)viewDidLoad {
26 | [super viewDidLoad];
27 | // Do any additional setup after loading the view.
28 | self.view.backgroundColor = [UIColor colorWithRed:245/255.0 green:245/255.0 blue:245/255.0 alpha:1.0];
29 |
30 | self.title = [NSString stringWithFormat:@"搜索\"%@\"相关结果",_key];
31 |
32 | [self initSegmentedControl];
33 | [self addSubControllers];
34 | }
35 |
36 | #pragma mark -
37 |
38 | - (void)initSegmentedControl
39 | {
40 | UIView *view = [[UIView alloc] initWithFrame:CGRectMake(0, 64, self.view.frame.size.width, 50)];
41 | view.backgroundColor = [UIColor whiteColor];
42 |
43 | UISegmentedControl *segmentedControl = [[UISegmentedControl alloc] initWithItems:@[@"CSDN",@"博客园",@"51CTO",@"开源中国"]];
44 | segmentedControl.frame = CGRectMake(10, 10,self.view.frame.size.width - 20, 30.0);
45 | segmentedControl.selectedSegmentIndex = 0;
46 | //设置分段控件点击相应事件
47 | [segmentedControl addTarget:self action:@selector(segmentedControlButtonAction:)forControlEvents:UIControlEventValueChanged];
48 |
49 | [view addSubview:segmentedControl];
50 |
51 | [self.view addSubview:view];
52 | }
53 |
54 | - (void)segmentedControlButtonAction:(UISegmentedControl *)sender
55 | {
56 | NSInteger index = sender.selectedSegmentIndex;
57 |
58 | // 点击处于当前页面的按钮,直接跳出
59 | if ((self.currentVC == _csdnVc && index == 0) || (self.currentVC == _cnblogsVc && index == 1) || (self.currentVC == _ctoVc && index == 2) || (self.currentVC == _oschinaVc && index == 3)) {
60 | return;
61 | } else {
62 |
63 | switch (index)
64 | {
65 | case 0:
66 | [self replaceController:self.currentVC newController:_csdnVc];
67 | break;
68 |
69 | case 1:
70 | [self replaceController:self.currentVC newController:_cnblogsVc];
71 | break;
72 |
73 | case 2:
74 | [self replaceController:self.currentVC newController:_ctoVc];
75 | break;
76 |
77 | case 3:
78 | [self replaceController:self.currentVC newController:_oschinaVc];
79 | break;
80 |
81 | default:
82 | break;
83 | }
84 | }
85 | }
86 |
87 | #pragma mark - privatemethods
88 |
89 | - (void)addSubControllers {
90 | _csdnVc = [HXArticleListViewController new];
91 | _csdnVc.view.frame = CGRectMake(0, 114, self.view.frame.size.width, self.view.frame.size.height - 114);
92 | _csdnVc.key = _key;
93 | _csdnVc.blogType = @"csdn";
94 | [self addChildViewController:_csdnVc];
95 |
96 |
97 | _cnblogsVc = [HXArticleListViewController new];
98 | _cnblogsVc.view.frame = CGRectMake(0, 114, self.view.frame.size.width, self.view.frame.size.height - 114);
99 | _cnblogsVc.key = _key;
100 | _cnblogsVc.blogType = @"cnblogs";
101 | [self addChildViewController:_cnblogsVc];
102 |
103 | _ctoVc = [HXArticleListViewController new];
104 | _ctoVc.view.frame = CGRectMake(0, 114, self.view.frame.size.width, self.view.frame.size.height - 114);
105 | _ctoVc.key = _key;
106 | _ctoVc.blogType = @"51cto";
107 | [self addChildViewController:_ctoVc];
108 |
109 | _oschinaVc = [HXArticleListViewController new];
110 | _oschinaVc.view.frame = CGRectMake(0, 114, self.view.frame.size.width, self.view.frame.size.height - 114);
111 | _oschinaVc.key = _key;
112 | _oschinaVc.blogType = @"oschina";
113 | [self addChildViewController:_oschinaVc];
114 |
115 | // 默认,第一个视图(你会发现,全程就这一个用了addSubview)
116 | [self.view addSubview:_csdnVc.view];
117 |
118 | self.currentVC = _csdnVc;
119 | }
120 |
121 | // 切换各个标签内容
122 | - (void)replaceController:(UIViewController *)oldController newController:(UIViewController *)newController
123 | {
124 | /**
125 | * 着重介绍一下它
126 | * transitionFromViewController:toViewController:duration:options:animations:completion:
127 | * fromViewController 当前显示在父视图控制器中的子视图控制器
128 | * toViewController 将要显示的姿势图控制器
129 | * duration 动画时间(这个属性,old friend 了 O(∩_∩)O)
130 | * options 动画效果(渐变,从下往上等等,具体查看API)
131 | * animations 转换过程中得动画
132 | * completion 转换完成
133 | */
134 | [self transitionFromViewController:oldController
135 | toViewController:newController
136 | duration:0
137 | options:UIViewAnimationOptionTransitionCrossDissolve
138 | animations:^{
139 | // NOPS;
140 | }
141 | completion:^(BOOL finished) {
142 | if (finished) {
143 | self.currentVC = newController;
144 | } else {
145 | self.currentVC = oldController;
146 | }
147 | }];
148 | }
149 |
150 | - (void)didReceiveMemoryWarning {
151 | [super didReceiveMemoryWarning];
152 | // Dispose of any resources that can be recreated.
153 | }
154 |
155 | @end
156 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/Request/HXRequestManager.h:
--------------------------------------------------------------------------------
1 | //
2 | // HXRequestManager.h
3 | // HXTechnologyBlogCrawler
4 | //
5 | // Created by 黄轩 on 16/8/20.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface HXRequestManager : NSObject
12 |
13 | - (void)requestWithBlogType:(NSString *)blogType key:(NSString *)key page:(NSInteger)page complete:(void(^)(NSArray *dataAry,NSString *findCount))complete;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // HXHtmlParser
4 | //
5 | // Created by 黄轩 on 16/8/18.
6 | // Copyright © 2016年 黄轩. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/HXTechnologyBlogCrawler/xiaoguo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangxuan518/HXTechnologyBlogCrawler/0a2b6b0224ac0117877ef724c8fca5ec515d0bff/HXTechnologyBlogCrawler/xiaoguo.gif
--------------------------------------------------------------------------------
/Podfile:
--------------------------------------------------------------------------------
1 | platform :ios, ‘8.0’
2 |
3 | target 'HXTechnologyBlogCrawler' do
4 |
5 | pod 'MJRefresh'
6 |
7 | end
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Podfile.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - MJRefresh (3.1.0)
3 |
4 | DEPENDENCIES:
5 | - MJRefresh
6 |
7 | SPEC CHECKSUMS:
8 | MJRefresh: 743e6404967d1c2c688472ea3ecfde247d872db4
9 |
10 | PODFILE CHECKSUM: 3e97bbe32e7bf5574669b64ec6a6420fb7521e7f
11 |
12 | COCOAPODS: 1.0.0
13 |
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefresh.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/MJRefresh.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshAutoFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshAutoGifFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoGifFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshAutoNormalFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoNormalFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshAutoStateFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoStateFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshBackFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshBackFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshBackGifFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackGifFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshBackNormalFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackNormalFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshBackStateFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackStateFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshComponent.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshComponent.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshConst.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/MJRefreshConst.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshGifHeader.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Header/MJRefreshGifHeader.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshHeader.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshHeader.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshNormalHeader.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Header/MJRefreshNormalHeader.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/MJRefreshStateHeader.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Header/MJRefreshStateHeader.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/UIScrollView+MJExtension.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/UIScrollView+MJExtension.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/UIScrollView+MJRefresh.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/UIScrollView+MJRefresh.h
--------------------------------------------------------------------------------
/Pods/Headers/Private/MJRefresh/UIView+MJExtension.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/UIView+MJExtension.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefresh.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/MJRefresh.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshAutoFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshAutoGifFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoGifFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshAutoNormalFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoNormalFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshAutoStateFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoStateFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshBackFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshBackFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshBackGifFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackGifFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshBackNormalFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackNormalFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshBackStateFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackStateFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshComponent.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshComponent.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshConst.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/MJRefreshConst.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshFooter.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshFooter.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshGifHeader.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Header/MJRefreshGifHeader.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshHeader.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Base/MJRefreshHeader.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshNormalHeader.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Header/MJRefreshNormalHeader.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/MJRefreshStateHeader.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/Custom/Header/MJRefreshStateHeader.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/UIScrollView+MJExtension.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/UIScrollView+MJExtension.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/UIScrollView+MJRefresh.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/UIScrollView+MJRefresh.h
--------------------------------------------------------------------------------
/Pods/Headers/Public/MJRefresh/UIView+MJExtension.h:
--------------------------------------------------------------------------------
1 | ../../../MJRefresh/MJRefresh/UIView+MJExtension.h
--------------------------------------------------------------------------------
/Pods/MJRefresh/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2015 MJRefresh (https://github.com/CoderMJLee/MJRefresh)
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshAutoFooter.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshFooter.h"
10 |
11 | @interface MJRefreshAutoFooter : MJRefreshFooter
12 | /** 是否自动刷新(默认为YES) */
13 | @property (assign, nonatomic, getter=isAutomaticallyRefresh) BOOL automaticallyRefresh;
14 |
15 | /** 当底部控件出现多少时就自动刷新(默认为1.0,也就是底部控件完全出现时,才会自动刷新) */
16 | @property (assign, nonatomic) CGFloat appearencePercentTriggerAutoRefresh MJRefreshDeprecated("请使用automaticallyChangeAlpha属性");
17 |
18 | /** 当底部控件出现多少时就自动刷新(默认为1.0,也就是底部控件完全出现时,才会自动刷新) */
19 | @property (assign, nonatomic) CGFloat triggerAutomaticallyRefreshPercent;
20 | @end
21 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshAutoFooter.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshAutoFooter.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshAutoFooter.h"
10 |
11 | @interface MJRefreshAutoFooter()
12 | @end
13 |
14 | @implementation MJRefreshAutoFooter
15 |
16 | #pragma mark - 初始化
17 | - (void)willMoveToSuperview:(UIView *)newSuperview
18 | {
19 | [super willMoveToSuperview:newSuperview];
20 |
21 | if (newSuperview) { // 新的父控件
22 | if (self.hidden == NO) {
23 | self.scrollView.mj_insetB += self.mj_h;
24 | }
25 |
26 | // 设置位置
27 | self.mj_y = _scrollView.mj_contentH;
28 | } else { // 被移除了
29 | if (self.hidden == NO) {
30 | self.scrollView.mj_insetB -= self.mj_h;
31 | }
32 | }
33 | }
34 |
35 | #pragma mark - 过期方法
36 | - (void)setAppearencePercentTriggerAutoRefresh:(CGFloat)appearencePercentTriggerAutoRefresh
37 | {
38 | self.triggerAutomaticallyRefreshPercent = appearencePercentTriggerAutoRefresh;
39 | }
40 |
41 | - (CGFloat)appearencePercentTriggerAutoRefresh
42 | {
43 | return self.triggerAutomaticallyRefreshPercent;
44 | }
45 |
46 | #pragma mark - 实现父类的方法
47 | - (void)prepare
48 | {
49 | [super prepare];
50 |
51 | // 默认底部控件100%出现时才会自动刷新
52 | self.triggerAutomaticallyRefreshPercent = 1.0;
53 |
54 | // 设置为默认状态
55 | self.automaticallyRefresh = YES;
56 | }
57 |
58 | - (void)scrollViewContentSizeDidChange:(NSDictionary *)change
59 | {
60 | [super scrollViewContentSizeDidChange:change];
61 |
62 | // 设置位置
63 | self.mj_y = self.scrollView.mj_contentH;
64 | }
65 |
66 | - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
67 | {
68 | [super scrollViewContentOffsetDidChange:change];
69 |
70 | if (self.state != MJRefreshStateIdle || !self.automaticallyRefresh || self.mj_y == 0) return;
71 |
72 | if (_scrollView.mj_insetT + _scrollView.mj_contentH > _scrollView.mj_h) { // 内容超过一个屏幕
73 | // 这里的_scrollView.mj_contentH替换掉self.mj_y更为合理
74 | if (_scrollView.mj_offsetY >= _scrollView.mj_contentH - _scrollView.mj_h + self.mj_h * self.triggerAutomaticallyRefreshPercent + _scrollView.mj_insetB - self.mj_h) {
75 | // 防止手松开时连续调用
76 | CGPoint old = [change[@"old"] CGPointValue];
77 | CGPoint new = [change[@"new"] CGPointValue];
78 | if (new.y <= old.y) return;
79 |
80 | // 当底部刷新控件完全出现时,才刷新
81 | [self beginRefreshing];
82 | }
83 | }
84 | }
85 |
86 | - (void)scrollViewPanStateDidChange:(NSDictionary *)change
87 | {
88 | [super scrollViewPanStateDidChange:change];
89 |
90 | if (self.state != MJRefreshStateIdle) return;
91 |
92 | if (_scrollView.panGestureRecognizer.state == UIGestureRecognizerStateEnded) {// 手松开
93 | if (_scrollView.mj_insetT + _scrollView.mj_contentH <= _scrollView.mj_h) { // 不够一个屏幕
94 | if (_scrollView.mj_offsetY >= - _scrollView.mj_insetT) { // 向上拽
95 | [self beginRefreshing];
96 | }
97 | } else { // 超出一个屏幕
98 | if (_scrollView.mj_offsetY >= _scrollView.mj_contentH + _scrollView.mj_insetB - _scrollView.mj_h) {
99 | [self beginRefreshing];
100 | }
101 | }
102 | }
103 | }
104 |
105 | - (void)setState:(MJRefreshState)state
106 | {
107 | MJRefreshCheckState
108 |
109 | if (state == MJRefreshStateRefreshing) {
110 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
111 | [self executeRefreshingCallback];
112 | });
113 | }
114 | }
115 |
116 | - (void)setHidden:(BOOL)hidden
117 | {
118 | BOOL lastHidden = self.isHidden;
119 |
120 | [super setHidden:hidden];
121 |
122 | if (!lastHidden && hidden) {
123 | self.state = MJRefreshStateIdle;
124 |
125 | self.scrollView.mj_insetB -= self.mj_h;
126 | } else if (lastHidden && !hidden) {
127 | self.scrollView.mj_insetB += self.mj_h;
128 |
129 | // 设置位置
130 | self.mj_y = _scrollView.mj_contentH;
131 | }
132 | }
133 | @end
134 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshBackFooter.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshFooter.h"
10 |
11 | @interface MJRefreshBackFooter : MJRefreshFooter
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshBackFooter.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshBackFooter.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshBackFooter.h"
10 |
11 | @interface MJRefreshBackFooter()
12 | @property (assign, nonatomic) NSInteger lastRefreshCount;
13 | @property (assign, nonatomic) CGFloat lastBottomDelta;
14 | @end
15 |
16 | @implementation MJRefreshBackFooter
17 |
18 | #pragma mark - 初始化
19 | - (void)willMoveToSuperview:(UIView *)newSuperview
20 | {
21 | [super willMoveToSuperview:newSuperview];
22 |
23 | [self scrollViewContentSizeDidChange:nil];
24 | }
25 |
26 | #pragma mark - 实现父类的方法
27 | - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
28 | {
29 | [super scrollViewContentOffsetDidChange:change];
30 |
31 | // 如果正在刷新,直接返回
32 | if (self.state == MJRefreshStateRefreshing) return;
33 |
34 | _scrollViewOriginalInset = self.scrollView.contentInset;
35 |
36 | // 当前的contentOffset
37 | CGFloat currentOffsetY = self.scrollView.mj_offsetY;
38 | // 尾部控件刚好出现的offsetY
39 | CGFloat happenOffsetY = [self happenOffsetY];
40 | // 如果是向下滚动到看不见尾部控件,直接返回
41 | if (currentOffsetY <= happenOffsetY) return;
42 |
43 | CGFloat pullingPercent = (currentOffsetY - happenOffsetY) / self.mj_h;
44 |
45 | // 如果已全部加载,仅设置pullingPercent,然后返回
46 | if (self.state == MJRefreshStateNoMoreData) {
47 | self.pullingPercent = pullingPercent;
48 | return;
49 | }
50 |
51 | if (self.scrollView.isDragging) {
52 | self.pullingPercent = pullingPercent;
53 | // 普通 和 即将刷新 的临界点
54 | CGFloat normal2pullingOffsetY = happenOffsetY + self.mj_h;
55 |
56 | if (self.state == MJRefreshStateIdle && currentOffsetY > normal2pullingOffsetY) {
57 | // 转为即将刷新状态
58 | self.state = MJRefreshStatePulling;
59 | } else if (self.state == MJRefreshStatePulling && currentOffsetY <= normal2pullingOffsetY) {
60 | // 转为普通状态
61 | self.state = MJRefreshStateIdle;
62 | }
63 | } else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
64 | // 开始刷新
65 | [self beginRefreshing];
66 | } else if (pullingPercent < 1) {
67 | self.pullingPercent = pullingPercent;
68 | }
69 | }
70 |
71 | - (void)scrollViewContentSizeDidChange:(NSDictionary *)change
72 | {
73 | [super scrollViewContentSizeDidChange:change];
74 |
75 | // 内容的高度
76 | CGFloat contentHeight = self.scrollView.mj_contentH + self.ignoredScrollViewContentInsetBottom;
77 | // 表格的高度
78 | CGFloat scrollHeight = self.scrollView.mj_h - self.scrollViewOriginalInset.top - self.scrollViewOriginalInset.bottom + self.ignoredScrollViewContentInsetBottom;
79 | // 设置位置和尺寸
80 | self.mj_y = MAX(contentHeight, scrollHeight);
81 | }
82 |
83 | - (void)setState:(MJRefreshState)state
84 | {
85 | MJRefreshCheckState
86 |
87 | // 根据状态来设置属性
88 | if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
89 | // 刷新完毕
90 | if (MJRefreshStateRefreshing == oldState) {
91 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
92 | self.scrollView.mj_insetB -= self.lastBottomDelta;
93 |
94 | // 自动调整透明度
95 | if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
96 | } completion:^(BOOL finished) {
97 | self.pullingPercent = 0.0;
98 | }];
99 | }
100 |
101 | CGFloat deltaH = [self heightForContentBreakView];
102 | // 刚刷新完毕
103 | if (MJRefreshStateRefreshing == oldState && deltaH > 0 && self.scrollView.mj_totalDataCount != self.lastRefreshCount) {
104 | self.scrollView.mj_offsetY = self.scrollView.mj_offsetY;
105 | }
106 | } else if (state == MJRefreshStateRefreshing) {
107 | // 记录刷新前的数量
108 | self.lastRefreshCount = self.scrollView.mj_totalDataCount;
109 |
110 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
111 | CGFloat bottom = self.mj_h + self.scrollViewOriginalInset.bottom;
112 | CGFloat deltaH = [self heightForContentBreakView];
113 | if (deltaH < 0) { // 如果内容高度小于view的高度
114 | bottom -= deltaH;
115 | }
116 | self.lastBottomDelta = bottom - self.scrollView.mj_insetB;
117 | self.scrollView.mj_insetB = bottom;
118 | self.scrollView.mj_offsetY = [self happenOffsetY] + self.mj_h;
119 | } completion:^(BOOL finished) {
120 | [self executeRefreshingCallback];
121 | }];
122 | }
123 | }
124 |
125 | #pragma mark - 公共方法
126 | - (void)endRefreshing
127 | {
128 | if ([self.scrollView isKindOfClass:[UICollectionView class]]) {
129 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
130 | [super endRefreshing];
131 | });
132 | } else {
133 | [super endRefreshing];
134 | }
135 | }
136 |
137 | - (void)noticeNoMoreData
138 | {
139 | if ([self.scrollView isKindOfClass:[UICollectionView class]]) {
140 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
141 | [super noticeNoMoreData];
142 | });
143 | } else {
144 | [super noticeNoMoreData];
145 | }
146 | }
147 |
148 | #pragma mark - 私有方法
149 | #pragma mark 获得scrollView的内容 超出 view 的高度
150 | - (CGFloat)heightForContentBreakView
151 | {
152 | CGFloat h = self.scrollView.frame.size.height - self.scrollViewOriginalInset.bottom - self.scrollViewOriginalInset.top;
153 | return self.scrollView.contentSize.height - h;
154 | }
155 |
156 | #pragma mark 刚好看到上拉刷新控件时的contentOffset.y
157 | - (CGFloat)happenOffsetY
158 | {
159 | CGFloat deltaH = [self heightForContentBreakView];
160 | if (deltaH > 0) {
161 | return deltaH - self.scrollViewOriginalInset.top;
162 | } else {
163 | return - self.scrollViewOriginalInset.top;
164 | }
165 | }
166 | @end
167 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshComponent.h:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // MJRefreshComponent.h
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 15/3/4.
7 | // Copyright (c) 2015年 小码哥. All rights reserved.
8 | // 刷新控件的基类
9 |
10 | #import
11 | #import "MJRefreshConst.h"
12 | #import "UIView+MJExtension.h"
13 | #import "UIScrollView+MJExtension.h"
14 | #import "UIScrollView+MJRefresh.h"
15 |
16 | /** 刷新控件的状态 */
17 | typedef NS_ENUM(NSInteger, MJRefreshState) {
18 | /** 普通闲置状态 */
19 | MJRefreshStateIdle = 1,
20 | /** 松开就可以进行刷新的状态 */
21 | MJRefreshStatePulling,
22 | /** 正在刷新中的状态 */
23 | MJRefreshStateRefreshing,
24 | /** 即将刷新的状态 */
25 | MJRefreshStateWillRefresh,
26 | /** 所有数据加载完毕,没有更多的数据了 */
27 | MJRefreshStateNoMoreData
28 | };
29 |
30 | /** 进入刷新状态的回调 */
31 | typedef void (^MJRefreshComponentRefreshingBlock)();
32 |
33 | /** 刷新控件的基类 */
34 | @interface MJRefreshComponent : UIView
35 | {
36 | /** 记录scrollView刚开始的inset */
37 | UIEdgeInsets _scrollViewOriginalInset;
38 | /** 父控件 */
39 | __weak UIScrollView *_scrollView;
40 | }
41 | #pragma mark - 刷新回调
42 | /** 正在刷新的回调 */
43 | @property (copy, nonatomic) MJRefreshComponentRefreshingBlock refreshingBlock;
44 | /** 设置回调对象和回调方法 */
45 | - (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action;
46 | /** 回调对象 */
47 | @property (weak, nonatomic) id refreshingTarget;
48 | /** 回调方法 */
49 | @property (assign, nonatomic) SEL refreshingAction;
50 | /** 触发回调(交给子类去调用) */
51 | - (void)executeRefreshingCallback;
52 |
53 | #pragma mark - 刷新状态控制
54 | /** 进入刷新状态 */
55 | - (void)beginRefreshing;
56 | /** 结束刷新状态 */
57 | - (void)endRefreshing;
58 | /** 是否正在刷新 */
59 | - (BOOL)isRefreshing;
60 | /** 刷新状态 一般交给子类内部实现 */
61 | @property (assign, nonatomic) MJRefreshState state;
62 |
63 | #pragma mark - 交给子类去访问
64 | /** 记录scrollView刚开始的inset */
65 | @property (assign, nonatomic, readonly) UIEdgeInsets scrollViewOriginalInset;
66 | /** 父控件 */
67 | @property (weak, nonatomic, readonly) UIScrollView *scrollView;
68 |
69 | #pragma mark - 交给子类们去实现
70 | /** 初始化 */
71 | - (void)prepare NS_REQUIRES_SUPER;
72 | /** 摆放子控件frame */
73 | - (void)placeSubviews NS_REQUIRES_SUPER;
74 | /** 当scrollView的contentOffset发生改变的时候调用 */
75 | - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change NS_REQUIRES_SUPER;
76 | /** 当scrollView的contentSize发生改变的时候调用 */
77 | - (void)scrollViewContentSizeDidChange:(NSDictionary *)change NS_REQUIRES_SUPER;
78 | /** 当scrollView的拖拽状态发生改变的时候调用 */
79 | - (void)scrollViewPanStateDidChange:(NSDictionary *)change NS_REQUIRES_SUPER;
80 |
81 |
82 | #pragma mark - 其他
83 | /** 拉拽的百分比(交给子类重写) */
84 | @property (assign, nonatomic) CGFloat pullingPercent;
85 | /** 根据拖拽比例自动切换透明度 */
86 | @property (assign, nonatomic, getter=isAutoChangeAlpha) BOOL autoChangeAlpha MJRefreshDeprecated("请使用automaticallyChangeAlpha属性");
87 | /** 根据拖拽比例自动切换透明度 */
88 | @property (assign, nonatomic, getter=isAutomaticallyChangeAlpha) BOOL automaticallyChangeAlpha;
89 | @end
90 |
91 | @interface UILabel(MJRefresh)
92 | + (instancetype)label;
93 | @end
94 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshComponent.m:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // MJRefreshComponent.m
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 15/3/4.
7 | // Copyright (c) 2015年 小码哥. All rights reserved.
8 | //
9 |
10 | #import "MJRefreshComponent.h"
11 | #import "MJRefreshConst.h"
12 | #import "UIView+MJExtension.h"
13 | #import "UIScrollView+MJRefresh.h"
14 |
15 | @interface MJRefreshComponent()
16 | @property (strong, nonatomic) UIPanGestureRecognizer *pan;
17 | @end
18 |
19 | @implementation MJRefreshComponent
20 | #pragma mark - 初始化
21 | - (instancetype)initWithFrame:(CGRect)frame
22 | {
23 | if (self = [super initWithFrame:frame]) {
24 | // 准备工作
25 | [self prepare];
26 |
27 | // 默认是普通状态
28 | self.state = MJRefreshStateIdle;
29 | }
30 | return self;
31 | }
32 |
33 | - (void)prepare
34 | {
35 | // 基本属性
36 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth;
37 | self.backgroundColor = [UIColor clearColor];
38 | }
39 |
40 | - (void)layoutSubviews
41 | {
42 | [super layoutSubviews];
43 |
44 | [self placeSubviews];
45 | }
46 |
47 | - (void)placeSubviews{}
48 |
49 | - (void)willMoveToSuperview:(UIView *)newSuperview
50 | {
51 | [super willMoveToSuperview:newSuperview];
52 |
53 | // 如果不是UIScrollView,不做任何事情
54 | if (newSuperview && ![newSuperview isKindOfClass:[UIScrollView class]]) return;
55 |
56 | // 旧的父控件移除监听
57 | [self removeObservers];
58 |
59 | if (newSuperview) { // 新的父控件
60 | // 设置宽度
61 | self.mj_w = newSuperview.mj_w;
62 | // 设置位置
63 | self.mj_x = 0;
64 |
65 | // 记录UIScrollView
66 | _scrollView = (UIScrollView *)newSuperview;
67 | // 设置永远支持垂直弹簧效果
68 | _scrollView.alwaysBounceVertical = YES;
69 | // 记录UIScrollView最开始的contentInset
70 | _scrollViewOriginalInset = _scrollView.contentInset;
71 |
72 | // 添加监听
73 | [self addObservers];
74 | }
75 | }
76 |
77 | - (void)drawRect:(CGRect)rect
78 | {
79 | [super drawRect:rect];
80 |
81 | if (self.state == MJRefreshStateWillRefresh) {
82 | // 预防view还没显示出来就调用了beginRefreshing
83 | self.state = MJRefreshStateRefreshing;
84 | }
85 | }
86 |
87 | #pragma mark - KVO监听
88 | - (void)addObservers
89 | {
90 | NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
91 | [self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentOffset options:options context:nil];
92 | [self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentSize options:options context:nil];
93 | self.pan = self.scrollView.panGestureRecognizer;
94 | [self.pan addObserver:self forKeyPath:MJRefreshKeyPathPanState options:options context:nil];
95 | }
96 |
97 | - (void)removeObservers
98 | {
99 | [self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentOffset];
100 | [self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentSize];;
101 | [self.pan removeObserver:self forKeyPath:MJRefreshKeyPathPanState];
102 | self.pan = nil;
103 | }
104 |
105 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
106 | {
107 | // 遇到这些情况就直接返回
108 | if (!self.userInteractionEnabled) return;
109 |
110 | // 这个就算看不见也需要处理
111 | if ([keyPath isEqualToString:MJRefreshKeyPathContentSize]) {
112 | [self scrollViewContentSizeDidChange:change];
113 | }
114 |
115 | // 看不见
116 | if (self.hidden) return;
117 | if ([keyPath isEqualToString:MJRefreshKeyPathContentOffset]) {
118 | [self scrollViewContentOffsetDidChange:change];
119 | } else if ([keyPath isEqualToString:MJRefreshKeyPathPanState]) {
120 | [self scrollViewPanStateDidChange:change];
121 | }
122 | }
123 |
124 | - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change{}
125 | - (void)scrollViewContentSizeDidChange:(NSDictionary *)change{}
126 | - (void)scrollViewPanStateDidChange:(NSDictionary *)change{}
127 |
128 | #pragma mark - 公共方法
129 | #pragma mark 设置回调对象和回调方法
130 | - (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action
131 | {
132 | self.refreshingTarget = target;
133 | self.refreshingAction = action;
134 | }
135 |
136 | #pragma mark 进入刷新状态
137 | - (void)beginRefreshing
138 | {
139 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
140 | self.alpha = 1.0;
141 | }];
142 | self.pullingPercent = 1.0;
143 | // 只要正在刷新,就完全显示
144 | if (self.window) {
145 | self.state = MJRefreshStateRefreshing;
146 | } else {
147 | self.state = MJRefreshStateWillRefresh;
148 | // 刷新(预防从另一个控制器回到这个控制器的情况,回来要重新刷新一下)
149 | [self setNeedsDisplay];
150 | }
151 | }
152 |
153 | #pragma mark 结束刷新状态
154 | - (void)endRefreshing
155 | {
156 | self.state = MJRefreshStateIdle;
157 | }
158 |
159 | #pragma mark 是否正在刷新
160 | - (BOOL)isRefreshing
161 | {
162 | return self.state == MJRefreshStateRefreshing || self.state == MJRefreshStateWillRefresh;
163 | }
164 |
165 | #pragma mark 自动切换透明度
166 | - (void)setAutoChangeAlpha:(BOOL)autoChangeAlpha
167 | {
168 | self.automaticallyChangeAlpha = autoChangeAlpha;
169 | }
170 |
171 | - (BOOL)isAutoChangeAlpha
172 | {
173 | return self.isAutomaticallyChangeAlpha;
174 | }
175 |
176 | - (void)setAutomaticallyChangeAlpha:(BOOL)automaticallyChangeAlpha
177 | {
178 | _automaticallyChangeAlpha = automaticallyChangeAlpha;
179 |
180 | if (self.isRefreshing) return;
181 |
182 | if (automaticallyChangeAlpha) {
183 | self.alpha = self.pullingPercent;
184 | } else {
185 | self.alpha = 1.0;
186 | }
187 | }
188 |
189 | #pragma mark 根据拖拽进度设置透明度
190 | - (void)setPullingPercent:(CGFloat)pullingPercent
191 | {
192 | _pullingPercent = pullingPercent;
193 |
194 | if (self.isRefreshing) return;
195 |
196 | if (self.isAutomaticallyChangeAlpha) {
197 | self.alpha = pullingPercent;
198 | }
199 | }
200 |
201 | #pragma mark - 内部方法
202 | - (void)executeRefreshingCallback
203 | {
204 | dispatch_async(dispatch_get_main_queue(), ^{
205 | if (self.refreshingBlock) {
206 | self.refreshingBlock();
207 | }
208 | if ([self.refreshingTarget respondsToSelector:self.refreshingAction]) {
209 | MJRefreshMsgSend(MJRefreshMsgTarget(self.refreshingTarget), self.refreshingAction, self);
210 | }
211 | });
212 | }
213 | @end
214 |
215 | @implementation UILabel(MJRefresh)
216 | + (instancetype)label
217 | {
218 | UILabel *label = [[self alloc] init];
219 | label.font = MJRefreshLabelFont;
220 | label.textColor = MJRefreshLabelTextColor;
221 | label.autoresizingMask = UIViewAutoresizingFlexibleWidth;
222 | label.textAlignment = NSTextAlignmentCenter;
223 | label.backgroundColor = [UIColor clearColor];
224 | return label;
225 | }
226 | @end
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshFooter.h:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // MJRefreshFooter.h
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 15/3/5.
7 | // Copyright (c) 2015年 小码哥. All rights reserved.
8 | // 上拉刷新控件
9 |
10 | #import "MJRefreshComponent.h"
11 |
12 | @interface MJRefreshFooter : MJRefreshComponent
13 | /** 创建footer */
14 | + (instancetype)footerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock;
15 | /** 创建footer */
16 | + (instancetype)footerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
17 |
18 | /** 提示没有更多的数据 */
19 | - (void)endRefreshingWithNoMoreData;
20 | - (void)noticeNoMoreData MJRefreshDeprecated("使用endRefreshingWithNoMoreData");
21 |
22 | /** 重置没有更多的数据(消除没有更多数据的状态) */
23 | - (void)resetNoMoreData;
24 |
25 | /** 忽略多少scrollView的contentInset的bottom */
26 | @property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetBottom;
27 |
28 | /** 自动根据有无数据来显示和隐藏(有数据就显示,没有数据隐藏。默认是NO) */
29 | @property (assign, nonatomic, getter=isAutomaticallyHidden) BOOL automaticallyHidden;
30 | @end
31 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshFooter.m:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // MJRefreshFooter.m
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 15/3/5.
7 | // Copyright (c) 2015年 小码哥. All rights reserved.
8 | //
9 |
10 | #import "MJRefreshFooter.h"
11 |
12 | @interface MJRefreshFooter()
13 |
14 | @end
15 |
16 | @implementation MJRefreshFooter
17 | #pragma mark - 构造方法
18 | + (instancetype)footerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock
19 | {
20 | MJRefreshFooter *cmp = [[self alloc] init];
21 | cmp.refreshingBlock = refreshingBlock;
22 | return cmp;
23 | }
24 | + (instancetype)footerWithRefreshingTarget:(id)target refreshingAction:(SEL)action
25 | {
26 | MJRefreshFooter *cmp = [[self alloc] init];
27 | [cmp setRefreshingTarget:target refreshingAction:action];
28 | return cmp;
29 | }
30 |
31 | #pragma mark - 重写父类的方法
32 | - (void)prepare
33 | {
34 | [super prepare];
35 |
36 | // 设置自己的高度
37 | self.mj_h = MJRefreshFooterHeight;
38 |
39 | // 默认不会自动隐藏
40 | self.automaticallyHidden = NO;
41 | }
42 |
43 | - (void)willMoveToSuperview:(UIView *)newSuperview
44 | {
45 | [super willMoveToSuperview:newSuperview];
46 |
47 | if (newSuperview) {
48 | // 监听scrollView数据的变化
49 | if ([self.scrollView isKindOfClass:[UITableView class]] || [self.scrollView isKindOfClass:[UICollectionView class]]) {
50 | [self.scrollView setMj_reloadDataBlock:^(NSInteger totalDataCount) {
51 | if (self.isAutomaticallyHidden) {
52 | self.hidden = (totalDataCount == 0);
53 | }
54 | }];
55 | }
56 | }
57 | }
58 |
59 | #pragma mark - 公共方法
60 | - (void)endRefreshingWithNoMoreData
61 | {
62 | self.state = MJRefreshStateNoMoreData;
63 | }
64 |
65 | - (void)noticeNoMoreData
66 | {
67 | [self endRefreshingWithNoMoreData];
68 | }
69 |
70 | - (void)resetNoMoreData
71 | {
72 | self.state = MJRefreshStateIdle;
73 | }
74 | @end
75 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshHeader.h:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // MJRefreshHeader.h
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 15/3/4.
7 | // Copyright (c) 2015年 小码哥. All rights reserved.
8 | // 下拉刷新控件:负责监控用户下拉的状态
9 |
10 | #import "MJRefreshComponent.h"
11 |
12 | @interface MJRefreshHeader : MJRefreshComponent
13 | /** 创建header */
14 | + (instancetype)headerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock;
15 | /** 创建header */
16 | + (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action;
17 |
18 | /** 这个key用来存储上一次下拉刷新成功的时间 */
19 | @property (copy, nonatomic) NSString *lastUpdatedTimeKey;
20 | /** 上一次下拉刷新成功的时间 */
21 | @property (strong, nonatomic, readonly) NSDate *lastUpdatedTime;
22 |
23 | /** 忽略多少scrollView的contentInset的top */
24 | @property (assign, nonatomic) CGFloat ignoredScrollViewContentInsetTop;
25 | @end
26 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Base/MJRefreshHeader.m:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // MJRefreshHeader.m
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 15/3/4.
7 | // Copyright (c) 2015年 小码哥. All rights reserved.
8 | //
9 |
10 | #import "MJRefreshHeader.h"
11 |
12 | @interface MJRefreshHeader()
13 | @property (assign, nonatomic) CGFloat insetTDelta;
14 | @end
15 |
16 | @implementation MJRefreshHeader
17 | #pragma mark - 构造方法
18 | + (instancetype)headerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock
19 | {
20 | MJRefreshHeader *cmp = [[self alloc] init];
21 | cmp.refreshingBlock = refreshingBlock;
22 | return cmp;
23 | }
24 | + (instancetype)headerWithRefreshingTarget:(id)target refreshingAction:(SEL)action
25 | {
26 | MJRefreshHeader *cmp = [[self alloc] init];
27 | [cmp setRefreshingTarget:target refreshingAction:action];
28 | return cmp;
29 | }
30 |
31 | #pragma mark - 覆盖父类的方法
32 | - (void)prepare
33 | {
34 | [super prepare];
35 |
36 | // 设置key
37 | self.lastUpdatedTimeKey = MJRefreshHeaderLastUpdatedTimeKey;
38 |
39 | // 设置高度
40 | self.mj_h = MJRefreshHeaderHeight;
41 | }
42 |
43 | - (void)placeSubviews
44 | {
45 | [super placeSubviews];
46 |
47 | // 设置y值(当自己的高度发生改变了,肯定要重新调整Y值,所以放到placeSubviews方法中设置y值)
48 | self.mj_y = - self.mj_h - self.ignoredScrollViewContentInsetTop;
49 | }
50 |
51 | - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change
52 | {
53 | [super scrollViewContentOffsetDidChange:change];
54 |
55 | // 在刷新的refreshing状态
56 | if (self.state == MJRefreshStateRefreshing) {
57 | if (self.window == nil) return;
58 |
59 | // sectionheader停留解决
60 | CGFloat insetT = - self.scrollView.mj_offsetY > _scrollViewOriginalInset.top ? - self.scrollView.mj_offsetY : _scrollViewOriginalInset.top;
61 | insetT = insetT > self.mj_h + _scrollViewOriginalInset.top ? self.mj_h + _scrollViewOriginalInset.top : insetT;
62 | self.scrollView.mj_insetT = insetT;
63 |
64 | self.insetTDelta = _scrollViewOriginalInset.top - insetT;
65 | return;
66 | }
67 |
68 | // 跳转到下一个控制器时,contentInset可能会变
69 | _scrollViewOriginalInset = self.scrollView.contentInset;
70 |
71 | // 当前的contentOffset
72 | CGFloat offsetY = self.scrollView.mj_offsetY;
73 | // 头部控件刚好出现的offsetY
74 | CGFloat happenOffsetY = - self.scrollViewOriginalInset.top;
75 |
76 | // 如果是向上滚动到看不见头部控件,直接返回
77 | // >= -> >
78 | if (offsetY > happenOffsetY) return;
79 |
80 | // 普通 和 即将刷新 的临界点
81 | CGFloat normal2pullingOffsetY = happenOffsetY - self.mj_h;
82 | CGFloat pullingPercent = (happenOffsetY - offsetY) / self.mj_h;
83 |
84 | if (self.scrollView.isDragging) { // 如果正在拖拽
85 | self.pullingPercent = pullingPercent;
86 | if (self.state == MJRefreshStateIdle && offsetY < normal2pullingOffsetY) {
87 | // 转为即将刷新状态
88 | self.state = MJRefreshStatePulling;
89 | } else if (self.state == MJRefreshStatePulling && offsetY >= normal2pullingOffsetY) {
90 | // 转为普通状态
91 | self.state = MJRefreshStateIdle;
92 | }
93 | } else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开
94 | // 开始刷新
95 | [self beginRefreshing];
96 | } else if (pullingPercent < 1) {
97 | self.pullingPercent = pullingPercent;
98 | }
99 | }
100 |
101 | - (void)setState:(MJRefreshState)state
102 | {
103 | MJRefreshCheckState
104 |
105 | // 根据状态做事情
106 | if (state == MJRefreshStateIdle) {
107 | if (oldState != MJRefreshStateRefreshing) return;
108 |
109 | // 保存刷新时间
110 | [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:self.lastUpdatedTimeKey];
111 | [[NSUserDefaults standardUserDefaults] synchronize];
112 |
113 | // 恢复inset和offset
114 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
115 | self.scrollView.mj_insetT += self.insetTDelta;
116 |
117 | // 自动调整透明度
118 | if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0;
119 | } completion:^(BOOL finished) {
120 | self.pullingPercent = 0.0;
121 | }];
122 | } else if (state == MJRefreshStateRefreshing) {
123 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
124 | // 增加滚动区域
125 | CGFloat top = self.scrollViewOriginalInset.top + self.mj_h;
126 | self.scrollView.mj_insetT = top;
127 |
128 | // 设置滚动位置
129 | self.scrollView.mj_offsetY = - top;
130 | } completion:^(BOOL finished) {
131 | [self executeRefreshingCallback];
132 | }];
133 | }
134 | }
135 |
136 | - (void)drawRect:(CGRect)rect
137 | {
138 | [super drawRect:rect];
139 |
140 |
141 | }
142 |
143 | #pragma mark - 公共方法
144 | - (void)endRefreshing
145 | {
146 | if ([self.scrollView isKindOfClass:[UICollectionView class]]) {
147 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
148 | [super endRefreshing];
149 | });
150 | } else {
151 | [super endRefreshing];
152 | }
153 | }
154 |
155 | - (NSDate *)lastUpdatedTime
156 | {
157 | return [[NSUserDefaults standardUserDefaults] objectForKey:self.lastUpdatedTimeKey];
158 | }
159 | @end
160 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoGifFooter.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshAutoGifFooter.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshAutoStateFooter.h"
10 |
11 | @interface MJRefreshAutoGifFooter : MJRefreshAutoStateFooter
12 | @property (weak, nonatomic, readonly) UIImageView *gifView;
13 |
14 | /** 设置state状态下的动画图片images 动画持续时间duration*/
15 | - (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
16 | - (void)setImages:(NSArray *)images forState:(MJRefreshState)state;
17 | @end
18 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoGifFooter.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshAutoGifFooter.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshAutoGifFooter.h"
10 |
11 | @interface MJRefreshAutoGifFooter()
12 | {
13 | __unsafe_unretained UIImageView *_gifView;
14 | }
15 | /** 所有状态对应的动画图片 */
16 | @property (strong, nonatomic) NSMutableDictionary *stateImages;
17 | /** 所有状态对应的动画时间 */
18 | @property (strong, nonatomic) NSMutableDictionary *stateDurations;
19 | @end
20 |
21 | @implementation MJRefreshAutoGifFooter
22 | #pragma mark - 懒加载
23 | - (UIImageView *)gifView
24 | {
25 | if (!_gifView) {
26 | UIImageView *gifView = [[UIImageView alloc] init];
27 | [self addSubview:_gifView = gifView];
28 | }
29 | return _gifView;
30 | }
31 |
32 | - (NSMutableDictionary *)stateImages
33 | {
34 | if (!_stateImages) {
35 | self.stateImages = [NSMutableDictionary dictionary];
36 | }
37 | return _stateImages;
38 | }
39 |
40 | - (NSMutableDictionary *)stateDurations
41 | {
42 | if (!_stateDurations) {
43 | self.stateDurations = [NSMutableDictionary dictionary];
44 | }
45 | return _stateDurations;
46 | }
47 |
48 | #pragma mark - 公共方法
49 | - (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state
50 | {
51 | if (images == nil) return;
52 |
53 | self.stateImages[@(state)] = images;
54 | self.stateDurations[@(state)] = @(duration);
55 |
56 | /* 根据图片设置控件的高度 */
57 | UIImage *image = [images firstObject];
58 | if (image.size.height > self.mj_h) {
59 | self.mj_h = image.size.height;
60 | }
61 | }
62 |
63 | - (void)setImages:(NSArray *)images forState:(MJRefreshState)state
64 | {
65 | [self setImages:images duration:images.count * 0.1 forState:state];
66 | }
67 |
68 | #pragma mark - 实现父类的方法
69 | - (void)placeSubviews
70 | {
71 | [super placeSubviews];
72 |
73 | if (self.gifView.constraints.count) return;
74 |
75 | self.gifView.frame = self.bounds;
76 | if (self.isRefreshingTitleHidden) {
77 | self.gifView.contentMode = UIViewContentModeCenter;
78 | } else {
79 | self.gifView.contentMode = UIViewContentModeRight;
80 | self.gifView.mj_w = self.mj_w * 0.5 - 90;
81 | }
82 | }
83 |
84 | - (void)setState:(MJRefreshState)state
85 | {
86 | MJRefreshCheckState
87 |
88 | // 根据状态做事情
89 | if (state == MJRefreshStateRefreshing) {
90 | NSArray *images = self.stateImages[@(state)];
91 | if (images.count == 0) return;
92 | [self.gifView stopAnimating];
93 |
94 | self.gifView.hidden = NO;
95 | if (images.count == 1) { // 单张图片
96 | self.gifView.image = [images lastObject];
97 | } else { // 多张图片
98 | self.gifView.animationImages = images;
99 | self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue];
100 | [self.gifView startAnimating];
101 | }
102 | } else if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
103 | [self.gifView stopAnimating];
104 | self.gifView.hidden = YES;
105 | }
106 | }
107 | @end
108 |
109 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoNormalFooter.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshAutoNormalFooter.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshAutoStateFooter.h"
10 |
11 | @interface MJRefreshAutoNormalFooter : MJRefreshAutoStateFooter
12 | /** 菊花的样式 */
13 | @property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle;
14 | @end
15 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoNormalFooter.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshAutoNormalFooter.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshAutoNormalFooter.h"
10 |
11 | @interface MJRefreshAutoNormalFooter()
12 | @property (weak, nonatomic) UIActivityIndicatorView *loadingView;
13 | @end
14 |
15 | @implementation MJRefreshAutoNormalFooter
16 | #pragma mark - 懒加载子控件
17 | - (UIActivityIndicatorView *)loadingView
18 | {
19 | if (!_loadingView) {
20 | UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:self.activityIndicatorViewStyle];
21 | loadingView.hidesWhenStopped = YES;
22 | [self addSubview:_loadingView = loadingView];
23 | }
24 | return _loadingView;
25 | }
26 |
27 | - (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
28 | {
29 | _activityIndicatorViewStyle = activityIndicatorViewStyle;
30 |
31 | self.loadingView = nil;
32 | [self setNeedsLayout];
33 | }
34 | #pragma makr - 重写父类的方法
35 | - (void)prepare
36 | {
37 | [super prepare];
38 |
39 | self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
40 | }
41 |
42 | - (void)placeSubviews
43 | {
44 | [super placeSubviews];
45 |
46 | if (self.loadingView.constraints.count) return;
47 |
48 | // 圈圈
49 | CGFloat loadingCenterX = self.mj_w * 0.5;
50 | if (!self.isRefreshingTitleHidden) {
51 | loadingCenterX -= 100;
52 | }
53 | CGFloat loadingCenterY = self.mj_h * 0.5;
54 | self.loadingView.center = CGPointMake(loadingCenterX, loadingCenterY);
55 | }
56 |
57 | - (void)setState:(MJRefreshState)state
58 | {
59 | MJRefreshCheckState
60 |
61 | // 根据状态做事情
62 | if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) {
63 | [self.loadingView stopAnimating];
64 | } else if (state == MJRefreshStateRefreshing) {
65 | [self.loadingView startAnimating];
66 | }
67 | }
68 |
69 | @end
70 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoStateFooter.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshAutoStateFooter.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/6/13.
6 | // Copyright © 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshAutoFooter.h"
10 |
11 | @interface MJRefreshAutoStateFooter : MJRefreshAutoFooter
12 | /** 显示刷新状态的label */
13 | @property (weak, nonatomic, readonly) UILabel *stateLabel;
14 |
15 | /** 设置state状态下的文字 */
16 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state;
17 |
18 | /** 隐藏刷新状态的文字 */
19 | @property (assign, nonatomic, getter=isRefreshingTitleHidden) BOOL refreshingTitleHidden;
20 | @end
21 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Auto/MJRefreshAutoStateFooter.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshAutoStateFooter.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/6/13.
6 | // Copyright © 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshAutoStateFooter.h"
10 |
11 | @interface MJRefreshAutoStateFooter()
12 | {
13 | /** 显示刷新状态的label */
14 | __unsafe_unretained UILabel *_stateLabel;
15 | }
16 | /** 所有状态对应的文字 */
17 | @property (strong, nonatomic) NSMutableDictionary *stateTitles;
18 | @end
19 |
20 | @implementation MJRefreshAutoStateFooter
21 | #pragma mark - 懒加载
22 | - (NSMutableDictionary *)stateTitles
23 | {
24 | if (!_stateTitles) {
25 | self.stateTitles = [NSMutableDictionary dictionary];
26 | }
27 | return _stateTitles;
28 | }
29 |
30 | - (UILabel *)stateLabel
31 | {
32 | if (!_stateLabel) {
33 | [self addSubview:_stateLabel = [UILabel label]];
34 | }
35 | return _stateLabel;
36 | }
37 |
38 | #pragma mark - 公共方法
39 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state
40 | {
41 | if (title == nil) return;
42 | self.stateTitles[@(state)] = title;
43 | self.stateLabel.text = self.stateTitles[@(self.state)];
44 | }
45 |
46 | #pragma mark - 私有方法
47 | - (void)stateLabelClick
48 | {
49 | if (self.state == MJRefreshStateIdle) {
50 | [self beginRefreshing];
51 | }
52 | }
53 |
54 | #pragma mark - 重写父类的方法
55 | - (void)prepare
56 | {
57 | [super prepare];
58 |
59 | // 初始化文字
60 | [self setTitle:MJRefreshAutoFooterIdleText forState:MJRefreshStateIdle];
61 | [self setTitle:MJRefreshAutoFooterRefreshingText forState:MJRefreshStateRefreshing];
62 | [self setTitle:MJRefreshAutoFooterNoMoreDataText forState:MJRefreshStateNoMoreData];
63 |
64 | // 监听label
65 | self.stateLabel.userInteractionEnabled = YES;
66 | [self.stateLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(stateLabelClick)]];
67 | }
68 |
69 | - (void)placeSubviews
70 | {
71 | [super placeSubviews];
72 |
73 | if (self.stateLabel.constraints.count) return;
74 |
75 | // 状态标签
76 | self.stateLabel.frame = self.bounds;
77 | }
78 |
79 | - (void)setState:(MJRefreshState)state
80 | {
81 | MJRefreshCheckState
82 |
83 | if (self.isRefreshingTitleHidden && state == MJRefreshStateRefreshing) {
84 | self.stateLabel.text = nil;
85 | } else {
86 | self.stateLabel.text = self.stateTitles[@(state)];
87 | }
88 | }
89 | @end
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackGifFooter.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshBackGifFooter.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshBackStateFooter.h"
10 |
11 | @interface MJRefreshBackGifFooter : MJRefreshBackStateFooter
12 | @property (weak, nonatomic, readonly) UIImageView *gifView;
13 |
14 | /** 设置state状态下的动画图片images 动画持续时间duration*/
15 | - (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
16 | - (void)setImages:(NSArray *)images forState:(MJRefreshState)state;
17 | @end
18 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackGifFooter.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshBackGifFooter.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshBackGifFooter.h"
10 |
11 | @interface MJRefreshBackGifFooter()
12 | {
13 | __unsafe_unretained UIImageView *_gifView;
14 | }
15 | /** 所有状态对应的动画图片 */
16 | @property (strong, nonatomic) NSMutableDictionary *stateImages;
17 | /** 所有状态对应的动画时间 */
18 | @property (strong, nonatomic) NSMutableDictionary *stateDurations;
19 | @end
20 |
21 | @implementation MJRefreshBackGifFooter
22 | #pragma mark - 懒加载
23 | - (UIImageView *)gifView
24 | {
25 | if (!_gifView) {
26 | UIImageView *gifView = [[UIImageView alloc] init];
27 | [self addSubview:_gifView = gifView];
28 | }
29 | return _gifView;
30 | }
31 |
32 | - (NSMutableDictionary *)stateImages
33 | {
34 | if (!_stateImages) {
35 | self.stateImages = [NSMutableDictionary dictionary];
36 | }
37 | return _stateImages;
38 | }
39 |
40 | - (NSMutableDictionary *)stateDurations
41 | {
42 | if (!_stateDurations) {
43 | self.stateDurations = [NSMutableDictionary dictionary];
44 | }
45 | return _stateDurations;
46 | }
47 |
48 | #pragma mark - 公共方法
49 | - (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state
50 | {
51 | if (images == nil) return;
52 |
53 | self.stateImages[@(state)] = images;
54 | self.stateDurations[@(state)] = @(duration);
55 |
56 | /* 根据图片设置控件的高度 */
57 | UIImage *image = [images firstObject];
58 | if (image.size.height > self.mj_h) {
59 | self.mj_h = image.size.height;
60 | }
61 | }
62 |
63 | - (void)setImages:(NSArray *)images forState:(MJRefreshState)state
64 | {
65 | [self setImages:images duration:images.count * 0.1 forState:state];
66 | }
67 |
68 | #pragma mark - 实现父类的方法
69 | - (void)setPullingPercent:(CGFloat)pullingPercent
70 | {
71 | [super setPullingPercent:pullingPercent];
72 | NSArray *images = self.stateImages[@(MJRefreshStateIdle)];
73 | if (self.state != MJRefreshStateIdle || images.count == 0) return;
74 | [self.gifView stopAnimating];
75 | NSUInteger index = images.count * pullingPercent;
76 | if (index >= images.count) index = images.count - 1;
77 | self.gifView.image = images[index];
78 | }
79 |
80 | - (void)placeSubviews
81 | {
82 | [super placeSubviews];
83 |
84 | if (self.gifView.constraints.count) return;
85 |
86 | self.gifView.frame = self.bounds;
87 | if (self.stateLabel.hidden) {
88 | self.gifView.contentMode = UIViewContentModeCenter;
89 | } else {
90 | self.gifView.contentMode = UIViewContentModeRight;
91 | self.gifView.mj_w = self.mj_w * 0.5 - 90;
92 | }
93 | }
94 |
95 | - (void)setState:(MJRefreshState)state
96 | {
97 | MJRefreshCheckState
98 |
99 | // 根据状态做事情
100 | if (state == MJRefreshStatePulling || state == MJRefreshStateRefreshing) {
101 | NSArray *images = self.stateImages[@(state)];
102 | if (images.count == 0) return;
103 |
104 | self.gifView.hidden = NO;
105 | [self.gifView stopAnimating];
106 | if (images.count == 1) { // 单张图片
107 | self.gifView.image = [images lastObject];
108 | } else { // 多张图片
109 | self.gifView.animationImages = images;
110 | self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue];
111 | [self.gifView startAnimating];
112 | }
113 | } else if (state == MJRefreshStateIdle) {
114 | self.gifView.hidden = NO;
115 | } else if (state == MJRefreshStateNoMoreData) {
116 | self.gifView.hidden = YES;
117 | }
118 | }
119 | @end
120 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackNormalFooter.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshBackNormalFooter.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshBackStateFooter.h"
10 |
11 | @interface MJRefreshBackNormalFooter : MJRefreshBackStateFooter
12 | @property (weak, nonatomic, readonly) UIImageView *arrowView;
13 | /** 菊花的样式 */
14 | @property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle;
15 | @end
16 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackNormalFooter.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshBackNormalFooter.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshBackNormalFooter.h"
10 |
11 | @interface MJRefreshBackNormalFooter()
12 | {
13 | __unsafe_unretained UIImageView *_arrowView;
14 | }
15 | @property (weak, nonatomic) UIActivityIndicatorView *loadingView;
16 | @end
17 |
18 | @implementation MJRefreshBackNormalFooter
19 | #pragma mark - 懒加载子控件
20 | - (UIImageView *)arrowView
21 | {
22 | if (!_arrowView) {
23 | UIImage *image = [UIImage imageNamed:MJRefreshSrcName(@"arrow.png")] ?: [UIImage imageNamed:MJRefreshFrameworkSrcName(@"arrow.png")];
24 | UIImageView *arrowView = [[UIImageView alloc] initWithImage:image];
25 | [self addSubview:_arrowView = arrowView];
26 | }
27 | return _arrowView;
28 | }
29 |
30 |
31 | - (UIActivityIndicatorView *)loadingView
32 | {
33 | if (!_loadingView) {
34 | UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:self.activityIndicatorViewStyle];
35 | loadingView.hidesWhenStopped = YES;
36 | [self addSubview:_loadingView = loadingView];
37 | }
38 | return _loadingView;
39 | }
40 |
41 | - (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
42 | {
43 | _activityIndicatorViewStyle = activityIndicatorViewStyle;
44 |
45 | self.loadingView = nil;
46 | [self setNeedsLayout];
47 | }
48 | #pragma makr - 重写父类的方法
49 | - (void)prepare
50 | {
51 | [super prepare];
52 |
53 | self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
54 | }
55 |
56 | - (void)placeSubviews
57 | {
58 | [super placeSubviews];
59 |
60 | // 箭头的中心点
61 | CGFloat arrowCenterX = self.mj_w * 0.5;
62 | if (!self.stateLabel.hidden) {
63 | arrowCenterX -= 100;
64 | }
65 | CGFloat arrowCenterY = self.mj_h * 0.5;
66 | CGPoint arrowCenter = CGPointMake(arrowCenterX, arrowCenterY);
67 |
68 | // 箭头
69 | if (self.arrowView.constraints.count == 0) {
70 | self.arrowView.mj_size = self.arrowView.image.size;
71 | self.arrowView.center = arrowCenter;
72 | }
73 |
74 | // 圈圈
75 | if (self.loadingView.constraints.count == 0) {
76 | self.loadingView.center = arrowCenter;
77 | }
78 | }
79 |
80 | - (void)setState:(MJRefreshState)state
81 | {
82 | MJRefreshCheckState
83 |
84 | // 根据状态做事情
85 | if (state == MJRefreshStateIdle) {
86 | if (oldState == MJRefreshStateRefreshing) {
87 | self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI);
88 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
89 | self.loadingView.alpha = 0.0;
90 | } completion:^(BOOL finished) {
91 | self.loadingView.alpha = 1.0;
92 | [self.loadingView stopAnimating];
93 |
94 | self.arrowView.hidden = NO;
95 | }];
96 | } else {
97 | self.arrowView.hidden = NO;
98 | [self.loadingView stopAnimating];
99 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
100 | self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI);
101 | }];
102 | }
103 | } else if (state == MJRefreshStatePulling) {
104 | self.arrowView.hidden = NO;
105 | [self.loadingView stopAnimating];
106 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
107 | self.arrowView.transform = CGAffineTransformIdentity;
108 | }];
109 | } else if (state == MJRefreshStateRefreshing) {
110 | self.arrowView.hidden = YES;
111 | [self.loadingView startAnimating];
112 | } else if (state == MJRefreshStateNoMoreData) {
113 | self.arrowView.hidden = YES;
114 | [self.loadingView stopAnimating];
115 | }
116 | }
117 |
118 | @end
119 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackStateFooter.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshBackStateFooter.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/6/13.
6 | // Copyright © 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshBackFooter.h"
10 |
11 | @interface MJRefreshBackStateFooter : MJRefreshBackFooter
12 | /** 显示刷新状态的label */
13 | @property (weak, nonatomic, readonly) UILabel *stateLabel;
14 | /** 设置state状态下的文字 */
15 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state;
16 |
17 | /** 获取state状态下的title */
18 | - (NSString *)titleForState:(MJRefreshState)state;
19 | @end
20 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Footer/Back/MJRefreshBackStateFooter.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshBackStateFooter.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/6/13.
6 | // Copyright © 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshBackStateFooter.h"
10 |
11 | @interface MJRefreshBackStateFooter()
12 | {
13 | /** 显示刷新状态的label */
14 | __unsafe_unretained UILabel *_stateLabel;
15 | }
16 | /** 所有状态对应的文字 */
17 | @property (strong, nonatomic) NSMutableDictionary *stateTitles;
18 | @end
19 |
20 | @implementation MJRefreshBackStateFooter
21 | #pragma mark - 懒加载
22 | - (NSMutableDictionary *)stateTitles
23 | {
24 | if (!_stateTitles) {
25 | self.stateTitles = [NSMutableDictionary dictionary];
26 | }
27 | return _stateTitles;
28 | }
29 |
30 | - (UILabel *)stateLabel
31 | {
32 | if (!_stateLabel) {
33 | [self addSubview:_stateLabel = [UILabel label]];
34 | }
35 | return _stateLabel;
36 | }
37 |
38 | #pragma mark - 公共方法
39 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state
40 | {
41 | if (title == nil) return;
42 | self.stateTitles[@(state)] = title;
43 | self.stateLabel.text = self.stateTitles[@(self.state)];
44 | }
45 |
46 | - (NSString *)titleForState:(MJRefreshState)state {
47 | return self.stateTitles[@(state)];
48 | }
49 |
50 | #pragma mark - 重写父类的方法
51 | - (void)prepare
52 | {
53 | [super prepare];
54 |
55 | // 初始化文字
56 | [self setTitle:MJRefreshBackFooterIdleText forState:MJRefreshStateIdle];
57 | [self setTitle:MJRefreshBackFooterPullingText forState:MJRefreshStatePulling];
58 | [self setTitle:MJRefreshBackFooterRefreshingText forState:MJRefreshStateRefreshing];
59 | [self setTitle:MJRefreshBackFooterNoMoreDataText forState:MJRefreshStateNoMoreData];
60 | }
61 |
62 | - (void)placeSubviews
63 | {
64 | [super placeSubviews];
65 |
66 | if (self.stateLabel.constraints.count) return;
67 |
68 | // 状态标签
69 | self.stateLabel.frame = self.bounds;
70 | }
71 |
72 | - (void)setState:(MJRefreshState)state
73 | {
74 | MJRefreshCheckState
75 |
76 | // 设置状态文字
77 | self.stateLabel.text = self.stateTitles[@(state)];
78 | }
79 | @end
80 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshGifHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshGifHeader.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshStateHeader.h"
10 |
11 | @interface MJRefreshGifHeader : MJRefreshStateHeader
12 | @property (weak, nonatomic, readonly) UIImageView *gifView;
13 |
14 | /** 设置state状态下的动画图片images 动画持续时间duration*/
15 | - (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state;
16 | - (void)setImages:(NSArray *)images forState:(MJRefreshState)state;
17 | @end
18 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshGifHeader.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshGifHeader.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshGifHeader.h"
10 |
11 | @interface MJRefreshGifHeader()
12 | {
13 | __unsafe_unretained UIImageView *_gifView;
14 | }
15 | /** 所有状态对应的动画图片 */
16 | @property (strong, nonatomic) NSMutableDictionary *stateImages;
17 | /** 所有状态对应的动画时间 */
18 | @property (strong, nonatomic) NSMutableDictionary *stateDurations;
19 | @end
20 |
21 | @implementation MJRefreshGifHeader
22 | #pragma mark - 懒加载
23 | - (UIImageView *)gifView
24 | {
25 | if (!_gifView) {
26 | UIImageView *gifView = [[UIImageView alloc] init];
27 | [self addSubview:_gifView = gifView];
28 | }
29 | return _gifView;
30 | }
31 |
32 | - (NSMutableDictionary *)stateImages
33 | {
34 | if (!_stateImages) {
35 | self.stateImages = [NSMutableDictionary dictionary];
36 | }
37 | return _stateImages;
38 | }
39 |
40 | - (NSMutableDictionary *)stateDurations
41 | {
42 | if (!_stateDurations) {
43 | self.stateDurations = [NSMutableDictionary dictionary];
44 | }
45 | return _stateDurations;
46 | }
47 |
48 | #pragma mark - 公共方法
49 | - (void)setImages:(NSArray *)images duration:(NSTimeInterval)duration forState:(MJRefreshState)state
50 | {
51 | if (images == nil) return;
52 |
53 | self.stateImages[@(state)] = images;
54 | self.stateDurations[@(state)] = @(duration);
55 |
56 | /* 根据图片设置控件的高度 */
57 | UIImage *image = [images firstObject];
58 | if (image.size.height > self.mj_h) {
59 | self.mj_h = image.size.height;
60 | }
61 | }
62 |
63 | - (void)setImages:(NSArray *)images forState:(MJRefreshState)state
64 | {
65 | [self setImages:images duration:images.count * 0.1 forState:state];
66 | }
67 |
68 | #pragma mark - 实现父类的方法
69 | - (void)setPullingPercent:(CGFloat)pullingPercent
70 | {
71 | [super setPullingPercent:pullingPercent];
72 | NSArray *images = self.stateImages[@(MJRefreshStateIdle)];
73 | if (self.state != MJRefreshStateIdle || images.count == 0) return;
74 | // 停止动画
75 | [self.gifView stopAnimating];
76 | // 设置当前需要显示的图片
77 | NSUInteger index = images.count * pullingPercent;
78 | if (index >= images.count) index = images.count - 1;
79 | self.gifView.image = images[index];
80 | }
81 |
82 | - (void)placeSubviews
83 | {
84 | [super placeSubviews];
85 |
86 | if (self.gifView.constraints.count) return;
87 |
88 | self.gifView.frame = self.bounds;
89 | if (self.stateLabel.hidden && self.lastUpdatedTimeLabel.hidden) {
90 | self.gifView.contentMode = UIViewContentModeCenter;
91 | } else {
92 | self.gifView.contentMode = UIViewContentModeRight;
93 | self.gifView.mj_w = self.mj_w * 0.5 - 90;
94 | }
95 | }
96 |
97 | - (void)setState:(MJRefreshState)state
98 | {
99 | MJRefreshCheckState
100 |
101 | // 根据状态做事情
102 | if (state == MJRefreshStatePulling || state == MJRefreshStateRefreshing) {
103 | NSArray *images = self.stateImages[@(state)];
104 | if (images.count == 0) return;
105 |
106 | [self.gifView stopAnimating];
107 | if (images.count == 1) { // 单张图片
108 | self.gifView.image = [images lastObject];
109 | } else { // 多张图片
110 | self.gifView.animationImages = images;
111 | self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue];
112 | [self.gifView startAnimating];
113 | }
114 | } else if (state == MJRefreshStateIdle) {
115 | [self.gifView stopAnimating];
116 | }
117 | }
118 | @end
119 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshNormalHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshNormalHeader.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshStateHeader.h"
10 |
11 | @interface MJRefreshNormalHeader : MJRefreshStateHeader
12 | @property (weak, nonatomic, readonly) UIImageView *arrowView;
13 | /** 菊花的样式 */
14 | @property (assign, nonatomic) UIActivityIndicatorViewStyle activityIndicatorViewStyle;
15 | @end
16 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshNormalHeader.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshNormalHeader.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshNormalHeader.h"
10 |
11 | @interface MJRefreshNormalHeader()
12 | {
13 | __unsafe_unretained UIImageView *_arrowView;
14 | }
15 | @property (weak, nonatomic) UIActivityIndicatorView *loadingView;
16 | @end
17 |
18 | @implementation MJRefreshNormalHeader
19 | #pragma mark - 懒加载子控件
20 | - (UIImageView *)arrowView
21 | {
22 | if (!_arrowView) {
23 | UIImage *image = [UIImage imageNamed:MJRefreshSrcName(@"arrow.png")] ?: [UIImage imageNamed:MJRefreshFrameworkSrcName(@"arrow.png")];
24 | UIImageView *arrowView = [[UIImageView alloc] initWithImage:image];
25 | [self addSubview:_arrowView = arrowView];
26 | }
27 | return _arrowView;
28 | }
29 |
30 | - (UIActivityIndicatorView *)loadingView
31 | {
32 | if (!_loadingView) {
33 | UIActivityIndicatorView *loadingView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:self.activityIndicatorViewStyle];
34 | loadingView.hidesWhenStopped = YES;
35 | [self addSubview:_loadingView = loadingView];
36 | }
37 | return _loadingView;
38 | }
39 |
40 | #pragma mark - 公共方法
41 | - (void)setActivityIndicatorViewStyle:(UIActivityIndicatorViewStyle)activityIndicatorViewStyle
42 | {
43 | _activityIndicatorViewStyle = activityIndicatorViewStyle;
44 |
45 | self.loadingView = nil;
46 | [self setNeedsLayout];
47 | }
48 |
49 | #pragma makr - 重写父类的方法
50 | - (void)prepare
51 | {
52 | [super prepare];
53 |
54 | self.activityIndicatorViewStyle = UIActivityIndicatorViewStyleGray;
55 | }
56 |
57 | - (void)placeSubviews
58 | {
59 | [super placeSubviews];
60 |
61 | // 箭头的中心点
62 | CGFloat arrowCenterX = self.mj_w * 0.5;
63 | if (!self.stateLabel.hidden) {
64 | arrowCenterX -= 100;
65 | }
66 | CGFloat arrowCenterY = self.mj_h * 0.5;
67 | CGPoint arrowCenter = CGPointMake(arrowCenterX, arrowCenterY);
68 |
69 | // 箭头
70 | if (self.arrowView.constraints.count == 0) {
71 | self.arrowView.mj_size = self.arrowView.image.size;
72 | self.arrowView.center = arrowCenter;
73 | }
74 |
75 | // 圈圈
76 | if (self.loadingView.constraints.count == 0) {
77 | self.loadingView.center = arrowCenter;
78 | }
79 | }
80 |
81 | - (void)setState:(MJRefreshState)state
82 | {
83 | MJRefreshCheckState
84 |
85 | // 根据状态做事情
86 | if (state == MJRefreshStateIdle) {
87 | if (oldState == MJRefreshStateRefreshing) {
88 | self.arrowView.transform = CGAffineTransformIdentity;
89 |
90 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{
91 | self.loadingView.alpha = 0.0;
92 | } completion:^(BOOL finished) {
93 | // 如果执行完动画发现不是idle状态,就直接返回,进入其他状态
94 | if (self.state != MJRefreshStateIdle) return;
95 |
96 | self.loadingView.alpha = 1.0;
97 | [self.loadingView stopAnimating];
98 | self.arrowView.hidden = NO;
99 | }];
100 | } else {
101 | [self.loadingView stopAnimating];
102 | self.arrowView.hidden = NO;
103 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
104 | self.arrowView.transform = CGAffineTransformIdentity;
105 | }];
106 | }
107 | } else if (state == MJRefreshStatePulling) {
108 | [self.loadingView stopAnimating];
109 | self.arrowView.hidden = NO;
110 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{
111 | self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI);
112 | }];
113 | } else if (state == MJRefreshStateRefreshing) {
114 | self.loadingView.alpha = 1.0; // 防止refreshing -> idle的动画完毕动作没有被执行
115 | [self.loadingView startAnimating];
116 | self.arrowView.hidden = YES;
117 | }
118 | }
119 | @end
120 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshStateHeader.h:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshStateHeader.h
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshHeader.h"
10 |
11 | @interface MJRefreshStateHeader : MJRefreshHeader
12 | #pragma mark - 刷新时间相关
13 | /** 利用这个block来决定显示的更新时间文字 */
14 | @property (copy, nonatomic) NSString *(^lastUpdatedTimeText)(NSDate *lastUpdatedTime);
15 | /** 显示上一次刷新时间的label */
16 | @property (weak, nonatomic, readonly) UILabel *lastUpdatedTimeLabel;
17 |
18 | #pragma mark - 状态相关
19 | /** 显示刷新状态的label */
20 | @property (weak, nonatomic, readonly) UILabel *stateLabel;
21 | /** 设置state状态下的文字 */
22 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state;
23 | @end
24 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/Custom/Header/MJRefreshStateHeader.m:
--------------------------------------------------------------------------------
1 | //
2 | // MJRefreshStateHeader.m
3 | // MJRefreshExample
4 | //
5 | // Created by MJ Lee on 15/4/24.
6 | // Copyright (c) 2015年 小码哥. All rights reserved.
7 | //
8 |
9 | #import "MJRefreshStateHeader.h"
10 |
11 | @interface MJRefreshStateHeader()
12 | {
13 | /** 显示上一次刷新时间的label */
14 | __unsafe_unretained UILabel *_lastUpdatedTimeLabel;
15 | /** 显示刷新状态的label */
16 | __unsafe_unretained UILabel *_stateLabel;
17 | }
18 | /** 所有状态对应的文字 */
19 | @property (strong, nonatomic) NSMutableDictionary *stateTitles;
20 | @end
21 |
22 | @implementation MJRefreshStateHeader
23 | #pragma mark - 懒加载
24 | - (NSMutableDictionary *)stateTitles
25 | {
26 | if (!_stateTitles) {
27 | self.stateTitles = [NSMutableDictionary dictionary];
28 | }
29 | return _stateTitles;
30 | }
31 |
32 | - (UILabel *)stateLabel
33 | {
34 | if (!_stateLabel) {
35 | [self addSubview:_stateLabel = [UILabel label]];
36 | }
37 | return _stateLabel;
38 | }
39 |
40 | - (UILabel *)lastUpdatedTimeLabel
41 | {
42 | if (!_lastUpdatedTimeLabel) {
43 | [self addSubview:_lastUpdatedTimeLabel = [UILabel label]];
44 | }
45 | return _lastUpdatedTimeLabel;
46 | }
47 |
48 | #pragma mark - 公共方法
49 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state
50 | {
51 | if (title == nil) return;
52 | self.stateTitles[@(state)] = title;
53 | self.stateLabel.text = self.stateTitles[@(self.state)];
54 | }
55 |
56 | #pragma mark - 日历获取在9.x之后的系统使用currentCalendar会出异常。在8.0之后使用系统新API。
57 | - (NSCalendar *)currentCalendar {
58 | if ([NSCalendar respondsToSelector:@selector(calendarWithIdentifier:)]) {
59 | return [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian];
60 | }
61 | return [NSCalendar currentCalendar];
62 | }
63 |
64 | #pragma mark key的处理
65 | - (void)setLastUpdatedTimeKey:(NSString *)lastUpdatedTimeKey
66 | {
67 | [super setLastUpdatedTimeKey:lastUpdatedTimeKey];
68 |
69 | // 如果label隐藏了,就不用再处理
70 | if (self.lastUpdatedTimeLabel.hidden) return;
71 |
72 | NSDate *lastUpdatedTime = [[NSUserDefaults standardUserDefaults] objectForKey:lastUpdatedTimeKey];
73 |
74 | // 如果有block
75 | if (self.lastUpdatedTimeText) {
76 | self.lastUpdatedTimeLabel.text = self.lastUpdatedTimeText(lastUpdatedTime);
77 | return;
78 | }
79 |
80 | if (lastUpdatedTime) {
81 | // 1.获得年月日
82 | NSCalendar *calendar = [self currentCalendar];
83 | NSUInteger unitFlags = NSCalendarUnitYear| NSCalendarUnitMonth | NSCalendarUnitDay |NSCalendarUnitHour |NSCalendarUnitMinute;
84 | NSDateComponents *cmp1 = [calendar components:unitFlags fromDate:lastUpdatedTime];
85 | NSDateComponents *cmp2 = [calendar components:unitFlags fromDate:[NSDate date]];
86 |
87 | // 2.格式化日期
88 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
89 | if ([cmp1 day] == [cmp2 day]) { // 今天
90 | formatter.dateFormat = @"今天 HH:mm";
91 | } else if ([cmp1 year] == [cmp2 year]) { // 今年
92 | formatter.dateFormat = @"MM-dd HH:mm";
93 | } else {
94 | formatter.dateFormat = @"yyyy-MM-dd HH:mm";
95 | }
96 | NSString *time = [formatter stringFromDate:lastUpdatedTime];
97 |
98 | // 3.显示日期
99 | self.lastUpdatedTimeLabel.text = [NSString stringWithFormat:@"最后更新:%@", time];
100 | } else {
101 | self.lastUpdatedTimeLabel.text = @"最后更新:无记录";
102 | }
103 | }
104 |
105 | #pragma mark - 覆盖父类的方法
106 | - (void)prepare
107 | {
108 | [super prepare];
109 |
110 | // 初始化文字
111 | [self setTitle:MJRefreshHeaderIdleText forState:MJRefreshStateIdle];
112 | [self setTitle:MJRefreshHeaderPullingText forState:MJRefreshStatePulling];
113 | [self setTitle:MJRefreshHeaderRefreshingText forState:MJRefreshStateRefreshing];
114 | }
115 |
116 | - (void)placeSubviews
117 | {
118 | [super placeSubviews];
119 |
120 | if (self.stateLabel.hidden) return;
121 |
122 | BOOL noConstrainsOnStatusLabel = self.stateLabel.constraints.count == 0;
123 |
124 | if (self.lastUpdatedTimeLabel.hidden) {
125 | // 状态
126 | if (noConstrainsOnStatusLabel) self.stateLabel.frame = self.bounds;
127 | } else {
128 | CGFloat stateLabelH = self.mj_h * 0.5;
129 | // 状态
130 | if (noConstrainsOnStatusLabel) {
131 | self.stateLabel.mj_x = 0;
132 | self.stateLabel.mj_y = 0;
133 | self.stateLabel.mj_w = self.mj_w;
134 | self.stateLabel.mj_h = stateLabelH;
135 | }
136 |
137 | // 更新时间
138 | if (self.lastUpdatedTimeLabel.constraints.count == 0) {
139 | self.lastUpdatedTimeLabel.mj_x = 0;
140 | self.lastUpdatedTimeLabel.mj_y = stateLabelH;
141 | self.lastUpdatedTimeLabel.mj_w = self.mj_w;
142 | self.lastUpdatedTimeLabel.mj_h = self.mj_h - self.lastUpdatedTimeLabel.mj_y;
143 | }
144 | }
145 | }
146 |
147 | - (void)setState:(MJRefreshState)state
148 | {
149 | MJRefreshCheckState
150 |
151 | // 设置状态文字
152 | self.stateLabel.text = self.stateTitles[@(state)];
153 |
154 | // 重新设置key(重新显示时间)
155 | self.lastUpdatedTimeKey = self.lastUpdatedTimeKey;
156 | }
157 | @end
158 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/arrow@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/huangxuan518/HXTechnologyBlogCrawler/0a2b6b0224ac0117877ef724c8fca5ec515d0bff/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/arrow@2x.png
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/MJRefresh.h:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 |
4 | #import "UIScrollView+MJRefresh.h"
5 | #import "UIScrollView+MJExtension.h"
6 | #import "UIView+MJExtension.h"
7 |
8 | #import "MJRefreshNormalHeader.h"
9 | #import "MJRefreshGifHeader.h"
10 |
11 | #import "MJRefreshBackNormalFooter.h"
12 | #import "MJRefreshBackGifFooter.h"
13 | #import "MJRefreshAutoNormalFooter.h"
14 | #import "MJRefreshAutoGifFooter.h"
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/MJRefreshConst.h:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | #import
4 | #import
5 |
6 | // 弱引用
7 | #define MJWeakSelf __weak typeof(self) weakSelf = self;
8 |
9 | // 日志输出
10 | #ifdef DEBUG
11 | #define MJRefreshLog(...) NSLog(__VA_ARGS__)
12 | #else
13 | #define MJRefreshLog(...)
14 | #endif
15 |
16 | // 过期提醒
17 | #define MJRefreshDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead)
18 |
19 | // 运行时objc_msgSend
20 | #define MJRefreshMsgSend(...) ((void (*)(void *, SEL, UIView *))objc_msgSend)(__VA_ARGS__)
21 | #define MJRefreshMsgTarget(target) (__bridge void *)(target)
22 |
23 | // RGB颜色
24 | #define MJRefreshColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0]
25 |
26 | // 文字颜色
27 | #define MJRefreshLabelTextColor MJRefreshColor(90, 90, 90)
28 |
29 | // 字体大小
30 | #define MJRefreshLabelFont [UIFont boldSystemFontOfSize:14]
31 |
32 | // 图片路径
33 | #define MJRefreshSrcName(file) [@"MJRefresh.bundle" stringByAppendingPathComponent:file]
34 | #define MJRefreshFrameworkSrcName(file) [@"Frameworks/MJRefresh.framework/MJRefresh.bundle" stringByAppendingPathComponent:file]
35 |
36 | // 常量
37 | UIKIT_EXTERN const CGFloat MJRefreshHeaderHeight;
38 | UIKIT_EXTERN const CGFloat MJRefreshFooterHeight;
39 | UIKIT_EXTERN const CGFloat MJRefreshFastAnimationDuration;
40 | UIKIT_EXTERN const CGFloat MJRefreshSlowAnimationDuration;
41 |
42 | UIKIT_EXTERN NSString *const MJRefreshKeyPathContentOffset;
43 | UIKIT_EXTERN NSString *const MJRefreshKeyPathContentSize;
44 | UIKIT_EXTERN NSString *const MJRefreshKeyPathContentInset;
45 | UIKIT_EXTERN NSString *const MJRefreshKeyPathPanState;
46 |
47 | UIKIT_EXTERN NSString *const MJRefreshHeaderLastUpdatedTimeKey;
48 |
49 | UIKIT_EXTERN NSString *const MJRefreshHeaderIdleText;
50 | UIKIT_EXTERN NSString *const MJRefreshHeaderPullingText;
51 | UIKIT_EXTERN NSString *const MJRefreshHeaderRefreshingText;
52 |
53 | UIKIT_EXTERN NSString *const MJRefreshAutoFooterIdleText;
54 | UIKIT_EXTERN NSString *const MJRefreshAutoFooterRefreshingText;
55 | UIKIT_EXTERN NSString *const MJRefreshAutoFooterNoMoreDataText;
56 |
57 | UIKIT_EXTERN NSString *const MJRefreshBackFooterIdleText;
58 | UIKIT_EXTERN NSString *const MJRefreshBackFooterPullingText;
59 | UIKIT_EXTERN NSString *const MJRefreshBackFooterRefreshingText;
60 | UIKIT_EXTERN NSString *const MJRefreshBackFooterNoMoreDataText;
61 |
62 | // 状态检查
63 | #define MJRefreshCheckState \
64 | MJRefreshState oldState = self.state; \
65 | if (state == oldState) return; \
66 | [super setState:state];
67 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/MJRefreshConst.m:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | #import
4 |
5 | const CGFloat MJRefreshHeaderHeight = 54.0;
6 | const CGFloat MJRefreshFooterHeight = 44.0;
7 | const CGFloat MJRefreshFastAnimationDuration = 0.25;
8 | const CGFloat MJRefreshSlowAnimationDuration = 0.4;
9 |
10 | NSString *const MJRefreshKeyPathContentOffset = @"contentOffset";
11 | NSString *const MJRefreshKeyPathContentInset = @"contentInset";
12 | NSString *const MJRefreshKeyPathContentSize = @"contentSize";
13 | NSString *const MJRefreshKeyPathPanState = @"state";
14 |
15 | NSString *const MJRefreshHeaderLastUpdatedTimeKey = @"MJRefreshHeaderLastUpdatedTimeKey";
16 |
17 | NSString *const MJRefreshHeaderIdleText = @"下拉可以刷新";
18 | NSString *const MJRefreshHeaderPullingText = @"松开立即刷新";
19 | NSString *const MJRefreshHeaderRefreshingText = @"正在刷新数据中...";
20 |
21 | NSString *const MJRefreshAutoFooterIdleText = @"点击或上拉加载更多";
22 | NSString *const MJRefreshAutoFooterRefreshingText = @"正在加载更多的数据...";
23 | NSString *const MJRefreshAutoFooterNoMoreDataText = @"已经全部加载完毕";
24 |
25 | NSString *const MJRefreshBackFooterIdleText = @"上拉可以加载更多";
26 | NSString *const MJRefreshBackFooterPullingText = @"松开立即加载更多";
27 | NSString *const MJRefreshBackFooterRefreshingText = @"正在加载更多的数据...";
28 | NSString *const MJRefreshBackFooterNoMoreDataText = @"已经全部加载完毕";
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/UIScrollView+MJExtension.h:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // UIScrollView+Extension.h
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 14-5-28.
7 | // Copyright (c) 2014年 小码哥. All rights reserved.
8 | //
9 |
10 | #import
11 |
12 | @interface UIScrollView (MJExtension)
13 | @property (assign, nonatomic) CGFloat mj_insetT;
14 | @property (assign, nonatomic) CGFloat mj_insetB;
15 | @property (assign, nonatomic) CGFloat mj_insetL;
16 | @property (assign, nonatomic) CGFloat mj_insetR;
17 |
18 | @property (assign, nonatomic) CGFloat mj_offsetX;
19 | @property (assign, nonatomic) CGFloat mj_offsetY;
20 |
21 | @property (assign, nonatomic) CGFloat mj_contentW;
22 | @property (assign, nonatomic) CGFloat mj_contentH;
23 | @end
24 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/UIScrollView+MJExtension.m:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // UIScrollView+Extension.m
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 14-5-28.
7 | // Copyright (c) 2014年 小码哥. All rights reserved.
8 | //
9 |
10 | #import "UIScrollView+MJExtension.h"
11 | #import
12 |
13 | @implementation UIScrollView (MJExtension)
14 |
15 | - (void)setMj_insetT:(CGFloat)mj_insetT
16 | {
17 | UIEdgeInsets inset = self.contentInset;
18 | inset.top = mj_insetT;
19 | self.contentInset = inset;
20 | }
21 |
22 | - (CGFloat)mj_insetT
23 | {
24 | return self.contentInset.top;
25 | }
26 |
27 | - (void)setMj_insetB:(CGFloat)mj_insetB
28 | {
29 | UIEdgeInsets inset = self.contentInset;
30 | inset.bottom = mj_insetB;
31 | self.contentInset = inset;
32 | }
33 |
34 | - (CGFloat)mj_insetB
35 | {
36 | return self.contentInset.bottom;
37 | }
38 |
39 | - (void)setMj_insetL:(CGFloat)mj_insetL
40 | {
41 | UIEdgeInsets inset = self.contentInset;
42 | inset.left = mj_insetL;
43 | self.contentInset = inset;
44 | }
45 |
46 | - (CGFloat)mj_insetL
47 | {
48 | return self.contentInset.left;
49 | }
50 |
51 | - (void)setMj_insetR:(CGFloat)mj_insetR
52 | {
53 | UIEdgeInsets inset = self.contentInset;
54 | inset.right = mj_insetR;
55 | self.contentInset = inset;
56 | }
57 |
58 | - (CGFloat)mj_insetR
59 | {
60 | return self.contentInset.right;
61 | }
62 |
63 | - (void)setMj_offsetX:(CGFloat)mj_offsetX
64 | {
65 | CGPoint offset = self.contentOffset;
66 | offset.x = mj_offsetX;
67 | self.contentOffset = offset;
68 | }
69 |
70 | - (CGFloat)mj_offsetX
71 | {
72 | return self.contentOffset.x;
73 | }
74 |
75 | - (void)setMj_offsetY:(CGFloat)mj_offsetY
76 | {
77 | CGPoint offset = self.contentOffset;
78 | offset.y = mj_offsetY;
79 | self.contentOffset = offset;
80 | }
81 |
82 | - (CGFloat)mj_offsetY
83 | {
84 | return self.contentOffset.y;
85 | }
86 |
87 | - (void)setMj_contentW:(CGFloat)mj_contentW
88 | {
89 | CGSize size = self.contentSize;
90 | size.width = mj_contentW;
91 | self.contentSize = size;
92 | }
93 |
94 | - (CGFloat)mj_contentW
95 | {
96 | return self.contentSize.width;
97 | }
98 |
99 | - (void)setMj_contentH:(CGFloat)mj_contentH
100 | {
101 | CGSize size = self.contentSize;
102 | size.height = mj_contentH;
103 | self.contentSize = size;
104 | }
105 |
106 | - (CGFloat)mj_contentH
107 | {
108 | return self.contentSize.height;
109 | }
110 | @end
111 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/UIScrollView+MJRefresh.h:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // UIScrollView+MJRefresh.h
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 15/3/4.
7 | // Copyright (c) 2015年 小码哥. All rights reserved.
8 | // 给ScrollView增加下拉刷新、上拉刷新的功能
9 |
10 | #import
11 | #import "MJRefreshConst.h"
12 |
13 | @class MJRefreshHeader, MJRefreshFooter;
14 |
15 | @interface UIScrollView (MJRefresh)
16 | /** 下拉刷新控件 */
17 | @property (strong, nonatomic) MJRefreshHeader *mj_header;
18 | @property (strong, nonatomic) MJRefreshHeader *header MJRefreshDeprecated("使用mj_header");
19 | /** 上拉刷新控件 */
20 | @property (strong, nonatomic) MJRefreshFooter *mj_footer;
21 | @property (strong, nonatomic) MJRefreshFooter *footer MJRefreshDeprecated("使用mj_footer");
22 |
23 | #pragma mark - other
24 | - (NSInteger)mj_totalDataCount;
25 | @property (copy, nonatomic) void (^mj_reloadDataBlock)(NSInteger totalDataCount);
26 | @end
27 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/UIScrollView+MJRefresh.m:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // UIScrollView+MJRefresh.m
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 15/3/4.
7 | // Copyright (c) 2015年 小码哥. All rights reserved.
8 | //
9 |
10 | #import "UIScrollView+MJRefresh.h"
11 | #import "MJRefreshHeader.h"
12 | #import "MJRefreshFooter.h"
13 | #import
14 |
15 | @implementation NSObject (MJRefresh)
16 |
17 | + (void)exchangeInstanceMethod1:(SEL)method1 method2:(SEL)method2
18 | {
19 | method_exchangeImplementations(class_getInstanceMethod(self, method1), class_getInstanceMethod(self, method2));
20 | }
21 |
22 | + (void)exchangeClassMethod1:(SEL)method1 method2:(SEL)method2
23 | {
24 | method_exchangeImplementations(class_getClassMethod(self, method1), class_getClassMethod(self, method2));
25 | }
26 |
27 | @end
28 |
29 | @implementation UIScrollView (MJRefresh)
30 |
31 | #pragma mark - header
32 | static const char MJRefreshHeaderKey = '\0';
33 | - (void)setMj_header:(MJRefreshHeader *)mj_header
34 | {
35 | if (mj_header != self.mj_header) {
36 | // 删除旧的,添加新的
37 | [self.mj_header removeFromSuperview];
38 | [self insertSubview:mj_header atIndex:0];
39 |
40 | // 存储新的
41 | [self willChangeValueForKey:@"mj_header"]; // KVO
42 | objc_setAssociatedObject(self, &MJRefreshHeaderKey,
43 | mj_header, OBJC_ASSOCIATION_ASSIGN);
44 | [self didChangeValueForKey:@"mj_header"]; // KVO
45 | }
46 | }
47 |
48 | - (MJRefreshHeader *)mj_header
49 | {
50 | return objc_getAssociatedObject(self, &MJRefreshHeaderKey);
51 | }
52 |
53 | #pragma mark - footer
54 | static const char MJRefreshFooterKey = '\0';
55 | - (void)setMj_footer:(MJRefreshFooter *)mj_footer
56 | {
57 | if (mj_footer != self.mj_footer) {
58 | // 删除旧的,添加新的
59 | [self.mj_footer removeFromSuperview];
60 | [self addSubview:mj_footer];
61 |
62 | // 存储新的
63 | [self willChangeValueForKey:@"mj_footer"]; // KVO
64 | objc_setAssociatedObject(self, &MJRefreshFooterKey,
65 | mj_footer, OBJC_ASSOCIATION_ASSIGN);
66 | [self didChangeValueForKey:@"mj_footer"]; // KVO
67 | }
68 | }
69 |
70 | - (MJRefreshFooter *)mj_footer
71 | {
72 | return objc_getAssociatedObject(self, &MJRefreshFooterKey);
73 | }
74 |
75 | #pragma mark - 过期
76 | - (void)setFooter:(MJRefreshFooter *)footer
77 | {
78 | self.mj_footer = footer;
79 | }
80 |
81 | - (MJRefreshFooter *)footer
82 | {
83 | return self.mj_footer;
84 | }
85 |
86 | - (void)setHeader:(MJRefreshHeader *)header
87 | {
88 | self.mj_header = header;
89 | }
90 |
91 | - (MJRefreshHeader *)header
92 | {
93 | return self.mj_header;
94 | }
95 |
96 | #pragma mark - other
97 | - (NSInteger)mj_totalDataCount
98 | {
99 | NSInteger totalCount = 0;
100 | if ([self isKindOfClass:[UITableView class]]) {
101 | UITableView *tableView = (UITableView *)self;
102 |
103 | for (NSInteger section = 0; section
11 |
12 | @interface UIView (MJExtension)
13 | @property (assign, nonatomic) CGFloat mj_x;
14 | @property (assign, nonatomic) CGFloat mj_y;
15 | @property (assign, nonatomic) CGFloat mj_w;
16 | @property (assign, nonatomic) CGFloat mj_h;
17 | @property (assign, nonatomic) CGSize mj_size;
18 | @property (assign, nonatomic) CGPoint mj_origin;
19 | @end
20 |
--------------------------------------------------------------------------------
/Pods/MJRefresh/MJRefresh/UIView+MJExtension.m:
--------------------------------------------------------------------------------
1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh
2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000
3 | // UIView+Extension.m
4 | // MJRefreshExample
5 | //
6 | // Created by MJ Lee on 14-5-28.
7 | // Copyright (c) 2014年 小码哥. All rights reserved.
8 | //
9 |
10 | #import "UIView+MJExtension.h"
11 |
12 | @implementation UIView (MJExtension)
13 | - (void)setMj_x:(CGFloat)mj_x
14 | {
15 | CGRect frame = self.frame;
16 | frame.origin.x = mj_x;
17 | self.frame = frame;
18 | }
19 |
20 | - (CGFloat)mj_x
21 | {
22 | return self.frame.origin.x;
23 | }
24 |
25 | - (void)setMj_y:(CGFloat)mj_y
26 | {
27 | CGRect frame = self.frame;
28 | frame.origin.y = mj_y;
29 | self.frame = frame;
30 | }
31 |
32 | - (CGFloat)mj_y
33 | {
34 | return self.frame.origin.y;
35 | }
36 |
37 | - (void)setMj_w:(CGFloat)mj_w
38 | {
39 | CGRect frame = self.frame;
40 | frame.size.width = mj_w;
41 | self.frame = frame;
42 | }
43 |
44 | - (CGFloat)mj_w
45 | {
46 | return self.frame.size.width;
47 | }
48 |
49 | - (void)setMj_h:(CGFloat)mj_h
50 | {
51 | CGRect frame = self.frame;
52 | frame.size.height = mj_h;
53 | self.frame = frame;
54 | }
55 |
56 | - (CGFloat)mj_h
57 | {
58 | return self.frame.size.height;
59 | }
60 |
61 | - (void)setMj_size:(CGSize)mj_size
62 | {
63 | CGRect frame = self.frame;
64 | frame.size = mj_size;
65 | self.frame = frame;
66 | }
67 |
68 | - (CGSize)mj_size
69 | {
70 | return self.frame.size;
71 | }
72 |
73 | - (void)setMj_origin:(CGPoint)mj_origin
74 | {
75 | CGRect frame = self.frame;
76 | frame.origin = mj_origin;
77 | self.frame = frame;
78 | }
79 |
80 | - (CGPoint)mj_origin
81 | {
82 | return self.frame.origin;
83 | }
84 | @end
85 |
--------------------------------------------------------------------------------
/Pods/Manifest.lock:
--------------------------------------------------------------------------------
1 | PODS:
2 | - MJRefresh (3.1.0)
3 |
4 | DEPENDENCIES:
5 | - MJRefresh
6 |
7 | SPEC CHECKSUMS:
8 | MJRefresh: 743e6404967d1c2c688472ea3ecfde247d872db4
9 |
10 | PODFILE CHECKSUM: 3e97bbe32e7bf5574669b64ec6a6420fb7521e7f
11 |
12 | COCOAPODS: 1.0.0
13 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/huangxuan518.xcuserdatad/xcschemes/MJRefresh.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
46 |
52 |
53 |
55 |
56 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/huangxuan518.xcuserdatad/xcschemes/Pods-HXTechnologyBlogCrawler.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
45 |
46 |
52 |
53 |
55 |
56 |
59 |
60 |
61 |
--------------------------------------------------------------------------------
/Pods/Pods.xcodeproj/xcuserdata/huangxuan518.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | MJRefresh.xcscheme
8 |
9 | isShown
10 |
11 |
12 | Pods-HXTechnologyBlogCrawler.xcscheme
13 |
14 | isShown
15 |
16 |
17 |
18 | SuppressBuildableAutocreation
19 |
20 | 8F74D9EA91F4C43190670066BAC37D44
21 |
22 | primary
23 |
24 |
25 | CAADC4FED420E6FE6B6A49C46F4FAFC6
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/MJRefresh/MJRefresh-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_MJRefresh : NSObject
3 | @end
4 | @implementation PodsDummy_MJRefresh
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/MJRefresh/MJRefresh-prefix.pch:
--------------------------------------------------------------------------------
1 | #ifdef __OBJC__
2 | #import
3 | #endif
4 |
5 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/MJRefresh/MJRefresh.xcconfig:
--------------------------------------------------------------------------------
1 | CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/MJRefresh
2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
3 | HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Private/MJRefresh" "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/MJRefresh"
4 | PODS_BUILD_DIR = $BUILD_DIR
5 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
6 | PODS_ROOT = ${SRCROOT}
7 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
8 | SKIP_INSTALL = YES
9 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-HXTechnologyBlogCrawler/Pods-HXTechnologyBlogCrawler-acknowledgements.markdown:
--------------------------------------------------------------------------------
1 | # Acknowledgements
2 | This application makes use of the following third party libraries:
3 |
4 | ## MJRefresh
5 |
6 | Copyright (c) 2013-2015 MJRefresh (https://github.com/CoderMJLee/MJRefresh)
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining a copy
9 | of this software and associated documentation files (the "Software"), to deal
10 | in the Software without restriction, including without limitation the rights
11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | copies of the Software, and to permit persons to whom the Software is
13 | furnished to do so, subject to the following conditions:
14 |
15 | The above copyright notice and this permission notice shall be included in
16 | all copies or substantial portions of the Software.
17 |
18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 | THE SOFTWARE.
25 |
26 | Generated by CocoaPods - https://cocoapods.org
27 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-HXTechnologyBlogCrawler/Pods-HXTechnologyBlogCrawler-acknowledgements.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | PreferenceSpecifiers
6 |
7 |
8 | FooterText
9 | This application makes use of the following third party libraries:
10 | Title
11 | Acknowledgements
12 | Type
13 | PSGroupSpecifier
14 |
15 |
16 | FooterText
17 | Copyright (c) 2013-2015 MJRefresh (https://github.com/CoderMJLee/MJRefresh)
18 |
19 | Permission is hereby granted, free of charge, to any person obtaining a copy
20 | of this software and associated documentation files (the "Software"), to deal
21 | in the Software without restriction, including without limitation the rights
22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
23 | copies of the Software, and to permit persons to whom the Software is
24 | furnished to do so, subject to the following conditions:
25 |
26 | The above copyright notice and this permission notice shall be included in
27 | all copies or substantial portions of the Software.
28 |
29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
35 | THE SOFTWARE.
36 |
37 | Title
38 | MJRefresh
39 | Type
40 | PSGroupSpecifier
41 |
42 |
43 | FooterText
44 | Generated by CocoaPods - https://cocoapods.org
45 | Title
46 |
47 | Type
48 | PSGroupSpecifier
49 |
50 |
51 | StringsTable
52 | Acknowledgements
53 | Title
54 | Acknowledgements
55 |
56 |
57 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-HXTechnologyBlogCrawler/Pods-HXTechnologyBlogCrawler-dummy.m:
--------------------------------------------------------------------------------
1 | #import
2 | @interface PodsDummy_Pods_HXTechnologyBlogCrawler : NSObject
3 | @end
4 | @implementation PodsDummy_Pods_HXTechnologyBlogCrawler
5 | @end
6 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-HXTechnologyBlogCrawler/Pods-HXTechnologyBlogCrawler-frameworks.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
5 | mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
6 |
7 | SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
8 |
9 | install_framework()
10 | {
11 | if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
12 | local source="${BUILT_PRODUCTS_DIR}/$1"
13 | elif [ -r "${BUILT_PRODUCTS_DIR}/$(basename "$1")" ]; then
14 | local source="${BUILT_PRODUCTS_DIR}/$(basename "$1")"
15 | elif [ -r "$1" ]; then
16 | local source="$1"
17 | fi
18 |
19 | local destination="${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
20 |
21 | if [ -L "${source}" ]; then
22 | echo "Symlinked..."
23 | source="$(readlink "${source}")"
24 | fi
25 |
26 | # use filter instead of exclude so missing patterns dont' throw errors
27 | echo "rsync -av --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${destination}\""
28 | rsync -av --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${destination}"
29 |
30 | local basename
31 | basename="$(basename -s .framework "$1")"
32 | binary="${destination}/${basename}.framework/${basename}"
33 | if ! [ -r "$binary" ]; then
34 | binary="${destination}/${basename}"
35 | fi
36 |
37 | # Strip invalid architectures so "fat" simulator / device frameworks work on device
38 | if [[ "$(file "$binary")" == *"dynamically linked shared library"* ]]; then
39 | strip_invalid_archs "$binary"
40 | fi
41 |
42 | # Resign the code if required by the build settings to avoid unstable apps
43 | code_sign_if_enabled "${destination}/$(basename "$1")"
44 |
45 | # Embed linked Swift runtime libraries. No longer necessary as of Xcode 7.
46 | if [ "${XCODE_VERSION_MAJOR}" -lt 7 ]; then
47 | local swift_runtime_libs
48 | swift_runtime_libs=$(xcrun otool -LX "$binary" | grep --color=never @rpath/libswift | sed -E s/@rpath\\/\(.+dylib\).*/\\1/g | uniq -u && exit ${PIPESTATUS[0]})
49 | for lib in $swift_runtime_libs; do
50 | echo "rsync -auv \"${SWIFT_STDLIB_PATH}/${lib}\" \"${destination}\""
51 | rsync -auv "${SWIFT_STDLIB_PATH}/${lib}" "${destination}"
52 | code_sign_if_enabled "${destination}/${lib}"
53 | done
54 | fi
55 | }
56 |
57 | # Signs a framework with the provided identity
58 | code_sign_if_enabled() {
59 | if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
60 | # Use the current code_sign_identitiy
61 | echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
62 | echo "/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements \"$1\""
63 | /usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements "$1"
64 | fi
65 | }
66 |
67 | # Strip invalid architectures
68 | strip_invalid_archs() {
69 | binary="$1"
70 | # Get architectures for current file
71 | archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
72 | stripped=""
73 | for arch in $archs; do
74 | if ! [[ "${VALID_ARCHS}" == *"$arch"* ]]; then
75 | # Strip non-valid architectures in-place
76 | lipo -remove "$arch" -output "$binary" "$binary" || exit 1
77 | stripped="$stripped $arch"
78 | fi
79 | done
80 | if [[ "$stripped" ]]; then
81 | echo "Stripped $binary of architectures:$stripped"
82 | fi
83 | }
84 |
85 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-HXTechnologyBlogCrawler/Pods-HXTechnologyBlogCrawler-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 |
4 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
5 |
6 | RESOURCES_TO_COPY=${PODS_ROOT}/resources-to-copy-${TARGETNAME}.txt
7 | > "$RESOURCES_TO_COPY"
8 |
9 | XCASSET_FILES=()
10 |
11 | case "${TARGETED_DEVICE_FAMILY}" in
12 | 1,2)
13 | TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
14 | ;;
15 | 1)
16 | TARGET_DEVICE_ARGS="--target-device iphone"
17 | ;;
18 | 2)
19 | TARGET_DEVICE_ARGS="--target-device ipad"
20 | ;;
21 | *)
22 | TARGET_DEVICE_ARGS="--target-device mac"
23 | ;;
24 | esac
25 |
26 | realpath() {
27 | DIRECTORY="$(cd "${1%/*}" && pwd)"
28 | FILENAME="${1##*/}"
29 | echo "$DIRECTORY/$FILENAME"
30 | }
31 |
32 | install_resource()
33 | {
34 | if [[ "$1" = /* ]] ; then
35 | RESOURCE_PATH="$1"
36 | else
37 | RESOURCE_PATH="${PODS_ROOT}/$1"
38 | fi
39 | if [[ ! -e "$RESOURCE_PATH" ]] ; then
40 | cat << EOM
41 | error: Resource "$RESOURCE_PATH" not found. Run 'pod install' to update the copy resources script.
42 | EOM
43 | exit 1
44 | fi
45 | case $RESOURCE_PATH in
46 | *.storyboard)
47 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc $RESOURCE_PATH --sdk ${SDKROOT} ${TARGET_DEVICE_ARGS}"
48 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .storyboard`.storyboardc" "$RESOURCE_PATH" --sdk "${SDKROOT}" ${TARGET_DEVICE_ARGS}
49 | ;;
50 | *.xib)
51 | echo "ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile ${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib $RESOURCE_PATH --sdk ${SDKROOT}"
52 | ibtool --reference-external-strings-file --errors --warnings --notices --minimum-deployment-target ${!DEPLOYMENT_TARGET_SETTING_NAME} --output-format human-readable-text --compile "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename \"$RESOURCE_PATH\" .xib`.nib" "$RESOURCE_PATH" --sdk "${SDKROOT}"
53 | ;;
54 | *.framework)
55 | echo "mkdir -p ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
56 | mkdir -p "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
57 | echo "rsync -av $RESOURCE_PATH ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
58 | rsync -av "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
59 | ;;
60 | *.xcdatamodel)
61 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH"`.mom\""
62 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodel`.mom"
63 | ;;
64 | *.xcdatamodeld)
65 | echo "xcrun momc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd\""
66 | xcrun momc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcdatamodeld`.momd"
67 | ;;
68 | *.xcmappingmodel)
69 | echo "xcrun mapc \"$RESOURCE_PATH\" \"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm\""
70 | xcrun mapc "$RESOURCE_PATH" "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename "$RESOURCE_PATH" .xcmappingmodel`.cdm"
71 | ;;
72 | *.xcassets)
73 | ABSOLUTE_XCASSET_FILE=$(realpath "$RESOURCE_PATH")
74 | XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
75 | ;;
76 | *)
77 | echo "$RESOURCE_PATH"
78 | echo "$RESOURCE_PATH" >> "$RESOURCES_TO_COPY"
79 | ;;
80 | esac
81 | }
82 | if [[ "$CONFIGURATION" == "Debug" ]]; then
83 | install_resource "MJRefresh/MJRefresh/MJRefresh.bundle"
84 | fi
85 | if [[ "$CONFIGURATION" == "Release" ]]; then
86 | install_resource "MJRefresh/MJRefresh/MJRefresh.bundle"
87 | fi
88 |
89 | mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
90 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
91 | if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
92 | mkdir -p "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
93 | rsync -avr --copy-links --no-relative --exclude '*/.svn/*' --files-from="$RESOURCES_TO_COPY" / "${INSTALL_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
94 | fi
95 | rm -f "$RESOURCES_TO_COPY"
96 |
97 | if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
98 | then
99 | # Find all other xcassets (this unfortunately includes those of path pods and other targets).
100 | OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
101 | while read line; do
102 | if [[ $line != "`realpath $PODS_ROOT`*" ]]; then
103 | XCASSET_FILES+=("$line")
104 | fi
105 | done <<<"$OTHER_XCASSETS"
106 |
107 | printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
108 | fi
109 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-HXTechnologyBlogCrawler/Pods-HXTechnologyBlogCrawler.debug.xcconfig:
--------------------------------------------------------------------------------
1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/MJRefresh"
3 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/MJRefresh"
4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/MJRefresh"
5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"MJRefresh"
6 | PODS_BUILD_DIR = $BUILD_DIR
7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}/Pods
9 |
--------------------------------------------------------------------------------
/Pods/Target Support Files/Pods-HXTechnologyBlogCrawler/Pods-HXTechnologyBlogCrawler.release.xcconfig:
--------------------------------------------------------------------------------
1 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
2 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/MJRefresh"
3 | LIBRARY_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/MJRefresh"
4 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/MJRefresh"
5 | OTHER_LDFLAGS = $(inherited) -ObjC -l"MJRefresh"
6 | PODS_BUILD_DIR = $BUILD_DIR
7 | PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
8 | PODS_ROOT = ${SRCROOT}/Pods
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HXTechnologyBlogCrawler 如果对你有一点点帮助,请给一颗★,你的支持是对我的最大鼓励!
2 | 技术博客搜索爬虫
3 |
4 | # 演示地址
5 | https://appetize.io/app/1511my7qa48yeeacwb2t4ycd2m
6 |
7 | # 预览图
8 | 
9 |
10 |
--------------------------------------------------------------------------------