├── .travis.yml ├── Example ├── Podfile ├── Podfile.lock ├── Pods │ ├── Local Podspecs │ │ └── WMPageController-JQHover.podspec.json │ ├── 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 │ │ │ │ ├── en.lproj │ │ │ │ │ └── Localizable.strings │ │ │ │ ├── zh-Hans.lproj │ │ │ │ │ └── Localizable.strings │ │ │ │ └── zh-Hant.lproj │ │ │ │ │ └── Localizable.strings │ │ │ ├── MJRefresh.h │ │ │ ├── MJRefreshConst.h │ │ │ ├── MJRefreshConst.m │ │ │ ├── NSBundle+MJRefresh.h │ │ │ ├── NSBundle+MJRefresh.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 │ │ │ └── Joker.xcuserdatad │ │ │ └── xcschemes │ │ │ ├── MJRefresh.xcscheme │ │ │ ├── Pods-WMPageController-JQHover_Example.xcscheme │ │ │ ├── Pods-WMPageController-JQHover_Tests.xcscheme │ │ │ ├── WMPageController-JQHover.xcscheme │ │ │ ├── WMPageController.xcscheme │ │ │ └── xcschememanagement.plist │ ├── Target Support Files │ │ ├── MJRefresh │ │ │ ├── Info.plist │ │ │ ├── MJRefresh-dummy.m │ │ │ ├── MJRefresh-prefix.pch │ │ │ ├── MJRefresh-umbrella.h │ │ │ ├── MJRefresh.modulemap │ │ │ └── MJRefresh.xcconfig │ │ ├── Pods-WMPageController-JQHover_Example │ │ │ ├── Info.plist │ │ │ ├── Pods-WMPageController-JQHover_Example-acknowledgements.markdown │ │ │ ├── Pods-WMPageController-JQHover_Example-acknowledgements.plist │ │ │ ├── Pods-WMPageController-JQHover_Example-dummy.m │ │ │ ├── Pods-WMPageController-JQHover_Example-frameworks.sh │ │ │ ├── Pods-WMPageController-JQHover_Example-resources.sh │ │ │ ├── Pods-WMPageController-JQHover_Example-umbrella.h │ │ │ ├── Pods-WMPageController-JQHover_Example.debug.xcconfig │ │ │ ├── Pods-WMPageController-JQHover_Example.modulemap │ │ │ └── Pods-WMPageController-JQHover_Example.release.xcconfig │ │ ├── Pods-WMPageController-JQHover_Tests │ │ │ ├── Info.plist │ │ │ ├── Pods-WMPageController-JQHover_Tests-acknowledgements.markdown │ │ │ ├── Pods-WMPageController-JQHover_Tests-acknowledgements.plist │ │ │ ├── Pods-WMPageController-JQHover_Tests-dummy.m │ │ │ ├── Pods-WMPageController-JQHover_Tests-frameworks.sh │ │ │ ├── Pods-WMPageController-JQHover_Tests-resources.sh │ │ │ ├── Pods-WMPageController-JQHover_Tests-umbrella.h │ │ │ ├── Pods-WMPageController-JQHover_Tests.debug.xcconfig │ │ │ ├── Pods-WMPageController-JQHover_Tests.modulemap │ │ │ └── Pods-WMPageController-JQHover_Tests.release.xcconfig │ │ ├── WMPageController-JQHover │ │ │ ├── Info.plist │ │ │ ├── WMPageController-JQHover-dummy.m │ │ │ ├── WMPageController-JQHover-prefix.pch │ │ │ ├── WMPageController-JQHover-umbrella.h │ │ │ ├── WMPageController-JQHover.modulemap │ │ │ └── WMPageController-JQHover.xcconfig │ │ └── WMPageController │ │ │ ├── Info.plist │ │ │ ├── WMPageController-dummy.m │ │ │ ├── WMPageController-prefix.pch │ │ │ ├── WMPageController-umbrella.h │ │ │ ├── WMPageController.modulemap │ │ │ └── WMPageController.xcconfig │ └── WMPageController │ │ ├── LICENSE │ │ ├── README.md │ │ └── WMPageController │ │ ├── UIViewController+WMPageController.h │ │ ├── UIViewController+WMPageController.m │ │ ├── WMMenuView │ │ ├── WMMenuItem.h │ │ ├── WMMenuItem.m │ │ ├── WMMenuView.h │ │ ├── WMMenuView.m │ │ ├── WMProgressView.h │ │ ├── WMProgressView.m │ │ ├── WMScrollView.h │ │ └── WMScrollView.m │ │ ├── WMPageController.h │ │ └── WMPageController.m ├── Tests │ ├── Tests-Info.plist │ ├── Tests-Prefix.pch │ ├── Tests.m │ └── en.lproj │ │ └── InfoPlist.strings ├── WMPageController-JQHover.xcodeproj │ ├── project.pbxproj │ ├── project.xcworkspace │ │ └── contents.xcworkspacedata │ └── xcshareddata │ │ └── xcschemes │ │ └── WMPageController-JQHover-Example.xcscheme ├── WMPageController-JQHover.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── Joker.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── WMPageController-JQHover │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json │ ├── JQAppDelegate.h │ ├── JQAppDelegate.m │ ├── JQCollectionViewDemoController.h │ ├── JQCollectionViewDemoController.m │ ├── JQDemoPageController.h │ ├── JQDemoPageController.m │ ├── JQDemoSubpageController.h │ ├── JQDemoSubpageController.m │ ├── JQScrollViewDemoController.h │ ├── JQScrollViewDemoController.m │ ├── JQTableViewDemoController.h │ ├── JQTableViewDemoController.m │ ├── JQViewController.h │ ├── JQViewController.m │ ├── WMPageController-JQHover-Info.plist │ ├── WMPageController-JQHover-Prefix.pch │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── Images └── demo.gif ├── LICENSE ├── README.md ├── WMPageController-JQHover.podspec ├── WMPageController-JQHover ├── Assets │ └── .gitkeep └── Classes │ ├── .gitkeep │ ├── JQHoverFooterView.h │ ├── JQHoverFooterView.m │ ├── JQHoverPage.h │ ├── UIScrollView+JQExtension.h │ ├── UIScrollView+JQExtension.m │ ├── UIScrollView+JQHover.h │ ├── UIScrollView+JQHover.m │ ├── UIView+JQExtension.h │ ├── UIView+JQExtension.m │ ├── WMPageController+JQPage.h │ └── WMPageController+JQPage.m └── _Pods.xcodeproj /.travis.yml: -------------------------------------------------------------------------------- 1 | # references: 2 | # * https://www.objc.io/issues/6-build-tools/travis-ci/ 3 | # * https://github.com/supermarin/xcpretty#usage 4 | 5 | osx_image: xcode7.3 6 | language: objective-c 7 | # cache: cocoapods 8 | # podfile: Example/Podfile 9 | # before_install: 10 | # - gem install cocoapods # Since Travis is not always on latest version 11 | # - pod install --project-directory=Example 12 | script: 13 | - set -o pipefail && xcodebuild test -enableCodeCoverage YES -workspace Example/WMPageController-JQHover.xcworkspace -scheme WMPageController-JQHover-Example -sdk iphonesimulator9.3 ONLY_ACTIVE_ARCH=NO | xcpretty 14 | - pod lib lint 15 | -------------------------------------------------------------------------------- /Example/Podfile: -------------------------------------------------------------------------------- 1 | use_frameworks! 2 | 3 | target 'WMPageController-JQHover_Example' do 4 | pod 'WMPageController-JQHover', :path => '../' 5 | pod 'MJRefresh' 6 | target 'WMPageController-JQHover_Tests' do 7 | inherit! :search_paths 8 | 9 | 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /Example/Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MJRefresh (3.1.15.3) 3 | - WMPageController (2.5.2) 4 | - WMPageController-JQHover (0.1.0): 5 | - WMPageController 6 | 7 | DEPENDENCIES: 8 | - MJRefresh 9 | - WMPageController-JQHover (from `../`) 10 | 11 | SPEC REPOS: 12 | https://github.com/cocoapods/specs.git: 13 | - MJRefresh 14 | - WMPageController 15 | 16 | EXTERNAL SOURCES: 17 | WMPageController-JQHover: 18 | :path: "../" 19 | 20 | SPEC CHECKSUMS: 21 | MJRefresh: b48380ae2b927b46c4ef000de9adb8dc748e1df7 22 | WMPageController: 0c7624d2b48e4f1ab92371688cf6744ed701575d 23 | WMPageController-JQHover: cf96b56ddfc48da5d367410863ce483e2d64a90d 24 | 25 | PODFILE CHECKSUM: db5828401da4c67c1c914a487342ff45f5ac7872 26 | 27 | COCOAPODS: 1.5.3 28 | -------------------------------------------------------------------------------- /Example/Pods/Local Podspecs/WMPageController-JQHover.podspec.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "WMPageController-JQHover", 3 | "version": "0.1.0", 4 | "summary": "Extension of WMPageController, implement pages hover menu.", 5 | "description": "Extension of WMPageController, implement pages hover menu.\nSame style as WMPageController. Painless to use.", 6 | "homepage": "https://github.com/coder-zjq/WMPageController-JQHover", 7 | "screenshots": "https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/master/Images/demo.gif", 8 | "license": { 9 | "type": "MIT", 10 | "file": "LICENSE" 11 | }, 12 | "authors": { 13 | "coder-zjq": "zjq_joker@163.com" 14 | }, 15 | "source": { 16 | "git": "https://github.com/coder-zjq/WMPageController-JQHover.git", 17 | "tag": "0.1.0" 18 | }, 19 | "platforms": { 20 | "ios": "8.0" 21 | }, 22 | "source_files": "WMPageController-JQHover/Classes/**/*", 23 | "dependencies": { 24 | "WMPageController": [ 25 | 26 | ] 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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("请使用triggerAutomaticallyRefreshPercent属性"); 17 | 18 | /** 当底部控件出现多少时就自动刷新(默认为1.0,也就是底部控件完全出现时,才会自动刷新) */ 19 | @property (assign, nonatomic) CGFloat triggerAutomaticallyRefreshPercent; 20 | 21 | /** 是否每一次拖拽只发一次请求 */ 22 | @property (assign, nonatomic, getter=isOnlyRefreshPerDrag) BOOL onlyRefreshPerDrag; 23 | @end 24 | -------------------------------------------------------------------------------- /Example/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 | /** 一个新的拖拽 */ 13 | @property (assign, nonatomic, getter=isOneNewPan) BOOL oneNewPan; 14 | @end 15 | 16 | @implementation MJRefreshAutoFooter 17 | 18 | #pragma mark - 初始化 19 | - (void)willMoveToSuperview:(UIView *)newSuperview 20 | { 21 | [super willMoveToSuperview:newSuperview]; 22 | 23 | if (newSuperview) { // 新的父控件 24 | if (self.hidden == NO) { 25 | self.scrollView.mj_insetB += self.mj_h; 26 | } 27 | 28 | // 设置位置 29 | self.mj_y = _scrollView.mj_contentH; 30 | } else { // 被移除了 31 | if (self.hidden == NO) { 32 | self.scrollView.mj_insetB -= self.mj_h; 33 | } 34 | } 35 | } 36 | 37 | #pragma mark - 过期方法 38 | - (void)setAppearencePercentTriggerAutoRefresh:(CGFloat)appearencePercentTriggerAutoRefresh 39 | { 40 | self.triggerAutomaticallyRefreshPercent = appearencePercentTriggerAutoRefresh; 41 | } 42 | 43 | - (CGFloat)appearencePercentTriggerAutoRefresh 44 | { 45 | return self.triggerAutomaticallyRefreshPercent; 46 | } 47 | 48 | #pragma mark - 实现父类的方法 49 | - (void)prepare 50 | { 51 | [super prepare]; 52 | 53 | // 默认底部控件100%出现时才会自动刷新 54 | self.triggerAutomaticallyRefreshPercent = 1.0; 55 | 56 | // 设置为默认状态 57 | self.automaticallyRefresh = YES; 58 | 59 | // 默认是当offset达到条件就发送请求(可连续) 60 | self.onlyRefreshPerDrag = NO; 61 | } 62 | 63 | - (void)scrollViewContentSizeDidChange:(NSDictionary *)change 64 | { 65 | [super scrollViewContentSizeDidChange:change]; 66 | 67 | // 设置位置 68 | self.mj_y = self.scrollView.mj_contentH; 69 | } 70 | 71 | - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change 72 | { 73 | [super scrollViewContentOffsetDidChange:change]; 74 | 75 | if (self.state != MJRefreshStateIdle || !self.automaticallyRefresh || self.mj_y == 0) return; 76 | 77 | if (_scrollView.mj_insetT + _scrollView.mj_contentH > _scrollView.mj_h) { // 内容超过一个屏幕 78 | // 这里的_scrollView.mj_contentH替换掉self.mj_y更为合理 79 | if (_scrollView.mj_offsetY >= _scrollView.mj_contentH - _scrollView.mj_h + self.mj_h * self.triggerAutomaticallyRefreshPercent + _scrollView.mj_insetB - self.mj_h) { 80 | // 防止手松开时连续调用 81 | CGPoint old = [change[@"old"] CGPointValue]; 82 | CGPoint new = [change[@"new"] CGPointValue]; 83 | if (new.y <= old.y) return; 84 | 85 | // 当底部刷新控件完全出现时,才刷新 86 | [self beginRefreshing]; 87 | } 88 | } 89 | } 90 | 91 | - (void)scrollViewPanStateDidChange:(NSDictionary *)change 92 | { 93 | [super scrollViewPanStateDidChange:change]; 94 | 95 | if (self.state != MJRefreshStateIdle) return; 96 | 97 | UIGestureRecognizerState panState = _scrollView.panGestureRecognizer.state; 98 | if (panState == UIGestureRecognizerStateEnded) {// 手松开 99 | if (_scrollView.mj_insetT + _scrollView.mj_contentH <= _scrollView.mj_h) { // 不够一个屏幕 100 | if (_scrollView.mj_offsetY >= - _scrollView.mj_insetT) { // 向上拽 101 | [self beginRefreshing]; 102 | } 103 | } else { // 超出一个屏幕 104 | if (_scrollView.mj_offsetY >= _scrollView.mj_contentH + _scrollView.mj_insetB - _scrollView.mj_h) { 105 | [self beginRefreshing]; 106 | } 107 | } 108 | } else if (panState == UIGestureRecognizerStateBegan) { 109 | self.oneNewPan = YES; 110 | } 111 | } 112 | 113 | - (void)beginRefreshing 114 | { 115 | if (!self.isOneNewPan && self.isOnlyRefreshPerDrag) return; 116 | 117 | [super beginRefreshing]; 118 | 119 | self.oneNewPan = NO; 120 | } 121 | 122 | - (void)setState:(MJRefreshState)state 123 | { 124 | MJRefreshCheckState 125 | 126 | if (state == MJRefreshStateRefreshing) { 127 | [self executeRefreshingCallback]; 128 | } else if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) { 129 | if (MJRefreshStateRefreshing == oldState) { 130 | if (self.endRefreshingCompletionBlock) { 131 | self.endRefreshingCompletionBlock(); 132 | } 133 | } 134 | } 135 | } 136 | 137 | - (void)setHidden:(BOOL)hidden 138 | { 139 | BOOL lastHidden = self.isHidden; 140 | 141 | [super setHidden:hidden]; 142 | 143 | if (!lastHidden && hidden) { 144 | self.state = MJRefreshStateIdle; 145 | 146 | self.scrollView.mj_insetB -= self.mj_h; 147 | } else if (lastHidden && !hidden) { 148 | self.scrollView.mj_insetB += self.mj_h; 149 | 150 | // 设置位置 151 | self.mj_y = _scrollView.mj_contentH; 152 | } 153 | } 154 | @end 155 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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.mj_inset; 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 | if (self.endRefreshingCompletionBlock) { 100 | self.endRefreshingCompletionBlock(); 101 | } 102 | }]; 103 | } 104 | 105 | CGFloat deltaH = [self heightForContentBreakView]; 106 | // 刚刷新完毕 107 | if (MJRefreshStateRefreshing == oldState && deltaH > 0 && self.scrollView.mj_totalDataCount != self.lastRefreshCount) { 108 | self.scrollView.mj_offsetY = self.scrollView.mj_offsetY; 109 | } 110 | } else if (state == MJRefreshStateRefreshing) { 111 | // 记录刷新前的数量 112 | self.lastRefreshCount = self.scrollView.mj_totalDataCount; 113 | 114 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 115 | CGFloat bottom = self.mj_h + self.scrollViewOriginalInset.bottom; 116 | CGFloat deltaH = [self heightForContentBreakView]; 117 | if (deltaH < 0) { // 如果内容高度小于view的高度 118 | bottom -= deltaH; 119 | } 120 | self.lastBottomDelta = bottom - self.scrollView.mj_insetB; 121 | self.scrollView.mj_insetB = bottom; 122 | self.scrollView.mj_offsetY = [self happenOffsetY] + self.mj_h; 123 | } completion:^(BOOL finished) { 124 | [self executeRefreshingCallback]; 125 | }]; 126 | } 127 | } 128 | #pragma mark - 私有方法 129 | #pragma mark 获得scrollView的内容 超出 view 的高度 130 | - (CGFloat)heightForContentBreakView 131 | { 132 | CGFloat h = self.scrollView.frame.size.height - self.scrollViewOriginalInset.bottom - self.scrollViewOriginalInset.top; 133 | return self.scrollView.contentSize.height - h; 134 | } 135 | 136 | #pragma mark 刚好看到上拉刷新控件时的contentOffset.y 137 | - (CGFloat)happenOffsetY 138 | { 139 | CGFloat deltaH = [self heightForContentBreakView]; 140 | if (deltaH > 0) { 141 | return deltaH - self.scrollViewOriginalInset.top; 142 | } else { 143 | return - self.scrollViewOriginalInset.top; 144 | } 145 | } 146 | @end 147 | -------------------------------------------------------------------------------- /Example/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 | #import "NSBundle+MJRefresh.h" 16 | 17 | /** 刷新控件的状态 */ 18 | typedef NS_ENUM(NSInteger, MJRefreshState) { 19 | /** 普通闲置状态 */ 20 | MJRefreshStateIdle = 1, 21 | /** 松开就可以进行刷新的状态 */ 22 | MJRefreshStatePulling, 23 | /** 正在刷新中的状态 */ 24 | MJRefreshStateRefreshing, 25 | /** 即将刷新的状态 */ 26 | MJRefreshStateWillRefresh, 27 | /** 所有数据加载完毕,没有更多的数据了 */ 28 | MJRefreshStateNoMoreData 29 | }; 30 | 31 | /** 进入刷新状态的回调 */ 32 | typedef void (^MJRefreshComponentRefreshingBlock)(void); 33 | /** 开始刷新后的回调(进入刷新状态后的回调) */ 34 | typedef void (^MJRefreshComponentbeginRefreshingCompletionBlock)(void); 35 | /** 结束刷新后的回调 */ 36 | typedef void (^MJRefreshComponentEndRefreshingCompletionBlock)(void); 37 | 38 | /** 刷新控件的基类 */ 39 | @interface MJRefreshComponent : UIView 40 | { 41 | /** 记录scrollView刚开始的inset */ 42 | UIEdgeInsets _scrollViewOriginalInset; 43 | /** 父控件 */ 44 | __weak UIScrollView *_scrollView; 45 | } 46 | #pragma mark - 刷新回调 47 | /** 正在刷新的回调 */ 48 | @property (copy, nonatomic) MJRefreshComponentRefreshingBlock refreshingBlock; 49 | /** 设置回调对象和回调方法 */ 50 | - (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action; 51 | 52 | /** 回调对象 */ 53 | @property (weak, nonatomic) id refreshingTarget; 54 | /** 回调方法 */ 55 | @property (assign, nonatomic) SEL refreshingAction; 56 | /** 触发回调(交给子类去调用) */ 57 | - (void)executeRefreshingCallback; 58 | 59 | #pragma mark - 刷新状态控制 60 | /** 进入刷新状态 */ 61 | - (void)beginRefreshing; 62 | - (void)beginRefreshingWithCompletionBlock:(void (^)(void))completionBlock; 63 | /** 开始刷新后的回调(进入刷新状态后的回调) */ 64 | @property (copy, nonatomic) MJRefreshComponentbeginRefreshingCompletionBlock beginRefreshingCompletionBlock; 65 | /** 结束刷新的回调 */ 66 | @property (copy, nonatomic) MJRefreshComponentEndRefreshingCompletionBlock endRefreshingCompletionBlock; 67 | /** 结束刷新状态 */ 68 | - (void)endRefreshing; 69 | - (void)endRefreshingWithCompletionBlock:(void (^)(void))completionBlock; 70 | /** 是否正在刷新 */ 71 | @property (assign, nonatomic, readonly, getter=isRefreshing) BOOL refreshing; 72 | //- (BOOL)isRefreshing; 73 | /** 刷新状态 一般交给子类内部实现 */ 74 | @property (assign, nonatomic) MJRefreshState state; 75 | 76 | #pragma mark - 交给子类去访问 77 | /** 记录scrollView刚开始的inset */ 78 | @property (assign, nonatomic, readonly) UIEdgeInsets scrollViewOriginalInset; 79 | /** 父控件 */ 80 | @property (weak, nonatomic, readonly) UIScrollView *scrollView; 81 | 82 | #pragma mark - 交给子类们去实现 83 | /** 初始化 */ 84 | - (void)prepare NS_REQUIRES_SUPER; 85 | /** 摆放子控件frame */ 86 | - (void)placeSubviews NS_REQUIRES_SUPER; 87 | /** 当scrollView的contentOffset发生改变的时候调用 */ 88 | - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change NS_REQUIRES_SUPER; 89 | /** 当scrollView的contentSize发生改变的时候调用 */ 90 | - (void)scrollViewContentSizeDidChange:(NSDictionary *)change NS_REQUIRES_SUPER; 91 | /** 当scrollView的拖拽状态发生改变的时候调用 */ 92 | - (void)scrollViewPanStateDidChange:(NSDictionary *)change NS_REQUIRES_SUPER; 93 | 94 | 95 | #pragma mark - 其他 96 | /** 拉拽的百分比(交给子类重写) */ 97 | @property (assign, nonatomic) CGFloat pullingPercent; 98 | /** 根据拖拽比例自动切换透明度 */ 99 | @property (assign, nonatomic, getter=isAutoChangeAlpha) BOOL autoChangeAlpha MJRefreshDeprecated("请使用automaticallyChangeAlpha属性"); 100 | /** 根据拖拽比例自动切换透明度 */ 101 | @property (assign, nonatomic, getter=isAutomaticallyChangeAlpha) BOOL automaticallyChangeAlpha; 102 | @end 103 | 104 | @interface UILabel(MJRefresh) 105 | + (instancetype)mj_label; 106 | - (CGFloat)mj_textWith; 107 | @end 108 | -------------------------------------------------------------------------------- /Example/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 MJRefreshDeprecated("不建议使用此属性,开发者请自行控制footer的显示和隐藏。基于安全考虑,在未来的某些版本此属性可能作废"); 30 | @end 31 | -------------------------------------------------------------------------------- /Example/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 | #include "UIScrollView+MJRefresh.h" 12 | 13 | @interface MJRefreshFooter() 14 | 15 | @end 16 | 17 | @implementation MJRefreshFooter 18 | #pragma mark - 构造方法 19 | + (instancetype)footerWithRefreshingBlock:(MJRefreshComponentRefreshingBlock)refreshingBlock 20 | { 21 | MJRefreshFooter *cmp = [[self alloc] init]; 22 | cmp.refreshingBlock = refreshingBlock; 23 | return cmp; 24 | } 25 | + (instancetype)footerWithRefreshingTarget:(id)target refreshingAction:(SEL)action 26 | { 27 | MJRefreshFooter *cmp = [[self alloc] init]; 28 | [cmp setRefreshingTarget:target refreshingAction:action]; 29 | return cmp; 30 | } 31 | 32 | #pragma mark - 重写父类的方法 33 | - (void)prepare 34 | { 35 | [super prepare]; 36 | 37 | // 设置自己的高度 38 | self.mj_h = MJRefreshFooterHeight; 39 | 40 | // 默认不会自动隐藏 41 | self.automaticallyHidden = NO; 42 | } 43 | 44 | - (void)willMoveToSuperview:(UIView *)newSuperview 45 | { 46 | [super willMoveToSuperview:newSuperview]; 47 | 48 | if (newSuperview) { 49 | // 监听scrollView数据的变化 50 | if ([self.scrollView isKindOfClass:[UITableView class]] || [self.scrollView isKindOfClass:[UICollectionView class]]) { 51 | [self.scrollView setMj_reloadDataBlock:^(NSInteger totalDataCount) { 52 | if (self.isAutomaticallyHidden) { 53 | self.hidden = (totalDataCount == 0); 54 | } 55 | }]; 56 | } 57 | } 58 | } 59 | 60 | #pragma mark - 公共方法 61 | - (void)endRefreshingWithNoMoreData 62 | { 63 | dispatch_async(dispatch_get_main_queue(), ^{ 64 | self.state = MJRefreshStateNoMoreData; 65 | }); 66 | } 67 | 68 | - (void)noticeNoMoreData 69 | { 70 | [self endRefreshingWithNoMoreData]; 71 | } 72 | 73 | - (void)resetNoMoreData 74 | { 75 | dispatch_async(dispatch_get_main_queue(), ^{ 76 | self.state = MJRefreshStateIdle; 77 | }); 78 | } 79 | 80 | - (void)setAutomaticallyHidden:(BOOL)automaticallyHidden 81 | { 82 | _automaticallyHidden = automaticallyHidden; 83 | } 84 | @end 85 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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 | // 暂时保留 58 | if (self.window == nil) return; 59 | 60 | // sectionheader停留解决 61 | CGFloat insetT = - self.scrollView.mj_offsetY > _scrollViewOriginalInset.top ? - self.scrollView.mj_offsetY : _scrollViewOriginalInset.top; 62 | insetT = insetT > self.mj_h + _scrollViewOriginalInset.top ? self.mj_h + _scrollViewOriginalInset.top : insetT; 63 | self.scrollView.mj_insetT = insetT; 64 | 65 | self.insetTDelta = _scrollViewOriginalInset.top - insetT; 66 | return; 67 | } 68 | 69 | // 跳转到下一个控制器时,contentInset可能会变 70 | _scrollViewOriginalInset = self.scrollView.mj_inset; 71 | 72 | // 当前的contentOffset 73 | CGFloat offsetY = self.scrollView.mj_offsetY; 74 | // 头部控件刚好出现的offsetY 75 | CGFloat happenOffsetY = - self.scrollViewOriginalInset.top; 76 | 77 | // 如果是向上滚动到看不见头部控件,直接返回 78 | // >= -> > 79 | if (offsetY > happenOffsetY) return; 80 | 81 | // 普通 和 即将刷新 的临界点 82 | CGFloat normal2pullingOffsetY = happenOffsetY - self.mj_h; 83 | CGFloat pullingPercent = (happenOffsetY - offsetY) / self.mj_h; 84 | 85 | if (self.scrollView.isDragging) { // 如果正在拖拽 86 | self.pullingPercent = pullingPercent; 87 | if (self.state == MJRefreshStateIdle && offsetY < normal2pullingOffsetY) { 88 | // 转为即将刷新状态 89 | self.state = MJRefreshStatePulling; 90 | } else if (self.state == MJRefreshStatePulling && offsetY >= normal2pullingOffsetY) { 91 | // 转为普通状态 92 | self.state = MJRefreshStateIdle; 93 | } 94 | } else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开 95 | // 开始刷新 96 | [self beginRefreshing]; 97 | } else if (pullingPercent < 1) { 98 | self.pullingPercent = pullingPercent; 99 | } 100 | } 101 | 102 | - (void)setState:(MJRefreshState)state 103 | { 104 | MJRefreshCheckState 105 | 106 | // 根据状态做事情 107 | if (state == MJRefreshStateIdle) { 108 | if (oldState != MJRefreshStateRefreshing) return; 109 | 110 | // 保存刷新时间 111 | [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:self.lastUpdatedTimeKey]; 112 | [[NSUserDefaults standardUserDefaults] synchronize]; 113 | 114 | // 恢复inset和offset 115 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{ 116 | self.scrollView.mj_insetT += self.insetTDelta; 117 | 118 | // 自动调整透明度 119 | if (self.isAutomaticallyChangeAlpha) self.alpha = 0.0; 120 | } completion:^(BOOL finished) { 121 | self.pullingPercent = 0.0; 122 | 123 | if (self.endRefreshingCompletionBlock) { 124 | self.endRefreshingCompletionBlock(); 125 | } 126 | }]; 127 | } else if (state == MJRefreshStateRefreshing) { 128 | dispatch_async(dispatch_get_main_queue(), ^{ 129 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 130 | CGFloat top = self.scrollViewOriginalInset.top + self.mj_h; 131 | // 增加滚动区域top 132 | self.scrollView.mj_insetT = top; 133 | // 设置滚动位置 134 | CGPoint offset = self.scrollView.contentOffset; 135 | offset.y = -top; 136 | [self.scrollView setContentOffset:offset animated:NO]; 137 | } completion:^(BOOL finished) { 138 | [self executeRefreshingCallback]; 139 | }]; 140 | }); 141 | } 142 | } 143 | 144 | #pragma mark - 公共方法 145 | - (NSDate *)lastUpdatedTime 146 | { 147 | return [[NSUserDefaults standardUserDefaults] objectForKey:self.lastUpdatedTimeKey]; 148 | } 149 | @end 150 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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)prepare 70 | { 71 | [super prepare]; 72 | 73 | // 初始化间距 74 | self.labelLeftInset = 20; 75 | } 76 | 77 | - (void)placeSubviews 78 | { 79 | [super placeSubviews]; 80 | 81 | if (self.gifView.constraints.count) return; 82 | 83 | self.gifView.frame = self.bounds; 84 | if (self.isRefreshingTitleHidden) { 85 | self.gifView.contentMode = UIViewContentModeCenter; 86 | } else { 87 | self.gifView.contentMode = UIViewContentModeRight; 88 | self.gifView.mj_w = self.mj_w * 0.5 - self.labelLeftInset - self.stateLabel.mj_textWith * 0.5; 89 | } 90 | } 91 | 92 | - (void)setState:(MJRefreshState)state 93 | { 94 | MJRefreshCheckState 95 | 96 | // 根据状态做事情 97 | if (state == MJRefreshStateRefreshing) { 98 | NSArray *images = self.stateImages[@(state)]; 99 | if (images.count == 0) return; 100 | [self.gifView stopAnimating]; 101 | 102 | self.gifView.hidden = NO; 103 | if (images.count == 1) { // 单张图片 104 | self.gifView.image = [images lastObject]; 105 | } else { // 多张图片 106 | self.gifView.animationImages = images; 107 | self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue]; 108 | [self.gifView startAnimating]; 109 | } 110 | } else if (state == MJRefreshStateNoMoreData || state == MJRefreshStateIdle) { 111 | [self.gifView stopAnimating]; 112 | self.gifView.hidden = YES; 113 | } 114 | } 115 | @end 116 | 117 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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 mark - 重写父类的方法 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 -= self.stateLabel.mj_textWith * 0.5 + self.labelLeftInset; 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 | -------------------------------------------------------------------------------- /Example/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 | /** 文字距离圈圈、箭头的距离 */ 13 | @property (assign, nonatomic) CGFloat labelLeftInset; 14 | /** 显示刷新状态的label */ 15 | @property (weak, nonatomic, readonly) UILabel *stateLabel; 16 | 17 | /** 设置state状态下的文字 */ 18 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state; 19 | 20 | /** 隐藏刷新状态的文字 */ 21 | @property (assign, nonatomic, getter=isRefreshingTitleHidden) BOOL refreshingTitleHidden; 22 | @end 23 | -------------------------------------------------------------------------------- /Example/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 mj_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.labelLeftInset = MJRefreshLabelLeftInset; 61 | 62 | // 初始化文字 63 | [self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterIdleText] forState:MJRefreshStateIdle]; 64 | [self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterRefreshingText] forState:MJRefreshStateRefreshing]; 65 | [self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshAutoFooterNoMoreDataText] forState:MJRefreshStateNoMoreData]; 66 | 67 | // 监听label 68 | self.stateLabel.userInteractionEnabled = YES; 69 | [self.stateLabel addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(stateLabelClick)]]; 70 | } 71 | 72 | - (void)placeSubviews 73 | { 74 | [super placeSubviews]; 75 | 76 | if (self.stateLabel.constraints.count) return; 77 | 78 | // 状态标签 79 | self.stateLabel.frame = self.bounds; 80 | } 81 | 82 | - (void)setState:(MJRefreshState)state 83 | { 84 | MJRefreshCheckState 85 | 86 | if (self.isRefreshingTitleHidden && state == MJRefreshStateRefreshing) { 87 | self.stateLabel.text = nil; 88 | } else { 89 | self.stateLabel.text = self.stateTitles[@(state)]; 90 | } 91 | } 92 | @end -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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)prepare 70 | { 71 | [super prepare]; 72 | 73 | // 初始化间距 74 | self.labelLeftInset = 20; 75 | } 76 | 77 | - (void)setPullingPercent:(CGFloat)pullingPercent 78 | { 79 | [super setPullingPercent:pullingPercent]; 80 | NSArray *images = self.stateImages[@(MJRefreshStateIdle)]; 81 | if (self.state != MJRefreshStateIdle || images.count == 0) return; 82 | [self.gifView stopAnimating]; 83 | NSUInteger index = images.count * pullingPercent; 84 | if (index >= images.count) index = images.count - 1; 85 | self.gifView.image = images[index]; 86 | } 87 | 88 | - (void)placeSubviews 89 | { 90 | [super placeSubviews]; 91 | 92 | if (self.gifView.constraints.count) return; 93 | 94 | self.gifView.frame = self.bounds; 95 | if (self.stateLabel.hidden) { 96 | self.gifView.contentMode = UIViewContentModeCenter; 97 | } else { 98 | self.gifView.contentMode = UIViewContentModeRight; 99 | self.gifView.mj_w = self.mj_w * 0.5 - self.labelLeftInset - self.stateLabel.mj_textWith * 0.5; 100 | } 101 | } 102 | 103 | - (void)setState:(MJRefreshState)state 104 | { 105 | MJRefreshCheckState 106 | 107 | // 根据状态做事情 108 | if (state == MJRefreshStatePulling || state == MJRefreshStateRefreshing) { 109 | NSArray *images = self.stateImages[@(state)]; 110 | if (images.count == 0) return; 111 | 112 | self.gifView.hidden = NO; 113 | [self.gifView stopAnimating]; 114 | if (images.count == 1) { // 单张图片 115 | self.gifView.image = [images lastObject]; 116 | } else { // 多张图片 117 | self.gifView.animationImages = images; 118 | self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue]; 119 | [self.gifView startAnimating]; 120 | } 121 | } else if (state == MJRefreshStateIdle) { 122 | self.gifView.hidden = NO; 123 | } else if (state == MJRefreshStateNoMoreData) { 124 | self.gifView.hidden = YES; 125 | } 126 | } 127 | @end 128 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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 | #import "NSBundle+MJRefresh.h" 11 | 12 | @interface MJRefreshBackNormalFooter() 13 | { 14 | __unsafe_unretained UIImageView *_arrowView; 15 | } 16 | @property (weak, nonatomic) UIActivityIndicatorView *loadingView; 17 | @end 18 | 19 | @implementation MJRefreshBackNormalFooter 20 | #pragma mark - 懒加载子控件 21 | - (UIImageView *)arrowView 22 | { 23 | if (!_arrowView) { 24 | UIImageView *arrowView = [[UIImageView alloc] initWithImage:[NSBundle mj_arrowImage]]; 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 mark - 重写父类的方法 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 -= self.labelLeftInset + self.stateLabel.mj_textWith * 0.5; 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 | self.arrowView.tintColor = self.stateLabel.textColor; 80 | } 81 | 82 | - (void)setState:(MJRefreshState)state 83 | { 84 | MJRefreshCheckState 85 | 86 | // 根据状态做事情 87 | if (state == MJRefreshStateIdle) { 88 | if (oldState == MJRefreshStateRefreshing) { 89 | self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI); 90 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{ 91 | self.loadingView.alpha = 0.0; 92 | } completion:^(BOOL finished) { 93 | self.loadingView.alpha = 1.0; 94 | [self.loadingView stopAnimating]; 95 | 96 | self.arrowView.hidden = NO; 97 | }]; 98 | } else { 99 | self.arrowView.hidden = NO; 100 | [self.loadingView stopAnimating]; 101 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 102 | self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI); 103 | }]; 104 | } 105 | } else if (state == MJRefreshStatePulling) { 106 | self.arrowView.hidden = NO; 107 | [self.loadingView stopAnimating]; 108 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 109 | self.arrowView.transform = CGAffineTransformIdentity; 110 | }]; 111 | } else if (state == MJRefreshStateRefreshing) { 112 | self.arrowView.hidden = YES; 113 | [self.loadingView startAnimating]; 114 | } else if (state == MJRefreshStateNoMoreData) { 115 | self.arrowView.hidden = YES; 116 | [self.loadingView stopAnimating]; 117 | } 118 | } 119 | 120 | @end 121 | -------------------------------------------------------------------------------- /Example/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 | /** 文字距离圈圈、箭头的距离 */ 13 | @property (assign, nonatomic) CGFloat labelLeftInset; 14 | /** 显示刷新状态的label */ 15 | @property (weak, nonatomic, readonly) UILabel *stateLabel; 16 | /** 设置state状态下的文字 */ 17 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state; 18 | 19 | /** 获取state状态下的title */ 20 | - (NSString *)titleForState:(MJRefreshState)state; 21 | @end 22 | -------------------------------------------------------------------------------- /Example/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 mj_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.labelLeftInset = MJRefreshLabelLeftInset; 57 | 58 | // 初始化文字 59 | [self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshBackFooterIdleText] forState:MJRefreshStateIdle]; 60 | [self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshBackFooterPullingText] forState:MJRefreshStatePulling]; 61 | [self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshBackFooterRefreshingText] forState:MJRefreshStateRefreshing]; 62 | [self setTitle:[NSBundle mj_localizedStringForKey:MJRefreshBackFooterNoMoreDataText] forState:MJRefreshStateNoMoreData]; 63 | } 64 | 65 | - (void)placeSubviews 66 | { 67 | [super placeSubviews]; 68 | 69 | if (self.stateLabel.constraints.count) return; 70 | 71 | // 状态标签 72 | self.stateLabel.frame = self.bounds; 73 | } 74 | 75 | - (void)setState:(MJRefreshState)state 76 | { 77 | MJRefreshCheckState 78 | 79 | // 设置状态文字 80 | self.stateLabel.text = self.stateTitles[@(state)]; 81 | } 82 | @end 83 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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)prepare 70 | { 71 | [super prepare]; 72 | 73 | // 初始化间距 74 | self.labelLeftInset = 20; 75 | } 76 | 77 | - (void)setPullingPercent:(CGFloat)pullingPercent 78 | { 79 | [super setPullingPercent:pullingPercent]; 80 | NSArray *images = self.stateImages[@(MJRefreshStateIdle)]; 81 | if (self.state != MJRefreshStateIdle || images.count == 0) return; 82 | // 停止动画 83 | [self.gifView stopAnimating]; 84 | // 设置当前需要显示的图片 85 | NSUInteger index = images.count * pullingPercent; 86 | if (index >= images.count) index = images.count - 1; 87 | self.gifView.image = images[index]; 88 | } 89 | 90 | - (void)placeSubviews 91 | { 92 | [super placeSubviews]; 93 | 94 | if (self.gifView.constraints.count) return; 95 | 96 | self.gifView.frame = self.bounds; 97 | if (self.stateLabel.hidden && self.lastUpdatedTimeLabel.hidden) { 98 | self.gifView.contentMode = UIViewContentModeCenter; 99 | } else { 100 | self.gifView.contentMode = UIViewContentModeRight; 101 | 102 | CGFloat stateWidth = self.stateLabel.mj_textWith; 103 | CGFloat timeWidth = 0.0; 104 | if (!self.lastUpdatedTimeLabel.hidden) { 105 | timeWidth = self.lastUpdatedTimeLabel.mj_textWith; 106 | } 107 | CGFloat textWidth = MAX(stateWidth, timeWidth); 108 | self.gifView.mj_w = self.mj_w * 0.5 - textWidth * 0.5 - self.labelLeftInset; 109 | } 110 | } 111 | 112 | - (void)setState:(MJRefreshState)state 113 | { 114 | MJRefreshCheckState 115 | 116 | // 根据状态做事情 117 | if (state == MJRefreshStatePulling || state == MJRefreshStateRefreshing) { 118 | NSArray *images = self.stateImages[@(state)]; 119 | if (images.count == 0) return; 120 | 121 | [self.gifView stopAnimating]; 122 | if (images.count == 1) { // 单张图片 123 | self.gifView.image = [images lastObject]; 124 | } else { // 多张图片 125 | self.gifView.animationImages = images; 126 | self.gifView.animationDuration = [self.stateDurations[@(state)] doubleValue]; 127 | [self.gifView startAnimating]; 128 | } 129 | } else if (state == MJRefreshStateIdle) { 130 | [self.gifView stopAnimating]; 131 | } 132 | } 133 | @end 134 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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 | #import "NSBundle+MJRefresh.h" 11 | 12 | @interface MJRefreshNormalHeader() 13 | { 14 | __unsafe_unretained UIImageView *_arrowView; 15 | } 16 | @property (weak, nonatomic) UIActivityIndicatorView *loadingView; 17 | @end 18 | 19 | @implementation MJRefreshNormalHeader 20 | #pragma mark - 懒加载子控件 21 | - (UIImageView *)arrowView 22 | { 23 | if (!_arrowView) { 24 | UIImageView *arrowView = [[UIImageView alloc] initWithImage:[NSBundle mj_arrowImage]]; 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 mark - 重写父类的方法 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 | CGFloat stateWidth = self.stateLabel.mj_textWith; 65 | CGFloat timeWidth = 0.0; 66 | if (!self.lastUpdatedTimeLabel.hidden) { 67 | timeWidth = self.lastUpdatedTimeLabel.mj_textWith; 68 | } 69 | CGFloat textWidth = MAX(stateWidth, timeWidth); 70 | arrowCenterX -= textWidth / 2 + self.labelLeftInset; 71 | } 72 | CGFloat arrowCenterY = self.mj_h * 0.5; 73 | CGPoint arrowCenter = CGPointMake(arrowCenterX, arrowCenterY); 74 | 75 | // 箭头 76 | if (self.arrowView.constraints.count == 0) { 77 | self.arrowView.mj_size = self.arrowView.image.size; 78 | self.arrowView.center = arrowCenter; 79 | } 80 | 81 | // 圈圈 82 | if (self.loadingView.constraints.count == 0) { 83 | self.loadingView.center = arrowCenter; 84 | } 85 | 86 | self.arrowView.tintColor = self.stateLabel.textColor; 87 | } 88 | 89 | - (void)setState:(MJRefreshState)state 90 | { 91 | MJRefreshCheckState 92 | 93 | // 根据状态做事情 94 | if (state == MJRefreshStateIdle) { 95 | if (oldState == MJRefreshStateRefreshing) { 96 | self.arrowView.transform = CGAffineTransformIdentity; 97 | 98 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{ 99 | self.loadingView.alpha = 0.0; 100 | } completion:^(BOOL finished) { 101 | // 如果执行完动画发现不是idle状态,就直接返回,进入其他状态 102 | if (self.state != MJRefreshStateIdle) return; 103 | 104 | self.loadingView.alpha = 1.0; 105 | [self.loadingView stopAnimating]; 106 | self.arrowView.hidden = NO; 107 | }]; 108 | } else { 109 | [self.loadingView stopAnimating]; 110 | self.arrowView.hidden = NO; 111 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 112 | self.arrowView.transform = CGAffineTransformIdentity; 113 | }]; 114 | } 115 | } else if (state == MJRefreshStatePulling) { 116 | [self.loadingView stopAnimating]; 117 | self.arrowView.hidden = NO; 118 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 119 | self.arrowView.transform = CGAffineTransformMakeRotation(0.000001 - M_PI); 120 | }]; 121 | } else if (state == MJRefreshStateRefreshing) { 122 | self.loadingView.alpha = 1.0; // 防止refreshing -> idle的动画完毕动作没有被执行 123 | [self.loadingView startAnimating]; 124 | self.arrowView.hidden = YES; 125 | } 126 | } 127 | @end 128 | -------------------------------------------------------------------------------- /Example/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 | /** 文字距离圈圈、箭头的距离 */ 20 | @property (assign, nonatomic) CGFloat labelLeftInset; 21 | /** 显示刷新状态的label */ 22 | @property (weak, nonatomic, readonly) UILabel *stateLabel; 23 | /** 设置state状态下的文字 */ 24 | - (void)setTitle:(NSString *)title forState:(MJRefreshState)state; 25 | @end 26 | -------------------------------------------------------------------------------- /Example/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/arrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/e6dd5bec3c564f9a10959cbdc83e56b9ac7c5599/Example/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/arrow@2x.png -------------------------------------------------------------------------------- /Example/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/e6dd5bec3c564f9a10959cbdc83e56b9ac7c5599/Example/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/en.lproj/Localizable.strings -------------------------------------------------------------------------------- /Example/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/e6dd5bec3c564f9a10959cbdc83e56b9ac7c5599/Example/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/zh-Hans.lproj/Localizable.strings -------------------------------------------------------------------------------- /Example/Pods/MJRefresh/MJRefresh/MJRefresh.bundle/zh-Hant.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | "MJRefreshHeaderIdleText" = "下拉可以刷新"; 2 | "MJRefreshHeaderPullingText" = "鬆開立即刷新"; 3 | "MJRefreshHeaderRefreshingText" = "正在刷新數據中..."; 4 | 5 | "MJRefreshAutoFooterIdleText" = "點擊或上拉加載更多"; 6 | "MJRefreshAutoFooterRefreshingText" = "正在加載更多的數據..."; 7 | "MJRefreshAutoFooterNoMoreDataText" = "已經全部加載完畢"; 8 | 9 | "MJRefreshBackFooterIdleText" = "上拉可以加載更多"; 10 | "MJRefreshBackFooterPullingText" = "鬆開立即加載更多"; 11 | "MJRefreshBackFooterRefreshingText" = "正在加載更多的數據..."; 12 | "MJRefreshBackFooterNoMoreDataText" = "已經全部加載完畢"; 13 | 14 | "MJRefreshHeaderLastTimeText" = "最後更新:"; 15 | "MJRefreshHeaderDateTodayText" = "今天"; 16 | "MJRefreshHeaderNoneLastDateText" = "無記錄"; 17 | -------------------------------------------------------------------------------- /Example/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" -------------------------------------------------------------------------------- /Example/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 | UIKIT_EXTERN const CGFloat MJRefreshLabelLeftInset; 34 | UIKIT_EXTERN const CGFloat MJRefreshHeaderHeight; 35 | UIKIT_EXTERN const CGFloat MJRefreshFooterHeight; 36 | UIKIT_EXTERN const CGFloat MJRefreshFastAnimationDuration; 37 | UIKIT_EXTERN const CGFloat MJRefreshSlowAnimationDuration; 38 | 39 | UIKIT_EXTERN NSString *const MJRefreshKeyPathContentOffset; 40 | UIKIT_EXTERN NSString *const MJRefreshKeyPathContentSize; 41 | UIKIT_EXTERN NSString *const MJRefreshKeyPathContentInset; 42 | UIKIT_EXTERN NSString *const MJRefreshKeyPathPanState; 43 | 44 | UIKIT_EXTERN NSString *const MJRefreshHeaderLastUpdatedTimeKey; 45 | 46 | UIKIT_EXTERN NSString *const MJRefreshHeaderIdleText; 47 | UIKIT_EXTERN NSString *const MJRefreshHeaderPullingText; 48 | UIKIT_EXTERN NSString *const MJRefreshHeaderRefreshingText; 49 | 50 | UIKIT_EXTERN NSString *const MJRefreshAutoFooterIdleText; 51 | UIKIT_EXTERN NSString *const MJRefreshAutoFooterRefreshingText; 52 | UIKIT_EXTERN NSString *const MJRefreshAutoFooterNoMoreDataText; 53 | 54 | UIKIT_EXTERN NSString *const MJRefreshBackFooterIdleText; 55 | UIKIT_EXTERN NSString *const MJRefreshBackFooterPullingText; 56 | UIKIT_EXTERN NSString *const MJRefreshBackFooterRefreshingText; 57 | UIKIT_EXTERN NSString *const MJRefreshBackFooterNoMoreDataText; 58 | 59 | UIKIT_EXTERN NSString *const MJRefreshHeaderLastTimeText; 60 | UIKIT_EXTERN NSString *const MJRefreshHeaderDateTodayText; 61 | UIKIT_EXTERN NSString *const MJRefreshHeaderNoneLastDateText; 62 | 63 | // 状态检查 64 | #define MJRefreshCheckState \ 65 | MJRefreshState oldState = self.state; \ 66 | if (state == oldState) return; \ 67 | [super setState:state]; 68 | -------------------------------------------------------------------------------- /Example/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 MJRefreshLabelLeftInset = 25; 6 | const CGFloat MJRefreshHeaderHeight = 54.0; 7 | const CGFloat MJRefreshFooterHeight = 44.0; 8 | const CGFloat MJRefreshFastAnimationDuration = 0.25; 9 | const CGFloat MJRefreshSlowAnimationDuration = 0.4; 10 | 11 | NSString *const MJRefreshKeyPathContentOffset = @"contentOffset"; 12 | NSString *const MJRefreshKeyPathContentInset = @"contentInset"; 13 | NSString *const MJRefreshKeyPathContentSize = @"contentSize"; 14 | NSString *const MJRefreshKeyPathPanState = @"state"; 15 | 16 | NSString *const MJRefreshHeaderLastUpdatedTimeKey = @"MJRefreshHeaderLastUpdatedTimeKey"; 17 | 18 | NSString *const MJRefreshHeaderIdleText = @"MJRefreshHeaderIdleText"; 19 | NSString *const MJRefreshHeaderPullingText = @"MJRefreshHeaderPullingText"; 20 | NSString *const MJRefreshHeaderRefreshingText = @"MJRefreshHeaderRefreshingText"; 21 | 22 | NSString *const MJRefreshAutoFooterIdleText = @"MJRefreshAutoFooterIdleText"; 23 | NSString *const MJRefreshAutoFooterRefreshingText = @"MJRefreshAutoFooterRefreshingText"; 24 | NSString *const MJRefreshAutoFooterNoMoreDataText = @"MJRefreshAutoFooterNoMoreDataText"; 25 | 26 | NSString *const MJRefreshBackFooterIdleText = @"MJRefreshBackFooterIdleText"; 27 | NSString *const MJRefreshBackFooterPullingText = @"MJRefreshBackFooterPullingText"; 28 | NSString *const MJRefreshBackFooterRefreshingText = @"MJRefreshBackFooterRefreshingText"; 29 | NSString *const MJRefreshBackFooterNoMoreDataText = @"MJRefreshBackFooterNoMoreDataText"; 30 | 31 | NSString *const MJRefreshHeaderLastTimeText = @"MJRefreshHeaderLastTimeText"; 32 | NSString *const MJRefreshHeaderDateTodayText = @"MJRefreshHeaderDateTodayText"; 33 | NSString *const MJRefreshHeaderNoneLastDateText = @"MJRefreshHeaderNoneLastDateText"; -------------------------------------------------------------------------------- /Example/Pods/MJRefresh/MJRefresh/NSBundle+MJRefresh.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSBundle+MJRefresh.h 3 | // MJRefreshExample 4 | // 5 | // Created by MJ Lee on 16/6/13. 6 | // Copyright © 2016年 小码哥. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface NSBundle (MJRefresh) 12 | + (instancetype)mj_refreshBundle; 13 | + (UIImage *)mj_arrowImage; 14 | + (NSString *)mj_localizedStringForKey:(NSString *)key value:(NSString *)value; 15 | + (NSString *)mj_localizedStringForKey:(NSString *)key; 16 | @end 17 | -------------------------------------------------------------------------------- /Example/Pods/MJRefresh/MJRefresh/NSBundle+MJRefresh.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSBundle+MJRefresh.m 3 | // MJRefreshExample 4 | // 5 | // Created by MJ Lee on 16/6/13. 6 | // Copyright © 2016年 小码哥. All rights reserved. 7 | // 8 | 9 | #import "NSBundle+MJRefresh.h" 10 | #import "MJRefreshComponent.h" 11 | 12 | @implementation NSBundle (MJRefresh) 13 | + (instancetype)mj_refreshBundle 14 | { 15 | static NSBundle *refreshBundle = nil; 16 | if (refreshBundle == nil) { 17 | // 这里不使用mainBundle是为了适配pod 1.x和0.x 18 | refreshBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[MJRefreshComponent class]] pathForResource:@"MJRefresh" ofType:@"bundle"]]; 19 | } 20 | return refreshBundle; 21 | } 22 | 23 | + (UIImage *)mj_arrowImage 24 | { 25 | static UIImage *arrowImage = nil; 26 | if (arrowImage == nil) { 27 | arrowImage = [[UIImage imageWithContentsOfFile:[[self mj_refreshBundle] pathForResource:@"arrow@2x" ofType:@"png"]] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; 28 | } 29 | return arrowImage; 30 | } 31 | 32 | + (NSString *)mj_localizedStringForKey:(NSString *)key 33 | { 34 | return [self mj_localizedStringForKey:key value:nil]; 35 | } 36 | 37 | + (NSString *)mj_localizedStringForKey:(NSString *)key value:(NSString *)value 38 | { 39 | static NSBundle *bundle = nil; 40 | if (bundle == nil) { 41 | // (iOS获取的语言字符串比较不稳定)目前框架只处理en、zh-Hans、zh-Hant三种情况,其他按照系统默认处理 42 | NSString *language = [NSLocale preferredLanguages].firstObject; 43 | if ([language hasPrefix:@"en"]) { 44 | language = @"en"; 45 | } else if ([language hasPrefix:@"zh"]) { 46 | if ([language rangeOfString:@"Hans"].location != NSNotFound) { 47 | language = @"zh-Hans"; // 简体中文 48 | } else { // zh-Hant\zh-HK\zh-TW 49 | language = @"zh-Hant"; // 繁體中文 50 | } 51 | } else { 52 | language = @"en"; 53 | } 54 | 55 | // 从MJRefresh.bundle中查找资源 56 | bundle = [NSBundle bundleWithPath:[[NSBundle mj_refreshBundle] pathForResource:language ofType:@"lproj"]]; 57 | } 58 | value = [bundle localizedStringForKey:key value:value table:nil]; 59 | return [[NSBundle mainBundle] localizedStringForKey:key value:value table:nil]; 60 | } 61 | @end 62 | -------------------------------------------------------------------------------- /Example/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 (readonly, nonatomic) UIEdgeInsets mj_inset; 14 | 15 | @property (assign, nonatomic) CGFloat mj_insetT; 16 | @property (assign, nonatomic) CGFloat mj_insetB; 17 | @property (assign, nonatomic) CGFloat mj_insetL; 18 | @property (assign, nonatomic) CGFloat mj_insetR; 19 | 20 | @property (assign, nonatomic) CGFloat mj_offsetX; 21 | @property (assign, nonatomic) CGFloat mj_offsetY; 22 | 23 | @property (assign, nonatomic) CGFloat mj_contentW; 24 | @property (assign, nonatomic) CGFloat mj_contentH; 25 | @end 26 | -------------------------------------------------------------------------------- /Example/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 | #pragma clang diagnostic push 14 | #pragma clang diagnostic ignored "-Wunguarded-availability-new" 15 | 16 | @implementation UIScrollView (MJExtension) 17 | 18 | static BOOL gt_ios_11_; 19 | + (void)load 20 | { 21 | // 缓存判断值 22 | gt_ios_11_ = [[[UIDevice currentDevice] systemVersion] compare:@"11.0" options:NSNumericSearch] != NSOrderedAscending; 23 | } 24 | 25 | - (UIEdgeInsets)mj_inset 26 | { 27 | #ifdef __IPHONE_11_0 28 | if (gt_ios_11_) { 29 | return self.adjustedContentInset; 30 | } 31 | #endif 32 | return self.contentInset; 33 | } 34 | 35 | - (void)setMj_insetT:(CGFloat)mj_insetT 36 | { 37 | UIEdgeInsets inset = self.contentInset; 38 | inset.top = mj_insetT; 39 | #ifdef __IPHONE_11_0 40 | if (gt_ios_11_) { 41 | inset.top -= (self.adjustedContentInset.top - self.contentInset.top); 42 | } 43 | #endif 44 | self.contentInset = inset; 45 | } 46 | 47 | - (CGFloat)mj_insetT 48 | { 49 | return self.mj_inset.top; 50 | } 51 | 52 | - (void)setMj_insetB:(CGFloat)mj_insetB 53 | { 54 | UIEdgeInsets inset = self.contentInset; 55 | inset.bottom = mj_insetB; 56 | #ifdef __IPHONE_11_0 57 | if (gt_ios_11_) { 58 | inset.bottom -= (self.adjustedContentInset.bottom - self.contentInset.bottom); 59 | } 60 | #endif 61 | self.contentInset = inset; 62 | } 63 | 64 | - (CGFloat)mj_insetB 65 | { 66 | return self.mj_inset.bottom; 67 | } 68 | 69 | - (void)setMj_insetL:(CGFloat)mj_insetL 70 | { 71 | UIEdgeInsets inset = self.contentInset; 72 | inset.left = mj_insetL; 73 | #ifdef __IPHONE_11_0 74 | if (gt_ios_11_) { 75 | inset.left -= (self.adjustedContentInset.left - self.contentInset.left); 76 | } 77 | #endif 78 | self.contentInset = inset; 79 | } 80 | 81 | - (CGFloat)mj_insetL 82 | { 83 | return self.mj_inset.left; 84 | } 85 | 86 | - (void)setMj_insetR:(CGFloat)mj_insetR 87 | { 88 | UIEdgeInsets inset = self.contentInset; 89 | inset.right = mj_insetR; 90 | #ifdef __IPHONE_11_0 91 | if (gt_ios_11_) { 92 | inset.right -= (self.adjustedContentInset.right - self.contentInset.right); 93 | } 94 | #endif 95 | self.contentInset = inset; 96 | } 97 | 98 | - (CGFloat)mj_insetR 99 | { 100 | return self.mj_inset.right; 101 | } 102 | 103 | - (void)setMj_offsetX:(CGFloat)mj_offsetX 104 | { 105 | CGPoint offset = self.contentOffset; 106 | offset.x = mj_offsetX; 107 | self.contentOffset = offset; 108 | } 109 | 110 | - (CGFloat)mj_offsetX 111 | { 112 | return self.contentOffset.x; 113 | } 114 | 115 | - (void)setMj_offsetY:(CGFloat)mj_offsetY 116 | { 117 | CGPoint offset = self.contentOffset; 118 | offset.y = mj_offsetY; 119 | self.contentOffset = offset; 120 | } 121 | 122 | - (CGFloat)mj_offsetY 123 | { 124 | return self.contentOffset.y; 125 | } 126 | 127 | - (void)setMj_contentW:(CGFloat)mj_contentW 128 | { 129 | CGSize size = self.contentSize; 130 | size.width = mj_contentW; 131 | self.contentSize = size; 132 | } 133 | 134 | - (CGFloat)mj_contentW 135 | { 136 | return self.contentSize.width; 137 | } 138 | 139 | - (void)setMj_contentH:(CGFloat)mj_contentH 140 | { 141 | CGSize size = self.contentSize; 142 | size.height = mj_contentH; 143 | self.contentSize = size; 144 | } 145 | 146 | - (CGFloat)mj_contentH 147 | { 148 | return self.contentSize.height; 149 | } 150 | @end 151 | #pragma clang diagnostic pop 152 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/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 insertSubview:mj_footer atIndex:0]; 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 | -------------------------------------------------------------------------------- /Example/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 | -------------------------------------------------------------------------------- /Example/Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - MJRefresh (3.1.15.3) 3 | - WMPageController (2.5.2) 4 | - WMPageController-JQHover (0.1.0): 5 | - WMPageController 6 | 7 | DEPENDENCIES: 8 | - MJRefresh 9 | - WMPageController-JQHover (from `../`) 10 | 11 | SPEC REPOS: 12 | https://github.com/cocoapods/specs.git: 13 | - MJRefresh 14 | - WMPageController 15 | 16 | EXTERNAL SOURCES: 17 | WMPageController-JQHover: 18 | :path: "../" 19 | 20 | SPEC CHECKSUMS: 21 | MJRefresh: b48380ae2b927b46c4ef000de9adb8dc748e1df7 22 | WMPageController: 0c7624d2b48e4f1ab92371688cf6744ed701575d 23 | WMPageController-JQHover: cf96b56ddfc48da5d367410863ce483e2d64a90d 24 | 25 | PODFILE CHECKSUM: db5828401da4c67c1c914a487342ff45f5ac7872 26 | 27 | COCOAPODS: 1.5.3 28 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/Joker.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 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/Joker.xcuserdatad/xcschemes/Pods-WMPageController-JQHover_Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/Joker.xcuserdatad/xcschemes/Pods-WMPageController-JQHover_Tests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/Joker.xcuserdatad/xcschemes/WMPageController-JQHover.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 47 | 48 | 54 | 55 | 56 | 57 | 58 | 59 | 65 | 66 | 68 | 69 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/Joker.xcuserdatad/xcschemes/WMPageController.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 | -------------------------------------------------------------------------------- /Example/Pods/Pods.xcodeproj/xcuserdata/Joker.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | MJRefresh.xcscheme 8 | 9 | isShown 10 | 11 | 12 | Pods-WMPageController-JQHover_Example.xcscheme 13 | 14 | isShown 15 | 16 | 17 | Pods-WMPageController-JQHover_Tests.xcscheme 18 | 19 | isShown 20 | 21 | 22 | WMPageController-JQHover.xcscheme 23 | 24 | isShown 25 | 26 | 27 | WMPageController.xcscheme 28 | 29 | isShown 30 | 31 | 32 | 33 | SuppressBuildableAutocreation 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/MJRefresh/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 | FMWK 17 | CFBundleShortVersionString 18 | 3.1.15 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/MJRefresh/MJRefresh-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_MJRefresh : NSObject 3 | @end 4 | @implementation PodsDummy_MJRefresh 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/MJRefresh/MJRefresh-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/MJRefresh/MJRefresh-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "MJRefreshAutoFooter.h" 14 | #import "MJRefreshBackFooter.h" 15 | #import "MJRefreshComponent.h" 16 | #import "MJRefreshFooter.h" 17 | #import "MJRefreshHeader.h" 18 | #import "MJRefreshAutoGifFooter.h" 19 | #import "MJRefreshAutoNormalFooter.h" 20 | #import "MJRefreshAutoStateFooter.h" 21 | #import "MJRefreshBackGifFooter.h" 22 | #import "MJRefreshBackNormalFooter.h" 23 | #import "MJRefreshBackStateFooter.h" 24 | #import "MJRefreshGifHeader.h" 25 | #import "MJRefreshNormalHeader.h" 26 | #import "MJRefreshStateHeader.h" 27 | #import "MJRefresh.h" 28 | #import "MJRefreshConst.h" 29 | #import "NSBundle+MJRefresh.h" 30 | #import "UIScrollView+MJExtension.h" 31 | #import "UIScrollView+MJRefresh.h" 32 | #import "UIView+MJExtension.h" 33 | 34 | FOUNDATION_EXPORT double MJRefreshVersionNumber; 35 | FOUNDATION_EXPORT const unsigned char MJRefreshVersionString[]; 36 | 37 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/MJRefresh/MJRefresh.modulemap: -------------------------------------------------------------------------------- 1 | framework module MJRefresh { 2 | umbrella header "MJRefresh-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/MJRefresh/MJRefresh.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | PODS_BUILD_DIR = ${BUILD_DIR} 4 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 5 | PODS_ROOT = ${SRCROOT} 6 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/MJRefresh 7 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 8 | SKIP_INSTALL = YES 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Example/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Example/Pods-WMPageController-JQHover_Example-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 | 27 | ## WMPageController 28 | 29 | The MIT License (MIT) 30 | 31 | Copyright (c) 2015 32 | 33 | Permission is hereby granted, free of charge, to any person obtaining a copy 34 | of this software and associated documentation files (the "Software"), to deal 35 | in the Software without restriction, including without limitation the rights 36 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 37 | copies of the Software, and to permit persons to whom the Software is 38 | furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in all 41 | copies or substantial portions of the Software. 42 | 43 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 44 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 45 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 46 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 47 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 48 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 49 | SOFTWARE. 50 | 51 | 52 | ## WMPageController-JQHover 53 | 54 | Copyright (c) 2018 coder-zjq 55 | 56 | Permission is hereby granted, free of charge, to any person obtaining a copy 57 | of this software and associated documentation files (the "Software"), to deal 58 | in the Software without restriction, including without limitation the rights 59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 60 | copies of the Software, and to permit persons to whom the Software is 61 | furnished to do so, subject to the following conditions: 62 | 63 | The above copyright notice and this permission notice shall be included in 64 | all copies or substantial portions of the Software. 65 | 66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 72 | THE SOFTWARE. 73 | 74 | Generated by CocoaPods - https://cocoapods.org 75 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Example/Pods-WMPageController-JQHover_Example-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 | License 38 | MIT 39 | Title 40 | MJRefresh 41 | Type 42 | PSGroupSpecifier 43 | 44 | 45 | FooterText 46 | The MIT License (MIT) 47 | 48 | Copyright (c) 2015 49 | 50 | Permission is hereby granted, free of charge, to any person obtaining a copy 51 | of this software and associated documentation files (the "Software"), to deal 52 | in the Software without restriction, including without limitation the rights 53 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 54 | copies of the Software, and to permit persons to whom the Software is 55 | furnished to do so, subject to the following conditions: 56 | 57 | The above copyright notice and this permission notice shall be included in all 58 | copies or substantial portions of the Software. 59 | 60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 61 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 62 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 63 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 64 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 65 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 66 | SOFTWARE. 67 | 68 | License 69 | MIT (LICENSE) 70 | Title 71 | WMPageController 72 | Type 73 | PSGroupSpecifier 74 | 75 | 76 | FooterText 77 | Copyright (c) 2018 coder-zjq <zjq_joker@163.com> 78 | 79 | Permission is hereby granted, free of charge, to any person obtaining a copy 80 | of this software and associated documentation files (the "Software"), to deal 81 | in the Software without restriction, including without limitation the rights 82 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 83 | copies of the Software, and to permit persons to whom the Software is 84 | furnished to do so, subject to the following conditions: 85 | 86 | The above copyright notice and this permission notice shall be included in 87 | all copies or substantial portions of the Software. 88 | 89 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 90 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 91 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 92 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 93 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 94 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 95 | THE SOFTWARE. 96 | 97 | License 98 | MIT 99 | Title 100 | WMPageController-JQHover 101 | Type 102 | PSGroupSpecifier 103 | 104 | 105 | FooterText 106 | Generated by CocoaPods - https://cocoapods.org 107 | Title 108 | 109 | Type 110 | PSGroupSpecifier 111 | 112 | 113 | StringsTable 114 | Acknowledgements 115 | Title 116 | Acknowledgements 117 | 118 | 119 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Example/Pods-WMPageController-JQHover_Example-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_WMPageController_JQHover_Example : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_WMPageController_JQHover_Example 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Example/Pods-WMPageController-JQHover_Example-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_WMPageController_JQHover_ExampleVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_WMPageController_JQHover_ExampleVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Example/Pods-WMPageController-JQHover_Example.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController" "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover/WMPageController_JQHover.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController/WMPageController.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "MJRefresh" -framework "WMPageController" -framework "WMPageController_JQHover" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Example/Pods-WMPageController-JQHover_Example.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_WMPageController_JQHover_Example { 2 | umbrella header "Pods-WMPageController-JQHover_Example-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Example/Pods-WMPageController-JQHover_Example.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController" "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover/WMPageController_JQHover.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController/WMPageController.framework/Headers" 5 | OTHER_LDFLAGS = $(inherited) -framework "MJRefresh" -framework "WMPageController" -framework "WMPageController_JQHover" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 9 | PODS_ROOT = ${SRCROOT}/Pods 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Tests/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 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Tests/Pods-WMPageController-JQHover_Tests-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | Generated by CocoaPods - https://cocoapods.org 4 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Tests/Pods-WMPageController-JQHover_Tests-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 | Generated by CocoaPods - https://cocoapods.org 18 | Title 19 | 20 | Type 21 | PSGroupSpecifier 22 | 23 | 24 | StringsTable 25 | Acknowledgements 26 | Title 27 | Acknowledgements 28 | 29 | 30 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Tests/Pods-WMPageController-JQHover_Tests-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_WMPageController_JQHover_Tests : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_WMPageController_JQHover_Tests 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Tests/Pods-WMPageController-JQHover_Tests-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_WMPageController_JQHover_TestsVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_WMPageController_JQHover_TestsVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Tests/Pods-WMPageController-JQHover_Tests.debug.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController" "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover/WMPageController_JQHover.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController/WMPageController.framework/Headers" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Tests/Pods-WMPageController-JQHover_Tests.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_WMPageController_JQHover_Tests { 2 | umbrella header "Pods-WMPageController-JQHover_Tests-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/Pods-WMPageController-JQHover_Tests/Pods-WMPageController-JQHover_Tests.release.xcconfig: -------------------------------------------------------------------------------- 1 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh" "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController" "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover" 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks' 4 | OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover/WMPageController_JQHover.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController/WMPageController.framework/Headers" 5 | PODS_BUILD_DIR = ${BUILD_DIR} 6 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 7 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 8 | PODS_ROOT = ${SRCROOT}/Pods 9 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController-JQHover/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 | FMWK 17 | CFBundleShortVersionString 18 | 0.1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController-JQHover/WMPageController-JQHover-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_WMPageController_JQHover : NSObject 3 | @end 4 | @implementation PodsDummy_WMPageController_JQHover 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController-JQHover/WMPageController-JQHover-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController-JQHover/WMPageController-JQHover-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "JQHoverFooterView.h" 14 | #import "JQHoverPage.h" 15 | #import "UIScrollView+JQExtension.h" 16 | #import "UIScrollView+JQHover.h" 17 | #import "UIView+JQExtension.h" 18 | #import "WMPageController+JQPage.h" 19 | 20 | FOUNDATION_EXPORT double WMPageController_JQHoverVersionNumber; 21 | FOUNDATION_EXPORT const unsigned char WMPageController_JQHoverVersionString[]; 22 | 23 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController-JQHover/WMPageController-JQHover.modulemap: -------------------------------------------------------------------------------- 1 | framework module WMPageController_JQHover { 2 | umbrella header "WMPageController-JQHover-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController-JQHover/WMPageController-JQHover.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/WMPageController-JQHover 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/WMPageController" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/../.. 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController/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 | FMWK 17 | CFBundleShortVersionString 18 | 2.5.2 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController/WMPageController-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_WMPageController : NSObject 3 | @end 4 | @implementation PodsDummy_WMPageController 5 | @end 6 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController/WMPageController-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController/WMPageController-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "UIViewController+WMPageController.h" 14 | #import "WMPageController.h" 15 | #import "WMMenuItem.h" 16 | #import "WMMenuView.h" 17 | #import "WMProgressView.h" 18 | #import "WMScrollView.h" 19 | 20 | FOUNDATION_EXPORT double WMPageControllerVersionNumber; 21 | FOUNDATION_EXPORT const unsigned char WMPageControllerVersionString[]; 22 | 23 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController/WMPageController.modulemap: -------------------------------------------------------------------------------- 1 | framework module WMPageController { 2 | umbrella header "WMPageController-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Example/Pods/Target Support Files/WMPageController/WMPageController.xcconfig: -------------------------------------------------------------------------------- 1 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/WMPageController 2 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 3 | OTHER_LDFLAGS = -framework "CoreGraphics" -framework "Foundation" -framework "UIKit" 4 | PODS_BUILD_DIR = ${BUILD_DIR} 5 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 6 | PODS_ROOT = ${SRCROOT} 7 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/WMPageController 8 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 9 | SKIP_INSTALL = YES 10 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/README.md: -------------------------------------------------------------------------------- 1 | # WMPageController [中文介绍](https://github.com/wangmchn/WMPageController/blob/master/README_zh-CN.md) 2 | [![Platform](http://img.shields.io/badge/platform-iOS-blue.svg?style=flat 3 | )](https://developer.apple.com/iphone/index.action) 4 | [![License](http://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat 5 | )](http://mit-license.org) 6 | ![CocoaPods Version](https://img.shields.io/badge/pod-v0.36.4-brightgreen.svg) 7 | 8 | An easy solution to page controllers like `NetEase News` 9 | ## Overview 10 | 11 | 12 | ## Change Log 13 | See [CHANGELOG](https://github.com/wangmchn/WMPageController/blob/master/CHANGELOG.md) for more information. 14 | 15 | ## Basic use 16 | Create an controller extends from `WMPageController`.There are two ways to init the `WMPageController`: 17 | 18 | #### Init with Classes 19 | Use the following constructor to init the controller: 20 | ```objective-c 21 | - (instancetype)initWithViewControllerClasses:(NSArray *)classes 22 | andTheirTitles:(NSArray *)titles; 23 | ``` 24 | Here are two important porperties: 25 | 26 | classes :contains the classes of child view controllers, just like [UITableViewController class]; 27 | titles :Each View controller's title to show in the menu view at the top of the view; 28 | 29 | #### Use datasource (Recommend This Way!) 30 | The usage is very familiar to `UITableView`, these are the methods need to implement: 31 | ```objective-c 32 | - (NSInteger)numbersOfChildControllersInPageController:(WMPageController *)pageController; 33 | 34 | - (__kindof UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index; 35 | 36 | - (NSString *)pageController:(WMPageController *)pageController titleAtIndex:(NSInteger)index; 37 | ``` 38 | Just implement these datasource methods in YOUR WMPageController after initialize it. 39 | 40 | ## Customize Content's Frame 41 | It's easy for you to customize your controller as following, just implement these two datasource methods.
42 | ``` 43 | - (CGRect)pageController:(WMPageController *)pageController preferredFrameForContentView:(WMScrollView *)contentView; 44 | 45 | - (CGRect)pageController:(WMPageController *)pageController preferredFrameForMenuView:(WMMenuView *)menuView; 46 | ``` 47 | When you want to change the frame of contentView, you need to call `-forceLayoutSubViews` method. This will recall the datasource method above and re-layout subviews. 48 | If you are interested, see `viewFrameExample` for more detail. 49 | 50 | ## Use Storyboard / xib 51 | 1.If you init the `WMPageController` with child controller's class,override the `-init` method in `WMPageController's childViewController`, For example: 52 | ```objective-c 53 | - (instancetype)init { 54 | return [self initWithNibName:@"xxxViewController" bundle:nil]; 55 | } 56 | ``` 57 | 2.If you are using datasource, Just implement `-pageController:viewControllerAtIndex:` as following: 58 | ```objective-c 59 | - (UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index { 60 | UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; 61 | UIViewController *vc = [sb instantiateViewControllerWithIdentifier:@"WMViewController"]; 62 | return vc; 63 | } 64 | ``` 65 | See `StoryboardExample` for more detail. 66 | 67 | ## Styles 68 | 69 | You can easily change style by setting `xxxPageController.style = WMMenuViewStyleLine`.
70 | If you want `menuView` to show on the navigation bar, set `.showOnNavigationBar = YES`; 71 | 72 | ## Using CocoaPods 73 | If you want the newest version, try 2.4.0 (This has some API modified) 74 | ``` 75 | pod 'WMPageController', '~> 2.4.0' 76 | ``` 77 | If you perfer the old, just use 2.3.0 and it's fine. 78 | ``` 79 | pod 'WMPageController', '2.3.0' 80 | ``` 81 | 82 | ## Note 83 | 1. If you have any trouble with content controller's frame or size,just try set `viewFrame` property, which make you free to customize your own size. 84 | 85 | 2. You can put every controller in `WMPageController`,But if you want have a `UICollectionViewController` in, please have an attention to `UICollectionViewController's` init method.
86 | You should override the `- init` to give `UICollectionViewController` a `UICollectionViewLayout`. 87 | Here is an example: 88 | ```objective-c 89 | - (instancetype)init { 90 | // init layout here... 91 | self = [self initWithCollectionViewLayout:layout]; 92 | if (self) { 93 | // insert code here... 94 | } 95 | return self; 96 | } 97 | ``` 98 | 99 | ## License 100 | This project is under MIT License. See LICENSE file for more information. 101 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/UIViewController+WMPageController.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+WMPageController.h 3 | // WMPageController 4 | // 5 | // Created by Mark on 15/6/11. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class WMPageController; 12 | 13 | @interface UIViewController (WMPageController) 14 | 15 | /** 16 | 获取控制器所在的WMPageController 17 | */ 18 | @property (nonatomic, nullable, strong, readonly) WMPageController *wm_pageController; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/UIViewController+WMPageController.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIViewController+WMPageController.m 3 | // WMPageController 4 | // 5 | // Created by Mark on 15/6/11. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import "UIViewController+WMPageController.h" 10 | #import "WMPageController.h" 11 | 12 | @implementation UIViewController (WMPageController) 13 | 14 | - (WMPageController *)wm_pageController { 15 | UIViewController *parentViewController = self.parentViewController; 16 | while (parentViewController) { 17 | if ([parentViewController isKindOfClass:[WMPageController class]]) { 18 | return (WMPageController *)parentViewController; 19 | } 20 | parentViewController = parentViewController.parentViewController; 21 | } 22 | return nil; 23 | } 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/WMMenuView/WMMenuItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // WMMenuItem.h 3 | // WMPageController 4 | // 5 | // Created by Mark on 15/4/26. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import 10 | @class WMMenuItem; 11 | 12 | typedef NS_ENUM(NSUInteger, WMMenuItemState) { 13 | WMMenuItemStateSelected, 14 | WMMenuItemStateNormal, 15 | }; 16 | 17 | NS_ASSUME_NONNULL_BEGIN 18 | @protocol WMMenuItemDelegate 19 | @optional 20 | - (void)didPressedMenuItem:(WMMenuItem *)menuItem; 21 | @end 22 | 23 | @interface WMMenuItem : UILabel 24 | 25 | @property (nonatomic, assign) CGFloat rate; ///> 设置 rate, 并刷新标题状态 (0~1) 26 | @property (nonatomic, assign) CGFloat normalSize; ///> Normal状态的字体大小,默认大小为15 27 | @property (nonatomic, assign) CGFloat selectedSize; ///> Selected状态的字体大小,默认大小为18 28 | @property (nonatomic, strong) UIColor *normalColor; ///> Normal状态的字体颜色,默认为黑色 (可动画) 29 | @property (nonatomic, strong) UIColor *selectedColor; ///> Selected状态的字体颜色,默认为红色 (可动画) 30 | @property (nonatomic, assign) CGFloat speedFactor; ///> 进度条的速度因数,默认 15,越小越快, 必须大于0 31 | @property (nonatomic, nullable, weak) id delegate; 32 | @property (nonatomic, assign, readonly) BOOL selected; 33 | 34 | - (void)setSelected:(BOOL)selected withAnimation:(BOOL)animation; 35 | 36 | @end 37 | NS_ASSUME_NONNULL_END 38 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/WMMenuView/WMMenuItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // WMMenuItem.m 3 | // WMPageController 4 | // 5 | // Created by Mark on 15/4/26. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import "WMMenuItem.h" 10 | 11 | @implementation WMMenuItem { 12 | CGFloat _selectedRed, _selectedGreen, _selectedBlue, _selectedAlpha; 13 | CGFloat _normalRed, _normalGreen, _normalBlue, _normalAlpha; 14 | int _sign; 15 | CGFloat _gap; 16 | CGFloat _step; 17 | __weak CADisplayLink *_link; 18 | } 19 | 20 | #pragma mark - Public Methods 21 | - (instancetype)initWithFrame:(CGRect)frame { 22 | if (self = [super initWithFrame:frame]) { 23 | self.normalColor = [UIColor blackColor]; 24 | self.selectedColor = [UIColor blackColor]; 25 | self.normalSize = 15; 26 | self.selectedSize = 18; 27 | self.numberOfLines = 0; 28 | 29 | [self setupGestureRecognizer]; 30 | } 31 | return self; 32 | } 33 | 34 | - (CGFloat)speedFactor { 35 | if (_speedFactor <= 0) { 36 | _speedFactor = 15.0; 37 | } 38 | return _speedFactor; 39 | } 40 | 41 | - (void)setupGestureRecognizer { 42 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(touchUpInside:)]; 43 | [self addGestureRecognizer:tap]; 44 | } 45 | 46 | - (void)setSelected:(BOOL)selected withAnimation:(BOOL)animation { 47 | _selected = selected; 48 | if (!animation) { 49 | self.rate = selected ? 1.0 : 0.0; 50 | return; 51 | } 52 | _sign = (selected == YES) ? 1 : -1; 53 | _gap = (selected == YES) ? (1.0 - self.rate) : (self.rate - 0.0); 54 | _step = _gap / self.speedFactor; 55 | if (_link) { 56 | [_link invalidate]; 57 | } 58 | CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(rateChange)]; 59 | [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; 60 | _link = link; 61 | } 62 | 63 | - (void)rateChange { 64 | if (_gap > 0.000001) { 65 | _gap -= _step; 66 | if (_gap < 0.0) { 67 | self.rate = (int)(self.rate + _sign * _step + 0.5); 68 | return; 69 | } 70 | self.rate += _sign * _step; 71 | } else { 72 | self.rate = (int)(self.rate + 0.5); 73 | [_link invalidate]; 74 | _link = nil; 75 | } 76 | } 77 | 78 | // 设置rate,并刷新标题状态 79 | - (void)setRate:(CGFloat)rate { 80 | if (rate < 0.0 || rate > 1.0) { return; } 81 | _rate = rate; 82 | CGFloat r = _normalRed + (_selectedRed - _normalRed) * rate; 83 | CGFloat g = _normalGreen + (_selectedGreen - _normalGreen) * rate; 84 | CGFloat b = _normalBlue + (_selectedBlue - _normalBlue) * rate; 85 | CGFloat a = _normalAlpha + (_selectedAlpha - _normalAlpha) * rate; 86 | self.textColor = [UIColor colorWithRed:r green:g blue:b alpha:a]; 87 | CGFloat minScale = self.normalSize / self.selectedSize; 88 | CGFloat trueScale = minScale + (1 - minScale)*rate; 89 | self.transform = CGAffineTransformMakeScale(trueScale, trueScale); 90 | } 91 | 92 | - (void)setSelectedColor:(UIColor *)selectedColor { 93 | _selectedColor = selectedColor; 94 | [selectedColor getRed:&_selectedRed green:&_selectedGreen blue:&_selectedBlue alpha:&_selectedAlpha]; 95 | } 96 | 97 | - (void)setNormalColor:(UIColor *)normalColor { 98 | _normalColor = normalColor; 99 | [normalColor getRed:&_normalRed green:&_normalGreen blue:&_normalBlue alpha:&_normalAlpha]; 100 | } 101 | 102 | - (void)touchUpInside:(id)sender { 103 | if ([self.delegate respondsToSelector:@selector(didPressedMenuItem:)]) { 104 | [self.delegate didPressedMenuItem:self]; 105 | } 106 | } 107 | 108 | @end 109 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/WMMenuView/WMMenuView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WMMenuView.h 3 | // WMPageController 4 | // 5 | // Created by Mark on 15/4/26. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WMMenuItem.h" 11 | #import "WMProgressView.h" 12 | @class WMMenuView; 13 | 14 | typedef NS_ENUM(NSUInteger, WMMenuViewStyle) { 15 | WMMenuViewStyleDefault, // 默认 16 | WMMenuViewStyleLine, // 带下划线 (若要选中字体大小不变,设置选中和非选中大小一样即可) 17 | WMMenuViewStyleTriangle, // 三角形 (progressHeight 为三角形的高, progressWidths 为底边长) 18 | WMMenuViewStyleFlood, // 涌入效果 (填充) 19 | WMMenuViewStyleFloodHollow, // 涌入效果 (空心的) 20 | WMMenuViewStyleSegmented, // 涌入带边框,即网易新闻选项卡 21 | }; 22 | 23 | // 原先基础上添加了几个方便布局的枚举,更多布局格式可以通过设置 `itemsMargins` 属性来自定义 24 | // 以下布局均只在 item 个数较少的情况下生效,即无法滚动 MenuView 时. 25 | typedef NS_ENUM(NSUInteger, WMMenuViewLayoutMode) { 26 | WMMenuViewLayoutModeScatter, // 默认的布局模式, item 会均匀分布在屏幕上,呈分散状 27 | WMMenuViewLayoutModeLeft, // Item 紧靠屏幕左侧 28 | WMMenuViewLayoutModeRight, // Item 紧靠屏幕右侧 29 | WMMenuViewLayoutModeCenter, // Item 紧挨且居中分布 30 | }; 31 | 32 | @protocol WMMenuViewDelegate 33 | @optional 34 | - (BOOL)menuView:(WMMenuView *)menu shouldSelesctedIndex:(NSInteger)index; 35 | - (void)menuView:(WMMenuView *)menu didSelesctedIndex:(NSInteger)index currentIndex:(NSInteger)currentIndex; 36 | - (CGFloat)menuView:(WMMenuView *)menu widthForItemAtIndex:(NSInteger)index; 37 | - (CGFloat)menuView:(WMMenuView *)menu itemMarginAtIndex:(NSInteger)index; 38 | - (CGFloat)menuView:(WMMenuView *)menu titleSizeForState:(WMMenuItemState)state atIndex:(NSInteger)index; 39 | - (UIColor *)menuView:(WMMenuView *)menu titleColorForState:(WMMenuItemState)state atIndex:(NSInteger)index; 40 | - (void)menuView:(WMMenuView *)menu didLayoutItemFrame:(WMMenuItem *)menuItem atIndex:(NSInteger)index; 41 | @end 42 | 43 | @protocol WMMenuViewDataSource 44 | 45 | @required 46 | - (NSInteger)numbersOfTitlesInMenuView:(WMMenuView *)menu; 47 | - (NSString *)menuView:(WMMenuView *)menu titleAtIndex:(NSInteger)index; 48 | 49 | @optional 50 | /** 51 | * 角标 (例如消息提醒的小红点) 的数据源方法,在 WMPageController 中实现这个方法来为 menuView 提供一个 badgeView 52 | 需要在返回的时候同时设置角标的 frame 属性,该 frame 为相对于 menuItem 的位置 53 | * 54 | * @param index 角标的序号 55 | * 56 | * @return 返回一个设置好 frame 的角标视图 57 | */ 58 | - (UIView *)menuView:(WMMenuView *)menu badgeViewAtIndex:(NSInteger)index; 59 | 60 | /** 61 | * 用于定制 WMMenuItem,可以对传出的 initialMenuItem 进行修改定制,也可以返回自己创建的子类,需要注意的是,此时的 item 的 frame 是不确定的,所以请勿根据此时的 frame 做计算! 62 | 如需根据 frame 修改,请使用代理 63 | * 64 | * @param menu 当前的 menuView,frame 也是不确定的 65 | * @param initialMenuItem 初始化完成的 menuItem 66 | * @param index Item 所属的位置; 67 | * 68 | * @return 定制完成的 MenuItem 69 | */ 70 | - (WMMenuItem *)menuView:(WMMenuView *)menu initialMenuItem:(WMMenuItem *)initialMenuItem atIndex:(NSInteger)index; 71 | 72 | @end 73 | 74 | @interface WMMenuView : UIView 75 | @property (nonatomic, strong) NSArray *progressWidths; 76 | @property (nonatomic, weak) WMProgressView *progressView; 77 | @property (nonatomic, assign) CGFloat progressHeight; 78 | @property (nonatomic, assign) WMMenuViewStyle style; 79 | @property (nonatomic, assign) WMMenuViewLayoutMode layoutMode; 80 | @property (nonatomic, assign) CGFloat contentMargin; 81 | @property (nonatomic, strong) UIColor *lineColor; 82 | @property (nonatomic, assign) CGFloat progressViewBottomSpace; 83 | @property (nonatomic, weak) id delegate; 84 | @property (nonatomic, weak) id dataSource; 85 | @property (nonatomic, weak) UIView *leftView; 86 | @property (nonatomic, weak) UIView *rightView; 87 | @property (nonatomic, copy) NSString *fontName; 88 | @property (nonatomic, weak) UIScrollView *scrollView; 89 | /** 进度条的速度因数,默认为 15,越小越快, 大于 0 */ 90 | @property (nonatomic, assign) CGFloat speedFactor; 91 | @property (nonatomic, assign) CGFloat progressViewCornerRadius; 92 | @property (nonatomic, assign) BOOL progressViewIsNaughty; 93 | @property (nonatomic, assign) BOOL showOnNavigationBar; 94 | 95 | - (void)slideMenuAtProgress:(CGFloat)progress; 96 | - (void)selectItemAtIndex:(NSInteger)index; 97 | - (void)resetFrames; 98 | - (void)reload; 99 | - (void)updateTitle:(NSString *)title atIndex:(NSInteger)index andWidth:(BOOL)update; 100 | - (void)updateAttributeTitle:(NSAttributedString *)title atIndex:(NSInteger)index andWidth:(BOOL)update; 101 | - (WMMenuItem *)itemAtIndex:(NSInteger)index; 102 | /// 立即刷新 menuView 的 contentOffset,使 title 居中 103 | - (void)refreshContenOffset; 104 | - (void)deselectedItemsIfNeeded; 105 | /** 106 | * 更新角标视图,如要移除,在 -menuView:badgeViewAtIndex: 中返回 nil 即可 107 | */ 108 | - (void)updateBadgeViewAtIndex:(NSInteger)index; 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/WMMenuView/WMProgressView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WMProgressView.h 3 | // WMPageController 4 | // 5 | // Created by Mark on 15/6/20. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | NS_ASSUME_NONNULL_BEGIN 12 | @interface WMProgressView : UIView 13 | @property (nonatomic, strong) NSArray *itemFrames; 14 | @property (nonatomic, assign) CGColorRef color; 15 | @property (nonatomic, assign) CGFloat progress; 16 | /** 进度条的速度因数,默认为 15,越小越快, 大于 0 */ 17 | @property (nonatomic, assign) CGFloat speedFactor; 18 | @property (nonatomic, assign) CGFloat cornerRadius; 19 | /// 调皮属性,用于实现新腾讯视频效果 20 | @property (nonatomic, assign) BOOL naughty; 21 | @property (nonatomic, assign) BOOL isTriangle; 22 | @property (nonatomic, assign) BOOL hollow; 23 | @property (nonatomic, assign) BOOL hasBorder; 24 | 25 | - (void)setProgressWithOutAnimate:(CGFloat)progress; 26 | - (void)moveToPostion:(NSInteger)pos; 27 | 28 | @end 29 | NS_ASSUME_NONNULL_END 30 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/WMMenuView/WMProgressView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WMProgressView.m 3 | // WMPageController 4 | // 5 | // Created by Mark on 15/6/20. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import "WMProgressView.h" 10 | @implementation WMProgressView { 11 | int _sign; 12 | CGFloat _gap; 13 | CGFloat _step; 14 | __weak CADisplayLink *_link; 15 | } 16 | 17 | - (CGFloat)speedFactor { 18 | if (_speedFactor <= 0) { 19 | _speedFactor = 15.0; 20 | } 21 | return _speedFactor; 22 | } 23 | 24 | - (void)setProgressWithOutAnimate:(CGFloat)progress { 25 | if (self.progress == progress) return; 26 | _progress = progress; 27 | [self setNeedsDisplay]; 28 | } 29 | 30 | - (void)setNaughty:(BOOL)naughty { 31 | _naughty = naughty; 32 | [self setNeedsDisplay]; 33 | } 34 | 35 | - (void)setCornerRadius:(CGFloat)cornerRadius { 36 | _cornerRadius = cornerRadius; 37 | [self setNeedsDisplay]; 38 | } 39 | 40 | - (void)moveToPostion:(NSInteger)pos { 41 | _gap = fabs(self.progress - pos); 42 | _sign = self.progress > pos ? -1 : 1; 43 | _step = _gap / self.speedFactor; 44 | if (_link) { 45 | [_link invalidate]; 46 | } 47 | CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(progressChanged)]; 48 | [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; 49 | _link = link; 50 | } 51 | 52 | - (void)setProgress:(CGFloat)progress { 53 | if (self.progress == progress) return; 54 | _progress = progress; 55 | [self setNeedsDisplay]; 56 | } 57 | 58 | - (void)progressChanged { 59 | if (_gap > 0.000001) { 60 | _gap -= _step; 61 | if (_gap < 0.0) { 62 | self.progress = (int)(self.progress + _sign * _step + 0.5); 63 | return; 64 | } 65 | self.progress += _sign * _step; 66 | } else { 67 | self.progress = (int)(self.progress + 0.5); 68 | [_link invalidate]; 69 | _link = nil; 70 | } 71 | } 72 | 73 | - (void)drawRect:(CGRect)rect { 74 | // Drawing code 75 | [super drawRect:rect]; 76 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 77 | CGFloat height = self.frame.size.height; 78 | int index = (int)self.progress; 79 | index = (index <= self.itemFrames.count - 1) ? index : (int)self.itemFrames.count - 1; 80 | CGFloat rate = self.progress - index; 81 | CGRect currentFrame = [self.itemFrames[index] CGRectValue]; 82 | CGFloat currentWidth = currentFrame.size.width; 83 | int nextIndex = index + 1 < self.itemFrames.count ? index + 1 : index; 84 | CGFloat nextWidth = [self.itemFrames[nextIndex] CGRectValue].size.width; 85 | 86 | CGFloat currentX = currentFrame.origin.x; 87 | CGFloat nextX = [self.itemFrames[nextIndex] CGRectValue].origin.x; 88 | CGFloat startX = currentX + (nextX - currentX) * rate; 89 | CGFloat width = currentWidth + (nextWidth - currentWidth)*rate; 90 | CGFloat endX = startX + width; 91 | 92 | if (self.naughty) { 93 | CGFloat currentMidX = currentX + currentWidth / 2.0; 94 | CGFloat nextMidX = nextX + nextWidth / 2.0; 95 | 96 | if (rate <= 0.5) { 97 | startX = currentX + (currentMidX - currentX) * rate * 2.0; 98 | CGFloat currentMaxX = currentX + currentWidth; 99 | endX = currentMaxX + (nextMidX - currentMaxX) * rate * 2.0; 100 | } else { 101 | startX = currentMidX + (nextX - currentMidX) * (rate - 0.5) * 2.0; 102 | CGFloat nextMaxX = nextX + nextWidth; 103 | endX = nextMidX + (nextMaxX - nextMidX) * (rate - 0.5) * 2.0; 104 | } 105 | width = endX - startX; 106 | } 107 | 108 | CGFloat lineWidth = (self.hollow || self.hasBorder) ? 1.0 : 0.0; 109 | 110 | if (self.isTriangle) { 111 | CGContextMoveToPoint(ctx, startX, height); 112 | CGContextAddLineToPoint(ctx, endX, height); 113 | CGContextAddLineToPoint(ctx, startX + width / 2.0, 0); 114 | CGContextClosePath(ctx); 115 | CGContextSetFillColorWithColor(ctx, self.color); 116 | CGContextFillPath(ctx); 117 | return; 118 | } 119 | 120 | UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(startX, lineWidth / 2.0, width, height - lineWidth) cornerRadius:self.cornerRadius]; 121 | CGContextAddPath(ctx, path.CGPath); 122 | 123 | if (self.hollow) { 124 | CGContextSetStrokeColorWithColor(ctx, self.color); 125 | CGContextStrokePath(ctx); 126 | return; 127 | } 128 | CGContextSetFillColorWithColor(ctx, self.color); 129 | CGContextFillPath(ctx); 130 | 131 | if (self.hasBorder) { 132 | // 计算点 133 | CGFloat startX = CGRectGetMinX([self.itemFrames.firstObject CGRectValue]); 134 | CGFloat endX = CGRectGetMaxX([self.itemFrames.lastObject CGRectValue]); 135 | UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(startX, lineWidth / 2.0, (endX - startX), height - lineWidth) cornerRadius:self.cornerRadius]; 136 | CGContextSetLineWidth(ctx, lineWidth); 137 | CGContextAddPath(ctx, path.CGPath); 138 | 139 | // 绘制 140 | CGContextSetStrokeColorWithColor(ctx, self.color); 141 | CGContextStrokePath(ctx); 142 | } 143 | } 144 | 145 | @end 146 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/WMMenuView/WMScrollView.h: -------------------------------------------------------------------------------- 1 | // 2 | // WMScrollView.h 3 | // WMPageController 4 | // 5 | // Created by lh on 15/11/21. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WMScrollView : UIScrollView 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/Pods/WMPageController/WMPageController/WMMenuView/WMScrollView.m: -------------------------------------------------------------------------------- 1 | // 2 | // WMScrollView.m 3 | // WMPageController 4 | // 5 | // Created by lh on 15/11/21. 6 | // Copyright (c) 2015年 yq. All rights reserved. 7 | // 8 | 9 | #import "WMScrollView.h" 10 | 11 | @implementation WMScrollView 12 | 13 | #pragma mark - 14 | 15 | - (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 16 | //MARK: UITableViewCell 删除手势 17 | if ([NSStringFromClass(otherGestureRecognizer.view.class) isEqualToString:@"UITableViewWrapperView"] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) { 18 | return YES; 19 | } 20 | return NO; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /Example/Tests/Tests-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 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /Example/Tests/Tests-Prefix.pch: -------------------------------------------------------------------------------- 1 | // The contents of this file are implicitly included at the beginning of every test case source file. 2 | 3 | #ifdef __OBJC__ 4 | 5 | 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /Example/Tests/Tests.m: -------------------------------------------------------------------------------- 1 | // 2 | // WMPageController-JQHoverTests.m 3 | // WMPageController-JQHoverTests 4 | // 5 | // Created by coder-zjq on 07/24/2018. 6 | // Copyright (c) 2018 coder-zjq. All rights reserved. 7 | // 8 | 9 | @import XCTest; 10 | 11 | @interface Tests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation Tests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | 36 | -------------------------------------------------------------------------------- /Example/Tests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover.xcodeproj/xcshareddata/xcschemes/WMPageController-JQHover-Example.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 66 | 68 | 74 | 75 | 76 | 77 | 78 | 79 | 85 | 87 | 93 | 94 | 95 | 96 | 98 | 99 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover.xcworkspace/xcuserdata/Joker.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/e6dd5bec3c564f9a10959cbdc83e56b9ac7c5599/Example/WMPageController-JQHover.xcworkspace/xcuserdata/Joker.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQAppDelegate.h 3 | // WMPageController-JQHover 4 | // 5 | // Created by coder-zjq on 07/24/2018. 6 | // Copyright (c) 2018 coder-zjq. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface JQAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // JQAppDelegate.m 3 | // WMPageController-JQHover 4 | // 5 | // Created by coder-zjq on 07/24/2018. 6 | // Copyright (c) 2018 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import "JQAppDelegate.h" 10 | 11 | @implementation JQAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // 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. 22 | // 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. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // 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. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // 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. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQCollectionViewDemoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQCollectionViewDemoController.h 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/9. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JQCollectionViewDemoController : UICollectionViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQCollectionViewDemoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JQCollectionViewDemoController.m 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/9. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import "JQCollectionViewDemoController.h" 10 | #import "JQHoverPage.h" 11 | #import "JQDemoPageController.h" 12 | #import "MJRefresh.h" 13 | 14 | @interface JQCollectionViewDemoController () 15 | 16 | @end 17 | 18 | @implementation JQCollectionViewDemoController 19 | 20 | static NSString * const reuseIdentifier = @"Cell"; 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | 25 | // Uncomment the following line to preserve selection between presentations 26 | // self.clearsSelectionOnViewWillAppear = NO; 27 | 28 | // Register cell classes 29 | self.collectionView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ 30 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 31 | [self.collectionView.mj_header endRefreshing]; 32 | }); 33 | }]; 34 | [self.collectionView registerClass:[UICollectionViewCell class] forCellWithReuseIdentifier:reuseIdentifier]; 35 | UICollectionViewFlowLayout *layout = (UICollectionViewFlowLayout *)self.collectionViewLayout; 36 | layout.itemSize = CGSizeMake(40, 40); 37 | layout.minimumLineSpacing = 10; 38 | layout.minimumInteritemSpacing = 10; 39 | layout.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10); 40 | 41 | // 1. init the hover footer view page 42 | CGFloat height = [UIScreen mainScreen].bounds.size.height - CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - CGRectGetHeight(self.navigationController.navigationBar.frame); 43 | JQHoverFooterView *footerView = [[JQHoverFooterView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, height)]; 44 | 45 | // 2. init the page and add the page to current controller's child view controller 46 | JQDemoPageController *page = [[JQDemoPageController alloc] init]; 47 | [self addChildViewController:page]; 48 | 49 | // 3. set the page to hover footer view, set the jq_hoverFooter to collectionView 50 | footerView.page = page; 51 | self.collectionView.jq_hoverFooter = footerView; 52 | // Do any additional setup after loading the view. 53 | } 54 | 55 | - (void)didReceiveMemoryWarning { 56 | [super didReceiveMemoryWarning]; 57 | // Dispose of any resources that can be recreated. 58 | } 59 | 60 | /* 61 | #pragma mark - Navigation 62 | 63 | // In a storyboard-based application, you will often want to do a little preparation before navigation 64 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 65 | // Get the new view controller using [segue destinationViewController]. 66 | // Pass the selected object to the new view controller. 67 | } 68 | */ 69 | 70 | #pragma mark 71 | 72 | - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { 73 | return 30; 74 | } 75 | 76 | - (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { 77 | UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath]; 78 | cell.backgroundColor = [UIColor redColor]; 79 | return cell; 80 | } 81 | 82 | 83 | #pragma mark 84 | 85 | /* 86 | // Uncomment this method to specify if the specified item should be highlighted during tracking 87 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldHighlightItemAtIndexPath:(NSIndexPath *)indexPath { 88 | return YES; 89 | } 90 | */ 91 | 92 | /* 93 | // Uncomment this method to specify if the specified item should be selected 94 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldSelectItemAtIndexPath:(NSIndexPath *)indexPath { 95 | return YES; 96 | } 97 | */ 98 | 99 | /* 100 | // Uncomment these methods to specify if an action menu should be displayed for the specified item, and react to actions performed on the item 101 | - (BOOL)collectionView:(UICollectionView *)collectionView shouldShowMenuForItemAtIndexPath:(NSIndexPath *)indexPath { 102 | return NO; 103 | } 104 | 105 | - (BOOL)collectionView:(UICollectionView *)collectionView canPerformAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { 106 | return NO; 107 | } 108 | 109 | - (void)collectionView:(UICollectionView *)collectionView performAction:(SEL)action forItemAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender { 110 | 111 | } 112 | */ 113 | 114 | @end 115 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQDemoPageController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQDemoPageController.h 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/9. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import "WMPageController+JQPage.h" 10 | 11 | @interface JQDemoPageController : WMPageController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQDemoPageController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JQDemoPageController.m 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/9. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import "JQDemoPageController.h" 10 | #import "JQDemoSubpageController.h" 11 | 12 | #define kScreenW [[UIScreen mainScreen] bounds].size.width 13 | #define kScreenH [[UIScreen mainScreen] bounds].size.height 14 | #define kStatusBarHeight ([UIApplication sharedApplication].statusBarFrame.size.height) 15 | @interface JQDemoPageController () 16 | 17 | @end 18 | 19 | @implementation JQDemoPageController 20 | 21 | - (void)viewDidLoad { 22 | [super viewDidLoad]; 23 | self.menuView.backgroundColor = [UIColor colorWithWhite:.9f alpha:1.f]; 24 | } 25 | 26 | - (void)didReceiveMemoryWarning { 27 | [super didReceiveMemoryWarning]; 28 | // Dispose of any resources that can be recreated. 29 | } 30 | 31 | - (NSInteger)numbersOfChildControllersInPageController:(WMPageController *)pageController { 32 | return 5; 33 | } 34 | 35 | - (NSString *)menuView:(WMMenuView *)menu titleAtIndex:(NSInteger)index { 36 | return [NSString stringWithFormat:@"page %ld", (long)index]; 37 | } 38 | 39 | - (CGRect)pageController:(WMPageController *)pageController preferredFrameForMenuView:(WMMenuView *)menuView { 40 | return CGRectMake(0, 0, kScreenW, 36); 41 | } 42 | 43 | - (CGRect)pageController:(WMPageController *)pageController preferredFrameForContentView:(nonnull WMScrollView *)contentView { 44 | return CGRectMake(0, 36, kScreenW, kScreenH - 64 -36); 45 | } 46 | 47 | //- (UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index { 48 | // JQDemoSubpageController *vc = [[JQDemoSubpageController alloc] init]; 49 | // return vc; 50 | //} 51 | 52 | - (UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index { 53 | JQDemoSubpageController *vc = [[JQDemoSubpageController alloc] init]; 54 | return vc; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQDemoSubpageController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQDemoSubpageController.h 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/9. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "WMPageController+JQPage.h" 11 | 12 | @interface JQDemoSubpageController : UITableViewController 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQDemoSubpageController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JQDemoSubpageController.m 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/9. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import "JQDemoSubpageController.h" 10 | #import "MJRefresh.h" 11 | 12 | @interface JQDemoSubpageController () 13 | 14 | @end 15 | 16 | @implementation JQDemoSubpageController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | self.tableView.rowHeight = 44.f; 21 | [self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:@"cell"]; 22 | self.tableView.mj_footer = [MJRefreshBackNormalFooter footerWithRefreshingBlock:^{ 23 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 24 | [self.tableView.mj_footer endRefreshing]; 25 | }); 26 | }]; 27 | } 28 | 29 | - (void)didReceiveMemoryWarning { 30 | [super didReceiveMemoryWarning]; 31 | // Dispose of any resources that can be recreated. 32 | } 33 | 34 | #pragma mark - Table view data source 35 | 36 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 37 | return 30; 38 | } 39 | 40 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 41 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell" forIndexPath:indexPath]; 42 | cell.textLabel.text = [NSString stringWithFormat:@"cell %ld", (long)indexPath.row]; 43 | return cell; 44 | } 45 | 46 | #pragma mark - 47 | #pragma mark - JQSubpageControllerDelegate 48 | 49 | - (UIScrollView *)scrollView { 50 | return self.tableView; 51 | } 52 | 53 | /* 54 | // Override to support conditional editing of the table view. 55 | - (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath { 56 | // Return NO if you do not want the specified item to be editable. 57 | return YES; 58 | } 59 | */ 60 | 61 | /* 62 | // Override to support editing the table view. 63 | - (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath { 64 | if (editingStyle == UITableViewCellEditingStyleDelete) { 65 | // Delete the row from the data source 66 | [tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade]; 67 | } else if (editingStyle == UITableViewCellEditingStyleInsert) { 68 | // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view 69 | } 70 | } 71 | */ 72 | 73 | /* 74 | // Override to support rearranging the table view. 75 | - (void)tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { 76 | } 77 | */ 78 | 79 | /* 80 | // Override to support conditional rearranging of the table view. 81 | - (BOOL)tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { 82 | // Return NO if you do not want the item to be re-orderable. 83 | return YES; 84 | } 85 | */ 86 | 87 | /* 88 | #pragma mark - Navigation 89 | 90 | // In a storyboard-based application, you will often want to do a little preparation before navigation 91 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 92 | // Get the new view controller using [segue destinationViewController]. 93 | // Pass the selected object to the new view controller. 94 | } 95 | */ 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQScrollViewDemoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQScrollViewDemoController.h 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/21. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JQScrollViewDemoController : UIViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQScrollViewDemoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JQScrollViewDemoController.m 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/21. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import "JQScrollViewDemoController.h" 10 | #import "JQHoverPage.h" 11 | #import "JQDemoPageController.h" 12 | #import "MJRefresh.h" 13 | 14 | @interface JQScrollViewDemoController () 15 | 16 | @property (strong, nonatomic) IBOutlet UIScrollView *scrollView; 17 | 18 | @end 19 | 20 | @implementation JQScrollViewDemoController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | // Do any additional setup after loading the view. 25 | self.automaticallyAdjustsScrollViewInsets = NO; 26 | self.scrollView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ 27 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 28 | [self.scrollView.mj_header endRefreshing]; 29 | }); 30 | }]; 31 | 32 | // 1. init the hover footer view page 33 | CGFloat height = [UIScreen mainScreen].bounds.size.height - CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - CGRectGetHeight(self.navigationController.navigationBar.frame); 34 | JQHoverFooterView *footerView = [[JQHoverFooterView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, height)]; 35 | 36 | // 2. init the page and add the page to current controller's child view controller 37 | JQDemoPageController *page = [[JQDemoPageController alloc] init]; 38 | [self addChildViewController:page]; 39 | 40 | // 3. set the page to hover footer view, set the jq_hoverFooter to collectionView 41 | footerView.page = page; 42 | self.scrollView.jq_hoverFooter = footerView; 43 | } 44 | 45 | - (void)didReceiveMemoryWarning { 46 | [super didReceiveMemoryWarning]; 47 | // Dispose of any resources that can be recreated. 48 | } 49 | 50 | /* 51 | #pragma mark - Navigation 52 | 53 | // In a storyboard-based application, you will often want to do a little preparation before navigation 54 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 55 | // Get the new view controller using [segue destinationViewController]. 56 | // Pass the selected object to the new view controller. 57 | } 58 | */ 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQTableViewDemoController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQTableViewDemoController.h 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/9. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface JQTableViewDemoController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQTableViewDemoController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JQTableViewDemoController.m 3 | // JQHoverPage_Example 4 | // 5 | // Created by Joker on 2018/7/9. 6 | // Copyright © 2018年 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import "JQTableViewDemoController.h" 10 | #import "JQHoverPage.h" 11 | #import "JQDemoPageController.h" 12 | #import "MJRefresh.h" 13 | 14 | @interface JQTableViewDemoController () 15 | 16 | @end 17 | 18 | @implementation JQTableViewDemoController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | 23 | // set up the tableView 24 | self.tableView.tableFooterView = [UIView new]; 25 | self.tableView.showsVerticalScrollIndicator = NO; 26 | self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ 27 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.f * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 28 | [self.tableView.mj_header endRefreshing]; 29 | }); 30 | }]; 31 | 32 | // setup the table header view 33 | UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 0, 100)]; 34 | label.backgroundColor = [UIColor redColor]; 35 | label.numberOfLines = 0; 36 | label.textAlignment = NSTextAlignmentCenter; 37 | label.textColor = [UIColor whiteColor]; 38 | label.text = @"This is tableView tableHeaderView.\nYou can replace it with your custom tableHeaderView."; 39 | self.tableView.tableHeaderView = label; 40 | 41 | // 1. init the hover footer view page 42 | CGFloat height = [UIScreen mainScreen].bounds.size.height - CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - CGRectGetHeight(self.navigationController.navigationBar.frame); 43 | JQHoverFooterView *footerView = [[JQHoverFooterView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, height)]; 44 | 45 | // 2. init the page and add the page to current controller's child view controller 46 | JQDemoPageController *page = [[JQDemoPageController alloc] init]; 47 | [self addChildViewController:page]; 48 | 49 | // 3. set the page to hover footer view, set the jq_hoverFooter to tableView 50 | footerView.page = page; 51 | self.tableView.jq_hoverFooter = footerView; 52 | 53 | } 54 | 55 | 56 | - (void)didReceiveMemoryWarning { 57 | [super didReceiveMemoryWarning]; 58 | // Dispose of any resources that can be recreated. 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQViewController.h 3 | // JQHoverPage 4 | // 5 | // Created by coder-zjq on 06/09/2018. 6 | // Copyright (c) 2018 coder-zjq. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | 11 | @interface JQViewController : UITableViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/JQViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JQViewController.m 3 | // JQHoverPage 4 | // 5 | // Created by coder-zjq on 06/09/2018. 6 | // Copyright (c) 2018 coder-zjq. All rights reserved. 7 | // 8 | 9 | #import "JQViewController.h" 10 | 11 | @interface JQViewController () 12 | 13 | @end 14 | 15 | @implementation JQViewController 16 | 17 | - (void)viewDidLoad 18 | { 19 | [super viewDidLoad]; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/WMPageController-JQHover-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UILaunchStoryboardName 28 | LaunchScreen 29 | UIMainStoryboardFile 30 | Main 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UISupportedInterfaceOrientations 36 | 37 | UIInterfaceOrientationPortrait 38 | UIInterfaceOrientationLandscapeLeft 39 | UIInterfaceOrientationLandscapeRight 40 | 41 | UISupportedInterfaceOrientations~ipad 42 | 43 | UIInterfaceOrientationPortrait 44 | UIInterfaceOrientationPortraitUpsideDown 45 | UIInterfaceOrientationLandscapeLeft 46 | UIInterfaceOrientationLandscapeRight 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/WMPageController-JQHover-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | @import UIKit; 15 | @import Foundation; 16 | #endif 17 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Example/WMPageController-JQHover/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // WMPageController-JQHover 4 | // 5 | // Created by coder-zjq on 07/24/2018. 6 | // Copyright (c) 2018 coder-zjq. All rights reserved. 7 | // 8 | 9 | @import UIKit; 10 | #import "JQAppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) 13 | { 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([JQAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/e6dd5bec3c564f9a10959cbdc83e56b9ac7c5599/Images/demo.gif -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018 coder-zjq 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JQHoverPage 2 | 3 | [![Version](https://img.shields.io/cocoapods/v/WMPageController-JQHover.svg?style=flat)](https://cocoapods.org/pods/WMPageController-JQHover) 4 | [![License](https://img.shields.io/cocoapods/l/WMPageController-JQHover.svg?style=flat)](https://cocoapods.org/pods/WMPageController-JQHover) 5 | [![Platform](https://img.shields.io/cocoapods/p/WMPageController-JQHover.svg?style=flat)](https://cocoapods.org/pods/JQHoverPage) 6 | 7 | ## Example 8 | 9 | To run the example project, clone the repo, and run `pod install` from the Example directory first. 10 | 11 | ![Example](https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/master/Images/demo.gif) 12 | 13 | ## Requirements 14 | 15 | iOS 8.0 + 16 | 17 | ## Installation 18 | 19 | JQHoverPage is available through [CocoaPods](https://cocoapods.org). To install it, simply add the following line to your Podfile: 20 | 21 | ```ruby 22 | pod 'WMPageController-JQHover' 23 | ``` 24 | ## Usage 25 | 26 | #### Setup the page use WMPageController([click to see more detail](https://github.com/wangmchn/WMPageController)) 27 | 28 | Main Page 29 | 30 | ``` objc 31 | 32 | #import "WMPageController+JQPage.h" 33 | 34 | @interface JQDemoPageController : WMPageController 35 | 36 | @end 37 | 38 | @implementation JQDemoPageController 39 | 40 | - (void)viewDidLoad { 41 | [super viewDidLoad]; 42 | self.menuView.backgroundColor = [UIColor colorWithWhite:.9f alpha:1.f]; 43 | } 44 | 45 | // the view controller should confirm the JQSubpageControllerDelegate protocol 46 | - (UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index { 47 | JQDemoSubpageController *vc = [[JQDemoSubpageController alloc] init]; 48 | return vc; 49 | } 50 | ``` 51 | 52 | Sub Page 53 | 54 | ```objc 55 | #import 56 | #import "WMPageController+JQPage.h" 57 | // subpage view controller should confirm the JQSubpageControllerDelegate protocol 58 | @interface JQDemoSubpageController : UITableViewController 59 | 60 | @end 61 | 62 | 63 | @implementation JQDemoSubpageController 64 | 65 | #pragma mark - 66 | #pragma mark - JQSubpageControllerDelegate 67 | 68 | // implementation JQSubpageControllerDelegate protocol, return the subpage scrollView. 69 | - (UIScrollView *)scrollView { 70 | return self.tableView; 71 | } 72 | ``` 73 | 74 | 75 | 76 | #### Append the page to UITableView / UICollectionView / UIScrollView 77 | 78 | UITableView 79 | 80 | ``` objc 81 | // 1. init the hover footer view page 82 | CGFloat height = [UIScreen mainScreen].bounds.size.height - CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - CGRectGetHeight(self.navigationController.navigationBar.frame); 83 | JQHoverFooterView *footerView = [[JQHoverFooterView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, height)]; 84 | 85 | // 2. init the page and add the page to current controller's child view controller 86 | JQDemoPageController *page = [[JQDemoPageController alloc] init]; 87 | [self addChildViewController:page]; 88 | 89 | // 3. set the page to hover footer view, set the jq_hoverFooter to tableView 90 | footerView.page = page; 91 | self.tableView.jq_hoverFooter = footerView; 92 | ``` 93 | 94 | 95 | 96 | UICollectionView 97 | 98 | ``` objc 99 | // 1. init the hover footer view page 100 | CGFloat height = [UIScreen mainScreen].bounds.size.height - CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - CGRectGetHeight(self.navigationController.navigationBar.frame); 101 | JQHoverFooterView *footerView = [[JQHoverFooterView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, height)]; 102 | 103 | // 2. init the page and add the page to current controller's child view controller 104 | JQDemoPageController *page = [[JQDemoPageController alloc] init]; 105 | [self addChildViewController:page]; 106 | 107 | // 3. set the page to hover footer view, set the jq_hoverFooter to collectionView 108 | footerView.page = page; 109 | self.collectionView.jq_hoverFooter = footerView; 110 | ``` 111 | 112 | 113 | 114 | UIScrollView 115 | 116 | ```objc 117 | // 1. init the hover footer view page 118 | CGFloat height = [UIScreen mainScreen].bounds.size.height - CGRectGetHeight([UIApplication sharedApplication].statusBarFrame) - CGRectGetHeight(self.navigationController.navigationBar.frame); 119 | JQHoverFooterView *footerView = [[JQHoverFooterView alloc] initWithFrame:CGRectMake(0, 0, [UIScreen mainScreen].bounds.size.width, height)]; 120 | 121 | // 2. init the page and add the page to current controller's child view controller 122 | JQDemoPageController *page = [[JQDemoPageController alloc] init]; 123 | [self addChildViewController:page]; 124 | 125 | // 3. set the page to hover footer view, set the jq_hoverFooter to collectionView 126 | footerView.page = page; 127 | self.scrollView.jq_hoverFooter = footerView; 128 | ``` 129 | 130 | (See more detail in Example project) 131 | 132 | ## Thanks To 133 | 134 | [WMPageController](https://github.com/wangmchn/WMPageController): provide the page implementation. 135 | 136 | [MJRefresh](https://github.com/CoderMJLee/MJRefresh ): provide the idea of this project. 137 | 138 | 139 | ## Author 140 | 141 | coder-zjq, zjq_joker@163.com 142 | 143 | ## License 144 | 145 | JQHoverPage is available under the MIT license. See the LICENSE file for more info. 146 | 147 | -------------------------------------------------------------------------------- /WMPageController-JQHover.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod lib lint WMPageController-JQHover.podspec' to ensure this is a 3 | # valid spec before submitting. 4 | # 5 | # Any lines starting with a # are optional, but their use is encouraged 6 | # To learn more about a Podspec see https://guides.cocoapods.org/syntax/podspec.html 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | s.name = 'WMPageController-JQHover' 11 | s.version = '0.1.0' 12 | s.summary = 'Extension of WMPageController, implement pages hover menu.' 13 | 14 | # This description is used to generate tags and improve search results. 15 | # * Think: What does it do? Why did you write it? What is the focus? 16 | # * Try to keep it short, snappy and to the point. 17 | # * Write the description between the DESC delimiters below. 18 | # * Finally, don't worry about the indent, CocoaPods strips it! 19 | 20 | s.description = <<-DESC 21 | Extension of WMPageController, implement pages hover menu. 22 | Same style as WMPageController. Painless to use. 23 | DESC 24 | 25 | s.homepage = 'https://github.com/coder-zjq/WMPageController-JQHover' 26 | s.screenshots = 'https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/master/Images/demo.gif' 27 | s.license = { :type => 'MIT', :file => 'LICENSE' } 28 | s.author = { 'coder-zjq' => 'zjq_joker@163.com' } 29 | s.source = { :git => 'https://github.com/coder-zjq/WMPageController-JQHover.git', :tag => s.version.to_s } 30 | # s.social_media_url = 'https://twitter.com/' 31 | 32 | s.ios.deployment_target = '8.0' 33 | 34 | s.source_files = 'WMPageController-JQHover/Classes/**/*' 35 | 36 | # s.resource_bundles = { 37 | # 'WMPageController-JQHover' => ['WMPageController-JQHover/Assets/*.png'] 38 | # } 39 | 40 | # s.public_header_files = 'Pod/Classes/**/*.h' 41 | # s.frameworks = 'UIKit', 'MapKit' 42 | s.dependency 'WMPageController' 43 | end 44 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/e6dd5bec3c564f9a10959cbdc83e56b9ac7c5599/WMPageController-JQHover/Assets/.gitkeep -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Coder-ZJQ/WMPageController-JQHover/e6dd5bec3c564f9a10959cbdc83e56b9ac7c5599/WMPageController-JQHover/Classes/.gitkeep -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/JQHoverFooterView.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQHoverFooterView.h 3 | // ScrollView 4 | // 5 | // Created by Joker on 2018/5/22. 6 | // Copyright © 2018年 Joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class WMPageController; 12 | 13 | typedef NS_ENUM(NSInteger, JQHoverTopBounceType) { 14 | JQHoverTopBounceTypeMain = 1, /**< 滑动到顶部时主页面顶部有弹簧效果 */ 15 | JQHoverTopBounceTypeSub = 2 /**< 滑动到顶部时子页面顶部有弹簧效果 */ 16 | }; 17 | 18 | /** 利用 WMPageController 封装底部菜单悬浮页面控件 */ 19 | @interface JQHoverFooterView : UIView 20 | 21 | /** 显示页面控制器 */ 22 | @property (weak, nonatomic) WMPageController *page; 23 | 24 | /** 顶部弹簧类型(主页面/子页面,可用于控制主页面/子页面头部刷新) */ 25 | @property (nonatomic) JQHoverTopBounceType topBounceType; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/JQHoverPage.h: -------------------------------------------------------------------------------- 1 | // 2 | // JQHoverPage.h 3 | // JQHoverPage 4 | // 5 | // Created by Joker on 2018/7/21. 6 | // 7 | 8 | #import "JQHoverFooterView.h" 9 | #import "UIScrollView+JQHover.h" 10 | #import "WMPageController+JQPage.h" 11 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/UIScrollView+JQExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+JQExtension.h 3 | // ScrollView 4 | // 5 | // Created by Joker on 2018/5/22. 6 | // Copyright © 2018年 Joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIScrollView (JQExtension) 12 | 13 | @property (readonly, nonatomic) UIEdgeInsets jq_inset; 14 | 15 | @property (assign, nonatomic) CGFloat jq_insetT; 16 | @property (assign, nonatomic) CGFloat jq_insetB; 17 | @property (assign, nonatomic) CGFloat jq_insetL; 18 | @property (assign, nonatomic) CGFloat jq_insetR; 19 | 20 | @property (assign, nonatomic) CGFloat jq_offsetX; 21 | @property (assign, nonatomic) CGFloat jq_offsetY; 22 | 23 | @property (assign, nonatomic) CGFloat jq_contentW; 24 | @property (assign, nonatomic) CGFloat jq_contentH; 25 | @end 26 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/UIScrollView+JQExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+JQExtension.m 3 | // ScrollView 4 | // 5 | // 参考自 MJ Lee MJRefresh 6 | // 代码地址: https://github.com/CoderMJLee/MJRefresh 7 | // 代码地址: 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 8 | // 9 | // Created by Joker on 2018/5/22. 10 | // Copyright © 2018年 Joker. All rights reserved. 11 | // 12 | 13 | #import "UIScrollView+JQExtension.h" 14 | 15 | #import 16 | 17 | #pragma clang diagnostic push 18 | #pragma clang diagnostic ignored "-Wunguarded-availability-new" 19 | 20 | @implementation UIScrollView (JQExtension) 21 | 22 | static BOOL gt_ios_11_; 23 | + (void)load 24 | { 25 | // 缓存判断值 26 | gt_ios_11_ = [[[UIDevice currentDevice] systemVersion] compare:@"11.0" options:NSNumericSearch] != NSOrderedAscending; 27 | } 28 | 29 | - (UIEdgeInsets)jq_inset 30 | { 31 | #ifdef __IPHONE_11_0 32 | if (gt_ios_11_) { 33 | return self.adjustedContentInset; 34 | } 35 | #endif 36 | return self.contentInset; 37 | } 38 | 39 | - (void)setJq_insetT:(CGFloat)jq_insetT 40 | { 41 | UIEdgeInsets inset = self.contentInset; 42 | inset.top = jq_insetT; 43 | #ifdef __IPHONE_11_0 44 | if (gt_ios_11_) { 45 | inset.top -= (self.adjustedContentInset.top - self.contentInset.top); 46 | } 47 | #endif 48 | self.contentInset = inset; 49 | } 50 | 51 | - (CGFloat)jq_insetT 52 | { 53 | return self.jq_inset.top; 54 | } 55 | 56 | - (void)setJq_insetB:(CGFloat)jq_insetB 57 | { 58 | UIEdgeInsets inset = self.contentInset; 59 | inset.bottom = jq_insetB; 60 | #ifdef __IPHONE_11_0 61 | if (gt_ios_11_) { 62 | inset.bottom -= (self.adjustedContentInset.bottom - self.contentInset.bottom); 63 | } 64 | #endif 65 | self.contentInset = inset; 66 | } 67 | 68 | - (CGFloat)jq_insetB 69 | { 70 | return self.jq_inset.bottom; 71 | } 72 | 73 | - (void)setJq_insetL:(CGFloat)jq_insetL 74 | { 75 | UIEdgeInsets inset = self.contentInset; 76 | inset.left = jq_insetL; 77 | #ifdef __IPHONE_11_0 78 | if (gt_ios_11_) { 79 | inset.left -= (self.adjustedContentInset.left - self.contentInset.left); 80 | } 81 | #endif 82 | self.contentInset = inset; 83 | } 84 | 85 | - (CGFloat)jq_insetL 86 | { 87 | return self.jq_inset.left; 88 | } 89 | 90 | - (void)setJq_insetR:(CGFloat)jq_insetR 91 | { 92 | UIEdgeInsets inset = self.contentInset; 93 | inset.right = jq_insetR; 94 | #ifdef __IPHONE_11_0 95 | if (gt_ios_11_) { 96 | inset.right -= (self.adjustedContentInset.right - self.contentInset.right); 97 | } 98 | #endif 99 | self.contentInset = inset; 100 | } 101 | 102 | - (CGFloat)jq_insetR 103 | { 104 | return self.jq_inset.right; 105 | } 106 | 107 | - (void)setJq_offsetX:(CGFloat)jq_offsetX 108 | { 109 | CGPoint offset = self.contentOffset; 110 | offset.x = jq_offsetX; 111 | self.contentOffset = offset; 112 | } 113 | 114 | - (CGFloat)jq_offsetX 115 | { 116 | return self.contentOffset.x; 117 | } 118 | 119 | - (void)setJq_offsetY:(CGFloat)jq_offsetY 120 | { 121 | CGPoint offset = self.contentOffset; 122 | offset.y = jq_offsetY; 123 | self.contentOffset = offset; 124 | } 125 | 126 | - (CGFloat)jq_offsetY 127 | { 128 | return self.contentOffset.y; 129 | } 130 | 131 | - (void)setJq_contentW:(CGFloat)jq_contentW 132 | { 133 | CGSize size = self.contentSize; 134 | size.width = jq_contentW; 135 | self.contentSize = size; 136 | } 137 | 138 | - (CGFloat)jq_contentW 139 | { 140 | return self.contentSize.width; 141 | } 142 | 143 | - (void)setJq_contentH:(CGFloat)jq_contentH 144 | { 145 | CGSize size = self.contentSize; 146 | size.height = jq_contentH; 147 | self.contentSize = size; 148 | } 149 | 150 | - (CGFloat)jq_contentH 151 | { 152 | return self.contentSize.height; 153 | } 154 | @end 155 | #pragma clang diagnostic pop 156 | 157 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/UIScrollView+JQHover.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+JQHover.h 3 | // ScrollView 4 | // 5 | // Created by Joker on 2018/5/22. 6 | // Copyright © 2018年 Joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class JQHoverFooterView; 12 | @interface UIScrollView (JQHover) 13 | 14 | /** 包裹悬浮底部控件 */ 15 | @property (strong, nonatomic) JQHoverFooterView *jq_hoverFooter; 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/UIScrollView+JQHover.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIScrollView+JQHover.m 3 | // ScrollView 4 | // 5 | // Created by Joker on 2018/5/22. 6 | // Copyright © 2018年 Joker. All rights reserved. 7 | // 8 | 9 | #import "UIScrollView+JQHover.h" 10 | #import 11 | #import "JQHoverFooterView.h" 12 | 13 | static const char JQHoverFooterViewAssociatedKey = '\0'; 14 | 15 | @implementation UIScrollView (JQHover) 16 | 17 | #pragma mark - 18 | #pragma mark - UIGestureRecognizerDelegate 19 | 20 | BOOL gestureRecognizerShouldRecognizeSimultaneouslyWithOtherGestureRecognizer(id self, SEL _cmd, UIGestureRecognizer *gestureRecognizer, UIGestureRecognizer *otherGestureRecognizer) { 21 | UIScrollView *scrollView = (UIScrollView *)self; 22 | if (scrollView.jq_hoverFooter) { 23 | return [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]; 24 | } else { 25 | return NO; 26 | } 27 | } 28 | 29 | /// 在load方法内替换方法实现 30 | + (void)load { 31 | static dispatch_once_t onceToken; 32 | dispatch_once(&onceToken, ^{ 33 | method_exchangeImplementations(class_getInstanceMethod(self, NSSelectorFromString(@"dealloc")), class_getInstanceMethod(self, @selector(jq_dealloc))); 34 | // 如果已实现则替换实现 35 | if ([self instancesRespondToSelector:@selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)]) { 36 | method_exchangeImplementations(class_getInstanceMethod(self, @selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:)),class_getInstanceMethod(self, @selector(jq_gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:))); 37 | } 38 | // 如果未实现则利用运行时添加实现 39 | else { 40 | class_addMethod(self, @selector(gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:), (IMP)gestureRecognizerShouldRecognizeSimultaneouslyWithOtherGestureRecognizer, "v@:"); 41 | } 42 | }); 43 | } 44 | 45 | /// 在替换的方法内判断是否处理多个手势 46 | - (BOOL)jq_gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { 47 | if (self.jq_hoverFooter) { 48 | return [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]] && [otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]; 49 | } else { 50 | return [self jq_gestureRecognizer:gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer]; 51 | } 52 | } 53 | 54 | #pragma mark - 55 | #pragma mark - getter & setter 56 | 57 | - (void)setJq_hoverFooter:(JQHoverFooterView *)jq_hoverFooter { 58 | if (jq_hoverFooter != self.jq_hoverFooter) { 59 | [self.jq_hoverFooter removeFromSuperview]; 60 | [self insertSubview:jq_hoverFooter atIndex:0]; 61 | [self willChangeValueForKey:@"jq_hoverFooter"]; 62 | objc_setAssociatedObject(self, &JQHoverFooterViewAssociatedKey, 63 | jq_hoverFooter, OBJC_ASSOCIATION_ASSIGN); 64 | [self didChangeValueForKey:@"jq_hoverFooter"]; 65 | } 66 | } 67 | 68 | - (JQHoverFooterView *)jq_hoverFooter { 69 | return objc_getAssociatedObject(self, &JQHoverFooterViewAssociatedKey); 70 | } 71 | 72 | - (void)jq_dealloc { 73 | if (self.jq_hoverFooter) { 74 | [self removeObserver:self.jq_hoverFooter forKeyPath:@"contentSize"]; 75 | [self removeObserver:self.jq_hoverFooter forKeyPath:@"contentOffset"]; 76 | } 77 | [self jq_dealloc]; 78 | } 79 | 80 | 81 | @end 82 | 83 | 84 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/UIView+JQExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+JQExtension.h 3 | // ScrollView 4 | // 5 | // Created by Joker on 2018/5/22. 6 | // Copyright © 2018年 Joker. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIView (JQExtension) 12 | 13 | @property (assign, nonatomic) CGFloat jq_x; 14 | @property (assign, nonatomic) CGFloat jq_y; 15 | @property (assign, nonatomic) CGFloat jq_w; 16 | @property (assign, nonatomic) CGFloat jq_h; 17 | @property (assign, nonatomic) CGFloat jq_centerX; 18 | @property (assign, nonatomic) CGFloat jq_centerY; 19 | @property (assign, nonatomic) CGSize jq_size; 20 | @property (assign, nonatomic) CGPoint jq_origin; 21 | @end 22 | 23 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/UIView+JQExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIView+JQExtension.m 3 | // ScrollView 4 | // 5 | // Created by Joker on 2018/5/22. 6 | // Copyright © 2018年 Joker. All rights reserved. 7 | // 8 | 9 | #import "UIView+JQExtension.h" 10 | 11 | @implementation UIView (JQExtension) 12 | - (void)setJq_x:(CGFloat)jq_x 13 | { 14 | CGRect frame = self.frame; 15 | frame.origin.x = jq_x; 16 | self.frame = frame; 17 | } 18 | 19 | - (CGFloat)jq_x 20 | { 21 | return self.frame.origin.x; 22 | } 23 | 24 | - (void)setJq_y:(CGFloat)jq_y 25 | { 26 | CGRect frame = self.frame; 27 | frame.origin.y = jq_y; 28 | self.frame = frame; 29 | } 30 | 31 | - (CGFloat)jq_y 32 | { 33 | return self.frame.origin.y; 34 | } 35 | 36 | - (void)setJq_w:(CGFloat)jq_w 37 | { 38 | CGRect frame = self.frame; 39 | frame.size.width = jq_w; 40 | self.frame = frame; 41 | } 42 | 43 | - (CGFloat)jq_w 44 | { 45 | return self.frame.size.width; 46 | } 47 | 48 | - (void)setJq_h:(CGFloat)jq_h 49 | { 50 | CGRect frame = self.frame; 51 | frame.size.height = jq_h; 52 | self.frame = frame; 53 | } 54 | 55 | - (CGFloat)jq_h 56 | { 57 | return self.frame.size.height; 58 | } 59 | 60 | - (void)setJq_size:(CGSize)jq_size 61 | { 62 | CGRect frame = self.frame; 63 | frame.size = jq_size; 64 | self.frame = frame; 65 | } 66 | 67 | - (CGSize)jq_size 68 | { 69 | return self.frame.size; 70 | } 71 | 72 | - (void)setJq_centerX:(CGFloat)jq_centerX 73 | { 74 | CGPoint center = self.center; 75 | center.x = jq_centerX; 76 | self.center = center; 77 | } 78 | 79 | - (CGFloat)jq_centerX 80 | { 81 | return CGRectGetMidX(self.frame); 82 | } 83 | 84 | - (void)setJq_centerY:(CGFloat)jq_centerY 85 | { 86 | CGPoint center = self.center; 87 | center.y = jq_centerY; 88 | self.center = center; 89 | } 90 | 91 | - (CGFloat)jq_centerY 92 | { 93 | return CGRectGetMidY(self.frame); 94 | } 95 | - (void)setJq_origin:(CGPoint)jq_origin 96 | { 97 | CGRect frame = self.frame; 98 | frame.origin = jq_origin; 99 | self.frame = frame; 100 | } 101 | 102 | - (CGPoint)jq_origin 103 | { 104 | return self.frame.origin; 105 | } 106 | @end 107 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/WMPageController+JQPage.h: -------------------------------------------------------------------------------- 1 | // 2 | // WMPageController+JQPage.h 3 | // JQHoverPage 4 | // 5 | // Created by Joker on 2018/7/23. 6 | // 7 | 8 | #import "WMPageController.h" 9 | 10 | @protocol JQSubpageControllerDelegate 11 | 12 | @property (nonatomic, readonly) UIScrollView *scrollView; 13 | 14 | @end 15 | 16 | @interface WMPageController (JQPage) 17 | 18 | - (UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /WMPageController-JQHover/Classes/WMPageController+JQPage.m: -------------------------------------------------------------------------------- 1 | // 2 | // WMPageController+JQPage.m 3 | // JQHoverPage 4 | // 5 | // Created by Joker on 2018/7/23. 6 | // 7 | 8 | #import "WMPageController+JQPage.h" 9 | 10 | @implementation WMPageController (JQPage) 11 | 12 | - (UIViewController *)pageController:(WMPageController *)pageController viewControllerAtIndex:(NSInteger)index { 13 | return nil; 14 | } 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /_Pods.xcodeproj: -------------------------------------------------------------------------------- 1 | Example/Pods/Pods.xcodeproj --------------------------------------------------------------------------------