├── .gitignore
├── Banners.png
├── LICENSE
├── README.md
├── TGRefreshOC
├── TGRefreshOC.podspec
├── TGRefreshOC.xcodeproj
│ ├── project.pbxproj
│ └── project.xcworkspace
│ │ └── contents.xcworkspacedata
└── TGRefreshOC
│ ├── AppDelegate.h
│ ├── AppDelegate.m
│ ├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ ├── TGRefreshOC
│ ├── TGRefresh.h
│ ├── TGRefreshOC.bundle
│ │ ├── normal@2x.png
│ │ ├── refresh@2x.png
│ │ └── tipok@2x.png
│ ├── TGRefreshOC.h
│ ├── TGRefreshOC.m
│ ├── UIScrollView+TGRefreshOC.h
│ └── UIScrollView+TGRefreshOC.m
│ ├── ViewController.h
│ ├── ViewController.m
│ └── main.m
├── logo.png
├── refresha.gif
└── refreshb.gif
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xccheckout
23 | *.xcscmblueprint
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 | *.ipa
28 | *.dSYM.zip
29 | *.dSYM
30 |
31 | # CocoaPods
32 | #
33 | # We recommend against adding the Pods directory to your .gitignore. However
34 | # you should judge for yourself, the pros and cons are mentioned at:
35 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
36 | #
37 | # Pods/
38 |
39 | # Carthage
40 | #
41 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
42 | # Carthage/Checkouts
43 |
44 | Carthage/Build
45 |
46 | # fastlane
47 | #
48 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
49 | # screenshots whenever they are needed.
50 | # For more information about the recommended setup visit:
51 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
52 |
53 | fastlane/report.xml
54 | fastlane/Preview.html
55 | fastlane/screenshots
56 | fastlane/test_output
57 |
58 | # Code Injection
59 | #
60 | # After new code Injection tools there's a generated folder /iOSInjectionProject
61 | # https://github.com/johnno1962/injectionforxcode
62 |
63 | iOSInjectionProject/
64 |
--------------------------------------------------------------------------------
/Banners.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/targetcloud/TGRefreshOC/d90ce6e689f177bbaea47b5edf1cf32b1f49c909/Banners.png
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 targetcloud
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## TGRefreshOC
4 | 弹簧、橡皮筋下拉刷新控件,类似QQ下拉刷新控件,但比QQ 更强,同时支持其他样式,目前总共2种样式,后续不断添加中...
5 |
6 | 
7 | 
8 | 
9 | 
10 |
11 |
12 | ## Swift Version
13 | https://github.com/targetcloud/TGRefreshSwift
14 |
15 |
16 | ## Recently Updated
17 | - 0.1.3 增加ignoreScrollViewContentInsetTop属性
18 | - 0.1.2 增加回显信息的渐显与渐隐时间属性设置
19 | - 0.1.1 优化并增强容错设计处理
20 | - 0.1.0 去掉了计时器,提高了性能,同时增加了容错性设计处理
21 |
22 |
23 | ## Features
24 | - [x] 支持链式编程配置,程序员的最爱
25 | - [x] 支持两种刷新结果提示
26 | - [x] 支持QQ和Normal两种下拉刷新样式
27 | - [x] 支持contentInset
28 | - [x] 支持Cocoapods
29 | - [x] 支持MJRefresh到TGRefresh风格切换,只需要把mj_header改为tg_header,改动2个字母即可
30 | - [x] 支持4种配置方式,普通配置、一句话配置、高级配置、最优配置,推荐使用最优配置
31 | - [x] 支持刷新结果回显配置
32 | - [x] 超轻量级、使用超灵活、功能超强大
33 | - [x] 用例丰富,快速上手
34 |
35 |
36 | ## Usage
37 | 首先写上这一句(必须的)
38 | ```
39 | #import
40 | ```
41 | 如果需要,在你的控制器中加上一句
42 | ```
43 | self.automaticallyAdjustsScrollViewInsets=NO;
44 | ```
45 |
46 | #### QQ效果
47 | ```
48 | self.tableview.tg_header = [TGRefreshOC refreshWithTarget:self action:@selector(doRefreshSenior) config:nil];
49 | ```
50 |
51 | #### 普通效果
52 | ```
53 | self.tableview.tg_header = [TGRefreshOC refreshWithTarget:self action:@selector(doRefreshSenior) config:^(TGRefreshOC *refresh) {
54 | refresh.tg_kind(RefreshKindNormal);
55 | }];
56 | ```
57 |
58 | #### 更多配置,使用链式编程配置
59 | ```
60 | self.tableview.tg_header = [TGRefreshOC refreshWithTarget:self action:@selector(doRefreshSenior) config:^(TGRefreshOC *refresh) {
61 | refresh.tg_refreshResultBgColor([[UIColor orangeColor] colorWithAlphaComponent:0.8])
62 | .tg_bgColor([UIColor colorWithWhite:0.8 alpha:1])
63 | .tg_refreshResultTextColor([UIColor whiteColor]);
64 | }];
65 | ```
66 |
67 | #### 开始刷新
68 | ```
69 | [self.tableview.tg_header beginRefreshing];
70 | ```
71 |
72 | #### (网络请求等情况得到数据后)结束刷新
73 | ```
74 | [self.tableview.tg_header endRefreshing];
75 | ```
76 |
77 | #### 结束刷新时的回显
78 | ```
79 | self.tableview.tg_header.refreshResultStr = @"成功刷新数据来自回显信息”;
80 | [self.tableview.tg_header endRefreshing];
81 | ```
82 |
83 | #### 可以配置的属性
84 | ```
85 | /** 类型,默认为QQ弹簧 皮筋效果 */
86 | @property(nonatomic,assign) TGRefreshKind kind;
87 | /** 背景色(在有contentInset时为scrollview等背景色) */
88 | @property(nonatomic,strong) UIColor * bgColor;
89 | /** 主题色(刷新文字颜色、ActivityIndicator颜色、橡皮筯颜色) */
90 | @property(nonatomic,strong) UIColor * tinColor;
91 | /** 垂直对齐,默认顶部 */
92 | @property(nonatomic,assign) TGRefreshAlignment verticalAlignment;
93 | /** 刷新成功时的提示文字 */
94 | @property(nonatomic,copy) NSString * refreshSuccessStr;
95 | /** 准备刷新时的提示文字 */
96 | @property(nonatomic,copy) NSString * refreshNormalStr;
97 | /** 即将刷新时的提示文字 */
98 | @property(nonatomic,copy) NSString * refreshPullingStr;
99 | /** 正在刷新时的提示文字 */
100 | @property(nonatomic,copy) NSString * refreshingStr;
101 | /** 更新结果的回显文字 */
102 | @property(nonatomic,copy) NSString * refreshResultStr;
103 | /** 更新结果的回显背景色 */
104 | @property(nonatomic,strong) UIColor * refreshResultBgColor;
105 | /** 更新结果的回显文字颜色 */
106 | @property(nonatomic,strong) UIColor * refreshResultTextColor;
107 | /** 更新结果的回显高度 */
108 | @property(nonatomic,assign) CGFloat refreshResultHeight;
109 | /** 自动改变透明度,默认已做优化 */
110 | @property(nonatomic,assign) BOOL automaticallyChangeAlpha;
111 | /** 回显时的渐显时间 0.1 ~ 2秒 默认0.5 */
112 | @property(nonatomic,assign) CGFloat fadeinTime;
113 | /** 回显时的渐隐时间 0.1 ~ 5秒 默认1.5 */
114 | @property(nonatomic,assign) CGFloat fadeoutTime;
115 | /** 忽略初始的InsetTop */
116 | @property(nonatomic,assign) BOOL ignoreScrollViewContentInsetTop;
117 | ```
118 | #### 使用链式编程配置时,请在所有属性前加tg_前缀即可
119 |
120 | ### 更多使用配置组合效果请下载本项目或fork本项目查看
121 |
122 | ## Installation
123 | - 下载并拖动TGRefreshOC到你的工程中,只需要拖动包含TGRefresh.h这一文件的目录即可
124 |
125 | - Cocoapods
126 | ```
127 | pod 'TGRefreshOC'
128 | ```
129 |
130 | ## Reference
131 | - http://blog.csdn.net/callzjy
132 | - https://github.com/targetcloud/baisibudejie
133 | - https://github.com/targetcloud/TGImage
134 |
135 | ## 运行效果
136 | 
137 |
138 | ## demo中的弹簧效果
139 | 
140 |
141 | ## demo中的Normal效果
142 | 
143 |
144 | 如果你觉得赞,请Star
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = "TGRefreshOC"
3 | s.version = "0.1.3"
4 | s.summary = "橡皮筋下拉刷新控件,弹簧下拉刷新控件,QQ效果下拉刷新,同时支持其他样式"
5 | s.homepage = "https://github.com/targetcloud/TGRefreshOC"
6 | s.license = "MIT"
7 | s.author = { "targetcloud" => "targetcloud@163.com" }
8 | s.platform = :ios, "8.0"
9 | s.source = { :git => "https://github.com/targetcloud/TGRefreshOC.git", :tag => s.version }
10 | s.source_files = "TGRefreshOC/TGRefreshOC/TGRefreshOC/**/*.{h,m}"
11 | s.resources = "TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.bundle"
12 | s.requires_arc = true
13 | end
14 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 6AEDAAE71EF7C1C1002C886D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AEDAAE61EF7C1C1002C886D /* main.m */; };
11 | 6AEDAAEA1EF7C1C1002C886D /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AEDAAE91EF7C1C1002C886D /* AppDelegate.m */; };
12 | 6AEDAAED1EF7C1C1002C886D /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AEDAAEC1EF7C1C1002C886D /* ViewController.m */; };
13 | 6AEDAAF01EF7C1C1002C886D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6AEDAAEE1EF7C1C1002C886D /* Main.storyboard */; };
14 | 6AEDAAF21EF7C1C1002C886D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6AEDAAF11EF7C1C1002C886D /* Assets.xcassets */; };
15 | 6AEDAAF51EF7C1C1002C886D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6AEDAAF31EF7C1C1002C886D /* LaunchScreen.storyboard */; };
16 | 6AEDAAFE1EF7C3E8002C886D /* TGRefreshOC.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 6AEDAAFD1EF7C3E8002C886D /* TGRefreshOC.bundle */; };
17 | 6AEDAB011EF7C44B002C886D /* TGRefreshOC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AEDAB001EF7C44B002C886D /* TGRefreshOC.m */; };
18 | 6AEDAB041EF83E79002C886D /* UIScrollView+TGRefreshOC.m in Sources */ = {isa = PBXBuildFile; fileRef = 6AEDAB031EF83E79002C886D /* UIScrollView+TGRefreshOC.m */; };
19 | /* End PBXBuildFile section */
20 |
21 | /* Begin PBXFileReference section */
22 | 6AEDAAE21EF7C1C1002C886D /* TGRefreshOC.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = TGRefreshOC.app; sourceTree = BUILT_PRODUCTS_DIR; };
23 | 6AEDAAE61EF7C1C1002C886D /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
24 | 6AEDAAE81EF7C1C1002C886D /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
25 | 6AEDAAE91EF7C1C1002C886D /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
26 | 6AEDAAEB1EF7C1C1002C886D /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
27 | 6AEDAAEC1EF7C1C1002C886D /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
28 | 6AEDAAEF1EF7C1C1002C886D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
29 | 6AEDAAF11EF7C1C1002C886D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
30 | 6AEDAAF41EF7C1C1002C886D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
31 | 6AEDAAF61EF7C1C1002C886D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
32 | 6AEDAAFD1EF7C3E8002C886D /* TGRefreshOC.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = TGRefreshOC.bundle; sourceTree = ""; };
33 | 6AEDAAFF1EF7C44B002C886D /* TGRefreshOC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TGRefreshOC.h; sourceTree = ""; };
34 | 6AEDAB001EF7C44B002C886D /* TGRefreshOC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TGRefreshOC.m; sourceTree = ""; };
35 | 6AEDAB021EF83E79002C886D /* UIScrollView+TGRefreshOC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIScrollView+TGRefreshOC.h"; sourceTree = ""; };
36 | 6AEDAB031EF83E79002C886D /* UIScrollView+TGRefreshOC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIScrollView+TGRefreshOC.m"; sourceTree = ""; };
37 | 6AEDAB051EF8455A002C886D /* TGRefresh.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TGRefresh.h; sourceTree = ""; };
38 | /* End PBXFileReference section */
39 |
40 | /* Begin PBXFrameworksBuildPhase section */
41 | 6AEDAADF1EF7C1C1002C886D /* Frameworks */ = {
42 | isa = PBXFrameworksBuildPhase;
43 | buildActionMask = 2147483647;
44 | files = (
45 | );
46 | runOnlyForDeploymentPostprocessing = 0;
47 | };
48 | /* End PBXFrameworksBuildPhase section */
49 |
50 | /* Begin PBXGroup section */
51 | 6AEDAAD91EF7C1C1002C886D = {
52 | isa = PBXGroup;
53 | children = (
54 | 6AEDAAE41EF7C1C1002C886D /* TGRefreshOC */,
55 | 6AEDAAE31EF7C1C1002C886D /* Products */,
56 | );
57 | sourceTree = "";
58 | };
59 | 6AEDAAE31EF7C1C1002C886D /* Products */ = {
60 | isa = PBXGroup;
61 | children = (
62 | 6AEDAAE21EF7C1C1002C886D /* TGRefreshOC.app */,
63 | );
64 | name = Products;
65 | sourceTree = "";
66 | };
67 | 6AEDAAE41EF7C1C1002C886D /* TGRefreshOC */ = {
68 | isa = PBXGroup;
69 | children = (
70 | 6AEDAAFC1EF7C201002C886D /* TGRefreshOC */,
71 | 6AEDAAE81EF7C1C1002C886D /* AppDelegate.h */,
72 | 6AEDAAE91EF7C1C1002C886D /* AppDelegate.m */,
73 | 6AEDAAEB1EF7C1C1002C886D /* ViewController.h */,
74 | 6AEDAAEC1EF7C1C1002C886D /* ViewController.m */,
75 | 6AEDAAEE1EF7C1C1002C886D /* Main.storyboard */,
76 | 6AEDAAF11EF7C1C1002C886D /* Assets.xcassets */,
77 | 6AEDAAF31EF7C1C1002C886D /* LaunchScreen.storyboard */,
78 | 6AEDAAF61EF7C1C1002C886D /* Info.plist */,
79 | 6AEDAAE51EF7C1C1002C886D /* Supporting Files */,
80 | );
81 | path = TGRefreshOC;
82 | sourceTree = "";
83 | };
84 | 6AEDAAE51EF7C1C1002C886D /* Supporting Files */ = {
85 | isa = PBXGroup;
86 | children = (
87 | 6AEDAAE61EF7C1C1002C886D /* main.m */,
88 | );
89 | name = "Supporting Files";
90 | sourceTree = "";
91 | };
92 | 6AEDAAFC1EF7C201002C886D /* TGRefreshOC */ = {
93 | isa = PBXGroup;
94 | children = (
95 | 6AEDAB051EF8455A002C886D /* TGRefresh.h */,
96 | 6AEDAAFF1EF7C44B002C886D /* TGRefreshOC.h */,
97 | 6AEDAB001EF7C44B002C886D /* TGRefreshOC.m */,
98 | 6AEDAB021EF83E79002C886D /* UIScrollView+TGRefreshOC.h */,
99 | 6AEDAB031EF83E79002C886D /* UIScrollView+TGRefreshOC.m */,
100 | 6AEDAAFD1EF7C3E8002C886D /* TGRefreshOC.bundle */,
101 | );
102 | path = TGRefreshOC;
103 | sourceTree = "";
104 | };
105 | /* End PBXGroup section */
106 |
107 | /* Begin PBXNativeTarget section */
108 | 6AEDAAE11EF7C1C1002C886D /* TGRefreshOC */ = {
109 | isa = PBXNativeTarget;
110 | buildConfigurationList = 6AEDAAF91EF7C1C1002C886D /* Build configuration list for PBXNativeTarget "TGRefreshOC" */;
111 | buildPhases = (
112 | 6AEDAADE1EF7C1C1002C886D /* Sources */,
113 | 6AEDAADF1EF7C1C1002C886D /* Frameworks */,
114 | 6AEDAAE01EF7C1C1002C886D /* Resources */,
115 | );
116 | buildRules = (
117 | );
118 | dependencies = (
119 | );
120 | name = TGRefreshOC;
121 | productName = TGRefreshOC;
122 | productReference = 6AEDAAE21EF7C1C1002C886D /* TGRefreshOC.app */;
123 | productType = "com.apple.product-type.application";
124 | };
125 | /* End PBXNativeTarget section */
126 |
127 | /* Begin PBXProject section */
128 | 6AEDAADA1EF7C1C1002C886D /* Project object */ = {
129 | isa = PBXProject;
130 | attributes = {
131 | LastUpgradeCheck = 0830;
132 | ORGANIZATIONNAME = targetcloud;
133 | TargetAttributes = {
134 | 6AEDAAE11EF7C1C1002C886D = {
135 | CreatedOnToolsVersion = 8.3.3;
136 | DevelopmentTeam = 38C5J53JU9;
137 | ProvisioningStyle = Manual;
138 | };
139 | };
140 | };
141 | buildConfigurationList = 6AEDAADD1EF7C1C1002C886D /* Build configuration list for PBXProject "TGRefreshOC" */;
142 | compatibilityVersion = "Xcode 3.2";
143 | developmentRegion = English;
144 | hasScannedForEncodings = 0;
145 | knownRegions = (
146 | en,
147 | Base,
148 | );
149 | mainGroup = 6AEDAAD91EF7C1C1002C886D;
150 | productRefGroup = 6AEDAAE31EF7C1C1002C886D /* Products */;
151 | projectDirPath = "";
152 | projectRoot = "";
153 | targets = (
154 | 6AEDAAE11EF7C1C1002C886D /* TGRefreshOC */,
155 | );
156 | };
157 | /* End PBXProject section */
158 |
159 | /* Begin PBXResourcesBuildPhase section */
160 | 6AEDAAE01EF7C1C1002C886D /* Resources */ = {
161 | isa = PBXResourcesBuildPhase;
162 | buildActionMask = 2147483647;
163 | files = (
164 | 6AEDAAF51EF7C1C1002C886D /* LaunchScreen.storyboard in Resources */,
165 | 6AEDAAF21EF7C1C1002C886D /* Assets.xcassets in Resources */,
166 | 6AEDAAFE1EF7C3E8002C886D /* TGRefreshOC.bundle in Resources */,
167 | 6AEDAAF01EF7C1C1002C886D /* Main.storyboard in Resources */,
168 | );
169 | runOnlyForDeploymentPostprocessing = 0;
170 | };
171 | /* End PBXResourcesBuildPhase section */
172 |
173 | /* Begin PBXSourcesBuildPhase section */
174 | 6AEDAADE1EF7C1C1002C886D /* Sources */ = {
175 | isa = PBXSourcesBuildPhase;
176 | buildActionMask = 2147483647;
177 | files = (
178 | 6AEDAB011EF7C44B002C886D /* TGRefreshOC.m in Sources */,
179 | 6AEDAB041EF83E79002C886D /* UIScrollView+TGRefreshOC.m in Sources */,
180 | 6AEDAAED1EF7C1C1002C886D /* ViewController.m in Sources */,
181 | 6AEDAAEA1EF7C1C1002C886D /* AppDelegate.m in Sources */,
182 | 6AEDAAE71EF7C1C1002C886D /* main.m in Sources */,
183 | );
184 | runOnlyForDeploymentPostprocessing = 0;
185 | };
186 | /* End PBXSourcesBuildPhase section */
187 |
188 | /* Begin PBXVariantGroup section */
189 | 6AEDAAEE1EF7C1C1002C886D /* Main.storyboard */ = {
190 | isa = PBXVariantGroup;
191 | children = (
192 | 6AEDAAEF1EF7C1C1002C886D /* Base */,
193 | );
194 | name = Main.storyboard;
195 | sourceTree = "";
196 | };
197 | 6AEDAAF31EF7C1C1002C886D /* LaunchScreen.storyboard */ = {
198 | isa = PBXVariantGroup;
199 | children = (
200 | 6AEDAAF41EF7C1C1002C886D /* Base */,
201 | );
202 | name = LaunchScreen.storyboard;
203 | sourceTree = "";
204 | };
205 | /* End PBXVariantGroup section */
206 |
207 | /* Begin XCBuildConfiguration section */
208 | 6AEDAAF71EF7C1C1002C886D /* Debug */ = {
209 | isa = XCBuildConfiguration;
210 | buildSettings = {
211 | ALWAYS_SEARCH_USER_PATHS = NO;
212 | CLANG_ANALYZER_NONNULL = YES;
213 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
214 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
215 | CLANG_CXX_LIBRARY = "libc++";
216 | CLANG_ENABLE_MODULES = YES;
217 | CLANG_ENABLE_OBJC_ARC = YES;
218 | CLANG_WARN_BOOL_CONVERSION = YES;
219 | CLANG_WARN_CONSTANT_CONVERSION = YES;
220 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
221 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
222 | CLANG_WARN_EMPTY_BODY = YES;
223 | CLANG_WARN_ENUM_CONVERSION = YES;
224 | CLANG_WARN_INFINITE_RECURSION = YES;
225 | CLANG_WARN_INT_CONVERSION = YES;
226 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
227 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
228 | CLANG_WARN_UNREACHABLE_CODE = YES;
229 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
230 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
231 | COPY_PHASE_STRIP = NO;
232 | DEBUG_INFORMATION_FORMAT = dwarf;
233 | ENABLE_STRICT_OBJC_MSGSEND = YES;
234 | ENABLE_TESTABILITY = YES;
235 | GCC_C_LANGUAGE_STANDARD = gnu99;
236 | GCC_DYNAMIC_NO_PIC = NO;
237 | GCC_NO_COMMON_BLOCKS = YES;
238 | GCC_OPTIMIZATION_LEVEL = 0;
239 | GCC_PREPROCESSOR_DEFINITIONS = (
240 | "DEBUG=1",
241 | "$(inherited)",
242 | );
243 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
244 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
245 | GCC_WARN_UNDECLARED_SELECTOR = YES;
246 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
247 | GCC_WARN_UNUSED_FUNCTION = YES;
248 | GCC_WARN_UNUSED_VARIABLE = YES;
249 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
250 | MTL_ENABLE_DEBUG_INFO = YES;
251 | ONLY_ACTIVE_ARCH = YES;
252 | SDKROOT = iphoneos;
253 | };
254 | name = Debug;
255 | };
256 | 6AEDAAF81EF7C1C1002C886D /* Release */ = {
257 | isa = XCBuildConfiguration;
258 | buildSettings = {
259 | ALWAYS_SEARCH_USER_PATHS = NO;
260 | CLANG_ANALYZER_NONNULL = YES;
261 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
262 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
263 | CLANG_CXX_LIBRARY = "libc++";
264 | CLANG_ENABLE_MODULES = YES;
265 | CLANG_ENABLE_OBJC_ARC = YES;
266 | CLANG_WARN_BOOL_CONVERSION = YES;
267 | CLANG_WARN_CONSTANT_CONVERSION = YES;
268 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
269 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
270 | CLANG_WARN_EMPTY_BODY = YES;
271 | CLANG_WARN_ENUM_CONVERSION = YES;
272 | CLANG_WARN_INFINITE_RECURSION = YES;
273 | CLANG_WARN_INT_CONVERSION = YES;
274 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
275 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
276 | CLANG_WARN_UNREACHABLE_CODE = YES;
277 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
278 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
279 | COPY_PHASE_STRIP = NO;
280 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
281 | ENABLE_NS_ASSERTIONS = NO;
282 | ENABLE_STRICT_OBJC_MSGSEND = YES;
283 | GCC_C_LANGUAGE_STANDARD = gnu99;
284 | GCC_NO_COMMON_BLOCKS = YES;
285 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
286 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
287 | GCC_WARN_UNDECLARED_SELECTOR = YES;
288 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
289 | GCC_WARN_UNUSED_FUNCTION = YES;
290 | GCC_WARN_UNUSED_VARIABLE = YES;
291 | IPHONEOS_DEPLOYMENT_TARGET = 10.3;
292 | MTL_ENABLE_DEBUG_INFO = NO;
293 | SDKROOT = iphoneos;
294 | VALIDATE_PRODUCT = YES;
295 | };
296 | name = Release;
297 | };
298 | 6AEDAAFA1EF7C1C1002C886D /* Debug */ = {
299 | isa = XCBuildConfiguration;
300 | buildSettings = {
301 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
302 | DEVELOPMENT_TEAM = 38C5J53JU9;
303 | INFOPLIST_FILE = TGRefreshOC/Info.plist;
304 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
305 | PRODUCT_BUNDLE_IDENTIFIER = net.targetcloud.TGRefreshOC;
306 | PRODUCT_NAME = "$(TARGET_NAME)";
307 | PROVISIONING_PROFILE = "09c8f1ec-443c-4108-8cdd-8c8b1ee6b2af";
308 | PROVISIONING_PROFILE_SPECIFIER = allapp;
309 | };
310 | name = Debug;
311 | };
312 | 6AEDAAFB1EF7C1C1002C886D /* Release */ = {
313 | isa = XCBuildConfiguration;
314 | buildSettings = {
315 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
316 | DEVELOPMENT_TEAM = 38C5J53JU9;
317 | INFOPLIST_FILE = TGRefreshOC/Info.plist;
318 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
319 | PRODUCT_BUNDLE_IDENTIFIER = net.targetcloud.TGRefreshOC;
320 | PRODUCT_NAME = "$(TARGET_NAME)";
321 | PROVISIONING_PROFILE = "09c8f1ec-443c-4108-8cdd-8c8b1ee6b2af";
322 | PROVISIONING_PROFILE_SPECIFIER = allapp;
323 | };
324 | name = Release;
325 | };
326 | /* End XCBuildConfiguration section */
327 |
328 | /* Begin XCConfigurationList section */
329 | 6AEDAADD1EF7C1C1002C886D /* Build configuration list for PBXProject "TGRefreshOC" */ = {
330 | isa = XCConfigurationList;
331 | buildConfigurations = (
332 | 6AEDAAF71EF7C1C1002C886D /* Debug */,
333 | 6AEDAAF81EF7C1C1002C886D /* Release */,
334 | );
335 | defaultConfigurationIsVisible = 0;
336 | defaultConfigurationName = Release;
337 | };
338 | 6AEDAAF91EF7C1C1002C886D /* Build configuration list for PBXNativeTarget "TGRefreshOC" */ = {
339 | isa = XCConfigurationList;
340 | buildConfigurations = (
341 | 6AEDAAFA1EF7C1C1002C886D /* Debug */,
342 | 6AEDAAFB1EF7C1C1002C886D /* Release */,
343 | );
344 | defaultConfigurationIsVisible = 0;
345 | defaultConfigurationName = Release;
346 | };
347 | /* End XCConfigurationList section */
348 | };
349 | rootObject = 6AEDAADA1EF7C1C1002C886D /* Project object */;
350 | }
351 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/19.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/19.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | - (void)applicationWillResignActive:(UIApplication *)application {
25 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
27 | }
28 |
29 |
30 | - (void)applicationDidEnterBackground:(UIApplication *)application {
31 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 |
36 | - (void)applicationWillEnterForeground:(UIApplication *)application {
37 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
38 | }
39 |
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
43 | }
44 |
45 |
46 | - (void)applicationWillTerminate:(UIApplication *)application {
47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48 | }
49 |
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/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 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefresh.h:
--------------------------------------------------------------------------------
1 | //
2 | // TGRefresh.h
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/20.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import "UIScrollView+TGRefreshOC.h"
10 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.bundle/normal@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/targetcloud/TGRefreshOC/d90ce6e689f177bbaea47b5edf1cf32b1f49c909/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.bundle/normal@2x.png
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.bundle/refresh@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/targetcloud/TGRefreshOC/d90ce6e689f177bbaea47b5edf1cf32b1f49c909/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.bundle/refresh@2x.png
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.bundle/tipok@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/targetcloud/TGRefreshOC/d90ce6e689f177bbaea47b5edf1cf32b1f49c909/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.bundle/tipok@2x.png
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.h:
--------------------------------------------------------------------------------
1 | //
2 | // TGRefreshOC.h
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/19.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | typedef NS_ENUM(NSInteger,TGRefreshKind) {
12 | RefreshKindQQ,
13 | RefreshKindNormal,
14 | };
15 |
16 | typedef NS_ENUM(NSInteger,TGRefreshAlignment) {
17 | TGRefreshAlignmentTop,
18 | TGRefreshAlignmentMidden,
19 | TGRefreshAlignmentBottom,
20 | };
21 |
22 | @interface TGRefreshOC : UIControl
23 | /** 类型,默认为QQ弹簧 皮筋效果 */
24 | @property(nonatomic,assign) TGRefreshKind kind;
25 | /** 背景色(在有contentInset时为scrollview等背景色) */
26 | @property(nonatomic,strong) UIColor * bgColor;
27 | /** 主题色(刷新文字颜色、ActivityIndicator颜色、橡皮筯颜色) */
28 | @property(nonatomic,strong) UIColor * tinColor;
29 | /** 垂直对齐,默认顶部 */
30 | @property(nonatomic,assign) TGRefreshAlignment verticalAlignment;
31 | /** 刷新成功时的提示文字 */
32 | @property(nonatomic,copy) NSString * refreshSuccessStr;
33 | /** 准备刷新时的提示文字 */
34 | @property(nonatomic,copy) NSString * refreshNormalStr;
35 | /** 即将刷新时的提示文字 */
36 | @property(nonatomic,copy) NSString * refreshPullingStr;
37 | /** 正在刷新时的提示文字 */
38 | @property(nonatomic,copy) NSString * refreshingStr;
39 | /** 更新结果的回显文字 */
40 | @property(nonatomic,copy) NSString * refreshResultStr;
41 | /** 更新结果的回显背景色 */
42 | @property(nonatomic,strong) UIColor * refreshResultBgColor;
43 | /** 更新结果的回显文字颜色 */
44 | @property(nonatomic,strong) UIColor * refreshResultTextColor;
45 | /** 更新结果的回显高度 */
46 | @property(nonatomic,assign) CGFloat refreshResultHeight;
47 | /** 自动改变透明度,默认已做优化 */
48 | @property(nonatomic,assign) BOOL automaticallyChangeAlpha;
49 | /** 忽略初始的InsetTop */
50 | @property(nonatomic,assign) BOOL ignoreScrollViewContentInsetTop;
51 | /** 回显时的渐显时间 0.1 ~ 2秒 默认0.5 */
52 | @property(nonatomic,assign) CGFloat fadeinTime;
53 | /** 回显时的渐隐时间 0.1 ~ 5秒 默认1.5 */
54 | @property(nonatomic,assign) CGFloat fadeoutTime;
55 |
56 | -(TGRefreshOC * (^)(TGRefreshKind))tg_kind;
57 | -(TGRefreshOC * (^)(UIColor *))tg_bgColor;
58 | -(TGRefreshOC * (^)(UIColor *))tg_tinColor;
59 | -(TGRefreshOC * (^)(TGRefreshAlignment))tg_verticalAlignment;
60 | -(TGRefreshOC * (^)(NSString *))tg_refreshSuccessStr;
61 | -(TGRefreshOC * (^)(NSString *))tg_refreshNormalStr;
62 | -(TGRefreshOC * (^)(NSString *))tg_refreshPullingStr;
63 | -(TGRefreshOC * (^)(NSString *))tg_refreshingStr;
64 | -(TGRefreshOC * (^)(NSString *))tg_refreshResultStr;
65 | -(TGRefreshOC * (^)(UIColor *))tg_refreshResultBgColor;
66 | -(TGRefreshOC * (^)(UIColor *))tg_refreshResultTextColor;
67 | -(TGRefreshOC * (^)(CGFloat))tg_refreshResultHeight;
68 | -(TGRefreshOC * (^)(BOOL))tg_automaticallyChangeAlpha;
69 | -(TGRefreshOC * (^)(BOOL))tg_ignoreScrollViewContentInsetTop;
70 | -(TGRefreshOC * (^)(CGFloat))tg_fadeinTime;
71 | -(TGRefreshOC * (^)(CGFloat))tg_fadeoutTime;
72 |
73 | -(instancetype) initWithConfig:(void(^)(TGRefreshOC * refresh)) block;
74 | +(instancetype) refreshWithTarget:(id)target action:(SEL)action config:(void(^)(TGRefreshOC * refresh)) block;
75 |
76 | -(void)beginRefreshing;
77 | -(void)endRefreshing;
78 | @end
79 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/TGRefreshOC/TGRefreshOC.m:
--------------------------------------------------------------------------------
1 | //
2 | // TGRefreshOC.m
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/19.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import "TGRefreshOC.h"
10 |
11 | #define kBeginHeight 40.0
12 | #define kDragHeight 90.0
13 | #define kCenter CGPointMake(self.bounds.size.width * 0.5, kBeginHeight * 0.5)
14 | #define kRadius 15.0
15 | #define kCoefficient 0.6
16 | #define kScreenH [UIScreen mainScreen].bounds.size.height
17 |
18 | typedef NS_ENUM(NSInteger, TGRefreshState) {
19 | RefreshStateNormal,
20 | RefreshStatePulling,
21 | RefreshStateRefresh,
22 | };
23 |
24 | @interface TGRefreshOC()
25 | @property (assign ,nonatomic) CGFloat deltaH;
26 | @property (weak, nonatomic) UIScrollView *sv;
27 | @property (weak, nonatomic) UIActivityIndicatorView *activityIndicatorView;
28 | @property (assign, nonatomic,getter=isAnimating) BOOL animating;
29 | @property (assign, nonatomic,getter=isRefreshing) BOOL refreshing;
30 | @property (assign,nonatomic) TGRefreshState refreshState;
31 | @property (weak,nonatomic) UIImageView *innerImageView;
32 | @property (weak,nonatomic) UIImageView *tipIcon;
33 | @property (weak,nonatomic) UILabel *tipLabel;
34 | @property (weak,nonatomic) UILabel *resultLabel;
35 | @end
36 |
37 | @implementation TGRefreshOC
38 | {
39 | CGFloat initInsetTop_;
40 | }
41 |
42 | #pragma mark : - 创建相关
43 | -(instancetype) initWithConfig:(void(^)(TGRefreshOC * refresh)) block{
44 | if (self = [super init]){
45 | !block? : block(self);
46 | }
47 | return self;
48 | }
49 |
50 | +(instancetype) refreshWithTarget:(id)target action:(SEL)action config:(void(^)(TGRefreshOC * refresh)) block{
51 | TGRefreshOC * refresh = [[self alloc] initWithConfig:block];
52 | [refresh addTarget:target action:action forControlEvents:UIControlEventValueChanged];
53 | return refresh;
54 | }
55 |
56 | #pragma mark : - KVO相关
57 | -(void)willMoveToSuperview:(UIView *)newSuperview{
58 | [super willMoveToSuperview:newSuperview];
59 | self.sv = (UIScrollView *)newSuperview;
60 | initInsetTop_ = self.sv.contentInset.top;
61 | self.backgroundColor = self.bgColor;
62 | self.frame = CGRectMake(0, -kBeginHeight, newSuperview.bounds.size.width, kBeginHeight);
63 | self.clipsToBounds = YES;
64 | [self.sv addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew context:nil];
65 | }
66 |
67 | -(void) removeFromSuperview{
68 | [self.superview removeObserver:self forKeyPath:@"contentOffset"];
69 | [super removeFromSuperview];
70 | }
71 |
72 | -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
73 | if ([keyPath isEqualToString:@"contentOffset"]) {
74 | CGPoint point = [change[@"new"] CGPointValue];
75 | CGFloat height = initInsetTop_>0 ? -(initInsetTop_ + point.y) : -(point.y);//有初始的inset则不用背景色
76 | if( height <= 0) {
77 | return;
78 | }
79 | self.frame = CGRectMake(0,
80 | self.ignoreScrollViewContentInsetTop -height ? : -height-initInsetTop_,
81 | self.sv.bounds.size.width,
82 | height);
83 | //NSLog(@"insetTop>%f height>%f Y>%f state>%ld",self.sv.contentInset.top,height,self.sv.contentOffset.y,(long)self.refreshState);
84 |
85 | switch (_kind) {
86 | case RefreshKindQQ:{
87 | if (_animating || _refreshing || self.refreshState == RefreshStateRefresh) {//动画中 刷新中 已经在计时缩小过程中 已经在刷新状态
88 | // if (_deltaH>0){
89 | // NSLog(@"_deltaH %f",_deltaH);
90 | // }
91 | return;
92 | }
93 | _deltaH = fmaxf(0, -point.y - kBeginHeight - initInsetTop_);
94 | self.innerImageView.hidden = NO;
95 | [self setNeedsDisplay];
96 | if (-point.y > kDragHeight + initInsetTop_) {
97 | [self beginRefreshing];
98 | }
99 | }
100 | break;
101 | case RefreshKindNormal:{
102 | if (self.refreshState == RefreshStateRefresh){
103 | return;
104 | }else if (self.sv.dragging) {
105 | if ((height > kBeginHeight) && (self.refreshState == RefreshStateNormal)){
106 | self.refreshState = RefreshStatePulling;
107 | }else if ((height <= kBeginHeight) && (self.refreshState == RefreshStatePulling)){
108 | self.refreshState = RefreshStateNormal;
109 | }else if (height <= kBeginHeight){
110 | self.refreshState = RefreshStateNormal;
111 | }
112 | }else{
113 | if (self.refreshState == RefreshStatePulling){
114 | [self beginRefreshing];
115 | }
116 | }
117 | self.tipLabel.alpha = self.automaticallyChangeAlpha ? (height/kBeginHeight) :
118 | (self.verticalAlignment == TGRefreshAlignmentTop ? (height/kBeginHeight) : 1);
119 | self.tipIcon.alpha = self.tipLabel.alpha;
120 | [self setNeedsDisplay];
121 | }
122 | break;
123 | default:
124 | break;
125 | }
126 | }
127 | }
128 |
129 | #pragma mark : - setter方法相关
130 | -(void) setRefreshState:(TGRefreshState)refreshState{
131 | _refreshState = refreshState;
132 | switch (_kind) {
133 | case RefreshKindNormal:
134 |
135 | [self normal:refreshState];
136 | break;
137 | case RefreshKindQQ:
138 |
139 | break;
140 | default:
141 | break;
142 | }
143 | }
144 |
145 | -(void) normal :(TGRefreshState)refreshState {
146 | self.tipIcon.image = [self getImage:@"normal@2x"];
147 | [self.tipIcon sizeToFit];
148 | switch (refreshState) {
149 | case RefreshStateNormal:{
150 | self.tipIcon.hidden = NO;
151 | self.tipLabel.hidden = NO;
152 | [self.activityIndicatorView stopAnimating];
153 | self.tipLabel.text = self.refreshNormalStr;
154 | [UIView animateWithDuration:0.25 animations:^{
155 | self.tipIcon.transform = CGAffineTransformIdentity;
156 | }];
157 | }
158 | break;
159 | case RefreshStatePulling:{
160 | self.tipIcon.hidden = NO;
161 | self.tipLabel.hidden = NO;
162 | self.tipLabel.text = self.refreshPullingStr;
163 | [UIView animateWithDuration:0.25 animations:^{
164 | self.tipIcon.transform = CGAffineTransformRotate(self.transform, M_PI + 0.001);
165 | }];
166 | }
167 | break;
168 | case RefreshStateRefresh:
169 | self.tipLabel.hidden = NO;
170 | self.tipLabel.text = self.refreshingStr;
171 | self.tipIcon.hidden = YES;
172 | [self.activityIndicatorView startAnimating];
173 | break;
174 | default:
175 | self.tipIcon.hidden = NO;
176 | self.tipLabel.hidden = NO;
177 | [self.activityIndicatorView stopAnimating];
178 | self.tipLabel.text = self.refreshNormalStr;
179 | break;
180 | }
181 | }
182 |
183 | #pragma mark : - 刷新和结束刷新
184 | -(void)beginRefreshing{
185 | if (self.refreshState == RefreshStateRefresh){
186 | return;
187 | }
188 | self.refreshState = RefreshStateRefresh;
189 | [UIView animateWithDuration:0.25 animations:^{
190 | UIEdgeInsets insets = self.sv.contentInset;
191 | insets.top += kBeginHeight;
192 | self.sv.contentInset = insets;
193 | } completion:^(BOOL finished) {
194 |
195 | }];
196 | switch (_kind) {
197 | case RefreshKindQQ:{
198 | if (!_animating){
199 | _animating = YES;
200 | [UIView animateWithDuration:0.25 animations:^{
201 | _deltaH = -kScreenH;
202 | [self setNeedsDisplay];
203 | } completion:^(BOOL finished) {
204 | self.sv.contentOffset = CGPointMake(0, -(kBeginHeight + initInsetTop_));
205 | _animating = NO;
206 | _refreshing = YES;
207 | [self.activityIndicatorView startAnimating];
208 | _innerImageView.hidden = YES;
209 | }];
210 | [self sendActionsForControlEvents:UIControlEventValueChanged];
211 | }
212 | }
213 | break;
214 | case RefreshKindNormal:{
215 | [self sendActionsForControlEvents:UIControlEventValueChanged];
216 | }
217 | break;
218 | default:
219 | break;
220 | }
221 | }
222 |
223 | -(void) layoutSubviews{
224 | [super layoutSubviews];
225 | [self.tipLabel sizeToFit];
226 | switch (_kind) {
227 | case RefreshKindQQ:
228 | self.alpha = self.frame.size.height/kBeginHeight;
229 | // self.activityIndicatorView.center = CGPointMake(kCenter.x, initInsetTop_ > 0 ? -kCenter.y : kCenter.y);
230 | self.activityIndicatorView.center = kCenter;
231 | break;
232 | case RefreshKindNormal:
233 | switch (_verticalAlignment) {
234 | case TGRefreshAlignmentTop:
235 | // self.tipLabel.center = kCenter;
236 | self.tipLabel.center = CGPointMake(self.bounds.size.width * 0.5,initInsetTop_ + kBeginHeight * 0.5);
237 | break;
238 | case TGRefreshAlignmentMidden:
239 | // self.tipLabel.center = CGPointMake(self.bounds.size.width * 0.5,fabs(self.frame.origin.y*0.5));
240 | self.tipLabel.center = CGPointMake(self.bounds.size.width * 0.5,initInsetTop_ + (fabs(self.frame.origin.y) - initInsetTop_)* 0.5);
241 | break;
242 | case TGRefreshAlignmentBottom:
243 | self.tipLabel.center = CGPointMake(self.bounds.size.width * 0.5,fabs(self.frame.origin.y) - kBeginHeight * 0.5 );
244 | break;
245 | default:
246 | self.tipLabel.center = CGPointMake(self.bounds.size.width * 0.5,fabs(self.frame.origin.y) - kBeginHeight * 0.5 );
247 | break;
248 | }
249 | self.tipLabel.center = CGPointMake(self.tipLabel.center.x, self.tipLabel.center.y - initInsetTop_);
250 |
251 | self.tipIcon.center = CGPointMake(self.tipLabel.frame.origin.x - self.tipIcon.frame.size.width - 3, self.tipLabel.center.y);
252 | self.activityIndicatorView.center = self.tipIcon.center;
253 | break;
254 | default:
255 | break;
256 | }
257 | }
258 |
259 | -(void)endRefreshing{
260 | self.tipIcon.transform = CGAffineTransformIdentity;
261 | _refreshing = NO;
262 | _animating = NO;
263 | self.tipLabel.text = self.refreshSuccessStr;
264 | self.tipIcon.image = [self getImage:@"tipok@2x"];
265 | [self.tipLabel sizeToFit];
266 | [self.tipIcon sizeToFit];
267 | self.tipLabel.center = self.activityIndicatorView.center;
268 |
269 | self.tipIcon.center = CGPointMake((self.tipLabel.frame.size.width < 1 ?
270 | self.activityIndicatorView.center.x :
271 | (self.tipLabel.frame.origin.x - (self.tipIcon.frame.size.width + 3))),
272 | self.activityIndicatorView.center.y);
273 | self.tipIcon.hidden = NO;
274 | self.tipLabel.hidden = NO;
275 | [self.activityIndicatorView stopAnimating];
276 | self.tipLabel.alpha = 0.1;
277 | [UIView animateWithDuration:0.25 animations:^{
278 | self.tipLabel.alpha = 1;
279 | } completion:^(BOOL finished) {
280 | [UIView animateWithDuration:0.25 animations:^{
281 | self.tipIcon.hidden = YES;
282 | self.tipLabel.hidden = YES;
283 | UIEdgeInsets inset = self.sv.contentInset;
284 | inset.top -= kBeginHeight;
285 | self.sv.contentInset = inset;
286 | } completion:^(BOOL finished) {
287 | if (self.refreshResultStr.length>0){
288 | self.resultLabel.alpha = 0.5;
289 | self.resultLabel.transform = CGAffineTransformMakeTranslation(0, -self.refreshResultHeight);
290 |
291 | self.resultLabel.text = self.refreshResultStr;
292 | [UIView animateWithDuration:self.fadeinTime animations:^{
293 | self.resultLabel.transform = CGAffineTransformIdentity;
294 | self.resultLabel.alpha = 1;
295 | } completion:^(BOOL finished) {
296 | [UIView animateWithDuration:self.fadeoutTime animations:^{
297 | self.resultLabel.transform = CGAffineTransformMakeTranslation(0, -self.refreshResultHeight);
298 | self.resultLabel.alpha = 0;
299 | _refreshState = RefreshStateNormal;
300 | _refreshResultStr = @"";
301 | }];
302 | }];
303 | }else{
304 | _refreshState = RefreshStateNormal;
305 | _refreshResultStr = @"";
306 | }
307 | }];
308 | }];
309 | }
310 |
311 | #pragma mark : - 懒加载
312 | -(UIImageView *) innerImageView{
313 | if (!_innerImageView){
314 | UIImageView * iv = [[UIImageView alloc] initWithImage:[self getImage:@"refresh@2x"]];
315 | [self addSubview:iv];
316 | _innerImageView = iv;
317 | }
318 | return _innerImageView;
319 | }
320 |
321 | -(UIImageView *) tipIcon{
322 | if (!_tipIcon){
323 | UIImageView * iv = [[UIImageView alloc] initWithImage:[self getImage:@"tipok@2x"]];
324 | iv.hidden = YES;
325 | [self addSubview:iv];
326 | _tipIcon = iv;
327 | }
328 | return _tipIcon;
329 | }
330 |
331 | -(UILabel *) tipLabel{
332 | if (!_tipLabel){
333 | UILabel * lbl = [[UILabel alloc] init];
334 | lbl.font = [UIFont systemFontOfSize:11];
335 | lbl.backgroundColor = [UIColor clearColor];
336 | [lbl setTextColor:self.tinColor];
337 | [self addSubview:lbl];
338 | _tipLabel = lbl;
339 | }
340 | return _tipLabel;
341 | }
342 |
343 | -(UILabel *) resultLabel{
344 | if (!_resultLabel){
345 | UILabel * lbl = [[UILabel alloc] init];
346 | lbl.textAlignment = NSTextAlignmentCenter;
347 | lbl.font = [UIFont systemFontOfSize:12];
348 | lbl.backgroundColor = self.refreshResultBgColor;
349 | [lbl setTextColor:self.refreshResultTextColor];
350 | lbl.frame = CGRectMake(self.sv.frame.origin.x, self.ignoreScrollViewContentInsetTop ? 0 : -initInsetTop_, self.sv.frame.size.width, self.refreshResultHeight);
351 | [self.sv addSubview:lbl];
352 | _resultLabel = lbl;
353 | }
354 | return _resultLabel;
355 | }
356 |
357 | -(UIActivityIndicatorView *) activityIndicatorView{
358 | if (!_activityIndicatorView) {
359 | UIActivityIndicatorView *act = [UIActivityIndicatorView new];
360 | act.transform = CGAffineTransformMakeScale(.7f, .7f);
361 | act.center = kCenter;
362 | act.color = self.tinColor;
363 | [self addSubview:act];
364 | _activityIndicatorView = act;
365 | }
366 | return _activityIndicatorView;
367 | }
368 |
369 | -(UIColor *) bgColor{
370 | UIColor * color = _bgColor ? (initInsetTop_ > 0 ? self.sv.backgroundColor : _bgColor) : self.sv.backgroundColor;
371 | CGFloat r;
372 | CGFloat g;
373 | CGFloat b;
374 | CGFloat a;
375 | [color getRed:&r green:&g blue:&b alpha:&a];
376 | color = [UIColor colorWithRed:r green:g blue:b alpha:1];
377 | return color;
378 | }
379 |
380 | -(UIColor *) tinColor{
381 | return _tinColor ? _tinColor : [UIColor grayColor];
382 | }
383 |
384 | -(NSString *) refreshSuccessStr{
385 | return _refreshSuccessStr ? _refreshSuccessStr : @"刷新成功";
386 | }
387 |
388 | -(NSString *) refreshNormalStr{
389 | return _refreshNormalStr ? _refreshNormalStr : @"下拉可以刷新";
390 | }
391 |
392 | -(NSString *) refreshPullingStr{
393 | return _refreshPullingStr ? _refreshPullingStr : @"松开立即刷新";
394 | }
395 |
396 | -(NSString *) refreshingStr{
397 | return _refreshingStr ? _refreshingStr : @"正在刷新数据中...";
398 | }
399 |
400 | -(UIColor *) refreshResultBgColor{
401 | return _refreshResultBgColor ? _refreshResultBgColor : [self.tinColor colorWithAlphaComponent:0.8];
402 | }
403 |
404 | -(UIColor *) refreshResultTextColor{
405 | return _refreshResultTextColor ? _refreshResultTextColor : [UIColor whiteColor];
406 | }
407 |
408 | -(CGFloat) refreshResultHeight{
409 | return _refreshResultHeight ? _refreshResultHeight : 34;
410 | }
411 |
412 | -(CGFloat) fadeinTime{
413 | _fadeinTime = _fadeinTime ? _fadeinTime : 0.5;
414 | return _fadeinTime < 0.1 ? 0.1 : ((_fadeinTime > 2) ? 2 : _fadeinTime);
415 | }
416 |
417 | -(CGFloat) fadeoutTime{
418 | _fadeoutTime = _fadeoutTime ? _fadeoutTime : 1.5;
419 | return _fadeoutTime < 0.1 ? 0.1 : ((_fadeoutTime > 5) ? 5 : _fadeoutTime);
420 | }
421 |
422 | #pragma mark : - 控件相关
423 | -(void)drawRect:(CGRect)rect{
424 | if (!_innerImageView){
425 | return;
426 | }
427 | switch (_kind) {
428 | case RefreshKindQQ:
429 |
430 | break;
431 |
432 | default:
433 | [self.bgColor setFill];
434 | return;
435 | break;
436 | }
437 |
438 | if (_refreshing) {
439 | return;
440 | }
441 |
442 | CGPoint startCenter = kCenter;
443 |
444 | _deltaH = (_deltaH > (kDragHeight - kBeginHeight))? (kDragHeight - kBeginHeight) : _deltaH;
445 |
446 | CGFloat radTop = kRadius - _deltaH * 0.1;
447 | CGFloat radBottom = kRadius - _deltaH * 0.2;
448 |
449 | if (_deltaH == -kScreenH){
450 | UIBezierPath *circle = [UIBezierPath bezierPathWithArcCenter:startCenter radius:0 startAngle:0 endAngle:2*M_PI clockwise:1];
451 | [self.tinColor setFill];
452 | [circle fill];
453 | return;
454 | }
455 |
456 | CGFloat Y = fmaxf(_deltaH, 0);
457 |
458 | CGFloat radBottomLeftAndRight = 0;
459 | if ((radTop - radBottom) > 0) {
460 | radBottomLeftAndRight = (pow(Y, 2)+pow(radBottom, 2)-pow(radTop, 2))/(2*(radTop - radBottom));
461 | }
462 | radBottomLeftAndRight = fmax(0, radBottomLeftAndRight);
463 |
464 | CGPoint centerBottom = relative(startCenter, 0, Y);
465 | CGPoint centerRight = relative(centerBottom, radBottom+radBottomLeftAndRight, 0);
466 | CGPoint centerLeft = relative(centerBottom, -radBottom-radBottomLeftAndRight, 0);
467 |
468 | _innerImageView.bounds = CGRectMake(0, 0,radTop * 2 * kCoefficient, radTop * 2 * kCoefficient);
469 | _innerImageView.center = kCenter;
470 |
471 | UIBezierPath *circle = [UIBezierPath bezierPathWithArcCenter:startCenter radius:radTop startAngle:0 endAngle:2*M_PI clockwise:1];
472 | if (_deltaH <= 0){
473 | [self.tinColor setFill];
474 | [circle fill];
475 | return;
476 | }
477 |
478 | [circle moveToPoint:centerBottom];
479 | [circle addArcWithCenter:centerBottom radius:radBottom startAngle:0 endAngle:2*M_PI clockwise:1];
480 |
481 | UIBezierPath *circle2 = [UIBezierPath bezierPathWithArcCenter:centerRight radius:radBottomLeftAndRight startAngle:0 endAngle:2*M_PI clockwise:1];
482 | [circle2 moveToPoint:centerLeft];
483 | [circle2 addArcWithCenter:centerLeft radius:radBottomLeftAndRight startAngle:0 endAngle:2*M_PI clockwise:1];
484 |
485 | UIBezierPath *line = [UIBezierPath bezierPath];
486 | [line moveToPoint:startCenter];
487 | [line addLineToPoint:centerRight];
488 | [line addLineToPoint:centerBottom];
489 | [line addLineToPoint:centerLeft];
490 | [line closePath];
491 | [line appendPath:circle];
492 | [self.tinColor setFill];
493 | [line fill];
494 | [self.bgColor setFill];
495 | [circle2 fill];
496 | }
497 |
498 | CGPoint relative(CGPoint point, CGFloat x, CGFloat y){
499 | return CGPointMake(point.x + x, point.y + y);
500 | }
501 |
502 | #pragma mark : - 资源相关
503 | -(UIImage *)getImage:(NSString *)name{
504 | NSBundle *currentBundle = [NSBundle bundleWithPath:[[NSBundle bundleForClass:[TGRefreshOC class]] pathForResource:@"TGRefreshOC" ofType:@"bundle"]];
505 | UIImage *img = [UIImage imageWithContentsOfFile:[currentBundle pathForResource:name ofType:@"png"]];
506 | return img;
507 | }
508 |
509 | #pragma mark : - 链式配置相关
510 | -(TGRefreshOC * (^)(TGRefreshKind))tg_kind{
511 | return ^(TGRefreshKind kind){
512 | self.kind = kind;
513 | return self;
514 | };
515 | }
516 |
517 | -(TGRefreshOC * (^)(UIColor *))tg_bgColor{
518 | return ^(UIColor *color){
519 | CGFloat r;
520 | CGFloat g;
521 | CGFloat b;
522 | CGFloat a;
523 | [color getRed:&r green:&g blue:&b alpha:&a];
524 | color = [UIColor colorWithRed:r green:g blue:b alpha:1];
525 | self.bgColor = color;
526 | return self;
527 | };
528 | }
529 |
530 | -(TGRefreshOC * (^)(UIColor *))tg_tinColor{
531 | return ^(UIColor *color){
532 | self.tinColor = color;
533 | return self;
534 | };
535 | }
536 |
537 | -(TGRefreshOC * (^)(TGRefreshAlignment))tg_verticalAlignment{
538 | return ^(TGRefreshAlignment vl){
539 | self.verticalAlignment = vl;
540 | return self;
541 | };
542 | }
543 |
544 | -(TGRefreshOC * (^)(NSString *))tg_refreshSuccessStr{
545 | return ^(NSString *str){
546 | self.refreshSuccessStr = str;
547 | return self;
548 | };
549 | }
550 |
551 | -(TGRefreshOC * (^)(NSString *))tg_refreshNormalStr{
552 | return ^(NSString *str){
553 | self.refreshNormalStr = str;
554 | return self;
555 | };
556 | }
557 |
558 | -(TGRefreshOC * (^)(NSString *))tg_refreshPullingStr{
559 | return ^(NSString *str){
560 | self.refreshPullingStr = str;
561 | return self;
562 | };
563 | }
564 |
565 | -(TGRefreshOC * (^)(NSString *))tg_refreshingStr{
566 | return ^(NSString *str){
567 | self.refreshingStr = str;
568 | return self;
569 | };
570 | }
571 |
572 | -(TGRefreshOC * (^)(NSString *))tg_refreshResultStr{
573 | return ^(NSString *str){
574 | self.refreshResultStr = str;
575 | return self;
576 | };
577 | }
578 |
579 | -(TGRefreshOC * (^)(UIColor *))tg_refreshResultBgColor{
580 | return ^(UIColor *color){
581 | self.refreshResultBgColor = color;
582 | return self;
583 | };
584 | }
585 |
586 | -(TGRefreshOC * (^)(UIColor *))tg_refreshResultTextColor{
587 | return ^(UIColor *color){
588 | self.refreshResultTextColor = color;
589 | return self;
590 | };
591 | }
592 |
593 | -(TGRefreshOC * (^)(CGFloat))tg_refreshResultHeight{
594 | return ^(CGFloat height){
595 | self.refreshResultHeight = height;
596 | return self;
597 | };
598 | }
599 |
600 | -(TGRefreshOC * (^)(BOOL))tg_automaticallyChangeAlpha{
601 | return ^(BOOL autoAlpha){
602 | self.automaticallyChangeAlpha = autoAlpha;
603 | return self;
604 | };
605 | }
606 |
607 | -(TGRefreshOC * (^)(BOOL))tg_ignoreScrollViewContentInsetTop{
608 | return ^(BOOL ignoreSInsetTop){
609 | self.ignoreScrollViewContentInsetTop = ignoreSInsetTop;
610 | return self;
611 | };
612 | }
613 |
614 | -(TGRefreshOC * (^)(CGFloat))tg_fadeinTime{
615 | return ^(CGFloat time){
616 | time = time < 0.1 ? 0.1 : ((time > 2) ? 2 : time);
617 | self.fadeinTime = time;
618 | return self;
619 | };
620 | }
621 |
622 | -(TGRefreshOC * (^)(CGFloat))tg_fadeoutTime{
623 | return ^(CGFloat time){
624 | time = time < 0.1 ? 0.1 : ((time > 5) ? 5 : time);
625 | self.fadeoutTime = time;
626 | return self;
627 | };
628 | }
629 |
630 | @end
631 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/TGRefreshOC/UIScrollView+TGRefreshOC.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIScrollView+TGRefreshOC.h
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/20.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "TGRefreshOC.h"
11 |
12 | @class TGRefreshOC;
13 |
14 | @interface UIScrollView (TGRefreshOC)
15 | @property (strong, nonatomic) TGRefreshOC *tg_header;
16 | @end
17 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/TGRefreshOC/UIScrollView+TGRefreshOC.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIScrollView+TGRefreshOC.m
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/20.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import "UIScrollView+TGRefreshOC.h"
10 | #import
11 |
12 | @implementation UIScrollView (TGRefreshOC)
13 |
14 | static const char TGRefreshOCHeaderKey = '\0';
15 |
16 | - (void)setTg_header:(TGRefreshOC *)tg_header{
17 | if (tg_header != self.tg_header) {
18 | [self.tg_header removeFromSuperview];
19 | [self insertSubview:tg_header atIndex:0];
20 | [self willChangeValueForKey:@"tg_header"];
21 | objc_setAssociatedObject(self, &TGRefreshOCHeaderKey,tg_header, OBJC_ASSOCIATION_ASSIGN);
22 | [self didChangeValueForKey:@"tg_header"];
23 | }
24 | }
25 |
26 | - (TGRefreshOC *)tg_header{
27 | return objc_getAssociatedObject(self, &TGRefreshOCHeaderKey);
28 | }
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/19.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/19.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | // swift版本 https://github.com/targetcloud/TGRefreshSwift
8 |
9 | #import "ViewController.h"
10 | #import "TGRefresh.h"
11 |
12 | #define ScreenW [UIScreen mainScreen].bounds.size.width
13 |
14 | @interface ViewController ()
15 | @property (weak, nonatomic) IBOutlet UITableView *tv;
16 | @property (nonatomic ,weak) TGRefreshOC *refreshCtl;//高级用法时这行可以去掉
17 | @end
18 |
19 | @implementation ViewController
20 |
21 | - (void)viewDidLoad {
22 | [super viewDidLoad];
23 | self.tv.dataSource = self;
24 | self.tv.delegate = self;
25 | self.tv.tableFooterView = [UIView new];
26 | self.tv.allowsSelection = NO;
27 |
28 | self.automaticallyAdjustsScrollViewInsets=NO;
29 |
30 | //NSLog(@" tableview frame %@",NSStringFromCGRect(self.tv.frame));//{{0, 64}, {375, 603}}
31 |
32 | //普通用法
33 | //[self builderAndSetting];
34 |
35 | //简化成一句话用法
36 | //[self builderSimple];
37 |
38 | //高级用法
39 | //[self buildSenior];
40 |
41 | //最好用法
42 | [self buildBest];
43 | }
44 |
45 | //最好用法
46 | -(void)buildBest{
47 | //默认为QQ效果
48 | self.tv.tg_header = [TGRefreshOC refreshWithTarget:self action:@selector(doRefreshSenior) config:nil];
49 | [self.tv.tg_header beginRefreshing];
50 | }
51 |
52 | -(void)buildBest2{
53 | //普通效果
54 | self.tv.tg_header = [TGRefreshOC refreshWithTarget:self action:@selector(doRefreshSenior) config:^(TGRefreshOC *refresh) {
55 | refresh.tg_kind(RefreshKindNormal);
56 | }];
57 | [self.tv.tg_header beginRefreshing];
58 | }
59 |
60 | -(void)buildBest3{
61 | //更多配置,使用链式编程配置
62 | self.tv.tg_header = [TGRefreshOC refreshWithTarget:self action:@selector(doRefreshSenior) config:^(TGRefreshOC *refresh) {
63 | refresh.tg_refreshResultBgColor([[UIColor orangeColor] colorWithAlphaComponent:0.8])
64 | .tg_bgColor([UIColor colorWithWhite:0.8 alpha:1])
65 | .tg_fadeinTime(2)
66 | .tg_fadeoutTime(1)
67 | .tg_refreshResultTextColor([UIColor whiteColor]);
68 | }];
69 | [self.tv.tg_header beginRefreshing];
70 | }
71 |
72 | //高级用法
73 | -(void)buildSenior{
74 | self.tv.tg_header = [[TGRefreshOC alloc] initWithConfig:^(TGRefreshOC *refresh) {
75 | refresh.tg_refreshResultBgColor([[UIColor orangeColor] colorWithAlphaComponent:0.8])
76 | .tg_bgColor([UIColor colorWithWhite:0.9 alpha:1])
77 | .tg_refreshResultTextColor([UIColor whiteColor]);
78 | [refresh addTarget:self action:@selector(doRefreshSenior) forControlEvents:UIControlEventValueChanged];
79 | }];
80 | [self.tv.tg_header beginRefreshing];
81 | }
82 |
83 | //简化成一句话用法
84 | -(void)builderSimple{
85 | TGRefreshOC *refresh = [[TGRefreshOC alloc] initWithConfig:^(TGRefreshOC *refresh) {
86 | refresh.tg_refreshResultBgColor([[UIColor orangeColor] colorWithAlphaComponent:0.8])
87 | .tg_bgColor([UIColor colorWithWhite:0.8 alpha:1])
88 | .tg_refreshResultTextColor([UIColor whiteColor]);
89 | }];
90 |
91 | [self.tv addSubview:refresh];
92 | _refreshCtl = refresh;
93 | [refresh addTarget:self action:@selector(doRefresh) forControlEvents:UIControlEventValueChanged];
94 | [refresh beginRefreshing];
95 | }
96 |
97 | //普通用法
98 | -(void)builderAndSetting{
99 | //******************有contentInset测试****************
100 | //可以去掉这段
101 | // UILabel *label = [[UILabel alloc] init];
102 | // label.backgroundColor = [UIColor lightGrayColor];
103 | // label.frame = CGRectMake(0, -80, ScreenW, 80);
104 | // label.font = [UIFont systemFontOfSize:13];
105 | // label.numberOfLines = 0;
106 | // label.textColor = [UIColor whiteColor];
107 | // label.text = @"TGRefreshOC下拉刷新控件是一款同时支持QQ样式(橡皮筋)和普通样式的下拉刷新控件。支持链式配置,配置参数丰富,使用更简单灵活。 快来使用一下吧,比你想象中更强大哦:)";
108 | // label.textAlignment = NSTextAlignmentCenter;
109 | // [self.tv addSubview:label];
110 | // self.tv.contentInset = UIEdgeInsetsMake(80, 0, 0, 0);
111 | //***************************************************
112 |
113 | TGRefreshOC *refresh = [TGRefreshOC new];
114 | // refresh.kind = RefreshKindNormal;//QQ效果则注释此行
115 |
116 | //配置根据需要写,也可以不写任何配置
117 | //*****************普通配置***************************
118 | //与下面链式配置二选一,也可以一起写
119 | refresh.bgColor = [UIColor colorWithWhite:0.8 alpha:1];
120 | refresh.verticalAlignment = TGRefreshAlignmentTop;
121 | refresh.automaticallyChangeAlpha = YES;
122 | //***************************************************
123 |
124 | //*****************链式配置***************************
125 | //与上面普通配置二选一,也可以一起写
126 | refresh.tg_refreshResultBgColor([[UIColor orangeColor] colorWithAlphaComponent:0.8])
127 | .tg_refreshResultTextColor([UIColor whiteColor])
128 | .tg_refreshResultHeight(38)
129 | .tg_refreshNormalStr(@"pull down refresh")
130 | .tg_refreshPullingStr(@"let go")
131 | .tg_refreshingStr(@"refreshing...")
132 | .tg_refreshSuccessStr(@"success");
133 | //***************************************************
134 |
135 | [self.tv addSubview:refresh];
136 | _refreshCtl = refresh;
137 | [refresh addTarget:self action:@selector(doRefresh) forControlEvents:UIControlEventValueChanged];
138 | [refresh beginRefreshing];//一进入界面需要刷新写这一行
139 | }
140 |
141 | - (void)doRefresh{
142 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
143 | _refreshCtl.refreshResultStr = @"成功刷新到10条数据";
144 | [_refreshCtl endRefreshing];
145 | });
146 | }
147 |
148 | - (void)doRefreshSenior{
149 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
150 | self.tv.tg_header.refreshResultStr = @"成功刷新数据来自高级用法";
151 | [self.tv.tg_header endRefreshing];
152 | });
153 | }
154 |
155 | -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
156 | return 10;
157 | }
158 |
159 | -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
160 | static NSString *identifier = @"cell";
161 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
162 | if (!cell) {
163 | cell = [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:identifier];
164 | }
165 | cell.textLabel.text = [NSString stringWithFormat:@"第%ld行测试数据",(long)indexPath.row];
166 | return cell;
167 | }
168 |
169 | @end
170 |
--------------------------------------------------------------------------------
/TGRefreshOC/TGRefreshOC/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // TGRefreshOC
4 | //
5 | // Created by targetcloud on 2017/6/19.
6 | // Copyright © 2017年 targetcloud. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/targetcloud/TGRefreshOC/d90ce6e689f177bbaea47b5edf1cf32b1f49c909/logo.png
--------------------------------------------------------------------------------
/refresha.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/targetcloud/TGRefreshOC/d90ce6e689f177bbaea47b5edf1cf32b1f49c909/refresha.gif
--------------------------------------------------------------------------------
/refreshb.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/targetcloud/TGRefreshOC/d90ce6e689f177bbaea47b5edf1cf32b1f49c909/refreshb.gif
--------------------------------------------------------------------------------