├── Demo2 ├── BG.png ├── cute_girl.jpg ├── whiteplaceholder.png ├── PathCover │ ├── Resources │ │ ├── circle.png │ │ ├── meicon.png │ │ ├── circle@2x.png │ │ ├── pullrefresh.aif │ │ └── MenuBackground@2x.png │ ├── XHSoundManager.h │ ├── XHWaterDropRefresh.h │ ├── XHSoundManager.m │ ├── XHPathCover.h │ └── XHWaterDropRefresh.m ├── MJRefresh │ ├── MJRefresh.bundle │ │ └── arrow@2x.png │ ├── MJRefresh.h │ ├── MJRefreshLegendFooter.h │ ├── MJRefreshLegendHeader.h │ ├── MJRefreshGifFooter.h │ ├── MJRefreshGifHeader.h │ ├── UIView+MJExtension.h │ ├── UIScrollView+MJExtension.h │ ├── MJRefreshConst.m │ ├── MJRefreshComponent.h │ ├── MJRefreshFooter.h │ ├── MJRefreshHeader.h │ ├── UIView+MJExtension.m │ ├── MJRefreshConst.h │ ├── MJRefreshLegendFooter.m │ ├── MJRefreshComponent.m │ ├── MJRefreshGifFooter.m │ ├── UIScrollView+MJExtension.m │ ├── MJRefreshLegendHeader.m │ ├── MJRefreshGifHeader.m │ ├── UIScrollView+MJRefresh.h │ ├── UIScrollView+MJRefresh.m │ └── MJRefreshFooter.m ├── ProgressHUD │ ├── ProgressHUD.bundle │ │ ├── progresshud-error@2x.png │ │ └── progresshud-success@2x.png │ └── ProgressHUD.h ├── UIviewExtension.swift ├── bridging.h ├── Demo2.xcdatamodeld │ ├── .xccurrentversion │ └── Demo2.xcdatamodel │ │ └── contents ├── SDWebImage │ ├── UIImage+MultiFormat.h │ ├── SDWebImageOperation.h │ ├── UIImage+GIF.h │ ├── SDWebImageDecoder.h │ ├── UIImage+WebP.h │ ├── NSData+ImageContentType.h │ ├── UIView+WebCacheOperation.h │ ├── NSData+ImageContentType.m │ ├── SDWebImageCompat.m │ ├── SDWebImageDecoder.m │ ├── SDWebImageCompat.h │ ├── UIView+WebCacheOperation.m │ ├── UIImage+WebP.m │ ├── SDWebImageDownloaderOperation.h │ ├── UIImage+MultiFormat.m │ ├── SDWebImagePrefetcher.h │ ├── UIImageView+HighlightedWebCache.m │ ├── MKAnnotationView+WebCache.m │ ├── UIImageView+HighlightedWebCache.h │ ├── UIImage+GIF.m │ ├── SDWebImagePrefetcher.m │ ├── MKAnnotationView+WebCache.h │ ├── SDWebImageDownloader.h │ ├── SDImageCache.h │ └── UIImageView+WebCache.h ├── HZIndicatorView.h ├── HZPhotoBrowserView.h ├── XActionSheet.h ├── HZPhotoBrowser.h ├── HZPhotoBrowserConfig.h ├── Images.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Info.plist ├── LineView.swift ├── HZIndicatorView.m ├── Base.lproj │ ├── Main.storyboard │ └── LaunchScreen.xib ├── XActionSheet.m ├── AppDelegate.swift ├── ViewController.swift └── HZPhotoBrowserView.m ├── Demo2.xcodeproj ├── xcuserdata │ └── xlx.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── Demo2.xcscheme └── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ └── xlx.xcuserdatad │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ └── Demo2.xccheckout └── Demo2Tests ├── Info.plist └── Demo2Tests.swift /Demo2/BG.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/BG.png -------------------------------------------------------------------------------- /Demo2/cute_girl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/cute_girl.jpg -------------------------------------------------------------------------------- /Demo2/whiteplaceholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/whiteplaceholder.png -------------------------------------------------------------------------------- /Demo2/PathCover/Resources/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/PathCover/Resources/circle.png -------------------------------------------------------------------------------- /Demo2/PathCover/Resources/meicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/PathCover/Resources/meicon.png -------------------------------------------------------------------------------- /Demo2/PathCover/Resources/circle@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/PathCover/Resources/circle@2x.png -------------------------------------------------------------------------------- /Demo2/PathCover/Resources/pullrefresh.aif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/PathCover/Resources/pullrefresh.aif -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefresh.bundle/arrow@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/MJRefresh/MJRefresh.bundle/arrow@2x.png -------------------------------------------------------------------------------- /Demo2/PathCover/Resources/MenuBackground@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/PathCover/Resources/MenuBackground@2x.png -------------------------------------------------------------------------------- /Demo2/ProgressHUD/ProgressHUD.bundle/progresshud-error@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/ProgressHUD/ProgressHUD.bundle/progresshud-error@2x.png -------------------------------------------------------------------------------- /Demo2/ProgressHUD/ProgressHUD.bundle/progresshud-success@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2/ProgressHUD/ProgressHUD.bundle/progresshud-success@2x.png -------------------------------------------------------------------------------- /Demo2/UIviewExtension.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | 4 | 5 | extension UIView { 6 | func sayHello(){ 7 | println("哈喽,大家好,花川学院的学员们") 8 | } 9 | 10 | } -------------------------------------------------------------------------------- /Demo2.xcodeproj/xcuserdata/xlx.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /Demo2/bridging.h: -------------------------------------------------------------------------------- 1 | #import "MJRefresh.h" 2 | #import "ProgressHUD.h" 3 | #import "XHPathCover.h" 4 | #import "UIImageView+WebCache.h" 5 | #import "HZPhotoBrowser.h" 6 | #import "XActionSheet.h" -------------------------------------------------------------------------------- /Demo2.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo2.xcodeproj/project.xcworkspace/xcuserdata/xlx.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/superxlx/Demo2/HEAD/Demo2.xcodeproj/project.xcworkspace/xcuserdata/xlx.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Demo2/Demo2.xcdatamodeld/.xccurrentversion: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | _XCCurrentVersionName 6 | Demo2.xcdatamodel 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImage+MultiFormat.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+MultiFormat.h 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 07/06/13. 6 | // Copyright (c) 2013 Dailymotion. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (MultiFormat) 12 | 13 | + (UIImage *)sd_imageWithData:(NSData *)data; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Demo2/HZIndicatorView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HZIndicatorView.h 3 | // photoBrowser 4 | // 5 | // Created by huangzhenyu on 15/6/23. 6 | // Copyright (c) 2015年 eamon. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HZIndicatorView : UIView 12 | @property (nonatomic, assign) CGFloat progress; 13 | @property (nonatomic, assign) int viewMode;//显示模式 14 | @end 15 | -------------------------------------------------------------------------------- /Demo2/Demo2.xcdatamodeld/Demo2.xcdatamodel/contents: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Demo2/PathCover/XHSoundManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // XHSoundManager.h 3 | // XHPathCover 4 | // 5 | // Created by 曾 宪华 on 14-2-7. 6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XHSoundManager : NSObject 12 | 13 | + (instancetype)sharedInstance; 14 | 15 | - (void)playRefreshSound; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImageOperation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | 11 | @protocol SDWebImageOperation 12 | 13 | - (void)cancel; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Demo2/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 "MJRefreshGifHeader.h" 6 | #import "MJRefreshLegendHeader.h" 7 | #import "MJRefreshGifFooter.h" 8 | #import "MJRefreshLegendFooter.h" 9 | #import "MJRefreshConst.h" -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImage+GIF.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+GIF.h 3 | // LBGIFImage 4 | // 5 | // Created by Laurin Brandner on 06.01.12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface UIImage (GIF) 12 | 13 | + (UIImage *)sd_animatedGIFNamed:(NSString *)name; 14 | 15 | + (UIImage *)sd_animatedGIFWithData:(NSData *)data; 16 | 17 | - (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshLegendFooter.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 | // MJRefreshLegendFooter.h 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/5. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshFooter.h" 11 | 12 | @interface MJRefreshLegendFooter : MJRefreshFooter 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshLegendHeader.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 | // MJRefreshLegendHeader.h 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/4. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 传统的下拉刷新控件:箭头 + 圈圈 9 | 10 | #import "MJRefreshHeader.h" 11 | 12 | @interface MJRefreshLegendHeader : MJRefreshHeader 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImageDecoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * Created by james on 9/28/11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | #import 12 | #import "SDWebImageCompat.h" 13 | 14 | @interface UIImage (ForceDecode) 15 | 16 | + (UIImage *)decodedImageWithImage:(UIImage *)image; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshGifFooter.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 | // MJRefreshGifFooter.h 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/5. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshFooter.h" 11 | 12 | @interface MJRefreshGifFooter : MJRefreshFooter 13 | /** 正在刷新时的动画图片 */ 14 | @property (strong, nonatomic) NSArray *refreshingImages; 15 | @end 16 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImage+WebP.h: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+WebP.h 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 07/06/13. 6 | // Copyright (c) 2013 Dailymotion. All rights reserved. 7 | // 8 | 9 | #ifdef SD_WEBP 10 | 11 | #import 12 | 13 | // Fix for issue #416 Undefined symbols for architecture armv7 since WebP introduction when deploying to device 14 | void WebPInitPremultiplyNEON(void); 15 | 16 | void WebPInitUpsamplersNEON(void); 17 | 18 | void VP8DspInitNEON(void); 19 | 20 | @interface UIImage (WebP) 21 | 22 | + (UIImage *)sd_imageWithWebPData:(NSData *)data; 23 | 24 | @end 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshGifHeader.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 | // MJRefreshGifHeader.h 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/4. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 带有gif图片功能的下拉刷新控件 9 | 10 | #import "MJRefreshHeader.h" 11 | 12 | @interface MJRefreshGifHeader : MJRefreshHeader 13 | /** 设置state状态下的动画图片images */ 14 | - (void)setImages:(NSArray *)images forState:(MJRefreshHeaderState)state; 15 | @end 16 | -------------------------------------------------------------------------------- /Demo2/HZPhotoBrowserView.h: -------------------------------------------------------------------------------- 1 | // 2 | // HZPhotoBrowserView.h 3 | // photoBrowser 4 | // 5 | // Created by huangzhenyu on 15/6/23. 6 | // Copyright (c) 2015年 eamon. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface HZPhotoBrowserView : UIView 12 | @property (nonatomic,strong) UIScrollView *scrollview; 13 | @property (nonatomic,strong) UIImageView *imageview; 14 | @property (nonatomic, assign) CGFloat progress; 15 | @property (nonatomic, assign) BOOL beginLoadingImage; 16 | 17 | //单击回调 18 | @property (nonatomic, strong) void (^singleTapBlock)(UITapGestureRecognizer *recognizer); 19 | 20 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder; 21 | @end 22 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/NSData+ImageContentType.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Fabrice Aneche on 06/01/14. 3 | // Copyright (c) 2014 Dailymotion. All rights reserved. 4 | // 5 | 6 | #import 7 | 8 | @interface NSData (ImageContentType) 9 | 10 | /** 11 | * Compute the content type for an image data 12 | * 13 | * @param data the input data 14 | * 15 | * @return the content type as string (i.e. image/jpeg, image/gif) 16 | */ 17 | + (NSString *)sd_contentTypeForImageData:(NSData *)data; 18 | 19 | @end 20 | 21 | 22 | @interface NSData (ImageContentTypeDeprecated) 23 | 24 | + (NSString *)contentTypeForImageData:(NSData *)data __deprecated_msg("Use `sd_contentTypeForImageData:`"); 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Demo2.xcodeproj/xcuserdata/xlx.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Demo2.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 2A02EACB1B5D50B100DAB871 16 | 17 | primary 18 | 19 | 20 | 2A02EAE31B5D50B100DAB871 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/UIView+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 | // UIView+Extension.h 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 14-5-28. 7 | // Copyright (c) 2014年 itcast. All rights reserved. 8 | // 9 | 10 | #import 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 | -------------------------------------------------------------------------------- /Demo2/XActionSheet.h: -------------------------------------------------------------------------------- 1 | // 2 | // XActionSheet.h 3 | // Demo2 4 | // 5 | // Created by xlx on 15/7/29. 6 | // Copyright (c) 2015年 xlx. All rights reserved. 7 | // 8 | 9 | #import 10 | @class XActionSheet; 11 | @protocol XActionSheetDelegate 12 | @optional 13 | -(void)buttonClick:(NSInteger)index; 14 | 15 | @end 16 | @interface XActionSheet : UIViewController 17 | 18 | - (void)addCancelButton:(NSString *)Title; 19 | - (void)addButtonwithTitle:(NSString *)Title; 20 | - (void)addButtonWithTitleArray:(NSArray *)array; 21 | 22 | @property (nonatomic, strong) UIView *layView; 23 | @property (nonatomic, strong) UIButton *CancelButton; 24 | @property (nonatomic, strong) NSMutableArray *btnArray; 25 | 26 | @property (nonatomic, assign) iddelegate; 27 | @end 28 | -------------------------------------------------------------------------------- /Demo2Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.xlx.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Demo2/HZPhotoBrowser.h: -------------------------------------------------------------------------------- 1 | // 2 | // HZPhotoBrowser.h 3 | // photoBrowser 4 | // 5 | // Created by huangzhenyu on 15/6/23. 6 | // Copyright (c) 2015年 eamon. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "HZPhotoBrowserView.h" 11 | 12 | @class HZPhotoBrowser; 13 | 14 | @protocol HZPhotoBrowserDelegate 15 | 16 | - (UIImage *)photoBrowser:(HZPhotoBrowser *)browser placeholderImageForIndex:(NSInteger)index; 17 | - (NSURL *)photoBrowser:(HZPhotoBrowser *)browser highQualityImageURLForIndex:(NSInteger)index; 18 | @end 19 | 20 | @interface HZPhotoBrowser : UIViewController 21 | 22 | @property (nonatomic, weak) UIView *sourceImagesContainerView; 23 | @property (nonatomic, assign) int currentImageIndex; 24 | @property (nonatomic, assign) NSInteger imageCount;//图片总数 25 | 26 | @property (nonatomic, weak) id delegate; 27 | 28 | - (void)show; 29 | @end 30 | -------------------------------------------------------------------------------- /Demo2/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年 itcast. All rights reserved. 8 | // 9 | 10 | #import 11 | 12 | @interface UIScrollView (MJExtension) 13 | @property (assign, nonatomic) CGFloat mj_insetT; 14 | @property (assign, nonatomic) CGFloat mj_insetB; 15 | @property (assign, nonatomic) CGFloat mj_insetL; 16 | @property (assign, nonatomic) CGFloat mj_insetR; 17 | 18 | @property (assign, nonatomic) CGFloat mj_offsetX; 19 | @property (assign, nonatomic) CGFloat mj_offsetY; 20 | 21 | @property (assign, nonatomic) CGFloat mj_contentSizeW; 22 | @property (assign, nonatomic) CGFloat mj_contentSizeH; 23 | @end 24 | -------------------------------------------------------------------------------- /Demo2/PathCover/XHWaterDropRefresh.h: -------------------------------------------------------------------------------- 1 | // 2 | // XHWaterDropRefresh.h 3 | // XHPathCover 4 | // 5 | // Created by 曾 宪华 on 14-2-7. 6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface XHWaterDropRefresh : UIView 12 | 13 | @property (nonatomic, assign) CGFloat radius; // default is 5. 14 | @property (nonatomic, assign) CGFloat maxOffset; // default is 70 15 | @property (nonatomic, assign) CGFloat deformationLength; // default is 0.4 (between 0.1 -- 0.9) 16 | @property (nonatomic, assign) CGFloat offsetHeight; 17 | @property (nonatomic, strong) UIImage *refreshCircleImage; 18 | @property (nonatomic, readonly) BOOL isRefreshing; 19 | 20 | - (void)stopRefresh; 21 | - (void)startRefreshAnimation; 22 | 23 | @property (nonatomic, copy) void(^handleRefreshEvent)(void) ; 24 | @property (nonatomic) float currentOffset; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Demo2Tests/Demo2Tests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Demo2Tests.swift 3 | // Demo2Tests 4 | // 5 | // Created by xlx on 15/7/20. 6 | // Copyright (c) 2015年 xlx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import XCTest 11 | 12 | class Demo2Tests: XCTestCase { 13 | 14 | override func setUp() { 15 | super.setUp() 16 | // Put setup code here. This method is called before the invocation of each test method in the class. 17 | } 18 | 19 | override func tearDown() { 20 | // Put teardown code here. This method is called after the invocation of each test method in the class. 21 | super.tearDown() 22 | } 23 | 24 | func testExample() { 25 | // This is an example of a functional test case. 26 | XCTAssert(true, "Pass") 27 | } 28 | 29 | func testPerformanceExample() { 30 | // This is an example of a performance test case. 31 | self.measureBlock() { 32 | // Put the code you want to measure the time of here. 33 | } 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /Demo2/PathCover/XHSoundManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // XHSoundManager.m 3 | // XHPathCover 4 | // 5 | // Created by 曾 宪华 on 14-2-7. 6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved. 7 | // 8 | 9 | #import "XHSoundManager.h" 10 | #import 11 | 12 | @interface XHSoundManager () { 13 | SystemSoundID refreshSound; 14 | } 15 | 16 | @end 17 | 18 | @implementation XHSoundManager 19 | 20 | + (instancetype)sharedInstance { 21 | static XHSoundManager *instance; 22 | static dispatch_once_t onceToken; 23 | dispatch_once(&onceToken, ^{ 24 | instance = [[XHSoundManager alloc] init]; 25 | }); 26 | return instance; 27 | } 28 | 29 | - (id)init { 30 | self = [super init]; 31 | if (self) { 32 | NSURL *url = [[NSBundle mainBundle] URLForResource:@"pullrefresh" withExtension:@"aif"]; 33 | AudioServicesCreateSystemSoundID((__bridge CFURLRef)(url) , &refreshSound); 34 | } 35 | return self; 36 | } 37 | 38 | - (void)playRefreshSound { 39 | AudioServicesPlaySystemSound(refreshSound); 40 | } 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshConst.m: -------------------------------------------------------------------------------- 1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh 2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000 3 | #import 4 | 5 | const CGFloat MJRefreshHeaderHeight = 54.0; 6 | const CGFloat MJRefreshFooterHeight = 44.0; 7 | const CGFloat MJRefreshFastAnimationDuration = 0.25; 8 | const CGFloat MJRefreshSlowAnimationDuration = 0.4; 9 | 10 | NSString *const MJRefreshHeaderUpdatedTimeKey = @"MJRefreshHeaderUpdatedTimeKey"; 11 | NSString *const MJRefreshContentOffset = @"contentOffset"; 12 | NSString *const MJRefreshContentSize = @"contentSize"; 13 | NSString *const MJRefreshPanState = @"pan.state"; 14 | 15 | NSString *const MJRefreshHeaderStateIdleText = @"下拉可以刷新"; 16 | NSString *const MJRefreshHeaderStatePullingText = @"松开立即刷新"; 17 | NSString *const MJRefreshHeaderStateRefreshingText = @"正在刷新数据中..."; 18 | 19 | NSString *const MJRefreshFooterStateIdleText = @"点击加载更多"; 20 | NSString *const MJRefreshFooterStateRefreshingText = @"正在加载更多的数据..."; 21 | NSString *const MJRefreshFooterStateNoMoreDataText = @"已经全部加载完毕"; -------------------------------------------------------------------------------- /Demo2/HZPhotoBrowserConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // HZPhotoBrowserConfig.h 3 | // photoBrowser 4 | // 5 | // Created by huangzhenyu on 15/6/23. 6 | // Copyright (c) 2015年 eamon. All rights reserved. 7 | // 8 | 9 | typedef enum { 10 | HZIndicatorViewModeLoopDiagram, // 环形 11 | HZIndicatorViewModePieDiagram // 饼型 12 | } HZIndicatorViewMode; 13 | 14 | #define kAPPWidth [UIScreen mainScreen].bounds.size.width 15 | #define kAppHeight [UIScreen mainScreen].bounds.size.height 16 | 17 | //图片缩放比例 18 | #define kMinZoomScale 0.6f 19 | #define kMaxZoomScale 2.0f 20 | 21 | //是否支持横屏 22 | #define shouldSupportLandscape YES 23 | #define kIsFullWidthForLandScape YES //是否在横屏的时候直接满宽度,而不是满高度,一般是在有长图需求的时候设置为YES 24 | 25 | #define kIndicatorViewBackgroundColor [UIColor colorWithRed:0 green:0 blue:0 alpha:0.7] 26 | #define kPhotoBrowserBackgrounColor [UIColor colorWithRed:0 green:0 blue:0 alpha:1] 27 | 28 | // 图片间的间距 29 | #define kPhotoBrowserImageViewMargin 10 30 | 31 | // 图片下载进度指示器内部控件间的间距 32 | #define kIndicatorViewItemMargin 10 33 | 34 | // browser消失的动画时长 35 | #define kPhotoBrowserHideDuration 0.4f 36 | 37 | // browser出现的动画时长 38 | #define kPhotoBrowserShowDuration 0.4f 39 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIView+WebCacheOperation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageManager.h" 11 | 12 | @interface UIView (WebCacheOperation) 13 | 14 | /** 15 | * Set the image load operation (storage in a UIView based dictionary) 16 | * 17 | * @param operation the operation 18 | * @param key key for storing the operation 19 | */ 20 | - (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key; 21 | 22 | /** 23 | * Cancel all operations for the current UIView and key 24 | * 25 | * @param key key for identifying the operations 26 | */ 27 | - (void)sd_cancelImageLoadOperationWithKey:(NSString *)key; 28 | 29 | /** 30 | * Just remove the operations corresponding to the current UIView and key without cancelling them 31 | * 32 | * @param key key for identifying the operations 33 | */ 34 | - (void)sd_removeImageLoadOperationWithKey:(NSString *)key; 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/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年 itcast. All rights reserved. 8 | // 刷新组件:基本的开始刷新和结束刷新行为 9 | 10 | #import 11 | 12 | @interface MJRefreshComponent : UIView 13 | { 14 | UIEdgeInsets _scrollViewOriginalInset; 15 | __weak UIScrollView *_scrollView; 16 | } 17 | 18 | #pragma mark - 文字处理 19 | /** 文字颜色 */ 20 | @property (strong, nonatomic) UIColor *textColor; 21 | /** 字体大小 */ 22 | @property (strong, nonatomic) UIFont *font; 23 | 24 | #pragma mark - 刷新处理 25 | /** 正在刷新的回调 */ 26 | @property (copy, nonatomic) void (^refreshingBlock)(); 27 | /** 设置回调对象和回调方法 */ 28 | - (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action; 29 | @property (weak, nonatomic) id refreshingTarget; 30 | @property (assign, nonatomic) SEL refreshingAction; 31 | /** 进入刷新状态 */ 32 | - (void)beginRefreshing; 33 | /** 结束刷新状态 */ 34 | - (void)endRefreshing; 35 | /** 是否正在刷新 */ 36 | - (BOOL)isRefreshing; 37 | @end 38 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/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年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshComponent.h" 11 | 12 | typedef enum { 13 | MJRefreshFooterStateIdle = 1, // 普通闲置状态 14 | MJRefreshFooterStateRefreshing, // 正在刷新中的状态 15 | MJRefreshFooterStateNoMoreData // 所有数据加载完毕,没有更多的数据了 16 | } MJRefreshFooterState; 17 | 18 | @interface MJRefreshFooter : MJRefreshComponent 19 | /** 提示没有更多的数据 */ 20 | - (void)noticeNoMoreData; 21 | /** 重置没有更多的数据(消除没有更多数据的状态) */ 22 | - (void)resetNoMoreData; 23 | 24 | /** 刷新控件的状态(交给子类重写) */ 25 | @property (assign, nonatomic) MJRefreshFooterState state; 26 | 27 | /** 是否隐藏状态标签 */ 28 | @property (assign, nonatomic, getter=isStateHidden) BOOL stateHidden; 29 | 30 | /** 31 | * 设置state状态下的状态文字内容title 32 | */ 33 | - (void)setTitle:(NSString *)title forState:(MJRefreshFooterState)state; 34 | 35 | /** 是否自动刷新(默认为YES) */ 36 | @property (assign, nonatomic, getter=isAutomaticallyRefresh) BOOL automaticallyRefresh; 37 | 38 | /** 当底部控件出现多少时就自动刷新(默认为1.0,也就是底部控件完全出现时,才会自动刷新) */ 39 | @property (assign, nonatomic) CGFloat appearencePercentTriggerAutoRefresh; 40 | @end 41 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/NSData+ImageContentType.m: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Fabrice Aneche on 06/01/14. 3 | // Copyright (c) 2014 Dailymotion. All rights reserved. 4 | // 5 | 6 | #import "NSData+ImageContentType.h" 7 | 8 | 9 | @implementation NSData (ImageContentType) 10 | 11 | + (NSString *)sd_contentTypeForImageData:(NSData *)data { 12 | uint8_t c; 13 | [data getBytes:&c length:1]; 14 | switch (c) { 15 | case 0xFF: 16 | return @"image/jpeg"; 17 | case 0x89: 18 | return @"image/png"; 19 | case 0x47: 20 | return @"image/gif"; 21 | case 0x49: 22 | case 0x4D: 23 | return @"image/tiff"; 24 | case 0x52: 25 | // R as RIFF for WEBP 26 | if ([data length] < 12) { 27 | return nil; 28 | } 29 | 30 | NSString *testString = [[NSString alloc] initWithData:[data subdataWithRange:NSMakeRange(0, 12)] encoding:NSASCIIStringEncoding]; 31 | if ([testString hasPrefix:@"RIFF"] && [testString hasSuffix:@"WEBP"]) { 32 | return @"image/webp"; 33 | } 34 | 35 | return nil; 36 | } 37 | return nil; 38 | } 39 | 40 | @end 41 | 42 | 43 | @implementation NSData (ImageContentTypeDeprecated) 44 | 45 | + (NSString *)contentTypeForImageData:(NSData *)data { 46 | return [self sd_contentTypeForImageData:data]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /Demo2/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /Demo2/MJRefresh/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年 itcast. All rights reserved. 8 | // 下拉刷新控件:负责监控用户下拉的状态 9 | 10 | #import "MJRefreshComponent.h" 11 | 12 | // 下拉刷新控件的状态 13 | typedef enum { 14 | /** 普通闲置状态 */ 15 | MJRefreshHeaderStateIdle = 1, 16 | /** 松开就可以进行刷新的状态 */ 17 | MJRefreshHeaderStatePulling, 18 | /** 正在刷新中的状态 */ 19 | MJRefreshHeaderStateRefreshing, 20 | /** 即将刷新的状态 */ 21 | MJRefreshHeaderStateWillRefresh 22 | } MJRefreshHeaderState; 23 | 24 | @interface MJRefreshHeader : MJRefreshComponent 25 | /** 利用这个key来保存上次的刷新时间(不同界面的刷新控件应该用不同的dateKey,以区分不同界面的刷新时间) */ 26 | @property (copy, nonatomic) NSString *dateKey; 27 | 28 | /** 利用这个block来决定显示的更新时间 */ 29 | @property (copy, nonatomic) NSString *(^updatedTimeTitle)(NSDate *updatedTime); 30 | 31 | /** 32 | * 设置state状态下的状态文字内容title(别直接拿stateLabel修改文字) 33 | */ 34 | - (void)setTitle:(NSString *)title forState:(MJRefreshHeaderState)state; 35 | /** 刷新控件的状态 */ 36 | @property (assign, nonatomic) MJRefreshHeaderState state; 37 | 38 | #pragma mark - 文字控件的可见性处理 39 | /** 是否隐藏状态标签 */ 40 | @property (assign, nonatomic, getter=isStateHidden) BOOL stateHidden; 41 | /** 是否隐藏刷新时间标签 */ 42 | @property (assign, nonatomic, getter=isUpdatedTimeHidden) BOOL updatedTimeHidden; 43 | 44 | #pragma mark - 交给子类重写 45 | /** 下拉的百分比(交给子类重写) */ 46 | @property (assign, nonatomic) CGFloat pullingPercent; 47 | @end 48 | -------------------------------------------------------------------------------- /Demo2.xcodeproj/project.xcworkspace/xcshareddata/Demo2.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 866E8258-B2D2-4292-9E08-7A6879059963 9 | IDESourceControlProjectName 10 | Demo2 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | FCDDB4F675848B2FA8A74043A711B1BA9883CDE2 14 | https://github.com/superxlx/Demo2.git 15 | 16 | IDESourceControlProjectPath 17 | Demo2.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | FCDDB4F675848B2FA8A74043A711B1BA9883CDE2 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/superxlx/Demo2.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | FCDDB4F675848B2FA8A74043A711B1BA9883CDE2 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | FCDDB4F675848B2FA8A74043A711B1BA9883CDE2 36 | IDESourceControlWCCName 37 | XActionSheet 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Demo2/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | com.xlx.$(PRODUCT_NAME:rfc1034identifier) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImageCompat.m: -------------------------------------------------------------------------------- 1 | // 2 | // SDWebImageCompat.m 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 11/12/12. 6 | // Copyright (c) 2012 Dailymotion. All rights reserved. 7 | // 8 | 9 | #import "SDWebImageCompat.h" 10 | 11 | #if !__has_feature(objc_arc) 12 | #error SDWebImage is ARC only. Either turn on ARC for the project or use -fobjc-arc flag 13 | #endif 14 | 15 | inline UIImage *SDScaledImageForKey(NSString *key, UIImage *image) { 16 | if (!image) { 17 | return nil; 18 | } 19 | 20 | if ([image.images count] > 0) { 21 | NSMutableArray *scaledImages = [NSMutableArray array]; 22 | 23 | for (UIImage *tempImage in image.images) { 24 | [scaledImages addObject:SDScaledImageForKey(key, tempImage)]; 25 | } 26 | 27 | return [UIImage animatedImageWithImages:scaledImages duration:image.duration]; 28 | } 29 | else { 30 | if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) { 31 | CGFloat scale = [UIScreen mainScreen].scale; 32 | if (key.length >= 8) { 33 | NSRange range = [key rangeOfString:@"@2x."]; 34 | if (range.location != NSNotFound) { 35 | scale = 2.0; 36 | } 37 | 38 | range = [key rangeOfString:@"@3x."]; 39 | if (range.location != NSNotFound) { 40 | scale = 3.0; 41 | } 42 | } 43 | 44 | UIImage *scaledImage = [[UIImage alloc] initWithCGImage:image.CGImage scale:scale orientation:image.imageOrientation]; 45 | image = scaledImage; 46 | } 47 | return image; 48 | } 49 | } 50 | 51 | NSString *const SDWebImageErrorDomain = @"SDWebImageErrorDomain"; 52 | -------------------------------------------------------------------------------- /Demo2/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年 itcast. 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 | -------------------------------------------------------------------------------- /Demo2/LineView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // LineView.swift 3 | // Demo2 4 | // 5 | // Created by xlx on 15/7/27. 6 | // Copyright (c) 2015年 xlx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class LineView: UIView { 12 | 13 | var labelTile = ["动态","关注","粉丝","文章","文集"] 14 | override func drawRect(rect: CGRect) { 15 | var context = UIGraphicsGetCurrentContext() 16 | CGContextSetRGBStrokeColor(context, 0, 0, 0, 0.3) 17 | CGContextSetLineWidth(context, 0.5) 18 | 19 | for var i = 1 ; i <= 4 ; i++ { 20 | CGContextMoveToPoint(context, (CGFloat)(i)*rect.width/5, 10) 21 | CGContextAddLineToPoint(context, (CGFloat)(i)*rect.width/5, rect.height - 10) 22 | } 23 | 24 | CGContextMoveToPoint(context, 0, 5) 25 | CGContextAddLineToPoint(context, rect.width, 5) 26 | 27 | CGContextMoveToPoint(context, 0, rect.height - 5) 28 | CGContextAddLineToPoint(context, rect.width, rect.height - 5) 29 | 30 | CGContextStrokePath(context) 31 | 32 | } 33 | 34 | override init(frame: CGRect) { 35 | super.init(frame: frame) 36 | self.backgroundColor = UIColor.whiteColor() 37 | for var i = 0 ; i<5 ; i++ { 38 | var label = UILabel(frame: CGRectMake((CGFloat)(i) * frame.width / 5, frame.height / 3, frame.width / 5, frame.height / 3 * 2)) 39 | 40 | label.text = labelTile[i] 41 | label.textColor = UIColor.grayColor() 42 | label.font = UIFont.systemFontOfSize(13) 43 | label.textAlignment = NSTextAlignment.Center 44 | self.addSubview(label) 45 | 46 | } 47 | 48 | 49 | } 50 | 51 | required init(coder aDecoder: NSCoder) { 52 | fatalError("init(coder:) has not been implemented") 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /Demo2/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 | 5 | // 日志输出 6 | #ifdef DEBUG 7 | #define MJLog(...) NSLog(__VA_ARGS__) 8 | #else 9 | #define MJLog(...) 10 | #endif 11 | 12 | // 过期提醒 13 | #define MJDeprecated(instead) NS_DEPRECATED(2_0, 2_0, 2_0, 2_0, instead) 14 | 15 | // 运行时objc_msgSend 16 | #define msgSend(...) ((void (*)(void *, SEL, UIView *))objc_msgSend)(__VA_ARGS__) 17 | #define msgTarget(target) (__bridge void *)(target) 18 | 19 | // RGB颜色 20 | #define MJColor(r, g, b) [UIColor colorWithRed:(r)/255.0 green:(g)/255.0 blue:(b)/255.0 alpha:1.0] 21 | 22 | // 文字颜色 23 | #define MJRefreshLabelTextColor MJColor(100, 100, 100) 24 | 25 | // 字体大小 26 | #define MJRefreshLabelFont [UIFont boldSystemFontOfSize:13] 27 | 28 | // 图片路径 29 | #define MJRefreshSrcName(file) [@"MJRefresh.bundle" stringByAppendingPathComponent:file] 30 | 31 | // 常量 32 | UIKIT_EXTERN const CGFloat MJRefreshHeaderHeight; 33 | UIKIT_EXTERN const CGFloat MJRefreshFooterHeight; 34 | UIKIT_EXTERN const CGFloat MJRefreshFastAnimationDuration; 35 | UIKIT_EXTERN const CGFloat MJRefreshSlowAnimationDuration; 36 | 37 | UIKIT_EXTERN NSString *const MJRefreshHeaderUpdatedTimeKey; 38 | UIKIT_EXTERN NSString *const MJRefreshContentOffset; 39 | UIKIT_EXTERN NSString *const MJRefreshContentSize; 40 | UIKIT_EXTERN NSString *const MJRefreshPanState; 41 | 42 | UIKIT_EXTERN NSString *const MJRefreshHeaderStateIdleText; 43 | UIKIT_EXTERN NSString *const MJRefreshHeaderStatePullingText; 44 | UIKIT_EXTERN NSString *const MJRefreshHeaderStateRefreshingText; 45 | 46 | UIKIT_EXTERN NSString *const MJRefreshFooterStateIdleText; 47 | UIKIT_EXTERN NSString *const MJRefreshFooterStateRefreshingText; 48 | UIKIT_EXTERN NSString *const MJRefreshFooterStateNoMoreDataText; -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImageDecoder.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * Created by james on 9/28/11. 6 | * 7 | * For the full copyright and license information, please view the LICENSE 8 | * file that was distributed with this source code. 9 | */ 10 | 11 | #import "SDWebImageDecoder.h" 12 | 13 | @implementation UIImage (ForceDecode) 14 | 15 | + (UIImage *)decodedImageWithImage:(UIImage *)image { 16 | // do not decode animated images 17 | if (image.images) { return image; } 18 | 19 | CGImageRef imageRef = image.CGImage; 20 | 21 | CGImageAlphaInfo alpha = CGImageGetAlphaInfo(imageRef); 22 | BOOL anyAlpha = (alpha == kCGImageAlphaFirst || 23 | alpha == kCGImageAlphaLast || 24 | alpha == kCGImageAlphaPremultipliedFirst || 25 | alpha == kCGImageAlphaPremultipliedLast); 26 | 27 | if (anyAlpha) { return image; } 28 | 29 | size_t width = CGImageGetWidth(imageRef); 30 | size_t height = CGImageGetHeight(imageRef); 31 | 32 | CGContextRef context = CGBitmapContextCreate(NULL, width, 33 | height, 34 | CGImageGetBitsPerComponent(imageRef), 35 | 0, 36 | CGImageGetColorSpace(imageRef), 37 | kCGBitmapByteOrderDefault | kCGImageAlphaPremultipliedFirst); 38 | 39 | // Draw the image into the context and retrieve the new image, which will now have an alpha layer 40 | CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); 41 | CGImageRef imageRefWithAlpha = CGBitmapContextCreateImage(context); 42 | UIImage *imageWithAlpha = [UIImage imageWithCGImage:imageRefWithAlpha]; 43 | 44 | CGContextRelease(context); 45 | CGImageRelease(imageRefWithAlpha); 46 | 47 | return imageWithAlpha; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImageCompat.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * (c) Jamie Pinkham 5 | * 6 | * For the full copyright and license information, please view the LICENSE 7 | * file that was distributed with this source code. 8 | */ 9 | 10 | #import 11 | 12 | #ifdef __OBJC_GC__ 13 | #error SDWebImage does not support Objective-C Garbage Collection 14 | #endif 15 | 16 | #if __IPHONE_OS_VERSION_MIN_REQUIRED != 20000 && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_5_0 17 | #error SDWebImage doesn't support Deployement Target version < 5.0 18 | #endif 19 | 20 | #if !TARGET_OS_IPHONE 21 | #import 22 | #ifndef UIImage 23 | #define UIImage NSImage 24 | #endif 25 | #ifndef UIImageView 26 | #define UIImageView NSImageView 27 | #endif 28 | #else 29 | 30 | #import 31 | 32 | #endif 33 | 34 | #ifndef NS_ENUM 35 | #define NS_ENUM(_type, _name) enum _name : _type _name; enum _name : _type 36 | #endif 37 | 38 | #ifndef NS_OPTIONS 39 | #define NS_OPTIONS(_type, _name) enum _name : _type _name; enum _name : _type 40 | #endif 41 | 42 | #if OS_OBJECT_USE_OBJC 43 | #undef SDDispatchQueueRelease 44 | #undef SDDispatchQueueSetterSementics 45 | #define SDDispatchQueueRelease(q) 46 | #define SDDispatchQueueSetterSementics strong 47 | #else 48 | #undef SDDispatchQueueRelease 49 | #undef SDDispatchQueueSetterSementics 50 | #define SDDispatchQueueRelease(q) (dispatch_release(q)) 51 | #define SDDispatchQueueSetterSementics assign 52 | #endif 53 | 54 | extern UIImage *SDScaledImageForKey(NSString *key, UIImage *image); 55 | 56 | typedef void(^SDWebImageNoParamsBlock)(); 57 | 58 | extern NSString *const SDWebImageErrorDomain; 59 | 60 | #define dispatch_main_sync_safe(block)\ 61 | if ([NSThread isMainThread]) {\ 62 | block();\ 63 | } else {\ 64 | dispatch_sync(dispatch_get_main_queue(), block);\ 65 | } 66 | 67 | #define dispatch_main_async_safe(block)\ 68 | if ([NSThread isMainThread]) {\ 69 | block();\ 70 | } else {\ 71 | dispatch_async(dispatch_get_main_queue(), block);\ 72 | } 73 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIView+WebCacheOperation.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "UIView+WebCacheOperation.h" 10 | #import "objc/runtime.h" 11 | 12 | static char loadOperationKey; 13 | 14 | @implementation UIView (WebCacheOperation) 15 | 16 | - (NSMutableDictionary *)operationDictionary { 17 | NSMutableDictionary *operations = objc_getAssociatedObject(self, &loadOperationKey); 18 | if (operations) { 19 | return operations; 20 | } 21 | operations = [NSMutableDictionary dictionary]; 22 | objc_setAssociatedObject(self, &loadOperationKey, operations, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 23 | return operations; 24 | } 25 | 26 | - (void)sd_setImageLoadOperation:(id)operation forKey:(NSString *)key { 27 | [self sd_cancelImageLoadOperationWithKey:key]; 28 | NSMutableDictionary *operationDictionary = [self operationDictionary]; 29 | [operationDictionary setObject:operation forKey:key]; 30 | } 31 | 32 | - (void)sd_cancelImageLoadOperationWithKey:(NSString *)key { 33 | // Cancel in progress downloader from queue 34 | NSMutableDictionary *operationDictionary = [self operationDictionary]; 35 | id operations = [operationDictionary objectForKey:key]; 36 | if (operations) { 37 | if ([operations isKindOfClass:[NSArray class]]) { 38 | for (id operation in operations) { 39 | if (operation) { 40 | [operation cancel]; 41 | } 42 | } 43 | } else if ([operations conformsToProtocol:@protocol(SDWebImageOperation)]){ 44 | [(id) operations cancel]; 45 | } 46 | [operationDictionary removeObjectForKey:key]; 47 | } 48 | } 49 | 50 | - (void)sd_removeImageLoadOperationWithKey:(NSString *)key { 51 | NSMutableDictionary *operationDictionary = [self operationDictionary]; 52 | [operationDictionary removeObjectForKey:key]; 53 | } 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshLegendFooter.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 | // MJRefreshLegendFooter.m 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/5. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshLegendFooter.h" 11 | #import "MJRefreshConst.h" 12 | #import "UIView+MJExtension.h" 13 | #import "UIScrollView+MJExtension.h" 14 | 15 | @interface MJRefreshLegendFooter() 16 | @property (nonatomic, weak) UIActivityIndicatorView *activityView; 17 | @end 18 | 19 | @implementation MJRefreshLegendFooter 20 | #pragma mark - 懒加载 21 | - (UIActivityIndicatorView *)activityView 22 | { 23 | if (!_activityView) { 24 | UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 25 | [self addSubview:_activityView = activityView]; 26 | } 27 | return _activityView; 28 | } 29 | 30 | #pragma mark - 初始化方法 31 | - (void)layoutSubviews 32 | { 33 | [super layoutSubviews]; 34 | 35 | // 指示器 36 | if (self.stateHidden) { 37 | self.activityView.center = CGPointMake(self.mj_w * 0.5, self.mj_h * 0.5); 38 | } else { 39 | self.activityView.center = CGPointMake(self.mj_w * 0.5 - 100, self.mj_h * 0.5); 40 | } 41 | } 42 | 43 | #pragma mark - 公共方法 44 | - (void)setState:(MJRefreshFooterState)state 45 | { 46 | if (self.state == state) return; 47 | 48 | switch (state) { 49 | case MJRefreshFooterStateIdle: 50 | [self.activityView stopAnimating]; 51 | break; 52 | 53 | case MJRefreshFooterStateRefreshing: 54 | [self.activityView startAnimating]; 55 | break; 56 | 57 | case MJRefreshFooterStateNoMoreData: 58 | [self.activityView stopAnimating]; 59 | break; 60 | 61 | default: 62 | break; 63 | } 64 | 65 | // super里面有回调,应该在最后面调用 66 | [super setState:state]; 67 | } 68 | @end 69 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshComponent.m: -------------------------------------------------------------------------------- 1 | // 代码地址: https://github.com/CoderMJLee/MJRefresh 2 | // 代码地址: http://code4app.com/ios/%E5%BF%AB%E9%80%9F%E9%9B%86%E6%88%90%E4%B8%8B%E6%8B%89%E4%B8%8A%E6%8B%89%E5%88%B7%E6%96%B0/52326ce26803fabc46000000 3 | // MJRefreshComponent.m 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/4. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshComponent.h" 11 | #import "MJRefreshConst.h" 12 | #import "UIView+MJExtension.h" 13 | 14 | @interface MJRefreshComponent() 15 | /** 记录scrollView刚开始的inset */ 16 | @property (assign, nonatomic) UIEdgeInsets scrollViewOriginalInset; 17 | /** 父控件 */ 18 | @property (weak, nonatomic) UIScrollView *scrollView; 19 | @end 20 | 21 | @implementation MJRefreshComponent 22 | #pragma mark - 初始化 23 | - (instancetype)initWithFrame:(CGRect)frame 24 | { 25 | if (self = [super initWithFrame:frame]) { 26 | // 基本属性 27 | self.autoresizingMask = UIViewAutoresizingFlexibleWidth; 28 | self.backgroundColor = [UIColor clearColor]; 29 | 30 | // 默认文字颜色和字体大小 31 | self.textColor = MJRefreshLabelTextColor; 32 | self.font = MJRefreshLabelFont; 33 | } 34 | return self; 35 | } 36 | 37 | - (void)willMoveToSuperview:(UIView *)newSuperview 38 | { 39 | [super willMoveToSuperview:newSuperview]; 40 | 41 | // 旧的父控件 42 | [self.superview removeObserver:self forKeyPath:MJRefreshContentOffset context:nil]; 43 | 44 | if (newSuperview) { // 新的父控件 45 | [newSuperview addObserver:self forKeyPath:MJRefreshContentOffset options:NSKeyValueObservingOptionNew context:nil]; 46 | 47 | // 设置宽度 48 | self.mj_w = newSuperview.mj_w; 49 | // 设置位置 50 | self.mj_x = 0; 51 | 52 | // 记录UIScrollView 53 | self.scrollView = (UIScrollView *)newSuperview; 54 | // 设置永远支持垂直弹簧效果 55 | self.scrollView.alwaysBounceVertical = YES; 56 | // 记录UIScrollView最开始的contentInset 57 | self.scrollViewOriginalInset = self.scrollView.contentInset; 58 | } 59 | } 60 | 61 | #pragma mark - 公共方法 62 | - (void)setRefreshingTarget:(id)target refreshingAction:(SEL)action 63 | { 64 | self.refreshingTarget = target; 65 | self.refreshingAction = action; 66 | } 67 | 68 | - (void)beginRefreshing 69 | { 70 | 71 | } 72 | 73 | - (void)endRefreshing 74 | { 75 | 76 | } 77 | 78 | - (BOOL)isRefreshing { 79 | return NO; 80 | } 81 | @end 82 | -------------------------------------------------------------------------------- /Demo2/ProgressHUD/ProgressHUD.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) 2014 Related Code - http://relatedcode.com 3 | // 4 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 5 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 6 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 7 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 8 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 9 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 10 | // THE SOFTWARE. 11 | 12 | #import 13 | 14 | //------------------------------------------------------------------------------------------------------------------------------------------------- 15 | #define HUD_STATUS_FONT [UIFont boldSystemFontOfSize:16] 16 | #define HUD_STATUS_COLOR [UIColor blackColor] 17 | 18 | #define HUD_SPINNER_COLOR [UIColor colorWithRed:185.0/255.0 green:220.0/255.0 blue:47.0/255.0 alpha:1.0] 19 | #define HUD_BACKGROUND_COLOR [UIColor colorWithWhite:0.0 alpha:0.1] 20 | #define HUD_WINDOW_COLOR [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.2] 21 | 22 | #define HUD_IMAGE_SUCCESS [UIImage imageNamed:@"ProgressHUD.bundle/progresshud-success.png"] 23 | #define HUD_IMAGE_ERROR [UIImage imageNamed:@"ProgressHUD.bundle/progresshud-error.png"] 24 | 25 | //------------------------------------------------------------------------------------------------------------------------------------------------- 26 | @interface ProgressHUD : UIView 27 | //------------------------------------------------------------------------------------------------------------------------------------------------- 28 | 29 | + (ProgressHUD *)shared; 30 | 31 | + (void)dismiss; 32 | 33 | + (void)show:(NSString *)status; 34 | + (void)show:(NSString *)status Interaction:(BOOL)Interaction; 35 | 36 | + (void)showSuccess:(NSString *)status; 37 | + (void)showSuccess:(NSString *)status Interaction:(BOOL)Interaction; 38 | 39 | + (void)showError:(NSString *)status; 40 | + (void)showError:(NSString *)status Interaction:(BOOL)Interaction; 41 | 42 | @property (nonatomic, assign) BOOL interaction; 43 | 44 | @property (nonatomic, retain) UIWindow *window; 45 | @property (nonatomic, retain) UIView *background; 46 | @property (nonatomic, retain) UIToolbar *hud; 47 | @property (nonatomic, retain) UIActivityIndicatorView *spinner; 48 | @property (nonatomic, retain) UIImageView *image; 49 | @property (nonatomic, retain) UILabel *label; 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImage+WebP.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+WebP.m 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 07/06/13. 6 | // Copyright (c) 2013 Dailymotion. All rights reserved. 7 | // 8 | 9 | #ifdef SD_WEBP 10 | #import "UIImage+WebP.h" 11 | #import "webp/decode.h" 12 | 13 | // Callback for CGDataProviderRelease 14 | static void FreeImageData(void *info, const void *data, size_t size) 15 | { 16 | free((void *)data); 17 | } 18 | 19 | @implementation UIImage (WebP) 20 | 21 | + (UIImage *)sd_imageWithWebPData:(NSData *)data { 22 | WebPDecoderConfig config; 23 | if (!WebPInitDecoderConfig(&config)) { 24 | return nil; 25 | } 26 | 27 | if (WebPGetFeatures(data.bytes, data.length, &config.input) != VP8_STATUS_OK) { 28 | return nil; 29 | } 30 | 31 | config.output.colorspace = config.input.has_alpha ? MODE_rgbA : MODE_RGB; 32 | config.options.use_threads = 1; 33 | 34 | // Decode the WebP image data into a RGBA value array. 35 | if (WebPDecode(data.bytes, data.length, &config) != VP8_STATUS_OK) { 36 | return nil; 37 | } 38 | 39 | int width = config.input.width; 40 | int height = config.input.height; 41 | if (config.options.use_scaling) { 42 | width = config.options.scaled_width; 43 | height = config.options.scaled_height; 44 | } 45 | 46 | // Construct a UIImage from the decoded RGBA value array. 47 | CGDataProviderRef provider = 48 | CGDataProviderCreateWithData(NULL, config.output.u.RGBA.rgba, config.output.u.RGBA.size, FreeImageData); 49 | CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB(); 50 | CGBitmapInfo bitmapInfo = config.input.has_alpha ? kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast : 0; 51 | size_t components = config.input.has_alpha ? 4 : 3; 52 | CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault; 53 | CGImageRef imageRef = CGImageCreate(width, height, 8, components * 8, components * width, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent); 54 | 55 | CGColorSpaceRelease(colorSpaceRef); 56 | CGDataProviderRelease(provider); 57 | 58 | UIImage *image = [[UIImage alloc] initWithCGImage:imageRef]; 59 | CGImageRelease(imageRef); 60 | 61 | return image; 62 | } 63 | 64 | @end 65 | 66 | #if !COCOAPODS 67 | // Functions to resolve some undefined symbols when using WebP and force_load flag 68 | void WebPInitPremultiplyNEON(void) {} 69 | void WebPInitUpsamplersNEON(void) {} 70 | void VP8DspInitNEON(void) {} 71 | #endif 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /Demo2/PathCover/XHPathCover.h: -------------------------------------------------------------------------------- 1 | // 2 | // XHPathConver.h 3 | // XHPathCover 4 | // 5 | // Created by 曾 宪华 on 14-2-7. 6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | // user info key for Dictionary 12 | extern NSString *const XHUserNameKey; 13 | extern NSString *const XHBirthdayKey; 14 | 15 | @interface XHPathCover : UIView 16 | 17 | // parallax background 18 | @property (nonatomic, strong) UIImageView *bannerImageView; 19 | @property (nonatomic, strong) UIImageView *bannerImageViewWithImageEffects; 20 | 21 | // user info 22 | @property (nonatomic, strong) UIButton *avatarButton; 23 | @property (nonatomic, strong) UILabel *userNameLabel; 24 | @property (nonatomic, strong) UILabel *birthdayLabel; 25 | 26 | 27 | //scrollView call back 28 | @property (nonatomic) BOOL touching; 29 | @property (nonatomic) CGFloat offsetY; 30 | 31 | // parallax background origin Y for parallaxHeight 32 | @property (nonatomic, assign) CGFloat parallaxHeight; // default is 170, this height was not self heigth. 33 | 34 | @property (nonatomic, assign) BOOL isZoomingEffect; // default is NO, if isZoomingEffect is YES, will be dissmiss parallax effect 35 | @property (nonatomic, assign) BOOL isLightEffect; // default is YES 36 | @property (nonatomic, assign) CGFloat lightEffectPadding; // default is 80 37 | @property (nonatomic, assign) CGFloat lightEffectAlpha; // default is 1.12 (between 1 - 2) 38 | 39 | @property (nonatomic, copy) void(^handleRefreshEvent)(void); 40 | 41 | @property (nonatomic, copy) void(^handleTapBackgroundImageEvent)(void); 42 | 43 | // stop Refresh 44 | - (void)stopRefresh; 45 | 46 | // background image 47 | - (void)setBackgroundImage:(UIImage *)backgroundImage; 48 | // custom set url for subClass, There is not work 49 | - (void)setBackgroundImageUrlString:(NSString *)backgroundImageUrlString; 50 | 51 | // avatar image 52 | - (void)setAvatarImage:(UIImage *)avatarImage; 53 | // custom set url for subClass, There is not work 54 | - (void)setAvatarUrlString:(NSString *)avatarUrlString; 55 | 56 | // set info, Example : NSDictionary *info = [NSDictionary dictionaryWithObjectsAndKeys:@"Jack", @"userName", @"1990-10-19", @"birthday", nil]; 57 | - (void)setInfo:(NSDictionary *)info; 58 | 59 | - (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView; 60 | - (void)scrollViewDidScroll:(UIScrollView *)scrollView; 61 | - (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate; 62 | - (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView; 63 | @end 64 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshGifFooter.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 | // MJRefreshGifFooter.m 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/5. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshGifFooter.h" 11 | #import "MJRefreshConst.h" 12 | #import "UIView+MJExtension.h" 13 | #import "UIScrollView+MJExtension.h" 14 | 15 | @interface MJRefreshGifFooter() 16 | /** 播放动画图片的控件 */ 17 | @property (weak, nonatomic) UIImageView *gifView; 18 | @end 19 | 20 | @implementation MJRefreshGifFooter 21 | #pragma mark - 懒加载 22 | - (UIImageView *)gifView 23 | { 24 | if (!_gifView) { 25 | UIImageView *gifView = [[UIImageView alloc] init]; 26 | [self addSubview:_gifView = gifView]; 27 | } 28 | return _gifView; 29 | } 30 | 31 | #pragma mark - 初始化方法 32 | - (void)layoutSubviews 33 | { 34 | [super layoutSubviews]; 35 | 36 | // 指示器 37 | self.gifView.frame = self.bounds; 38 | if (self.stateHidden) { 39 | self.gifView.contentMode = UIViewContentModeCenter; 40 | } else { 41 | self.gifView.contentMode = UIViewContentModeRight; 42 | self.gifView.mj_w = self.mj_w * 0.5 - 90; 43 | } 44 | } 45 | 46 | #pragma mark - 公共方法 47 | - (void)setState:(MJRefreshFooterState)state 48 | { 49 | if (self.state == state) return; 50 | 51 | switch (state) { 52 | case MJRefreshFooterStateIdle: 53 | self.gifView.hidden = YES; 54 | [self.gifView stopAnimating]; 55 | break; 56 | 57 | case MJRefreshFooterStateRefreshing: 58 | self.gifView.hidden = NO; 59 | [self.gifView startAnimating]; 60 | break; 61 | 62 | case MJRefreshFooterStateNoMoreData: 63 | self.gifView.hidden = YES; 64 | [self.gifView stopAnimating]; 65 | break; 66 | 67 | default: 68 | break; 69 | } 70 | 71 | // super里面有回调,应该在最后面调用 72 | [super setState:state]; 73 | } 74 | 75 | - (void)setRefreshingImages:(NSArray *)refreshingImages 76 | { 77 | _refreshingImages = refreshingImages; 78 | 79 | self.gifView.animationImages = refreshingImages; 80 | self.gifView.animationDuration = refreshingImages.count * 0.1; 81 | 82 | // 根据图片设置控件的高度 83 | UIImage *image = [refreshingImages firstObject]; 84 | if (image.size.height > self.mj_h) { 85 | _scrollView.mj_insetB -= self.mj_h; 86 | self.mj_h = image.size.height; 87 | _scrollView.mj_insetB += self.mj_h; 88 | } 89 | } 90 | @end 91 | -------------------------------------------------------------------------------- /Demo2/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年 itcast. All rights reserved. 8 | // 9 | 10 | #import "UIScrollView+MJExtension.h" 11 | 12 | @implementation UIScrollView (MJExtension) 13 | - (void)setMj_insetT:(CGFloat)mj_insetT 14 | { 15 | UIEdgeInsets inset = self.contentInset; 16 | inset.top = mj_insetT; 17 | self.contentInset = inset; 18 | } 19 | 20 | - (CGFloat)mj_insetT 21 | { 22 | return self.contentInset.top; 23 | } 24 | 25 | - (void)setMj_insetB:(CGFloat)mj_insetB 26 | { 27 | UIEdgeInsets inset = self.contentInset; 28 | inset.bottom = mj_insetB; 29 | self.contentInset = inset; 30 | } 31 | 32 | - (CGFloat)mj_insetB 33 | { 34 | return self.contentInset.bottom; 35 | } 36 | 37 | - (void)setMj_insetL:(CGFloat)mj_insetL 38 | { 39 | UIEdgeInsets inset = self.contentInset; 40 | inset.left = mj_insetL; 41 | self.contentInset = inset; 42 | } 43 | 44 | - (CGFloat)mj_insetL 45 | { 46 | return self.contentInset.left; 47 | } 48 | 49 | - (void)setMj_insetR:(CGFloat)mj_insetR 50 | { 51 | UIEdgeInsets inset = self.contentInset; 52 | inset.right = mj_insetR; 53 | self.contentInset = inset; 54 | } 55 | 56 | - (CGFloat)mj_insetR 57 | { 58 | return self.contentInset.right; 59 | } 60 | 61 | - (void)setMj_offsetX:(CGFloat)mj_offsetX 62 | { 63 | CGPoint offset = self.contentOffset; 64 | offset.x = mj_offsetX; 65 | self.contentOffset = offset; 66 | } 67 | 68 | - (CGFloat)mj_offsetX 69 | { 70 | return self.contentOffset.x; 71 | } 72 | 73 | - (void)setMj_offsetY:(CGFloat)mj_offsetY 74 | { 75 | CGPoint offset = self.contentOffset; 76 | offset.y = mj_offsetY; 77 | self.contentOffset = offset; 78 | } 79 | 80 | - (CGFloat)mj_offsetY 81 | { 82 | return self.contentOffset.y; 83 | } 84 | 85 | - (void)setMj_contentSizeW:(CGFloat)mj_contentSizeW 86 | { 87 | CGSize size = self.contentSize; 88 | size.width = mj_contentSizeW; 89 | self.contentSize = size; 90 | } 91 | 92 | - (CGFloat)mj_contentSizeW 93 | { 94 | return self.contentSize.width; 95 | } 96 | 97 | - (void)setMj_contentSizeH:(CGFloat)mj_contentSizeH 98 | { 99 | CGSize size = self.contentSize; 100 | size.height = mj_contentSizeH; 101 | self.contentSize = size; 102 | } 103 | 104 | - (CGFloat)mj_contentSizeH 105 | { 106 | return self.contentSize.height; 107 | } 108 | @end 109 | -------------------------------------------------------------------------------- /Demo2/HZIndicatorView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HZIndicatorView.m 3 | // photoBrowser 4 | // 5 | // Created by huangzhenyu on 15/6/23. 6 | // Copyright (c) 2015年 eamon. All rights reserved. 7 | // 8 | 9 | #import "HZIndicatorView.h" 10 | #import "HZPhotoBrowserConfig.h" 11 | 12 | @implementation HZIndicatorView 13 | 14 | - (instancetype)initWithFrame:(CGRect)frame 15 | { 16 | if (self = [super initWithFrame:frame]) { 17 | self.backgroundColor = kIndicatorViewBackgroundColor; 18 | self.clipsToBounds = YES; 19 | self.viewMode = HZIndicatorViewModeLoopDiagram;//圆 20 | } 21 | return self; 22 | } 23 | 24 | - (void)setProgress:(CGFloat)progress 25 | { 26 | _progress = progress; 27 | [self setNeedsDisplay]; 28 | if (progress >= 1) { 29 | [self removeFromSuperview]; 30 | } 31 | } 32 | 33 | - (void)setFrame:(CGRect)frame 34 | { 35 | frame.size.width = 42; 36 | frame.size.height = 42; 37 | self.layer.cornerRadius = 21; 38 | [super setFrame:frame]; 39 | } 40 | 41 | - (void)drawRect:(CGRect)rect 42 | { 43 | CGContextRef ctx = UIGraphicsGetCurrentContext(); 44 | 45 | CGFloat xCenter = rect.size.width * 0.5; 46 | CGFloat yCenter = rect.size.height * 0.5; 47 | [[UIColor whiteColor] set]; 48 | 49 | switch (self.viewMode) { 50 | case HZIndicatorViewModePieDiagram: 51 | { 52 | CGFloat radius = MIN(rect.size.width * 0.5, rect.size.height * 0.5) - kIndicatorViewItemMargin; 53 | 54 | 55 | CGFloat w = radius * 2 + kIndicatorViewItemMargin; 56 | CGFloat h = w; 57 | CGFloat x = (rect.size.width - w) * 0.5; 58 | CGFloat y = (rect.size.height - h) * 0.5; 59 | CGContextAddEllipseInRect(ctx, CGRectMake(x, y, w, h)); 60 | CGContextFillPath(ctx); 61 | 62 | [kIndicatorViewBackgroundColor set]; 63 | CGContextMoveToPoint(ctx, xCenter, yCenter); 64 | CGContextAddLineToPoint(ctx, xCenter, 0); 65 | CGFloat to = - M_PI * 0.5 + self.progress * M_PI * 2 + 0.001; // 初始值 66 | CGContextAddArc(ctx, xCenter, yCenter, radius, - M_PI * 0.5, to, 1); 67 | CGContextClosePath(ctx); 68 | 69 | CGContextFillPath(ctx); 70 | } 71 | break; 72 | 73 | default: 74 | { 75 | CGContextSetLineWidth(ctx, 4); 76 | CGContextSetLineCap(ctx, kCGLineCapRound); 77 | CGFloat to = - M_PI * 0.5 + self.progress * M_PI * 2 + 0.05; // 初始值0.05 78 | CGFloat radius = MIN(rect.size.width, rect.size.height) * 0.5 - kIndicatorViewItemMargin; 79 | CGContextAddArc(ctx, xCenter, yCenter, radius, - M_PI * 0.5, to, 0); 80 | CGContextStrokePath(ctx); 81 | } 82 | break; 83 | } 84 | } 85 | @end 86 | -------------------------------------------------------------------------------- /Demo2/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 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImageDownloaderOperation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageDownloader.h" 11 | #import "SDWebImageOperation.h" 12 | 13 | extern NSString *const SDWebImageDownloadStartNotification; 14 | extern NSString *const SDWebImageDownloadReceiveResponseNotification; 15 | extern NSString *const SDWebImageDownloadStopNotification; 16 | extern NSString *const SDWebImageDownloadFinishNotification; 17 | 18 | @interface SDWebImageDownloaderOperation : NSOperation 19 | 20 | /** 21 | * The request used by the operation's connection. 22 | */ 23 | @property (strong, nonatomic, readonly) NSURLRequest *request; 24 | 25 | 26 | @property (assign, nonatomic) BOOL shouldDecompressImages; 27 | 28 | /** 29 | * Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. 30 | * 31 | * This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`. 32 | */ 33 | @property (nonatomic, assign) BOOL shouldUseCredentialStorage; 34 | 35 | /** 36 | * The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. 37 | * 38 | * This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. 39 | */ 40 | @property (nonatomic, strong) NSURLCredential *credential; 41 | 42 | /** 43 | * The SDWebImageDownloaderOptions for the receiver. 44 | */ 45 | @property (assign, nonatomic, readonly) SDWebImageDownloaderOptions options; 46 | 47 | /** 48 | * The expected size of data. 49 | */ 50 | @property (assign, nonatomic) NSInteger expectedSize; 51 | 52 | /** 53 | * The response returned by the operation's connection. 54 | */ 55 | @property (strong, nonatomic) NSURLResponse *response; 56 | 57 | /** 58 | * Initializes a `SDWebImageDownloaderOperation` object 59 | * 60 | * @see SDWebImageDownloaderOperation 61 | * 62 | * @param request the URL request 63 | * @param options downloader options 64 | * @param progressBlock the block executed when a new chunk of data arrives. 65 | * @note the progress block is executed on a background queue 66 | * @param completedBlock the block executed when the download is done. 67 | * @note the completed block is executed on the main queue for success. If errors are found, there is a chance the block will be executed on a background queue 68 | * @param cancelBlock the block executed if the download (operation) is cancelled 69 | * 70 | * @return the initialized instance 71 | */ 72 | - (id)initWithRequest:(NSURLRequest *)request 73 | options:(SDWebImageDownloaderOptions)options 74 | progress:(SDWebImageDownloaderProgressBlock)progressBlock 75 | completed:(SDWebImageDownloaderCompletedBlock)completedBlock 76 | cancelled:(SDWebImageNoParamsBlock)cancelBlock; 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshLegendHeader.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 | // MJRefreshLegendHeader.m 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/4. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshLegendHeader.h" 11 | #import "MJRefreshConst.h" 12 | #import "UIView+MJExtension.h" 13 | 14 | @interface MJRefreshLegendHeader() 15 | @property (nonatomic, weak) UIImageView *arrowImage; 16 | @property (nonatomic, weak) UIActivityIndicatorView *activityView; 17 | @end 18 | 19 | @implementation MJRefreshLegendHeader 20 | #pragma mark - 懒加载 21 | - (UIImageView *)arrowImage 22 | { 23 | if (!_arrowImage) { 24 | UIImageView *arrowImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:MJRefreshSrcName(@"arrow.png")]]; 25 | [self addSubview:_arrowImage = arrowImage]; 26 | } 27 | return _arrowImage; 28 | } 29 | 30 | - (UIActivityIndicatorView *)activityView 31 | { 32 | if (!_activityView) { 33 | UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; 34 | activityView.bounds = self.arrowImage.bounds; 35 | [self addSubview:_activityView = activityView]; 36 | } 37 | return _activityView; 38 | } 39 | 40 | #pragma mark - 初始化 41 | - (void)layoutSubviews 42 | { 43 | [super layoutSubviews]; 44 | 45 | // 箭头 46 | CGFloat arrowX = (self.stateHidden && self.updatedTimeHidden) ? self.mj_w * 0.5 : (self.mj_w * 0.5 - 100); 47 | self.arrowImage.center = CGPointMake(arrowX, self.mj_h * 0.5); 48 | 49 | // 指示器 50 | self.activityView.center = self.arrowImage.center; 51 | } 52 | 53 | #pragma mark - 公共方法 54 | #pragma mark 设置状态 55 | - (void)setState:(MJRefreshHeaderState)state 56 | { 57 | if (self.state == state) return; 58 | 59 | // 旧状态 60 | MJRefreshHeaderState oldState = self.state; 61 | 62 | switch (state) { 63 | case MJRefreshHeaderStateIdle: { 64 | if (oldState == MJRefreshHeaderStateRefreshing) { 65 | self.arrowImage.transform = CGAffineTransformIdentity; 66 | 67 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{ 68 | self.activityView.alpha = 0.0; 69 | } completion:^(BOOL finished) { 70 | self.arrowImage.alpha = 1.0; 71 | self.activityView.alpha = 1.0; 72 | [self.activityView stopAnimating]; 73 | }]; 74 | } else { 75 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 76 | self.arrowImage.transform = CGAffineTransformIdentity; 77 | }]; 78 | } 79 | break; 80 | } 81 | 82 | case MJRefreshHeaderStatePulling: { 83 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 84 | self.arrowImage.transform = CGAffineTransformMakeRotation(0.000001 - M_PI); 85 | }]; 86 | break; 87 | } 88 | 89 | case MJRefreshHeaderStateRefreshing: { 90 | [self.activityView startAnimating]; 91 | self.arrowImage.alpha = 0.0; 92 | break; 93 | } 94 | 95 | default: 96 | break; 97 | } 98 | 99 | // super里面有回调,应该在最后面调用 100 | [super setState:state]; 101 | } 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /Demo2/Base.lproj/LaunchScreen.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImage+MultiFormat.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+MultiFormat.m 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 07/06/13. 6 | // Copyright (c) 2013 Dailymotion. All rights reserved. 7 | // 8 | 9 | #import "UIImage+MultiFormat.h" 10 | #import "UIImage+GIF.h" 11 | #import "NSData+ImageContentType.h" 12 | #import 13 | 14 | #ifdef SD_WEBP 15 | #import "UIImage+WebP.h" 16 | #endif 17 | 18 | @implementation UIImage (MultiFormat) 19 | 20 | + (UIImage *)sd_imageWithData:(NSData *)data { 21 | if (!data) { 22 | return nil; 23 | } 24 | 25 | UIImage *image; 26 | NSString *imageContentType = [NSData sd_contentTypeForImageData:data]; 27 | if ([imageContentType isEqualToString:@"image/gif"]) { 28 | image = [UIImage sd_animatedGIFWithData:data]; 29 | } 30 | #ifdef SD_WEBP 31 | else if ([imageContentType isEqualToString:@"image/webp"]) 32 | { 33 | image = [UIImage sd_imageWithWebPData:data]; 34 | } 35 | #endif 36 | else { 37 | image = [[UIImage alloc] initWithData:data]; 38 | UIImageOrientation orientation = [self sd_imageOrientationFromImageData:data]; 39 | if (orientation != UIImageOrientationUp) { 40 | image = [UIImage imageWithCGImage:image.CGImage 41 | scale:image.scale 42 | orientation:orientation]; 43 | } 44 | } 45 | 46 | 47 | return image; 48 | } 49 | 50 | 51 | +(UIImageOrientation)sd_imageOrientationFromImageData:(NSData *)imageData { 52 | UIImageOrientation result = UIImageOrientationUp; 53 | CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL); 54 | if (imageSource) { 55 | CFDictionaryRef properties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, NULL); 56 | if (properties) { 57 | CFTypeRef val; 58 | int exifOrientation; 59 | val = CFDictionaryGetValue(properties, kCGImagePropertyOrientation); 60 | if (val) { 61 | CFNumberGetValue(val, kCFNumberIntType, &exifOrientation); 62 | result = [self sd_exifOrientationToiOSOrientation:exifOrientation]; 63 | } // else - if it's not set it remains at up 64 | CFRelease((CFTypeRef) properties); 65 | } else { 66 | //NSLog(@"NO PROPERTIES, FAIL"); 67 | } 68 | CFRelease(imageSource); 69 | } 70 | return result; 71 | } 72 | 73 | #pragma mark EXIF orientation tag converter 74 | // Convert an EXIF image orientation to an iOS one. 75 | // reference see here: http://sylvana.net/jpegcrop/exif_orientation.html 76 | + (UIImageOrientation) sd_exifOrientationToiOSOrientation:(int)exifOrientation { 77 | UIImageOrientation orientation = UIImageOrientationUp; 78 | switch (exifOrientation) { 79 | case 1: 80 | orientation = UIImageOrientationUp; 81 | break; 82 | 83 | case 3: 84 | orientation = UIImageOrientationDown; 85 | break; 86 | 87 | case 8: 88 | orientation = UIImageOrientationLeft; 89 | break; 90 | 91 | case 6: 92 | orientation = UIImageOrientationRight; 93 | break; 94 | 95 | case 2: 96 | orientation = UIImageOrientationUpMirrored; 97 | break; 98 | 99 | case 4: 100 | orientation = UIImageOrientationDownMirrored; 101 | break; 102 | 103 | case 5: 104 | orientation = UIImageOrientationLeftMirrored; 105 | break; 106 | 107 | case 7: 108 | orientation = UIImageOrientationRightMirrored; 109 | break; 110 | default: 111 | break; 112 | } 113 | return orientation; 114 | } 115 | 116 | 117 | 118 | @end 119 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImagePrefetcher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageManager.h" 11 | 12 | @class SDWebImagePrefetcher; 13 | 14 | @protocol SDWebImagePrefetcherDelegate 15 | 16 | @optional 17 | 18 | /** 19 | * Called when an image was prefetched. 20 | * 21 | * @param imagePrefetcher The current image prefetcher 22 | * @param imageURL The image url that was prefetched 23 | * @param finishedCount The total number of images that were prefetched (successful or not) 24 | * @param totalCount The total number of images that were to be prefetched 25 | */ 26 | - (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didPrefetchURL:(NSURL *)imageURL finishedCount:(NSUInteger)finishedCount totalCount:(NSUInteger)totalCount; 27 | 28 | /** 29 | * Called when all images are prefetched. 30 | * @param imagePrefetcher The current image prefetcher 31 | * @param totalCount The total number of images that were prefetched (whether successful or not) 32 | * @param skippedCount The total number of images that were skipped 33 | */ 34 | - (void)imagePrefetcher:(SDWebImagePrefetcher *)imagePrefetcher didFinishWithTotalCount:(NSUInteger)totalCount skippedCount:(NSUInteger)skippedCount; 35 | 36 | @end 37 | 38 | typedef void(^SDWebImagePrefetcherProgressBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfTotalUrls); 39 | typedef void(^SDWebImagePrefetcherCompletionBlock)(NSUInteger noOfFinishedUrls, NSUInteger noOfSkippedUrls); 40 | 41 | /** 42 | * Prefetch some URLs in the cache for future use. Images are downloaded in low priority. 43 | */ 44 | @interface SDWebImagePrefetcher : NSObject 45 | 46 | /** 47 | * The web image manager 48 | */ 49 | @property (strong, nonatomic, readonly) SDWebImageManager *manager; 50 | 51 | /** 52 | * Maximum number of URLs to prefetch at the same time. Defaults to 3. 53 | */ 54 | @property (nonatomic, assign) NSUInteger maxConcurrentDownloads; 55 | 56 | /** 57 | * SDWebImageOptions for prefetcher. Defaults to SDWebImageLowPriority. 58 | */ 59 | @property (nonatomic, assign) SDWebImageOptions options; 60 | 61 | /** 62 | * Queue options for Prefetcher. Defaults to Main Queue. 63 | */ 64 | @property (nonatomic, assign) dispatch_queue_t prefetcherQueue; 65 | 66 | @property (weak, nonatomic) id delegate; 67 | 68 | /** 69 | * Return the global image prefetcher instance. 70 | */ 71 | + (SDWebImagePrefetcher *)sharedImagePrefetcher; 72 | 73 | /** 74 | * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, 75 | * currently one image is downloaded at a time, 76 | * and skips images for failed downloads and proceed to the next image in the list 77 | * 78 | * @param urls list of URLs to prefetch 79 | */ 80 | - (void)prefetchURLs:(NSArray *)urls; 81 | 82 | /** 83 | * Assign list of URLs to let SDWebImagePrefetcher to queue the prefetching, 84 | * currently one image is downloaded at a time, 85 | * and skips images for failed downloads and proceed to the next image in the list 86 | * 87 | * @param urls list of URLs to prefetch 88 | * @param progressBlock block to be called when progress updates; 89 | * first parameter is the number of completed (successful or not) requests, 90 | * second parameter is the total number of images originally requested to be prefetched 91 | * @param completionBlock block to be called when prefetching is completed 92 | * first param is the number of completed (successful or not) requests, 93 | * second parameter is the number of skipped requests 94 | */ 95 | - (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock; 96 | 97 | /** 98 | * Remove and cancel queued list 99 | */ 100 | - (void)cancelPrefetching; 101 | 102 | 103 | @end 104 | -------------------------------------------------------------------------------- /Demo2/XActionSheet.m: -------------------------------------------------------------------------------- 1 | // 2 | // XActionSheet.m 3 | // Demo2 4 | // 5 | // Created by xlx on 15/7/29. 6 | // Copyright (c) 2015年 xlx. All rights reserved. 7 | // 8 | 9 | #import "XActionSheet.h" 10 | 11 | @interface XActionSheet () 12 | { 13 | CGFloat width; 14 | CGFloat height; 15 | } 16 | @end 17 | 18 | @implementation XActionSheet 19 | - (id)init{ 20 | self = [super init]; 21 | self.modalPresentationStyle = UIModalPresentationOverFullScreen; 22 | self.view.backgroundColor = [UIColor clearColor]; 23 | UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap)]; 24 | [self.view addGestureRecognizer:tap]; 25 | 26 | _btnArray = [[NSMutableArray alloc]init]; 27 | width = self.view.bounds.size.width; 28 | height = self.view.bounds.size.height; 29 | return self; 30 | } 31 | - (void)viewDidLoad { 32 | [super viewDidLoad]; 33 | } 34 | 35 | - (void)didReceiveMemoryWarning { 36 | [super didReceiveMemoryWarning]; 37 | // Dispose of any resources that can be recreated. 38 | } 39 | 40 | - (void)tap{ 41 | [self dismissViewControllerAnimated:true completion:^{ 42 | 43 | }]; 44 | } 45 | /** 46 | * 添加取消按钮 47 | */ 48 | -(void)addCancelButton:(NSString *)Title{ 49 | if (!_layView) { 50 | _layView = [[UIView alloc]initWithFrame:CGRectMake(width * 0.1,height - ( _btnArray.count * 40 + 40 + 30), width * 0.8, _btnArray.count * 40 + 40 + 20)]; 51 | _layView.layer.cornerRadius = 5; 52 | _layView.alpha = 0.8; 53 | _layView.layer.masksToBounds = true; 54 | [self.view addSubview:_layView]; 55 | }else{ 56 | CGFloat nowHeight = _layView.bounds.size.height; 57 | nowHeight += 50; 58 | _layView.frame = CGRectMake(width * 0.1, height - nowHeight, width * 0.8, nowHeight); 59 | } 60 | if (!_CancelButton) { 61 | _CancelButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 40 * _btnArray.count + 10, width * 0.8, 40)]; 62 | [_CancelButton setTitle:Title forState:normal]; 63 | _CancelButton.layer.cornerRadius = 5; 64 | _CancelButton.layer.masksToBounds = true; 65 | _CancelButton.backgroundColor = [UIColor brownColor]; 66 | [_CancelButton addTarget:self action:@selector(tap) forControlEvents:UIControlEventTouchUpInside]; 67 | [_layView addSubview:_CancelButton]; 68 | }else{ 69 | [_CancelButton setTitle:Title forState:normal]; 70 | } 71 | } 72 | /** 73 | * 添加按钮 74 | */ 75 | -(void)addButtonwithTitle:(NSString *)Title{ 76 | if (!_layView) { 77 | _layView = [[UIView alloc]initWithFrame:CGRectMake(width * 0.1,height - ( 40 + 10), width * 0.8, _btnArray.count * 40 + 40 + 20)]; 78 | _layView.layer.cornerRadius = 5; 79 | _layView.alpha = 0.8; 80 | _layView.layer.masksToBounds = true; 81 | [self.view addSubview:_layView]; 82 | }else{ 83 | CGFloat nowHeight = _layView.bounds.size.height; 84 | nowHeight += 40; 85 | _layView.frame = CGRectMake(width * 0.1, height - nowHeight, width * 0.8, nowHeight); 86 | } 87 | 88 | UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(0, _btnArray.count * 40, width * 0.8, 39)]; 89 | btn.tag = _btnArray.count; 90 | [btn addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside]; 91 | btn.backgroundColor = [UIColor colorWithRed:(CGFloat)52/255 green:(CGFloat)170/255 blue:(CGFloat)135/255 alpha:1]; 92 | [btn setTitle:Title forState:normal]; 93 | [_btnArray addObject:btn]; 94 | [_layView addSubview:btn]; 95 | 96 | CGFloat cancelY = _CancelButton.frame.origin.y; 97 | _CancelButton.frame = CGRectMake(0, cancelY + 40, width * 0.8, 40); 98 | } 99 | - (void)addButtonWithTitleArray:(NSArray *)array{ 100 | for (NSString *Title in array) { 101 | [self addButtonwithTitle:Title]; 102 | } 103 | } 104 | /** 105 | * 按钮点击动作 106 | */ 107 | - (void)buttonClick:(id)sender{ 108 | [self dismissViewControllerAnimated:true completion:^{ 109 | 110 | }]; 111 | UIButton *btn = (UIButton *)sender; 112 | [_delegate buttonClick:btn.tag]; 113 | } 114 | 115 | 116 | @end 117 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/MJRefreshGifHeader.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 | // MJRefreshGifHeader.m 4 | // MJRefreshExample 5 | // 6 | // Created by MJ Lee on 15/3/4. 7 | // Copyright (c) 2015年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshGifHeader.h" 11 | #import "MJRefreshConst.h" 12 | #import "UIView+MJExtension.h" 13 | 14 | @interface MJRefreshGifHeader() 15 | /** 所有状态对应的动画图片 */ 16 | @property (strong, nonatomic) NSMutableDictionary *stateImages; 17 | 18 | /** 播放动画图片的控件 */ 19 | @property (weak, nonatomic) UIImageView *gifView; 20 | @end 21 | 22 | @implementation MJRefreshGifHeader 23 | #pragma mark - 懒加载 24 | - (NSMutableDictionary *)stateImages 25 | { 26 | if (!_stateImages) { 27 | self.stateImages = [NSMutableDictionary dictionary]; 28 | } 29 | return _stateImages; 30 | } 31 | 32 | - (UIImageView *)gifView 33 | { 34 | if (!_gifView) { 35 | UIImageView *gifView = [[UIImageView alloc] init]; 36 | [self addSubview:_gifView = gifView]; 37 | } 38 | return _gifView; 39 | } 40 | 41 | #pragma mark - 初始化 42 | - (void)layoutSubviews 43 | { 44 | [super layoutSubviews]; 45 | 46 | self.gifView.frame = self.bounds; 47 | if (self.stateHidden && self.updatedTimeHidden) { 48 | self.gifView.contentMode = UIViewContentModeCenter; 49 | } else { 50 | self.gifView.contentMode = UIViewContentModeRight; 51 | self.gifView.mj_w = self.mj_w * 0.5 - 90; 52 | } 53 | } 54 | 55 | #pragma mark - 公共方法 56 | #pragma mark 设置状态 57 | - (void)setState:(MJRefreshHeaderState)state 58 | { 59 | if (self.state == state) return; 60 | 61 | // 旧状态 62 | MJRefreshHeaderState oldState = self.state; 63 | 64 | NSArray *images = self.stateImages[@(state)]; 65 | if (images.count != 0) { 66 | switch (state) { 67 | case MJRefreshHeaderStateIdle: { 68 | if (oldState == MJRefreshHeaderStateRefreshing) { 69 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(MJRefreshSlowAnimationDuration * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 70 | self.pullingPercent = 0.0; 71 | }); 72 | } else { 73 | self.pullingPercent = self.pullingPercent; 74 | } 75 | break; 76 | } 77 | 78 | case MJRefreshHeaderStatePulling: 79 | case MJRefreshHeaderStateRefreshing: { 80 | [self.gifView stopAnimating]; 81 | if (images.count == 1) { // 单张图片 82 | self.gifView.image = [images lastObject]; 83 | } else { // 多张图片 84 | self.gifView.animationImages = images; 85 | self.gifView.animationDuration = images.count * 0.1; 86 | [self.gifView startAnimating]; 87 | } 88 | break; 89 | } 90 | 91 | default: 92 | break; 93 | } 94 | } 95 | 96 | // super里面有回调,应该在最后面调用 97 | [super setState:state]; 98 | } 99 | 100 | - (void)setPullingPercent:(CGFloat)pullingPercent 101 | { 102 | [super setPullingPercent:pullingPercent]; 103 | 104 | NSArray *images = self.stateImages[@(self.state)]; 105 | switch (self.state) { 106 | case MJRefreshHeaderStateIdle: { 107 | [self.gifView stopAnimating]; 108 | NSUInteger index = images.count * self.pullingPercent; 109 | if (index >= images.count) index = images.count - 1; 110 | self.gifView.image = images[index]; 111 | break; 112 | } 113 | default: 114 | break; 115 | } 116 | } 117 | 118 | - (void)setImages:(NSArray *)images forState:(MJRefreshHeaderState)state 119 | { 120 | if (images == nil) return; 121 | 122 | self.stateImages[@(state)] = images; 123 | 124 | // 根据图片设置控件的高度 125 | UIImage *image = [images firstObject]; 126 | if (image.size.height > self.mj_h) { 127 | self.mj_h = image.size.height; 128 | } 129 | } 130 | @end 131 | -------------------------------------------------------------------------------- /Demo2.xcodeproj/xcuserdata/xlx.xcuserdatad/xcschemes/Demo2.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 29 | 35 | 36 | 37 | 38 | 39 | 44 | 45 | 47 | 53 | 54 | 55 | 56 | 57 | 63 | 64 | 65 | 66 | 75 | 77 | 83 | 84 | 85 | 86 | 87 | 88 | 94 | 96 | 102 | 103 | 104 | 105 | 107 | 108 | 111 | 112 | 113 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImageView+HighlightedWebCache.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "UIImageView+HighlightedWebCache.h" 10 | #import "UIView+WebCacheOperation.h" 11 | 12 | #define UIImageViewHighlightedWebCacheOperationKey @"highlightedImage" 13 | 14 | @implementation UIImageView (HighlightedWebCache) 15 | 16 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url { 17 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil]; 18 | } 19 | 20 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options { 21 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; 22 | } 23 | 24 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock { 25 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:completedBlock]; 26 | } 27 | 28 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock { 29 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:completedBlock]; 30 | } 31 | 32 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock { 33 | [self sd_cancelCurrentHighlightedImageLoad]; 34 | 35 | if (url) { 36 | __weak __typeof(self)wself = self; 37 | id operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { 38 | if (!wself) return; 39 | dispatch_main_sync_safe (^ 40 | { 41 | if (!wself) return; 42 | if (image) { 43 | wself.highlightedImage = image; 44 | [wself setNeedsLayout]; 45 | } 46 | if (completedBlock && finished) { 47 | completedBlock(image, error, cacheType, url); 48 | } 49 | }); 50 | }]; 51 | [self sd_setImageLoadOperation:operation forKey:UIImageViewHighlightedWebCacheOperationKey]; 52 | } else { 53 | dispatch_main_async_safe(^{ 54 | NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; 55 | if (completedBlock) { 56 | completedBlock(nil, error, SDImageCacheTypeNone, url); 57 | } 58 | }); 59 | } 60 | } 61 | 62 | - (void)sd_cancelCurrentHighlightedImageLoad { 63 | [self sd_cancelImageLoadOperationWithKey:UIImageViewHighlightedWebCacheOperationKey]; 64 | } 65 | 66 | @end 67 | 68 | 69 | @implementation UIImageView (HighlightedWebCacheDeprecated) 70 | 71 | - (void)setHighlightedImageWithURL:(NSURL *)url { 72 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:nil]; 73 | } 74 | 75 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options { 76 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:nil]; 77 | } 78 | 79 | - (void)setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock { 80 | [self sd_setHighlightedImageWithURL:url options:0 progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 81 | if (completedBlock) { 82 | completedBlock(image, error, cacheType); 83 | } 84 | }]; 85 | } 86 | 87 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock { 88 | [self sd_setHighlightedImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 89 | if (completedBlock) { 90 | completedBlock(image, error, cacheType); 91 | } 92 | }]; 93 | } 94 | 95 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock { 96 | [self sd_setHighlightedImageWithURL:url options:0 progress:progressBlock completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 97 | if (completedBlock) { 98 | completedBlock(image, error, cacheType); 99 | } 100 | }]; 101 | } 102 | 103 | - (void)cancelCurrentHighlightedImageLoad { 104 | [self sd_cancelCurrentHighlightedImageLoad]; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/MKAnnotationView+WebCache.m: -------------------------------------------------------------------------------- 1 | // 2 | // MKAnnotationView+WebCache.m 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 14/03/12. 6 | // Copyright (c) 2012 Dailymotion. All rights reserved. 7 | // 8 | 9 | #import "MKAnnotationView+WebCache.h" 10 | #import "objc/runtime.h" 11 | #import "UIView+WebCacheOperation.h" 12 | 13 | static char imageURLKey; 14 | 15 | @implementation MKAnnotationView (WebCache) 16 | 17 | - (NSURL *)sd_imageURL { 18 | return objc_getAssociatedObject(self, &imageURLKey); 19 | } 20 | 21 | - (void)sd_setImageWithURL:(NSURL *)url { 22 | [self sd_setImageWithURL:url placeholderImage:nil options:0 completed:nil]; 23 | } 24 | 25 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder { 26 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:nil]; 27 | } 28 | 29 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { 30 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options completed:nil]; 31 | } 32 | 33 | - (void)sd_setImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock { 34 | [self sd_setImageWithURL:url placeholderImage:nil options:0 completed:completedBlock]; 35 | } 36 | 37 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock { 38 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:completedBlock]; 39 | } 40 | 41 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock { 42 | [self sd_cancelCurrentImageLoad]; 43 | 44 | objc_setAssociatedObject(self, &imageURLKey, url, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 45 | self.image = placeholder; 46 | 47 | if (url) { 48 | __weak __typeof(self)wself = self; 49 | id operation = [SDWebImageManager.sharedManager downloadImageWithURL:url options:options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { 50 | if (!wself) return; 51 | dispatch_main_sync_safe(^{ 52 | __strong MKAnnotationView *sself = wself; 53 | if (!sself) return; 54 | if (image) { 55 | sself.image = image; 56 | } 57 | if (completedBlock && finished) { 58 | completedBlock(image, error, cacheType, url); 59 | } 60 | }); 61 | }]; 62 | [self sd_setImageLoadOperation:operation forKey:@"MKAnnotationViewImage"]; 63 | } else { 64 | dispatch_main_async_safe(^{ 65 | NSError *error = [NSError errorWithDomain:SDWebImageErrorDomain code:-1 userInfo:@{NSLocalizedDescriptionKey : @"Trying to load a nil url"}]; 66 | if (completedBlock) { 67 | completedBlock(nil, error, SDImageCacheTypeNone, url); 68 | } 69 | }); 70 | } 71 | } 72 | 73 | - (void)sd_cancelCurrentImageLoad { 74 | [self sd_cancelImageLoadOperationWithKey:@"MKAnnotationViewImage"]; 75 | } 76 | 77 | @end 78 | 79 | 80 | @implementation MKAnnotationView (WebCacheDeprecated) 81 | 82 | - (NSURL *)imageURL { 83 | return [self sd_imageURL]; 84 | } 85 | 86 | - (void)setImageWithURL:(NSURL *)url { 87 | [self sd_setImageWithURL:url placeholderImage:nil options:0 completed:nil]; 88 | } 89 | 90 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder { 91 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:nil]; 92 | } 93 | 94 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options { 95 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options completed:nil]; 96 | } 97 | 98 | - (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock { 99 | [self sd_setImageWithURL:url placeholderImage:nil options:0 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 100 | if (completedBlock) { 101 | completedBlock(image, error, cacheType); 102 | } 103 | }]; 104 | } 105 | 106 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock { 107 | [self sd_setImageWithURL:url placeholderImage:placeholder options:0 completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 108 | if (completedBlock) { 109 | completedBlock(image, error, cacheType); 110 | } 111 | }]; 112 | } 113 | 114 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock { 115 | [self sd_setImageWithURL:url placeholderImage:placeholder options:options completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 116 | if (completedBlock) { 117 | completedBlock(image, error, cacheType); 118 | } 119 | }]; 120 | } 121 | 122 | - (void)cancelCurrentImageLoad { 123 | [self sd_cancelCurrentImageLoad]; 124 | } 125 | 126 | @end 127 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImageView+HighlightedWebCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | #import "SDWebImageManager.h" 12 | 13 | /** 14 | * Integrates SDWebImage async downloading and caching of remote images with UIImageView for highlighted state. 15 | */ 16 | @interface UIImageView (HighlightedWebCache) 17 | 18 | /** 19 | * Set the imageView `highlightedImage` with an `url`. 20 | * 21 | * The download is asynchronous and cached. 22 | * 23 | * @param url The url for the image. 24 | */ 25 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url; 26 | 27 | /** 28 | * Set the imageView `highlightedImage` with an `url` and custom options. 29 | * 30 | * The download is asynchronous and cached. 31 | * 32 | * @param url The url for the image. 33 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 34 | */ 35 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options; 36 | 37 | /** 38 | * Set the imageView `highlightedImage` with an `url`. 39 | * 40 | * The download is asynchronous and cached. 41 | * 42 | * @param url The url for the image. 43 | * @param completedBlock A block called when operation has been completed. This block has no return value 44 | * and takes the requested UIImage as first parameter. In case of error the image parameter 45 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 46 | * indicating if the image was retrived from the local cache or from the network. 47 | * The fourth parameter is the original image url. 48 | */ 49 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock; 50 | 51 | /** 52 | * Set the imageView `highlightedImage` with an `url` and custom options. 53 | * 54 | * The download is asynchronous and cached. 55 | * 56 | * @param url The url for the image. 57 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 58 | * @param completedBlock A block called when operation has been completed. This block has no return value 59 | * and takes the requested UIImage as first parameter. In case of error the image parameter 60 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 61 | * indicating if the image was retrived from the local cache or from the network. 62 | * The fourth parameter is the original image url. 63 | */ 64 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock; 65 | 66 | /** 67 | * Set the imageView `highlightedImage` with an `url` and custom options. 68 | * 69 | * The download is asynchronous and cached. 70 | * 71 | * @param url The url for the image. 72 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 73 | * @param progressBlock A block called while image is downloading 74 | * @param completedBlock A block called when operation has been completed. This block has no return value 75 | * and takes the requested UIImage as first parameter. In case of error the image parameter 76 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 77 | * indicating if the image was retrived from the local cache or from the network. 78 | * The fourth parameter is the original image url. 79 | */ 80 | - (void)sd_setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock; 81 | 82 | /** 83 | * Cancel the current download 84 | */ 85 | - (void)sd_cancelCurrentHighlightedImageLoad; 86 | 87 | @end 88 | 89 | 90 | @interface UIImageView (HighlightedWebCacheDeprecated) 91 | 92 | - (void)setHighlightedImageWithURL:(NSURL *)url __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:`"); 93 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:`"); 94 | - (void)setHighlightedImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:completed:`"); 95 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:completed:`"); 96 | - (void)setHighlightedImageWithURL:(NSURL *)url options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setHighlightedImageWithURL:options:progress:completed:`"); 97 | 98 | - (void)cancelCurrentHighlightedImageLoad __deprecated_msg("Use `sd_cancelCurrentHighlightedImageLoad`"); 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImage+GIF.m: -------------------------------------------------------------------------------- 1 | // 2 | // UIImage+GIF.m 3 | // LBGIFImage 4 | // 5 | // Created by Laurin Brandner on 06.01.12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "UIImage+GIF.h" 10 | #import 11 | 12 | @implementation UIImage (GIF) 13 | 14 | + (UIImage *)sd_animatedGIFWithData:(NSData *)data { 15 | if (!data) { 16 | return nil; 17 | } 18 | 19 | CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL); 20 | 21 | size_t count = CGImageSourceGetCount(source); 22 | 23 | UIImage *animatedImage; 24 | 25 | if (count <= 1) { 26 | animatedImage = [[UIImage alloc] initWithData:data]; 27 | } 28 | else { 29 | NSMutableArray *images = [NSMutableArray array]; 30 | 31 | NSTimeInterval duration = 0.0f; 32 | 33 | for (size_t i = 0; i < count; i++) { 34 | CGImageRef image = CGImageSourceCreateImageAtIndex(source, i, NULL); 35 | 36 | duration += [self sd_frameDurationAtIndex:i source:source]; 37 | 38 | [images addObject:[UIImage imageWithCGImage:image scale:[UIScreen mainScreen].scale orientation:UIImageOrientationUp]]; 39 | 40 | CGImageRelease(image); 41 | } 42 | 43 | if (!duration) { 44 | duration = (1.0f / 10.0f) * count; 45 | } 46 | 47 | animatedImage = [UIImage animatedImageWithImages:images duration:duration]; 48 | } 49 | 50 | CFRelease(source); 51 | 52 | return animatedImage; 53 | } 54 | 55 | + (float)sd_frameDurationAtIndex:(NSUInteger)index source:(CGImageSourceRef)source { 56 | float frameDuration = 0.1f; 57 | CFDictionaryRef cfFrameProperties = CGImageSourceCopyPropertiesAtIndex(source, index, nil); 58 | NSDictionary *frameProperties = (__bridge NSDictionary *)cfFrameProperties; 59 | NSDictionary *gifProperties = frameProperties[(NSString *)kCGImagePropertyGIFDictionary]; 60 | 61 | NSNumber *delayTimeUnclampedProp = gifProperties[(NSString *)kCGImagePropertyGIFUnclampedDelayTime]; 62 | if (delayTimeUnclampedProp) { 63 | frameDuration = [delayTimeUnclampedProp floatValue]; 64 | } 65 | else { 66 | 67 | NSNumber *delayTimeProp = gifProperties[(NSString *)kCGImagePropertyGIFDelayTime]; 68 | if (delayTimeProp) { 69 | frameDuration = [delayTimeProp floatValue]; 70 | } 71 | } 72 | 73 | // Many annoying ads specify a 0 duration to make an image flash as quickly as possible. 74 | // We follow Firefox's behavior and use a duration of 100 ms for any frames that specify 75 | // a duration of <= 10 ms. See and 76 | // for more information. 77 | 78 | if (frameDuration < 0.011f) { 79 | frameDuration = 0.100f; 80 | } 81 | 82 | CFRelease(cfFrameProperties); 83 | return frameDuration; 84 | } 85 | 86 | + (UIImage *)sd_animatedGIFNamed:(NSString *)name { 87 | CGFloat scale = [UIScreen mainScreen].scale; 88 | 89 | if (scale > 1.0f) { 90 | NSString *retinaPath = [[NSBundle mainBundle] pathForResource:[name stringByAppendingString:@"@2x"] ofType:@"gif"]; 91 | 92 | NSData *data = [NSData dataWithContentsOfFile:retinaPath]; 93 | 94 | if (data) { 95 | return [UIImage sd_animatedGIFWithData:data]; 96 | } 97 | 98 | NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; 99 | 100 | data = [NSData dataWithContentsOfFile:path]; 101 | 102 | if (data) { 103 | return [UIImage sd_animatedGIFWithData:data]; 104 | } 105 | 106 | return [UIImage imageNamed:name]; 107 | } 108 | else { 109 | NSString *path = [[NSBundle mainBundle] pathForResource:name ofType:@"gif"]; 110 | 111 | NSData *data = [NSData dataWithContentsOfFile:path]; 112 | 113 | if (data) { 114 | return [UIImage sd_animatedGIFWithData:data]; 115 | } 116 | 117 | return [UIImage imageNamed:name]; 118 | } 119 | } 120 | 121 | - (UIImage *)sd_animatedImageByScalingAndCroppingToSize:(CGSize)size { 122 | if (CGSizeEqualToSize(self.size, size) || CGSizeEqualToSize(size, CGSizeZero)) { 123 | return self; 124 | } 125 | 126 | CGSize scaledSize = size; 127 | CGPoint thumbnailPoint = CGPointZero; 128 | 129 | CGFloat widthFactor = size.width / self.size.width; 130 | CGFloat heightFactor = size.height / self.size.height; 131 | CGFloat scaleFactor = (widthFactor > heightFactor) ? widthFactor : heightFactor; 132 | scaledSize.width = self.size.width * scaleFactor; 133 | scaledSize.height = self.size.height * scaleFactor; 134 | 135 | if (widthFactor > heightFactor) { 136 | thumbnailPoint.y = (size.height - scaledSize.height) * 0.5; 137 | } 138 | else if (widthFactor < heightFactor) { 139 | thumbnailPoint.x = (size.width - scaledSize.width) * 0.5; 140 | } 141 | 142 | NSMutableArray *scaledImages = [NSMutableArray array]; 143 | 144 | UIGraphicsBeginImageContextWithOptions(size, NO, 0.0); 145 | 146 | for (UIImage *image in self.images) { 147 | [image drawInRect:CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledSize.width, scaledSize.height)]; 148 | UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); 149 | 150 | [scaledImages addObject:newImage]; 151 | } 152 | 153 | UIGraphicsEndImageContext(); 154 | 155 | return [UIImage animatedImageWithImages:scaledImages duration:self.duration]; 156 | } 157 | 158 | @end 159 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImagePrefetcher.m: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDWebImagePrefetcher.h" 10 | 11 | #if (!defined(DEBUG) && !defined (SD_VERBOSE)) || defined(SD_LOG_NONE) 12 | #define NSLog(...) 13 | #endif 14 | 15 | @interface SDWebImagePrefetcher () 16 | 17 | @property (strong, nonatomic) SDWebImageManager *manager; 18 | @property (strong, nonatomic) NSArray *prefetchURLs; 19 | @property (assign, nonatomic) NSUInteger requestedCount; 20 | @property (assign, nonatomic) NSUInteger skippedCount; 21 | @property (assign, nonatomic) NSUInteger finishedCount; 22 | @property (assign, nonatomic) NSTimeInterval startedTime; 23 | @property (copy, nonatomic) SDWebImagePrefetcherCompletionBlock completionBlock; 24 | @property (copy, nonatomic) SDWebImagePrefetcherProgressBlock progressBlock; 25 | 26 | @end 27 | 28 | @implementation SDWebImagePrefetcher 29 | 30 | + (SDWebImagePrefetcher *)sharedImagePrefetcher { 31 | static dispatch_once_t once; 32 | static id instance; 33 | dispatch_once(&once, ^{ 34 | instance = [self new]; 35 | }); 36 | return instance; 37 | } 38 | 39 | - (id)init { 40 | if ((self = [super init])) { 41 | _manager = [SDWebImageManager new]; 42 | _options = SDWebImageLowPriority; 43 | _prefetcherQueue = dispatch_get_main_queue(); 44 | self.maxConcurrentDownloads = 3; 45 | } 46 | return self; 47 | } 48 | 49 | - (void)setMaxConcurrentDownloads:(NSUInteger)maxConcurrentDownloads { 50 | self.manager.imageDownloader.maxConcurrentDownloads = maxConcurrentDownloads; 51 | } 52 | 53 | - (NSUInteger)maxConcurrentDownloads { 54 | return self.manager.imageDownloader.maxConcurrentDownloads; 55 | } 56 | 57 | - (void)startPrefetchingAtIndex:(NSUInteger)index { 58 | if (index >= self.prefetchURLs.count) return; 59 | self.requestedCount++; 60 | [self.manager downloadImageWithURL:self.prefetchURLs[index] options:self.options progress:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished, NSURL *imageURL) { 61 | if (!finished) return; 62 | self.finishedCount++; 63 | 64 | if (image) { 65 | if (self.progressBlock) { 66 | self.progressBlock(self.finishedCount,[self.prefetchURLs count]); 67 | } 68 | NSLog(@"Prefetched %@ out of %@", @(self.finishedCount), @(self.prefetchURLs.count)); 69 | } 70 | else { 71 | if (self.progressBlock) { 72 | self.progressBlock(self.finishedCount,[self.prefetchURLs count]); 73 | } 74 | NSLog(@"Prefetched %@ out of %@ (Failed)", @(self.finishedCount), @(self.prefetchURLs.count)); 75 | 76 | // Add last failed 77 | self.skippedCount++; 78 | } 79 | if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didPrefetchURL:finishedCount:totalCount:)]) { 80 | [self.delegate imagePrefetcher:self 81 | didPrefetchURL:self.prefetchURLs[index] 82 | finishedCount:self.finishedCount 83 | totalCount:self.prefetchURLs.count 84 | ]; 85 | } 86 | if (self.prefetchURLs.count > self.requestedCount) { 87 | dispatch_async(self.prefetcherQueue, ^{ 88 | [self startPrefetchingAtIndex:self.requestedCount]; 89 | }); 90 | } 91 | else if (self.finishedCount == self.requestedCount) { 92 | [self reportStatus]; 93 | if (self.completionBlock) { 94 | self.completionBlock(self.finishedCount, self.skippedCount); 95 | self.completionBlock = nil; 96 | } 97 | self.progressBlock = nil; 98 | } 99 | }]; 100 | } 101 | 102 | - (void)reportStatus { 103 | NSUInteger total = [self.prefetchURLs count]; 104 | NSLog(@"Finished prefetching (%@ successful, %@ skipped, timeElasped %.2f)", @(total - self.skippedCount), @(self.skippedCount), CFAbsoluteTimeGetCurrent() - self.startedTime); 105 | if ([self.delegate respondsToSelector:@selector(imagePrefetcher:didFinishWithTotalCount:skippedCount:)]) { 106 | [self.delegate imagePrefetcher:self 107 | didFinishWithTotalCount:(total - self.skippedCount) 108 | skippedCount:self.skippedCount 109 | ]; 110 | } 111 | } 112 | 113 | - (void)prefetchURLs:(NSArray *)urls { 114 | [self prefetchURLs:urls progress:nil completed:nil]; 115 | } 116 | 117 | - (void)prefetchURLs:(NSArray *)urls progress:(SDWebImagePrefetcherProgressBlock)progressBlock completed:(SDWebImagePrefetcherCompletionBlock)completionBlock { 118 | [self cancelPrefetching]; // Prevent duplicate prefetch request 119 | self.startedTime = CFAbsoluteTimeGetCurrent(); 120 | self.prefetchURLs = urls; 121 | self.completionBlock = completionBlock; 122 | self.progressBlock = progressBlock; 123 | 124 | if(urls.count == 0){ 125 | if(completionBlock){ 126 | completionBlock(0,0); 127 | } 128 | }else{ 129 | // Starts prefetching from the very first image on the list with the max allowed concurrency 130 | NSUInteger listCount = self.prefetchURLs.count; 131 | for (NSUInteger i = 0; i < self.maxConcurrentDownloads && self.requestedCount < listCount; i++) { 132 | [self startPrefetchingAtIndex:i]; 133 | } 134 | } 135 | } 136 | 137 | - (void)cancelPrefetching { 138 | self.prefetchURLs = nil; 139 | self.skippedCount = 0; 140 | self.requestedCount = 0; 141 | self.finishedCount = 0; 142 | [self.manager cancelAll]; 143 | } 144 | 145 | @end 146 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/MKAnnotationView+WebCache.h: -------------------------------------------------------------------------------- 1 | // 2 | // MKAnnotationView+WebCache.h 3 | // SDWebImage 4 | // 5 | // Created by Olivier Poitrey on 14/03/12. 6 | // Copyright (c) 2012 Dailymotion. All rights reserved. 7 | // 8 | 9 | #import "MapKit/MapKit.h" 10 | #import "SDWebImageManager.h" 11 | 12 | /** 13 | * Integrates SDWebImage async downloading and caching of remote images with MKAnnotationView. 14 | */ 15 | @interface MKAnnotationView (WebCache) 16 | 17 | /** 18 | * Get the current image URL. 19 | * 20 | * Note that because of the limitations of categories this property can get out of sync 21 | * if you use sd_setImage: directly. 22 | */ 23 | - (NSURL *)sd_imageURL; 24 | 25 | /** 26 | * Set the imageView `image` with an `url`. 27 | * 28 | * The download is asynchronous and cached. 29 | * 30 | * @param url The url for the image. 31 | */ 32 | - (void)sd_setImageWithURL:(NSURL *)url; 33 | 34 | /** 35 | * Set the imageView `image` with an `url` and a placeholder. 36 | * 37 | * The download is asynchronous and cached. 38 | * 39 | * @param url The url for the image. 40 | * @param placeholder The image to be set initially, until the image request finishes. 41 | * @see sd_setImageWithURL:placeholderImage:options: 42 | */ 43 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder; 44 | 45 | /** 46 | * Set the imageView `image` with an `url`, placeholder and custom options. 47 | * 48 | * The download is asynchronous and cached. 49 | * 50 | * @param url The url for the image. 51 | * @param placeholder The image to be set initially, until the image request finishes. 52 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 53 | */ 54 | 55 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options; 56 | 57 | /** 58 | * Set the imageView `image` with an `url`. 59 | * 60 | * The download is asynchronous and cached. 61 | * 62 | * @param url The url for the image. 63 | * @param completedBlock A block called when operation has been completed. This block has no return value 64 | * and takes the requested UIImage as first parameter. In case of error the image parameter 65 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 66 | * indicating if the image was retrived from the local cache or from the network. 67 | * The fourth parameter is the original image url. 68 | */ 69 | - (void)sd_setImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock; 70 | 71 | /** 72 | * Set the imageView `image` with an `url`, placeholder. 73 | * 74 | * The download is asynchronous and cached. 75 | * 76 | * @param url The url for the image. 77 | * @param placeholder The image to be set initially, until the image request finishes. 78 | * @param completedBlock A block called when operation has been completed. This block has no return value 79 | * and takes the requested UIImage as first parameter. In case of error the image parameter 80 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 81 | * indicating if the image was retrived from the local cache or from the network. 82 | * The fourth parameter is the original image url. 83 | */ 84 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock; 85 | 86 | /** 87 | * Set the imageView `image` with an `url`, placeholder and custom options. 88 | * 89 | * The download is asynchronous and cached. 90 | * 91 | * @param url The url for the image. 92 | * @param placeholder The image to be set initially, until the image request finishes. 93 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 94 | * @param completedBlock A block called when operation has been completed. This block has no return value 95 | * and takes the requested UIImage as first parameter. In case of error the image parameter 96 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 97 | * indicating if the image was retrived from the local cache or from the network. 98 | * The fourth parameter is the original image url. 99 | */ 100 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock; 101 | 102 | /** 103 | * Cancel the current download 104 | */ 105 | - (void)sd_cancelCurrentImageLoad; 106 | 107 | @end 108 | 109 | 110 | @interface MKAnnotationView (WebCacheDeprecated) 111 | 112 | - (NSURL *)imageURL __deprecated_msg("Use `sd_imageURL`"); 113 | 114 | - (void)setImageWithURL:(NSURL *)url __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:`"); 115 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:`"); 116 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:options:`"); 117 | 118 | - (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:completed:`"); 119 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:completed:`"); 120 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:options:completed:`"); 121 | 122 | - (void)cancelCurrentImageLoad __deprecated_msg("Use `sd_cancelCurrentImageLoad`"); 123 | 124 | @end 125 | -------------------------------------------------------------------------------- /Demo2/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Demo2 4 | // 5 | // Created by xlx on 15/7/20. 6 | // Copyright (c) 2015年 xlx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | import CoreData 11 | 12 | @UIApplicationMain 13 | class AppDelegate: UIResponder, UIApplicationDelegate { 14 | 15 | var window: UIWindow? 16 | 17 | 18 | func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { 19 | // Override point for customization after application launch. 20 | return true 21 | } 22 | 23 | func applicationWillResignActive(application: UIApplication) { 24 | // 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. 25 | // 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. 26 | } 27 | 28 | func applicationDidEnterBackground(application: UIApplication) { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | func applicationWillEnterForeground(application: UIApplication) { 34 | // 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. 35 | } 36 | 37 | func applicationDidBecomeActive(application: UIApplication) { 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 | func applicationWillTerminate(application: UIApplication) { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | // Saves changes in the application's managed object context before the application terminates. 44 | self.saveContext() 45 | } 46 | 47 | // MARK: - Core Data stack 48 | 49 | lazy var applicationDocumentsDirectory: NSURL = { 50 | // The directory the application uses to store the Core Data store file. This code uses a directory named "com.xlx.Demo2" in the application's documents Application Support directory. 51 | let urls = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) 52 | return urls[urls.count-1] as! NSURL 53 | }() 54 | 55 | lazy var managedObjectModel: NSManagedObjectModel = { 56 | // The managed object model for the application. This property is not optional. It is a fatal error for the application not to be able to find and load its model. 57 | let modelURL = NSBundle.mainBundle().URLForResource("Demo2", withExtension: "momd")! 58 | return NSManagedObjectModel(contentsOfURL: modelURL)! 59 | }() 60 | 61 | lazy var persistentStoreCoordinator: NSPersistentStoreCoordinator? = { 62 | // The persistent store coordinator for the application. This implementation creates and return a coordinator, having added the store for the application to it. This property is optional since there are legitimate error conditions that could cause the creation of the store to fail. 63 | // Create the coordinator and store 64 | var coordinator: NSPersistentStoreCoordinator? = NSPersistentStoreCoordinator(managedObjectModel: self.managedObjectModel) 65 | let url = self.applicationDocumentsDirectory.URLByAppendingPathComponent("Demo2.sqlite") 66 | var error: NSError? = nil 67 | var failureReason = "There was an error creating or loading the application's saved data." 68 | if coordinator!.addPersistentStoreWithType(NSSQLiteStoreType, configuration: nil, URL: url, options: nil, error: &error) == nil { 69 | coordinator = nil 70 | // Report any error we got. 71 | var dict = [String: AnyObject]() 72 | dict[NSLocalizedDescriptionKey] = "Failed to initialize the application's saved data" 73 | dict[NSLocalizedFailureReasonErrorKey] = failureReason 74 | dict[NSUnderlyingErrorKey] = error 75 | error = NSError(domain: "YOUR_ERROR_DOMAIN", code: 9999, userInfo: dict) 76 | // Replace this with code to handle the error appropriately. 77 | // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 78 | NSLog("Unresolved error \(error), \(error!.userInfo)") 79 | abort() 80 | } 81 | 82 | return coordinator 83 | }() 84 | 85 | lazy var managedObjectContext: NSManagedObjectContext? = { 86 | // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail. 87 | let coordinator = self.persistentStoreCoordinator 88 | if coordinator == nil { 89 | return nil 90 | } 91 | var managedObjectContext = NSManagedObjectContext() 92 | managedObjectContext.persistentStoreCoordinator = coordinator 93 | return managedObjectContext 94 | }() 95 | 96 | // MARK: - Core Data Saving support 97 | 98 | func saveContext () { 99 | if let moc = self.managedObjectContext { 100 | var error: NSError? = nil 101 | if moc.hasChanges && !moc.save(&error) { 102 | // Replace this implementation with code to handle the error appropriately. 103 | // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. 104 | NSLog("Unresolved error \(error), \(error!.userInfo)") 105 | abort() 106 | } 107 | } 108 | } 109 | 110 | } 111 | 112 | -------------------------------------------------------------------------------- /Demo2/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // Demo2 4 | // 5 | // Created by xlx on 15/7/20. 6 | // Copyright (c) 2015年 xlx. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource,HZPhotoBrowserDelegate,XActionSheetDelegate{ 12 | 13 | var tableView:UITableView! 14 | var ObjectArray = [String]() 15 | var i = 0 16 | 17 | var head:XHPathCover! 18 | override func viewDidLoad() { 19 | super.viewDidLoad() 20 | // Do any additional setup after loading the view, typically from a nib. 21 | 22 | 23 | self.tableView = UITableView(frame: self.view.frame) 24 | self.view.addSubview(self.tableView) 25 | self.tableView.delegate = self 26 | self.tableView.dataSource = self 27 | self.tableView.registerClass(UITableViewCell.classForCoder(), forCellReuseIdentifier: "cell") 28 | self.tableView.tableFooterView = UIView() 29 | 30 | for i ; i < 10 ; i++ { 31 | self.ObjectArray.append("\(i)") 32 | } 33 | 34 | // self.tableView.addLegendHeaderWithRefreshingTarget(self, refreshingAction: "headRefresh") 35 | self.tableView.addGifFooterWithRefreshingTarget(self, refreshingAction: "footRefresh") 36 | 37 | head = XHPathCover(frame: CGRectMake(0, 0, 320, 200)) 38 | head.setBackgroundImage(UIImage(named: "BG")) 39 | head.setAvatarImage(UIImage(named: "cute_girl.jpg")) 40 | head.isZoomingEffect = true; 41 | head.setInfo(NSDictionary(objectsAndKeys: "StrongX",XHUserNameKey,"iOS工程师",XHBirthdayKey)as [NSObject:AnyObject]) 42 | head.avatarButton.layer.cornerRadius = 33; 43 | head.avatarButton.layer.masksToBounds = true 44 | head.avatarButton.addTarget(self, action: "PhotoBrowser", forControlEvents: UIControlEvents.TouchUpInside) 45 | head.handleRefreshEvent = { 46 | self.headRefresh() 47 | } 48 | 49 | var Line = LineView(frame: CGRectMake(0, 200, 320, 60)) 50 | 51 | var HeadView = UIView(frame: CGRectMake(0, 0, 320, 200 + 60)) 52 | 53 | HeadView.addSubview(Line) 54 | HeadView.addSubview(head) 55 | 56 | tableView.tableHeaderView = HeadView 57 | 58 | head.sayHello() 59 | 60 | tableView.sayHello() 61 | 62 | 63 | } 64 | 65 | override func didReceiveMemoryWarning() { 66 | super.didReceiveMemoryWarning() 67 | // Dispose of any resources that can be recreated. 68 | } 69 | func scrollViewDidScroll(scrollView: UIScrollView) { 70 | head.scrollViewDidScroll(scrollView) 71 | } 72 | func scrollViewDidEndDecelerating(scrollView: UIScrollView) { 73 | head.scrollViewDidEndDecelerating(scrollView) 74 | } 75 | func scrollViewDidEndDragging(scrollView: UIScrollView, willDecelerate decelerate: Bool) { 76 | head.scrollViewDidEndDragging(scrollView, willDecelerate: decelerate) 77 | } 78 | func scrollViewWillBeginDragging(scrollView: UIScrollView) { 79 | head.scrollViewWillBeginDragging(scrollView) 80 | } 81 | func numberOfSectionsInTableView(tableView: UITableView) -> Int { 82 | return 1 83 | } 84 | 85 | func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 86 | return ObjectArray.count 87 | } 88 | func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat { 89 | return 80 90 | } 91 | func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 92 | var cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! UITableViewCell 93 | 94 | for view in cell.contentView.subviews { 95 | view.removeFromSuperview() 96 | } 97 | 98 | var image = UIImageView(frame: CGRectMake(10, 10, 60, 60)) 99 | image.layer.cornerRadius = 30 100 | image.layer.masksToBounds = true 101 | image.sd_setImageWithURL(NSURL(string: "http://ac-hn8w3hlp.clouddn.com/fVju6pA4WGzVGNGsVdVXEzB.png"), placeholderImage: UIImage(named: "cute_girl.jpg")) 102 | cell.contentView.addSubview(image) 103 | 104 | var label = UILabel(frame: CGRectMake(80, 30, 100, 20)) 105 | label.text = "这是第\(indexPath.row)行" 106 | cell.contentView.addSubview(label) 107 | 108 | 109 | 110 | return cell 111 | } 112 | func headRefresh(){ 113 | ProgressHUD.show("亲爱的,别急嘛~~~") 114 | self.Delay(2, closure: { () -> () in 115 | self.ObjectArray.removeAll(keepCapacity: false) 116 | self.i = 0 117 | for self.i ; self.i < 10 ; self.i++ { 118 | self.ObjectArray.append("\(self.i)") 119 | } 120 | // self.tableView.header.endRefreshing() 121 | self.tableView.reloadData() 122 | self.head.stopRefresh() 123 | ProgressHUD.showSuccess("人家准备好了!") 124 | }) 125 | } 126 | func footRefresh(){ 127 | ProgressHUD.show("还有更多内容") 128 | self.Delay(2, closure: { () -> () in 129 | var j = self.i + 10 130 | for self.i ; self.i < j ; self.i++ { 131 | self.ObjectArray.append("\(self.i)") 132 | } 133 | self.tableView.footer.endRefreshing() 134 | self.tableView.reloadData() 135 | ProgressHUD.showSuccess("好了啦~~") 136 | }) 137 | } 138 | func Delay(time:Double,closure:()->()){ 139 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(time * Double(NSEC_PER_SEC))), dispatch_get_main_queue(), closure) 140 | } 141 | 142 | func PhotoBrowser(){ 143 | var action = XActionSheet() 144 | action.delegate = self 145 | // action.addButtonwithTitle("拍照") 146 | action.addCancelButton("取消") 147 | // action.addButtonwithTitle("相册") 148 | // action.addButtonwithTitle("查看高清大图") 149 | action.addButtonWithTitleArray(["拍照","相册","查看高清大图"]) 150 | self.presentViewController(action, animated: true) { () -> Void in 151 | 152 | } 153 | 154 | } 155 | func photoBrowser(browser: HZPhotoBrowser!, placeholderImageForIndex index: Int) -> UIImage! { 156 | return head.avatarButton.currentImage 157 | } 158 | func photoBrowser(browser: HZPhotoBrowser!, highQualityImageURLForIndex index: Int) -> NSURL! { 159 | var url = NSURL(string: "http://ac-hn8w3hlp.clouddn.com/dGWm2GEFNFoisI6beHBUQjD.png") 160 | return url 161 | } 162 | func buttonClick(index: Int) { 163 | println("\(index)") 164 | if(index == 2){ 165 | var BrowserVC = HZPhotoBrowser() 166 | BrowserVC.sourceImagesContainerView = head.avatarButton 167 | BrowserVC.imageCount = 1 168 | BrowserVC.currentImageIndex = 0 169 | BrowserVC.delegate = self 170 | BrowserVC.show() 171 | 172 | } 173 | } 174 | } 175 | 176 | -------------------------------------------------------------------------------- /Demo2/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年 itcast. All rights reserved. 8 | // 给ScrollView增加下拉刷新、上拉刷新的功能 9 | 10 | #import 11 | #import "MJRefreshConst.h" 12 | 13 | @class MJRefreshGifHeader, MJRefreshLegendHeader, MJRefreshHeader; 14 | @class MJRefreshGifFooter, MJRefreshLegendFooter, MJRefreshFooter; 15 | 16 | @interface UIScrollView (MJRefresh) 17 | #pragma mark - 访问下拉刷新控件 18 | /** 下拉刷新控件 */ 19 | @property (strong, nonatomic, readonly) MJRefreshHeader *header; 20 | /** gif功能的下拉刷新控件 */ 21 | @property (nonatomic, readonly) MJRefreshGifHeader *gifHeader; 22 | /** 传统的下拉刷新控件 */ 23 | @property (nonatomic, readonly) MJRefreshLegendHeader *legendHeader; 24 | 25 | #pragma mark - 添加下拉刷新控件 26 | /** 27 | * 添加一个传统的下拉刷新控件 28 | * 29 | * @param block 进入刷新状态就会自动调用这个block 30 | */ 31 | - (MJRefreshLegendHeader *)addLegendHeaderWithRefreshingBlock:(void (^)())block; 32 | /** 33 | * 添加一个传统的下拉刷新控件 34 | * 35 | * @param block 进入刷新状态就会自动调用这个block 36 | * @param dateKey 用来记录刷新时间的key 37 | */ 38 | - (MJRefreshLegendHeader *)addLegendHeaderWithRefreshingBlock:(void (^)())block dateKey:(NSString *)dateKey; 39 | /** 40 | * 添加一个传统的下拉刷新控件 41 | * 42 | * @param target 进入刷新状态就会自动调用target对象的action方法 43 | * @param action 进入刷新状态就会自动调用target对象的action方法 44 | */ 45 | - (MJRefreshLegendHeader *)addLegendHeaderWithRefreshingTarget:(id)target refreshingAction:(SEL)action; 46 | /** 47 | * 添加一个传统的下拉刷新控件 48 | * 49 | * @param target 进入刷新状态就会自动调用target对象的action方法 50 | * @param action 进入刷新状态就会自动调用target对象的action方法 51 | * @param dateKey 用来记录刷新时间的key 52 | */ 53 | - (MJRefreshLegendHeader *)addLegendHeaderWithRefreshingTarget:(id)target refreshingAction:(SEL)action dateKey:(NSString *)dateKey; 54 | /** 55 | * 添加一个gif图片的下拉刷新控件 56 | * 57 | * @param block 进入刷新状态就会自动调用这个block 58 | */ 59 | - (MJRefreshGifHeader *)addGifHeaderWithRefreshingBlock:(void (^)())block; 60 | /** 61 | * 添加一个gif图片的下拉刷新控件 62 | * 63 | * @param block 进入刷新状态就会自动调用这个block 64 | * @param dateKey 用来记录刷新时间的key 65 | */ 66 | - (MJRefreshGifHeader *)addGifHeaderWithRefreshingBlock:(void (^)())block dateKey:(NSString *)dateKey; 67 | /** 68 | * 添加一个gif图片的下拉刷新控件 69 | * 70 | * @param target 进入刷新状态就会自动调用target对象的action方法 71 | * @param action 进入刷新状态就会自动调用target对象的action方法 72 | */ 73 | - (MJRefreshGifHeader *)addGifHeaderWithRefreshingTarget:(id)target refreshingAction:(SEL)action; 74 | /** 75 | * 添加一个gif图片的下拉刷新控件 76 | * 77 | * @param target 进入刷新状态就会自动调用target对象的action方法 78 | * @param action 进入刷新状态就会自动调用target对象的action方法 79 | * @param dateKey 用来记录刷新时间的key 80 | */ 81 | - (MJRefreshGifHeader *)addGifHeaderWithRefreshingTarget:(id)target refreshingAction:(SEL)action dateKey:(NSString *)dateKey; 82 | 83 | #pragma mark - 移除下拉刷新控件 84 | /** 85 | * 移除下拉刷新控件 86 | */ 87 | - (void)removeHeader; 88 | 89 | #pragma mark - 访问上拉刷新控件 90 | /** 上拉刷新控件 */ 91 | @property (strong, nonatomic, readonly) MJRefreshFooter *footer; 92 | /** gif功能的上拉刷新控件 */ 93 | @property (nonatomic, readonly) MJRefreshGifFooter *gifFooter; 94 | /** 传统的上拉刷新控件 */ 95 | @property (nonatomic, readonly) MJRefreshLegendFooter *legendFooter; 96 | 97 | #pragma mark - 添加上拉刷新控件 98 | /** 99 | * 添加一个传统的上拉刷新控件 100 | * 101 | * @param block 进入刷新状态就会自动调用这个block 102 | */ 103 | - (MJRefreshLegendFooter *)addLegendFooterWithRefreshingBlock:(void (^)())block; 104 | /** 105 | * 添加一个传统的上拉刷新控件 106 | * 107 | * @param target 进入刷新状态就会自动调用target对象的action方法 108 | * @param action 进入刷新状态就会自动调用target对象的action方法 109 | */ 110 | - (MJRefreshLegendFooter *)addLegendFooterWithRefreshingTarget:(id)target refreshingAction:(SEL)action; 111 | /** 112 | * 添加一个gif图片的上拉刷新控件 113 | * 114 | * @param block 进入刷新状态就会自动调用这个block 115 | */ 116 | - (MJRefreshGifFooter *)addGifFooterWithRefreshingBlock:(void (^)())block; 117 | /** 118 | * 添加一个gif图片的上拉刷新控件 119 | * 120 | * @param target 进入刷新状态就会自动调用target对象的action方法 121 | * @param action 进入刷新状态就会自动调用target对象的action方法 122 | */ 123 | - (MJRefreshGifFooter *)addGifFooterWithRefreshingTarget:(id)target refreshingAction:(SEL)action; 124 | 125 | #pragma mark - 移除上拉刷新控件 126 | /** 127 | * 移除上拉刷新控件 128 | */ 129 | - (void)removeFooter; 130 | @end 131 | 132 | #pragma mark - 1.0.0版本以前的接口 133 | @interface UIScrollView(MJRefreshDeprecated) 134 | #pragma mark - 下拉刷新 135 | /** 136 | * 添加一个下拉刷新头部控件 137 | * 138 | * @param callback 回调 139 | */ 140 | - (void)addHeaderWithCallback:(void (^)())callback MJDeprecated("建议使用addLegendHeaderWithRefreshingBlock:"); 141 | 142 | /** 143 | * 添加一个下拉刷新头部控件 144 | * 145 | * @param callback 回调 146 | * @param dateKey 刷新时间保存的key值 147 | */ 148 | - (void)addHeaderWithCallback:(void (^)())callback dateKey:(NSString*)dateKey MJDeprecated("建议使用addLegendHeaderWithRefreshingBlock:dateKey:"); 149 | 150 | /** 151 | * 添加一个下拉刷新头部控件 152 | * 153 | * @param target 目标 154 | * @param action 回调方法 155 | */ 156 | - (void)addHeaderWithTarget:(id)target action:(SEL)action MJDeprecated("建议使用addLegendHeaderWithRefreshingTarget:refreshingAction:"); 157 | 158 | /** 159 | * 添加一个下拉刷新头部控件 160 | * 161 | * @param target 目标 162 | * @param action 回调方法 163 | * @param dateKey 刷新时间保存的key值 164 | */ 165 | - (void)addHeaderWithTarget:(id)target action:(SEL)action dateKey:(NSString*)dateKey MJDeprecated("建议使用addLegendHeaderWithRefreshingTarget:refreshingAction:dateKey:"); 166 | 167 | /** 168 | * 主动让下拉刷新头部控件进入刷新状态 169 | */ 170 | - (void)headerBeginRefreshing MJDeprecated("建议使用[self.tableView.header beginRefreshing]"); 171 | 172 | /** 173 | * 让下拉刷新头部控件停止刷新状态 174 | */ 175 | - (void)headerEndRefreshing MJDeprecated("建议使用[self.tableView.header endRefreshing]"); 176 | 177 | /** 178 | * 下拉刷新头部控件的可见性 179 | */ 180 | @property (nonatomic, assign, getter = isHeaderHidden) BOOL headerHidden MJDeprecated("建议使用self.tableView.header.hidden"); 181 | 182 | /** 183 | * 是否正在下拉刷新 184 | */ 185 | @property (nonatomic, assign, readonly, getter = isHeaderRefreshing) BOOL headerRefreshing MJDeprecated("建议使用self.tableView.header.isRefreshing"); 186 | 187 | #pragma mark - 上拉刷新 188 | /** 189 | * 添加一个上拉刷新尾部控件 190 | * 191 | * @param callback 回调 192 | */ 193 | - (void)addFooterWithCallback:(void (^)())callback MJDeprecated("建议使用addLegendFooterWithRefreshingBlock:"); 194 | 195 | /** 196 | * 添加一个上拉刷新尾部控件 197 | * 198 | * @param target 目标 199 | * @param action 回调方法 200 | */ 201 | - (void)addFooterWithTarget:(id)target action:(SEL)action MJDeprecated("建议使用addLegendFooterWithRefreshingTarget:refreshingAction:"); 202 | 203 | /** 204 | * 主动让上拉刷新尾部控件进入刷新状态 205 | */ 206 | - (void)footerBeginRefreshing MJDeprecated("建议使用[self.tableView.footer beginRefreshing]"); 207 | 208 | /** 209 | * 让上拉刷新尾部控件停止刷新状态 210 | */ 211 | - (void)footerEndRefreshing MJDeprecated("建议使用[self.tableView.footer endRefreshing]"); 212 | 213 | /** 214 | * 上拉刷新头部控件的可见性 215 | */ 216 | @property (nonatomic, assign, getter = isFooterHidden) BOOL footerHidden MJDeprecated("建议使用self.tableView.footer.hidden"); 217 | 218 | /** 219 | * 是否正在上拉刷新 220 | */ 221 | @property (nonatomic, assign, readonly, getter = isFooterRefreshing) BOOL footerRefreshing MJDeprecated("建议使用self.tableView.footer.isRefreshing"); 222 | @end 223 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDWebImageDownloader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | #import "SDWebImageOperation.h" 12 | 13 | typedef NS_OPTIONS(NSUInteger, SDWebImageDownloaderOptions) { 14 | SDWebImageDownloaderLowPriority = 1 << 0, 15 | SDWebImageDownloaderProgressiveDownload = 1 << 1, 16 | 17 | /** 18 | * By default, request prevent the of NSURLCache. With this flag, NSURLCache 19 | * is used with default policies. 20 | */ 21 | SDWebImageDownloaderUseNSURLCache = 1 << 2, 22 | 23 | /** 24 | * Call completion block with nil image/imageData if the image was read from NSURLCache 25 | * (to be combined with `SDWebImageDownloaderUseNSURLCache`). 26 | */ 27 | 28 | SDWebImageDownloaderIgnoreCachedResponse = 1 << 3, 29 | /** 30 | * In iOS 4+, continue the download of the image if the app goes to background. This is achieved by asking the system for 31 | * extra time in background to let the request finish. If the background task expires the operation will be cancelled. 32 | */ 33 | 34 | SDWebImageDownloaderContinueInBackground = 1 << 4, 35 | 36 | /** 37 | * Handles cookies stored in NSHTTPCookieStore by setting 38 | * NSMutableURLRequest.HTTPShouldHandleCookies = YES; 39 | */ 40 | SDWebImageDownloaderHandleCookies = 1 << 5, 41 | 42 | /** 43 | * Enable to allow untrusted SSL ceriticates. 44 | * Useful for testing purposes. Use with caution in production. 45 | */ 46 | SDWebImageDownloaderAllowInvalidSSLCertificates = 1 << 6, 47 | 48 | /** 49 | * Put the image in the high priority queue. 50 | */ 51 | SDWebImageDownloaderHighPriority = 1 << 7, 52 | }; 53 | 54 | typedef NS_ENUM(NSInteger, SDWebImageDownloaderExecutionOrder) { 55 | /** 56 | * Default value. All download operations will execute in queue style (first-in-first-out). 57 | */ 58 | SDWebImageDownloaderFIFOExecutionOrder, 59 | 60 | /** 61 | * All download operations will execute in stack style (last-in-first-out). 62 | */ 63 | SDWebImageDownloaderLIFOExecutionOrder 64 | }; 65 | 66 | extern NSString *const SDWebImageDownloadStartNotification; 67 | extern NSString *const SDWebImageDownloadStopNotification; 68 | 69 | typedef void(^SDWebImageDownloaderProgressBlock)(NSInteger receivedSize, NSInteger expectedSize); 70 | 71 | typedef void(^SDWebImageDownloaderCompletedBlock)(UIImage *image, NSData *data, NSError *error, BOOL finished); 72 | 73 | typedef NSDictionary *(^SDWebImageDownloaderHeadersFilterBlock)(NSURL *url, NSDictionary *headers); 74 | 75 | /** 76 | * Asynchronous downloader dedicated and optimized for image loading. 77 | */ 78 | @interface SDWebImageDownloader : NSObject 79 | 80 | /** 81 | * Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory. 82 | * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. 83 | */ 84 | @property (assign, nonatomic) BOOL shouldDecompressImages; 85 | 86 | @property (assign, nonatomic) NSInteger maxConcurrentDownloads; 87 | 88 | /** 89 | * Shows the current amount of downloads that still need to be downloaded 90 | */ 91 | @property (readonly, nonatomic) NSUInteger currentDownloadCount; 92 | 93 | 94 | /** 95 | * The timeout value (in seconds) for the download operation. Default: 15.0. 96 | */ 97 | @property (assign, nonatomic) NSTimeInterval downloadTimeout; 98 | 99 | 100 | /** 101 | * Changes download operations execution order. Default value is `SDWebImageDownloaderFIFOExecutionOrder`. 102 | */ 103 | @property (assign, nonatomic) SDWebImageDownloaderExecutionOrder executionOrder; 104 | 105 | /** 106 | * Singleton method, returns the shared instance 107 | * 108 | * @return global shared instance of downloader class 109 | */ 110 | + (SDWebImageDownloader *)sharedDownloader; 111 | 112 | /** 113 | * Set username 114 | */ 115 | @property (strong, nonatomic) NSString *username; 116 | 117 | /** 118 | * Set password 119 | */ 120 | @property (strong, nonatomic) NSString *password; 121 | 122 | /** 123 | * Set filter to pick headers for downloading image HTTP request. 124 | * 125 | * This block will be invoked for each downloading image request, returned 126 | * NSDictionary will be used as headers in corresponding HTTP request. 127 | */ 128 | @property (nonatomic, copy) SDWebImageDownloaderHeadersFilterBlock headersFilter; 129 | 130 | /** 131 | * Set a value for a HTTP header to be appended to each download HTTP request. 132 | * 133 | * @param value The value for the header field. Use `nil` value to remove the header. 134 | * @param field The name of the header field to set. 135 | */ 136 | - (void)setValue:(NSString *)value forHTTPHeaderField:(NSString *)field; 137 | 138 | /** 139 | * Returns the value of the specified HTTP header field. 140 | * 141 | * @return The value associated with the header field field, or `nil` if there is no corresponding header field. 142 | */ 143 | - (NSString *)valueForHTTPHeaderField:(NSString *)field; 144 | 145 | /** 146 | * Sets a subclass of `SDWebImageDownloaderOperation` as the default 147 | * `NSOperation` to be used each time SDWebImage constructs a request 148 | * operation to download an image. 149 | * 150 | * @param operationClass The subclass of `SDWebImageDownloaderOperation` to set 151 | * as default. Passing `nil` will revert to `SDWebImageDownloaderOperation`. 152 | */ 153 | - (void)setOperationClass:(Class)operationClass; 154 | 155 | /** 156 | * Creates a SDWebImageDownloader async downloader instance with a given URL 157 | * 158 | * The delegate will be informed when the image is finish downloaded or an error has happen. 159 | * 160 | * @see SDWebImageDownloaderDelegate 161 | * 162 | * @param url The URL to the image to download 163 | * @param options The options to be used for this download 164 | * @param progressBlock A block called repeatedly while the image is downloading 165 | * @param completedBlock A block called once the download is completed. 166 | * If the download succeeded, the image parameter is set, in case of error, 167 | * error parameter is set with the error. The last parameter is always YES 168 | * if SDWebImageDownloaderProgressiveDownload isn't use. With the 169 | * SDWebImageDownloaderProgressiveDownload option, this block is called 170 | * repeatedly with the partial image object and the finished argument set to NO 171 | * before to be called a last time with the full image and finished argument 172 | * set to YES. In case of error, the finished argument is always YES. 173 | * 174 | * @return A cancellable SDWebImageOperation 175 | */ 176 | - (id )downloadImageWithURL:(NSURL *)url 177 | options:(SDWebImageDownloaderOptions)options 178 | progress:(SDWebImageDownloaderProgressBlock)progressBlock 179 | completed:(SDWebImageDownloaderCompletedBlock)completedBlock; 180 | 181 | /** 182 | * Sets the download queue suspension state 183 | */ 184 | - (void)setSuspended:(BOOL)suspended; 185 | 186 | @end 187 | -------------------------------------------------------------------------------- /Demo2/PathCover/XHWaterDropRefresh.m: -------------------------------------------------------------------------------- 1 | // 2 | // XHWaterDropRefresh.m 3 | // XHPathCover 4 | // 5 | // Created by 曾 宪华 on 14-2-7. 6 | // Copyright (c) 2014年 曾宪华 开发团队(http://iyilunba.com ) 本人QQ:543413507 本人QQ群(142557668). All rights reserved. 7 | // 8 | 9 | #import "XHWaterDropRefresh.h" 10 | #import "XHSoundManager.h" 11 | 12 | @interface XHWaterDropRefresh () { 13 | BOOL _isRefresh; 14 | } 15 | 16 | @property (nonatomic, strong) CAShapeLayer *shapeLayer; 17 | @property (nonatomic, strong) CAShapeLayer *lineLayer; 18 | @property (nonatomic, strong) UIImageView *refreshView; 19 | 20 | 21 | @property (nonatomic, strong) NSTimer *timer; 22 | 23 | @end 24 | 25 | @implementation XHWaterDropRefresh 26 | 27 | #pragma mark - Propertys 28 | 29 | - (BOOL)isRefreshing { 30 | return _isRefresh; 31 | } 32 | 33 | 34 | #pragma mark - Life cycle 35 | 36 | - (id)initWithFrame:(CGRect)frame 37 | { 38 | self = [super initWithFrame:frame]; 39 | if (self) { 40 | // Initialization code 41 | [self _setup]; 42 | } 43 | return self; 44 | } 45 | 46 | - (id)initWithCoder:(NSCoder *)aDecoder 47 | { 48 | self = [super initWithCoder:aDecoder]; 49 | if(self) 50 | { 51 | [self _setup]; 52 | } 53 | return self; 54 | } 55 | 56 | - (void)dealloc { 57 | self.refreshCircleImage = nil; 58 | 59 | self.shapeLayer = nil; 60 | self.lineLayer = nil; 61 | self.refreshView = nil; 62 | } 63 | 64 | - (void)_setup { 65 | self.deformationLength = 0.4; 66 | self.maxOffset = 70; // 改变最大拉断距离 67 | self.radius = 5.; // 改变圆圈的半径 68 | self.offsetHeight = 20; // 改变线条的长度 69 | 70 | CGRect frame = self.frame; 71 | frame.size = CGSizeMake(30, 100); //固定 30 * 100 为什么要固定本身的大小呢? 72 | self.frame = frame; 73 | 74 | _lineLayer = [CAShapeLayer layer]; 75 | _lineLayer.fillColor = [UIColor colorWithRed:222./255. green:216./255. blue:211./255. alpha:0.5].CGColor; 76 | [self.layer addSublayer:_lineLayer]; 77 | 78 | 79 | _shapeLayer = [CAShapeLayer layer]; 80 | _shapeLayer.fillColor = [UIColor colorWithRed:222./255. green:216./255. blue:211./255. alpha:1].CGColor; 81 | _shapeLayer.strokeColor = [[UIColor whiteColor] CGColor]; 82 | _shapeLayer.lineWidth = 2; 83 | [self.layer addSublayer:_shapeLayer]; 84 | 85 | self.currentOffset = 0; 86 | } 87 | 88 | #pragma mark - Publish Api 89 | 90 | - (void)stopRefresh { 91 | _isRefresh = NO; 92 | 93 | CABasicAnimation* anim = [CABasicAnimation animationWithKeyPath:@"opacity"]; 94 | anim.fromValue = @(1); 95 | anim.toValue = @(0); 96 | anim.duration = 0.2; 97 | anim.delegate = self; 98 | [_refreshView.layer addAnimation:anim forKey:nil]; 99 | _refreshView.layer.opacity = 0; 100 | 101 | 102 | anim = [CABasicAnimation animationWithKeyPath:@"opacity"]; 103 | anim.fromValue = @(0); 104 | anim.toValue = @(1); 105 | anim.beginTime = 0.2; 106 | anim.duration = 0.2; 107 | anim.delegate = self; 108 | [_shapeLayer addAnimation:anim forKey:nil]; 109 | _shapeLayer.opacity = 0; 110 | } 111 | 112 | 113 | - (void)startRefreshAnimation { 114 | if(self.refreshView == nil) { 115 | _refreshView = [[UIImageView alloc] initWithImage:self.refreshCircleImage]; 116 | CGRect refreshViewFrame = _refreshView.frame; 117 | refreshViewFrame.size = CGSizeMake(18, 18); 118 | [self addSubview:_refreshView]; 119 | } 120 | _shapeLayer.opacity = 0; 121 | 122 | _refreshView.center = CGPointMake(15,self.frame.size.height - 20 - _radius); 123 | [_refreshView.layer removeAllAnimations]; 124 | _refreshView.layer.opacity = 1; 125 | 126 | CABasicAnimation* animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; 127 | animation.duration = 1; 128 | animation.fromValue = @0; 129 | animation.toValue = @(M_PI*2); 130 | animation.repeatCount = INT_MAX; 131 | 132 | [_refreshView.layer addAnimation:animation forKey:@"rotation"]; 133 | } 134 | 135 | #pragma mark - CGMutablePathRef Help Method 136 | 137 | - (CGMutablePathRef)createPathWithOffset:(float)currentOffset { 138 | CGMutablePathRef path = CGPathCreateMutable(); 139 | float top = self.frame.size.height - 20 - _radius*2 - currentOffset; 140 | float wdiff = currentOffset * self.deformationLength; // 改变拉断之前,水滴的长度 141 | 142 | if(currentOffset == 0) { 143 | CGPathAddEllipseInRect(path, NULL, CGRectMake(15-_radius, top, _radius*2, _radius*2)); 144 | } else { 145 | CGPathAddArc(path, NULL, 15, top+_radius, _radius, 0, M_PI, YES); 146 | float bottom = top + wdiff+_radius*2; 147 | if(currentOffset < 10) { 148 | CGPathAddCurveToPoint(path, NULL,15-_radius,bottom,15,bottom, 15,bottom); 149 | CGPathAddCurveToPoint(path, NULL, 15,bottom,15+_radius,bottom, 15+_radius, top+_radius); 150 | } else { 151 | CGPathAddCurveToPoint(path, NULL,15-_radius ,top +_radius, 15 - _radius ,bottom - _radius, 15, bottom); 152 | CGPathAddCurveToPoint(path,NULL, 15 + _radius, bottom - _radius, 15+_radius,top +_radius , 15+_radius, top+_radius); 153 | } 154 | } 155 | CGPathCloseSubpath(path); 156 | 157 | return path; 158 | } 159 | 160 | - (void)setCurrentOffset:(float)currentOffset { 161 | if(_isRefresh) 162 | return; 163 | 164 | [self privateSetCurrentOffset:currentOffset]; 165 | } 166 | 167 | - (void)privateSetCurrentOffset:(float)currentOffset { 168 | currentOffset = currentOffset>0?0:currentOffset; 169 | currentOffset = -currentOffset; 170 | _currentOffset = currentOffset; 171 | if(currentOffset < _maxOffset) { 172 | float wdiff = currentOffset* 0.2; 173 | float top = self.frame.size.height - 20 - _radius*2 - currentOffset; 174 | 175 | CGMutablePathRef path = [self createPathWithOffset:currentOffset]; 176 | _shapeLayer.path = path; 177 | CGPathRelease(path); 178 | 179 | 180 | CGMutablePathRef line = CGPathCreateMutable(); 181 | float w = ((_maxOffset - currentOffset)/_maxOffset) + 1; 182 | CGPathAddRect(line, NULL, CGRectMake(15-w/2, top + wdiff + _radius*2,w, currentOffset-wdiff + self.offsetHeight)); // 最好的+20就是线条的长度 183 | _lineLayer.path = line; 184 | 185 | self.transform = CGAffineTransformMakeScale(0.8+0.2*(w-1), 1); 186 | } else { 187 | if(self.timer == nil) 188 | { 189 | _isRefresh = YES; 190 | self.transform = CGAffineTransformIdentity; 191 | self.timer = [NSTimer timerWithTimeInterval:0.02 target:self selector:@selector(resetWater) userInfo:nil repeats:YES]; 192 | [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; 193 | [_timer fire]; 194 | } 195 | } 196 | } 197 | 198 | - (void)resetWater { 199 | [self privateSetCurrentOffset:-(_currentOffset-(_maxOffset/8))]; 200 | if(_currentOffset == 0) { 201 | [self.timer invalidate]; 202 | self.timer = nil; 203 | 204 | // play refresh stop sound 205 | [[XHSoundManager sharedInstance] playRefreshSound]; 206 | 207 | if(self.handleRefreshEvent != nil) { 208 | self.handleRefreshEvent(); 209 | } 210 | [self startRefreshAnimation]; 211 | } 212 | } 213 | 214 | 215 | - (void)animationDidStop:(CABasicAnimation *)anim finished:(BOOL)flag { 216 | if(anim.beginTime > 0) { 217 | _shapeLayer.opacity = 1; 218 | } else { 219 | [_refreshView.layer removeAllAnimations]; 220 | } 221 | } 222 | 223 | /* 224 | // Only override drawRect: if you perform custom drawing. 225 | // An empty implementation adversely affects performance during animation. 226 | - (void)drawRect:(CGRect)rect 227 | { 228 | // Drawing code 229 | } 230 | */ 231 | 232 | @end 233 | -------------------------------------------------------------------------------- /Demo2/HZPhotoBrowserView.m: -------------------------------------------------------------------------------- 1 | // 2 | // HZPhotoBrowserView.m 3 | // photoBrowser 4 | // 5 | // Created by huangzhenyu on 15/6/23. 6 | // Copyright (c) 2015年 eamon. All rights reserved. 7 | // 8 | 9 | #import "HZPhotoBrowserView.h" 10 | #import "HZIndicatorView.h" 11 | #import "HZPhotoBrowserConfig.h" 12 | #import "UIImageView+WebCache.h" 13 | 14 | @interface HZPhotoBrowserView() 15 | @property (nonatomic,strong) HZIndicatorView *indicatorView; 16 | @property (nonatomic,strong) UITapGestureRecognizer *doubleTap; 17 | @property (nonatomic,strong) UITapGestureRecognizer *singleTap; 18 | @property (nonatomic, assign) BOOL hasLoadedImage;//图片下载成功为YES 否则为NO 19 | @property (nonatomic, strong) NSURL *imageUrl; 20 | @property (nonatomic, strong) UIImage *placeHolderImage; 21 | @property (nonatomic, strong) UIButton *reloadButton; 22 | @end 23 | 24 | @implementation HZPhotoBrowserView 25 | - (instancetype)initWithFrame:(CGRect)frame 26 | { 27 | if (self = [super initWithFrame:frame]) { 28 | [self addSubview:self.scrollview]; 29 | //添加单双击事件 30 | [self addGestureRecognizer:self.doubleTap]; 31 | [self addGestureRecognizer:self.singleTap]; 32 | } 33 | return self; 34 | } 35 | 36 | - (UIScrollView *)scrollview 37 | { 38 | if (!_scrollview) { 39 | _scrollview = [[UIScrollView alloc] init]; 40 | _scrollview.frame = CGRectMake(0, 0, kAPPWidth, kAppHeight); 41 | [_scrollview addSubview:self.imageview]; 42 | _scrollview.delegate = self; 43 | _scrollview.clipsToBounds = YES; 44 | } 45 | return _scrollview; 46 | } 47 | 48 | - (UIImageView *)imageview 49 | { 50 | if (!_imageview) { 51 | _imageview = [[UIImageView alloc] init]; 52 | _imageview.frame = CGRectMake(0, 0, kAPPWidth, kAppHeight); 53 | _imageview.userInteractionEnabled = YES; 54 | } 55 | return _imageview; 56 | } 57 | 58 | - (UITapGestureRecognizer *)doubleTap 59 | { 60 | if (!_doubleTap) { 61 | _doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)]; 62 | _doubleTap.numberOfTapsRequired = 2; 63 | _doubleTap.numberOfTouchesRequired =1; 64 | } 65 | return _doubleTap; 66 | } 67 | 68 | - (UITapGestureRecognizer *)singleTap 69 | { 70 | if (!_singleTap) { 71 | _singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleSingleTap:)]; 72 | _singleTap.numberOfTapsRequired = 1; 73 | _singleTap.numberOfTouchesRequired = 1; 74 | //只能有一个手势存在 75 | [_singleTap requireGestureRecognizerToFail:self.doubleTap]; 76 | 77 | } 78 | return _singleTap; 79 | } 80 | 81 | #pragma mark 双击 82 | - (void)handleDoubleTap:(UITapGestureRecognizer *)recognizer 83 | { 84 | //图片加载完之后才能响应双击放大 85 | if (!self.hasLoadedImage) { 86 | return; 87 | } 88 | CGPoint touchPoint = [recognizer locationInView:self]; 89 | if (self.scrollview.zoomScale <= 1.0) { 90 | 91 | CGFloat scaleX = touchPoint.x + self.scrollview.contentOffset.x;//需要放大的图片的X点 92 | CGFloat sacleY = touchPoint.y + self.scrollview.contentOffset.y;//需要放大的图片的Y点 93 | [self.scrollview zoomToRect:CGRectMake(scaleX, sacleY, 10, 10) animated:YES]; 94 | 95 | } else { 96 | [self.scrollview setZoomScale:1.0 animated:YES]; //还原 97 | } 98 | 99 | } 100 | #pragma mark 单击 101 | - (void)handleSingleTap:(UITapGestureRecognizer *)recognizer 102 | { 103 | if (self.singleTapBlock) { 104 | self.singleTapBlock(recognizer); 105 | } 106 | } 107 | 108 | 109 | - (void)setProgress:(CGFloat)progress 110 | { 111 | _progress = progress; 112 | _indicatorView.progress = progress; 113 | } 114 | 115 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder 116 | { 117 | if (_reloadButton) { 118 | [_reloadButton removeFromSuperview]; 119 | } 120 | _imageUrl = url; 121 | _placeHolderImage = placeholder; 122 | //添加进度指示器 123 | HZIndicatorView *indicatorView = [[HZIndicatorView alloc] init]; 124 | indicatorView.viewMode = HZIndicatorViewModeLoopDiagram; 125 | indicatorView.center = CGPointMake(kAPPWidth * 0.5, kAppHeight * 0.5); 126 | self.indicatorView = indicatorView; 127 | [self addSubview:indicatorView]; 128 | 129 | //SDWebImage加载图片 130 | __weak __typeof(self)weakSelf = self; 131 | [_imageview sd_setImageWithURL:url placeholderImage:placeholder options:SDWebImageRetryFailed progress:^(NSInteger receivedSize, NSInteger expectedSize) { 132 | __strong __typeof(weakSelf)strongSelf = weakSelf; 133 | strongSelf.indicatorView.progress = (CGFloat)receivedSize / expectedSize; 134 | 135 | } completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) { 136 | __strong __typeof(weakSelf)strongSelf = weakSelf; 137 | [_indicatorView removeFromSuperview]; 138 | 139 | if (error) { 140 | //图片加载失败的处理,此处可以自定义各种操作(...) 141 | 142 | UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom]; 143 | strongSelf.reloadButton = button; 144 | button.layer.cornerRadius = 2; 145 | button.clipsToBounds = YES; 146 | button.bounds = CGRectMake(0, 0, 200, 40); 147 | button.center = CGPointMake(kAPPWidth * 0.5, kAppHeight * 0.5); 148 | button.titleLabel.font = [UIFont systemFontOfSize:14]; 149 | button.backgroundColor = [UIColor colorWithRed:0.1f green:0.1f blue:0.1f alpha:0.3f]; 150 | [button setTitle:@"原图加载失败,点击重新加载" forState:UIControlStateNormal]; 151 | [button setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; 152 | [button addTarget:strongSelf action:@selector(reloadImage) forControlEvents:UIControlEventTouchUpInside]; 153 | 154 | [self addSubview:button]; 155 | return; 156 | } 157 | strongSelf.hasLoadedImage = YES;//图片加载成功 158 | }]; 159 | } 160 | 161 | - (void)reloadImage 162 | { 163 | [self setImageWithURL:_imageUrl placeholderImage:_placeHolderImage]; 164 | } 165 | 166 | - (void)layoutSubviews 167 | { 168 | [super layoutSubviews]; 169 | _indicatorView.center = _scrollview.center; 170 | _scrollview.frame = self.bounds; 171 | _reloadButton.center = CGPointMake(kAPPWidth * 0.5, kAppHeight * 0.5); 172 | [self adjustFrames]; 173 | } 174 | 175 | - (void)adjustFrames 176 | { 177 | CGRect frame = self.scrollview.frame; 178 | if (self.imageview.image) { 179 | CGSize imageSize = self.imageview.image.size; 180 | CGRect imageFrame = CGRectMake(0, 0, imageSize.width, imageSize.height); 181 | if (kIsFullWidthForLandScape) { 182 | CGFloat ratio = frame.size.width/imageFrame.size.width; 183 | imageFrame.size.height = imageFrame.size.height*ratio; 184 | imageFrame.size.width = frame.size.width; 185 | } else{ 186 | if (frame.size.width<=frame.size.height) { 187 | 188 | CGFloat ratio = frame.size.width/imageFrame.size.width; 189 | imageFrame.size.height = imageFrame.size.height*ratio; 190 | imageFrame.size.width = frame.size.width; 191 | }else{ 192 | CGFloat ratio = frame.size.height/imageFrame.size.height; 193 | imageFrame.size.width = imageFrame.size.width*ratio; 194 | imageFrame.size.height = frame.size.height; 195 | } 196 | } 197 | 198 | self.imageview.frame = imageFrame; 199 | self.scrollview.contentSize = self.imageview.frame.size; 200 | self.imageview.center = [self centerOfScrollViewContent:self.scrollview]; 201 | 202 | 203 | CGFloat maxScale = frame.size.height/imageFrame.size.height; 204 | maxScale = frame.size.width/imageFrame.size.width>maxScale?frame.size.width/imageFrame.size.width:maxScale; 205 | maxScale = maxScale>kMaxZoomScale?maxScale:kMaxZoomScale; 206 | 207 | self.scrollview.minimumZoomScale = kMinZoomScale; 208 | self.scrollview.maximumZoomScale = maxScale; 209 | self.scrollview.zoomScale = 1.0f; 210 | }else{ 211 | frame.origin = CGPointZero; 212 | self.imageview.frame = frame; 213 | self.scrollview.contentSize = self.imageview.frame.size; 214 | } 215 | self.scrollview.contentOffset = CGPointZero; 216 | 217 | } 218 | 219 | - (CGPoint)centerOfScrollViewContent:(UIScrollView *)scrollView 220 | { 221 | CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width)? 222 | (scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 : 0.0; 223 | CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height)? 224 | (scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 : 0.0; 225 | CGPoint actualCenter = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, 226 | scrollView.contentSize.height * 0.5 + offsetY); 227 | return actualCenter; 228 | } 229 | 230 | #pragma mark UIScrollViewDelegate 231 | - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView 232 | { 233 | return self.imageview; 234 | } 235 | 236 | - (void)scrollViewDidZoom:(UIScrollView *)scrollView 237 | { 238 | self.imageview.center = [self centerOfScrollViewContent:scrollView]; 239 | } 240 | @end 241 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/SDImageCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import 10 | #import "SDWebImageCompat.h" 11 | 12 | typedef NS_ENUM(NSInteger, SDImageCacheType) { 13 | /** 14 | * The image wasn't available the SDWebImage caches, but was downloaded from the web. 15 | */ 16 | SDImageCacheTypeNone, 17 | /** 18 | * The image was obtained from the disk cache. 19 | */ 20 | SDImageCacheTypeDisk, 21 | /** 22 | * The image was obtained from the memory cache. 23 | */ 24 | SDImageCacheTypeMemory 25 | }; 26 | 27 | typedef void(^SDWebImageQueryCompletedBlock)(UIImage *image, SDImageCacheType cacheType); 28 | 29 | typedef void(^SDWebImageCheckCacheCompletionBlock)(BOOL isInCache); 30 | 31 | typedef void(^SDWebImageCalculateSizeBlock)(NSUInteger fileCount, NSUInteger totalSize); 32 | 33 | /** 34 | * SDImageCache maintains a memory cache and an optional disk cache. Disk cache write operations are performed 35 | * asynchronous so it doesn’t add unnecessary latency to the UI. 36 | */ 37 | @interface SDImageCache : NSObject 38 | 39 | /** 40 | * Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory. 41 | * Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption. 42 | */ 43 | @property (assign, nonatomic) BOOL shouldDecompressImages; 44 | 45 | /** 46 | * disable iCloud backup [defaults to YES] 47 | */ 48 | @property (assign, nonatomic) BOOL shouldDisableiCloud; 49 | 50 | /** 51 | * use memory cache [defaults to YES] 52 | */ 53 | @property (assign, nonatomic) BOOL shouldCacheImagesInMemory; 54 | 55 | /** 56 | * The maximum "total cost" of the in-memory image cache. The cost function is the number of pixels held in memory. 57 | */ 58 | @property (assign, nonatomic) NSUInteger maxMemoryCost; 59 | 60 | /** 61 | * The maximum number of objects the cache should hold. 62 | */ 63 | @property (assign, nonatomic) NSUInteger maxMemoryCountLimit; 64 | 65 | /** 66 | * The maximum length of time to keep an image in the cache, in seconds 67 | */ 68 | @property (assign, nonatomic) NSInteger maxCacheAge; 69 | 70 | /** 71 | * The maximum size of the cache, in bytes. 72 | */ 73 | @property (assign, nonatomic) NSUInteger maxCacheSize; 74 | 75 | /** 76 | * Returns global shared cache instance 77 | * 78 | * @return SDImageCache global instance 79 | */ 80 | + (SDImageCache *)sharedImageCache; 81 | 82 | /** 83 | * Init a new cache store with a specific namespace 84 | * 85 | * @param ns The namespace to use for this cache store 86 | */ 87 | - (id)initWithNamespace:(NSString *)ns; 88 | 89 | /** 90 | * Init a new cache store with a specific namespace and directory 91 | * 92 | * @param ns The namespace to use for this cache store 93 | * @param directory Directory to cache disk images in 94 | */ 95 | - (id)initWithNamespace:(NSString *)ns diskCacheDirectory:(NSString *)directory; 96 | 97 | -(NSString *)makeDiskCachePath:(NSString*)fullNamespace; 98 | 99 | /** 100 | * Add a read-only cache path to search for images pre-cached by SDImageCache 101 | * Useful if you want to bundle pre-loaded images with your app 102 | * 103 | * @param path The path to use for this read-only cache path 104 | */ 105 | - (void)addReadOnlyCachePath:(NSString *)path; 106 | 107 | /** 108 | * Store an image into memory and disk cache at the given key. 109 | * 110 | * @param image The image to store 111 | * @param key The unique image cache key, usually it's image absolute URL 112 | */ 113 | - (void)storeImage:(UIImage *)image forKey:(NSString *)key; 114 | 115 | /** 116 | * Store an image into memory and optionally disk cache at the given key. 117 | * 118 | * @param image The image to store 119 | * @param key The unique image cache key, usually it's image absolute URL 120 | * @param toDisk Store the image to disk cache if YES 121 | */ 122 | - (void)storeImage:(UIImage *)image forKey:(NSString *)key toDisk:(BOOL)toDisk; 123 | 124 | /** 125 | * Store an image into memory and optionally disk cache at the given key. 126 | * 127 | * @param image The image to store 128 | * @param recalculate BOOL indicates if imageData can be used or a new data should be constructed from the UIImage 129 | * @param imageData The image data as returned by the server, this representation will be used for disk storage 130 | * instead of converting the given image object into a storable/compressed image format in order 131 | * to save quality and CPU 132 | * @param key The unique image cache key, usually it's image absolute URL 133 | * @param toDisk Store the image to disk cache if YES 134 | */ 135 | - (void)storeImage:(UIImage *)image recalculateFromImage:(BOOL)recalculate imageData:(NSData *)imageData forKey:(NSString *)key toDisk:(BOOL)toDisk; 136 | 137 | /** 138 | * Query the disk cache asynchronously. 139 | * 140 | * @param key The unique key used to store the wanted image 141 | */ 142 | - (NSOperation *)queryDiskCacheForKey:(NSString *)key done:(SDWebImageQueryCompletedBlock)doneBlock; 143 | 144 | /** 145 | * Query the memory cache synchronously. 146 | * 147 | * @param key The unique key used to store the wanted image 148 | */ 149 | - (UIImage *)imageFromMemoryCacheForKey:(NSString *)key; 150 | 151 | /** 152 | * Query the disk cache synchronously after checking the memory cache. 153 | * 154 | * @param key The unique key used to store the wanted image 155 | */ 156 | - (UIImage *)imageFromDiskCacheForKey:(NSString *)key; 157 | 158 | /** 159 | * Remove the image from memory and disk cache synchronously 160 | * 161 | * @param key The unique image cache key 162 | */ 163 | - (void)removeImageForKey:(NSString *)key; 164 | 165 | 166 | /** 167 | * Remove the image from memory and disk cache asynchronously 168 | * 169 | * @param key The unique image cache key 170 | * @param completion An block that should be executed after the image has been removed (optional) 171 | */ 172 | - (void)removeImageForKey:(NSString *)key withCompletion:(SDWebImageNoParamsBlock)completion; 173 | 174 | /** 175 | * Remove the image from memory and optionally disk cache asynchronously 176 | * 177 | * @param key The unique image cache key 178 | * @param fromDisk Also remove cache entry from disk if YES 179 | */ 180 | - (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk; 181 | 182 | /** 183 | * Remove the image from memory and optionally disk cache asynchronously 184 | * 185 | * @param key The unique image cache key 186 | * @param fromDisk Also remove cache entry from disk if YES 187 | * @param completion An block that should be executed after the image has been removed (optional) 188 | */ 189 | - (void)removeImageForKey:(NSString *)key fromDisk:(BOOL)fromDisk withCompletion:(SDWebImageNoParamsBlock)completion; 190 | 191 | /** 192 | * Clear all memory cached images 193 | */ 194 | - (void)clearMemory; 195 | 196 | /** 197 | * Clear all disk cached images. Non-blocking method - returns immediately. 198 | * @param completion An block that should be executed after cache expiration completes (optional) 199 | */ 200 | - (void)clearDiskOnCompletion:(SDWebImageNoParamsBlock)completion; 201 | 202 | /** 203 | * Clear all disk cached images 204 | * @see clearDiskOnCompletion: 205 | */ 206 | - (void)clearDisk; 207 | 208 | /** 209 | * Remove all expired cached image from disk. Non-blocking method - returns immediately. 210 | * @param completionBlock An block that should be executed after cache expiration completes (optional) 211 | */ 212 | - (void)cleanDiskWithCompletionBlock:(SDWebImageNoParamsBlock)completionBlock; 213 | 214 | /** 215 | * Remove all expired cached image from disk 216 | * @see cleanDiskWithCompletionBlock: 217 | */ 218 | - (void)cleanDisk; 219 | 220 | /** 221 | * Get the size used by the disk cache 222 | */ 223 | - (NSUInteger)getSize; 224 | 225 | /** 226 | * Get the number of images in the disk cache 227 | */ 228 | - (NSUInteger)getDiskCount; 229 | 230 | /** 231 | * Asynchronously calculate the disk cache's size. 232 | */ 233 | - (void)calculateSizeWithCompletionBlock:(SDWebImageCalculateSizeBlock)completionBlock; 234 | 235 | /** 236 | * Async check if image exists in disk cache already (does not load the image) 237 | * 238 | * @param key the key describing the url 239 | * @param completionBlock the block to be executed when the check is done. 240 | * @note the completion block will be always executed on the main queue 241 | */ 242 | - (void)diskImageExistsWithKey:(NSString *)key completion:(SDWebImageCheckCacheCompletionBlock)completionBlock; 243 | 244 | /** 245 | * Check if image exists in disk cache already (does not load the image) 246 | * 247 | * @param key the key describing the url 248 | * 249 | * @return YES if an image exists for the given key 250 | */ 251 | - (BOOL)diskImageExistsWithKey:(NSString *)key; 252 | 253 | /** 254 | * Get the cache path for a certain key (needs the cache path root folder) 255 | * 256 | * @param key the key (can be obtained from url using cacheKeyForURL) 257 | * @param path the cach path root folder 258 | * 259 | * @return the cache path 260 | */ 261 | - (NSString *)cachePathForKey:(NSString *)key inPath:(NSString *)path; 262 | 263 | /** 264 | * Get the default cache path for a certain key 265 | * 266 | * @param key the key (can be obtained from url using cacheKeyForURL) 267 | * 268 | * @return the default cache path 269 | */ 270 | - (NSString *)defaultCachePathForKey:(NSString *)key; 271 | 272 | @end 273 | -------------------------------------------------------------------------------- /Demo2/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年 itcast. All rights reserved. 8 | // 9 | 10 | #import "UIScrollView+MJRefresh.h" 11 | #import "MJRefreshGifHeader.h" 12 | #import "MJRefreshLegendHeader.h" 13 | #import "MJRefreshGifFooter.h" 14 | #import "MJRefreshLegendFooter.h" 15 | #import 16 | 17 | @implementation UIScrollView (MJRefresh) 18 | #pragma mark - 下拉刷新 19 | - (MJRefreshLegendHeader *)addLegendHeaderWithRefreshingBlock:(void (^)())block dateKey:(NSString *)dateKey 20 | { 21 | MJRefreshLegendHeader *header = [self addLegendHeader]; 22 | header.refreshingBlock = block; 23 | header.dateKey = dateKey; 24 | return header; 25 | } 26 | 27 | - (MJRefreshLegendHeader *)addLegendHeaderWithRefreshingTarget:(id)target refreshingAction:(SEL)action dateKey:(NSString *)dateKey 28 | { 29 | MJRefreshLegendHeader *header = [self addLegendHeader]; 30 | header.refreshingTarget = target; 31 | header.refreshingAction = action; 32 | header.dateKey = dateKey; 33 | return header; 34 | } 35 | 36 | - (MJRefreshLegendHeader *)addLegendHeaderWithRefreshingTarget:(id)target refreshingAction:(SEL)action 37 | { 38 | return [self addLegendHeaderWithRefreshingTarget:target refreshingAction:action dateKey:nil]; 39 | } 40 | 41 | - (MJRefreshLegendHeader *)addLegendHeaderWithRefreshingBlock:(void (^)())block 42 | { 43 | return [self addLegendHeaderWithRefreshingBlock:block dateKey:nil]; 44 | } 45 | 46 | - (MJRefreshLegendHeader *)addLegendHeader 47 | { 48 | MJRefreshLegendHeader *header = [[MJRefreshLegendHeader alloc] init]; 49 | self.header = header; 50 | 51 | return header; 52 | } 53 | 54 | - (MJRefreshGifHeader *)addGifHeaderWithRefreshingBlock:(void (^)())block dateKey:(NSString *)dateKey 55 | { 56 | MJRefreshGifHeader *header = [self addGifHeader]; 57 | header.refreshingBlock = block; 58 | header.dateKey = dateKey; 59 | return header; 60 | } 61 | 62 | - (MJRefreshGifHeader *)addGifHeaderWithRefreshingTarget:(id)target refreshingAction:(SEL)action dateKey:(NSString *)dateKey 63 | { 64 | MJRefreshGifHeader *header = [self addGifHeader]; 65 | header.refreshingTarget = target; 66 | header.refreshingAction = action; 67 | header.dateKey = dateKey; 68 | return header; 69 | } 70 | 71 | - (MJRefreshGifHeader *)addGifHeaderWithRefreshingBlock:(void (^)())block 72 | { 73 | return [self addGifHeaderWithRefreshingBlock:block dateKey:nil]; 74 | } 75 | 76 | - (MJRefreshGifHeader *)addGifHeaderWithRefreshingTarget:(id)target refreshingAction:(SEL)action 77 | { 78 | return [self addGifHeaderWithRefreshingTarget:target refreshingAction:action dateKey:nil]; 79 | } 80 | 81 | - (MJRefreshGifHeader *)addGifHeader 82 | { 83 | MJRefreshGifHeader *header = [[MJRefreshGifHeader alloc] init]; 84 | self.header = header; 85 | 86 | return header; 87 | } 88 | 89 | - (void)removeHeader 90 | { 91 | self.header = nil; 92 | } 93 | 94 | #pragma mark - Property Methods 95 | #pragma mark gifHeader 96 | - (MJRefreshGifHeader *)gifHeader 97 | { 98 | if ([self.header isKindOfClass:[MJRefreshGifHeader class]]) { 99 | return (MJRefreshGifHeader *)self.header; 100 | } 101 | 102 | return nil; 103 | } 104 | 105 | #pragma mark legendHeader 106 | - (MJRefreshLegendHeader *)legendHeader 107 | { 108 | if ([self.header isKindOfClass:[MJRefreshLegendHeader class]]) { 109 | return (MJRefreshLegendHeader *)self.header; 110 | } 111 | 112 | return nil; 113 | } 114 | 115 | #pragma mark header 116 | static char MJRefreshHeaderKey; 117 | - (void)setHeader:(MJRefreshHeader *)header 118 | { 119 | if (header != self.header) { 120 | [self.header removeFromSuperview]; 121 | 122 | [self willChangeValueForKey:@"header"]; 123 | objc_setAssociatedObject(self, &MJRefreshHeaderKey, 124 | header, 125 | OBJC_ASSOCIATION_ASSIGN); 126 | [self didChangeValueForKey:@"header"]; 127 | 128 | [self addSubview:header]; 129 | } 130 | } 131 | 132 | - (MJRefreshHeader *)header 133 | { 134 | return objc_getAssociatedObject(self, &MJRefreshHeaderKey); 135 | } 136 | 137 | #pragma mark - 上拉刷新 138 | - (MJRefreshLegendFooter *)addLegendFooterWithRefreshingBlock:(void (^)())block 139 | { 140 | MJRefreshLegendFooter *footer = [self addLegendFooter]; 141 | footer.refreshingBlock = block; 142 | return footer; 143 | } 144 | 145 | - (MJRefreshLegendFooter *)addLegendFooterWithRefreshingTarget:(id)target refreshingAction:(SEL)action 146 | { 147 | MJRefreshLegendFooter *footer = [self addLegendFooter]; 148 | footer.refreshingTarget = target; 149 | footer.refreshingAction = action; 150 | return footer; 151 | } 152 | 153 | - (MJRefreshLegendFooter *)addLegendFooter 154 | { 155 | MJRefreshLegendFooter *footer = [[MJRefreshLegendFooter alloc] init]; 156 | self.footer = footer; 157 | 158 | return footer; 159 | } 160 | 161 | - (MJRefreshGifFooter *)addGifFooterWithRefreshingBlock:(void (^)())block 162 | { 163 | MJRefreshGifFooter *footer = [self addGifFooter]; 164 | footer.refreshingBlock = block; 165 | return footer; 166 | } 167 | 168 | - (MJRefreshGifFooter *)addGifFooterWithRefreshingTarget:(id)target refreshingAction:(SEL)action 169 | { 170 | MJRefreshGifFooter *footer = [self addGifFooter]; 171 | footer.refreshingTarget = target; 172 | footer.refreshingAction = action; 173 | return footer; 174 | } 175 | 176 | - (MJRefreshGifFooter *)addGifFooter 177 | { 178 | MJRefreshGifFooter *footer = [[MJRefreshGifFooter alloc] init]; 179 | self.footer = footer; 180 | 181 | return footer; 182 | } 183 | 184 | - (void)removeFooter 185 | { 186 | self.footer = nil; 187 | } 188 | 189 | static char MJRefreshFooterKey; 190 | - (void)setFooter:(MJRefreshFooter *)footer 191 | { 192 | if (footer != self.footer) { 193 | [self.footer removeFromSuperview]; 194 | 195 | [self willChangeValueForKey:@"footer"]; 196 | objc_setAssociatedObject(self, &MJRefreshFooterKey, 197 | footer, 198 | OBJC_ASSOCIATION_ASSIGN); 199 | [self didChangeValueForKey:@"footer"]; 200 | 201 | [self addSubview:footer]; 202 | } 203 | } 204 | 205 | - (MJRefreshGifFooter *)gifFooter 206 | { 207 | if ([self.footer isKindOfClass:[MJRefreshGifFooter class]]) { 208 | return (MJRefreshGifFooter *)self.footer; 209 | } 210 | return nil; 211 | } 212 | 213 | - (MJRefreshLegendFooter *)legendFooter 214 | { 215 | if ([self.footer isKindOfClass:[MJRefreshLegendFooter class]]) { 216 | return (MJRefreshLegendFooter *)self.footer; 217 | } 218 | return nil; 219 | } 220 | 221 | 222 | - (MJRefreshFooter *)footer 223 | { 224 | return objc_getAssociatedObject(self, &MJRefreshFooterKey); 225 | } 226 | 227 | #pragma mark - swizzle 228 | + (void)load 229 | { 230 | Method method1 = class_getInstanceMethod([self class], NSSelectorFromString(@"dealloc")); 231 | Method method2 = class_getInstanceMethod([self class], @selector(deallocSwizzle)); 232 | method_exchangeImplementations(method1, method2); 233 | } 234 | 235 | - (void)deallocSwizzle 236 | { 237 | [self removeFooter]; 238 | [self removeHeader]; 239 | 240 | [self deallocSwizzle]; 241 | } 242 | 243 | @end 244 | 245 | 246 | #pragma mark - 1.0.0版本以前的接口 247 | @implementation UIScrollView(MJRefreshDeprecated) 248 | #pragma mark - 下拉刷新 249 | /** 250 | * 添加一个下拉刷新头部控件 251 | * 252 | * @param callback 回调 253 | */ 254 | - (void)addHeaderWithCallback:(void (^)())callback 255 | { 256 | [self addHeaderWithCallback:callback dateKey:nil]; 257 | } 258 | 259 | /** 260 | * 添加一个下拉刷新头部控件 261 | * 262 | * @param callback 回调 263 | * @param dateKey 刷新时间保存的key值 264 | */ 265 | - (void)addHeaderWithCallback:(void (^)())callback dateKey:(NSString*)dateKey 266 | { 267 | [self addLegendHeader]; 268 | self.header.dateKey = dateKey; 269 | self.header.refreshingBlock = callback; 270 | } 271 | 272 | /** 273 | * 添加一个下拉刷新头部控件 274 | * 275 | * @param target 目标 276 | * @param action 回调方法 277 | */ 278 | - (void)addHeaderWithTarget:(id)target action:(SEL)action 279 | { 280 | [self addHeaderWithTarget:target action:action dateKey:nil]; 281 | } 282 | 283 | /** 284 | * 添加一个下拉刷新头部控件 285 | * 286 | * @param target 目标 287 | * @param action 回调方法 288 | * @param dateKey 刷新时间保存的key值 289 | */ 290 | - (void)addHeaderWithTarget:(id)target action:(SEL)action dateKey:(NSString*)dateKey 291 | { 292 | [self addLegendHeader]; 293 | self.header.dateKey = dateKey; 294 | [self.header setRefreshingTarget:target refreshingAction:action]; 295 | } 296 | 297 | /** 298 | * 主动让下拉刷新头部控件进入刷新状态 299 | */ 300 | - (void)headerBeginRefreshing 301 | { 302 | [self.header beginRefreshing]; 303 | } 304 | 305 | /** 306 | * 让下拉刷新头部控件停止刷新状态 307 | */ 308 | - (void)headerEndRefreshing 309 | { 310 | [self.header endRefreshing]; 311 | } 312 | 313 | /** 314 | * 下拉刷新头部控件的可见性 315 | */ 316 | - (void)setHeaderHidden:(BOOL)headerHidden 317 | { 318 | self.header.hidden = headerHidden; 319 | } 320 | 321 | - (BOOL)isHeaderHidden 322 | { 323 | return self.header.isHidden; 324 | } 325 | 326 | /** 327 | * 是否正在下拉刷新 328 | */ 329 | - (BOOL)isHeaderRefreshing 330 | { 331 | return self.header.isRefreshing; 332 | } 333 | 334 | #pragma mark - 上拉刷新 335 | /** 336 | * 添加一个上拉刷新尾部控件 337 | * 338 | * @param callback 回调 339 | */ 340 | - (void)addFooterWithCallback:(void (^)())callback 341 | { 342 | [self addLegendFooter]; 343 | self.footer.refreshingBlock = callback; 344 | } 345 | 346 | /** 347 | * 添加一个上拉刷新尾部控件 348 | * 349 | * @param target 目标 350 | * @param action 回调方法 351 | */ 352 | - (void)addFooterWithTarget:(id)target action:(SEL)action 353 | { 354 | [self addLegendFooter]; 355 | [self.footer setRefreshingTarget:target refreshingAction:action]; 356 | } 357 | 358 | /** 359 | * 主动让上拉刷新尾部控件进入刷新状态 360 | */ 361 | - (void)footerBeginRefreshing 362 | { 363 | [self.footer beginRefreshing]; 364 | } 365 | 366 | /** 367 | * 让上拉刷新尾部控件停止刷新状态 368 | */ 369 | - (void)footerEndRefreshing 370 | { 371 | [self.footer endRefreshing]; 372 | } 373 | 374 | /** 375 | * 上拉刷新头部控件的可见性 376 | */ 377 | - (void)setFooterHidden:(BOOL)footerHidden 378 | { 379 | self.footer.hidden = footerHidden; 380 | } 381 | 382 | - (BOOL)isFooterHidden 383 | { 384 | return self.footer.isHidden; 385 | } 386 | 387 | /** 388 | * 是否正在上拉刷新 389 | */ 390 | - (BOOL)isFooterRefreshing 391 | { 392 | return self.footer.isRefreshing; 393 | } 394 | @end 395 | -------------------------------------------------------------------------------- /Demo2/SDWebImage/UIImageView+WebCache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the SDWebImage package. 3 | * (c) Olivier Poitrey 4 | * 5 | * For the full copyright and license information, please view the LICENSE 6 | * file that was distributed with this source code. 7 | */ 8 | 9 | #import "SDWebImageCompat.h" 10 | #import "SDWebImageManager.h" 11 | 12 | /** 13 | * Integrates SDWebImage async downloading and caching of remote images with UIImageView. 14 | * 15 | * Usage with a UITableViewCell sub-class: 16 | * 17 | * @code 18 | 19 | #import 20 | 21 | ... 22 | 23 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 24 | { 25 | static NSString *MyIdentifier = @"MyIdentifier"; 26 | 27 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier]; 28 | 29 | if (cell == nil) { 30 | cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] 31 | autorelease]; 32 | } 33 | 34 | // Here we use the provided sd_setImageWithURL: method to load the web image 35 | // Ensure you use a placeholder image otherwise cells will be initialized with no image 36 | [cell.imageView sd_setImageWithURL:[NSURL URLWithString:@"http://example.com/image.jpg"] 37 | placeholderImage:[UIImage imageNamed:@"placeholder"]]; 38 | 39 | cell.textLabel.text = @"My Text"; 40 | return cell; 41 | } 42 | 43 | * @endcode 44 | */ 45 | @interface UIImageView (WebCache) 46 | 47 | /** 48 | * Get the current image URL. 49 | * 50 | * Note that because of the limitations of categories this property can get out of sync 51 | * if you use sd_setImage: directly. 52 | */ 53 | - (NSURL *)sd_imageURL; 54 | 55 | /** 56 | * Set the imageView `image` with an `url`. 57 | * 58 | * The download is asynchronous and cached. 59 | * 60 | * @param url The url for the image. 61 | */ 62 | - (void)sd_setImageWithURL:(NSURL *)url; 63 | 64 | /** 65 | * Set the imageView `image` with an `url` and a placeholder. 66 | * 67 | * The download is asynchronous and cached. 68 | * 69 | * @param url The url for the image. 70 | * @param placeholder The image to be set initially, until the image request finishes. 71 | * @see sd_setImageWithURL:placeholderImage:options: 72 | */ 73 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder; 74 | 75 | /** 76 | * Set the imageView `image` with an `url`, placeholder and custom options. 77 | * 78 | * The download is asynchronous and cached. 79 | * 80 | * @param url The url for the image. 81 | * @param placeholder The image to be set initially, until the image request finishes. 82 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 83 | */ 84 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options; 85 | 86 | /** 87 | * Set the imageView `image` with an `url`. 88 | * 89 | * The download is asynchronous and cached. 90 | * 91 | * @param url The url for the image. 92 | * @param completedBlock A block called when operation has been completed. This block has no return value 93 | * and takes the requested UIImage as first parameter. In case of error the image parameter 94 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 95 | * indicating if the image was retrived from the local cache or from the network. 96 | * The fourth parameter is the original image url. 97 | */ 98 | - (void)sd_setImageWithURL:(NSURL *)url completed:(SDWebImageCompletionBlock)completedBlock; 99 | 100 | /** 101 | * Set the imageView `image` with an `url`, placeholder. 102 | * 103 | * The download is asynchronous and cached. 104 | * 105 | * @param url The url for the image. 106 | * @param placeholder The image to be set initially, until the image request finishes. 107 | * @param completedBlock A block called when operation has been completed. This block has no return value 108 | * and takes the requested UIImage as first parameter. In case of error the image parameter 109 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 110 | * indicating if the image was retrived from the local cache or from the network. 111 | * The fourth parameter is the original image url. 112 | */ 113 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletionBlock)completedBlock; 114 | 115 | /** 116 | * Set the imageView `image` with an `url`, placeholder and custom options. 117 | * 118 | * The download is asynchronous and cached. 119 | * 120 | * @param url The url for the image. 121 | * @param placeholder The image to be set initially, until the image request finishes. 122 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 123 | * @param completedBlock A block called when operation has been completed. This block has no return value 124 | * and takes the requested UIImage as first parameter. In case of error the image parameter 125 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 126 | * indicating if the image was retrived from the local cache or from the network. 127 | * The fourth parameter is the original image url. 128 | */ 129 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletionBlock)completedBlock; 130 | 131 | /** 132 | * Set the imageView `image` with an `url`, placeholder and custom options. 133 | * 134 | * The download is asynchronous and cached. 135 | * 136 | * @param url The url for the image. 137 | * @param placeholder The image to be set initially, until the image request finishes. 138 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 139 | * @param progressBlock A block called while image is downloading 140 | * @param completedBlock A block called when operation has been completed. This block has no return value 141 | * and takes the requested UIImage as first parameter. In case of error the image parameter 142 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 143 | * indicating if the image was retrived from the local cache or from the network. 144 | * The fourth parameter is the original image url. 145 | */ 146 | - (void)sd_setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock; 147 | 148 | /** 149 | * Set the imageView `image` with an `url` and a optionaly placeholder image. 150 | * 151 | * The download is asynchronous and cached. 152 | * 153 | * @param url The url for the image. 154 | * @param placeholder The image to be set initially, until the image request finishes. 155 | * @param options The options to use when downloading the image. @see SDWebImageOptions for the possible values. 156 | * @param progressBlock A block called while image is downloading 157 | * @param completedBlock A block called when operation has been completed. This block has no return value 158 | * and takes the requested UIImage as first parameter. In case of error the image parameter 159 | * is nil and the second parameter may contain an NSError. The third parameter is a Boolean 160 | * indicating if the image was retrived from the local cache or from the network. 161 | * The fourth parameter is the original image url. 162 | */ 163 | - (void)sd_setImageWithPreviousCachedImageWithURL:(NSURL *)url andPlaceholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletionBlock)completedBlock; 164 | 165 | /** 166 | * Download an array of images and starts them in an animation loop 167 | * 168 | * @param arrayOfURLs An array of NSURL 169 | */ 170 | - (void)sd_setAnimationImagesWithURLs:(NSArray *)arrayOfURLs; 171 | 172 | /** 173 | * Cancel the current download 174 | */ 175 | - (void)sd_cancelCurrentImageLoad; 176 | 177 | - (void)sd_cancelCurrentAnimationImagesLoad; 178 | 179 | /** 180 | * Show activity UIActivityIndicatorView 181 | */ 182 | - (void)setShowActivityIndicatorView:(BOOL)show; 183 | 184 | /** 185 | * set desired UIActivityIndicatorViewStyle 186 | * 187 | * @param style The style of the UIActivityIndicatorView 188 | */ 189 | - (void)setIndicatorStyle:(UIActivityIndicatorViewStyle)style; 190 | 191 | @end 192 | 193 | 194 | @interface UIImageView (WebCacheDeprecated) 195 | 196 | - (NSURL *)imageURL __deprecated_msg("Use `sd_imageURL`"); 197 | 198 | - (void)setImageWithURL:(NSURL *)url __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:`"); 199 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:`"); 200 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:options`"); 201 | 202 | - (void)setImageWithURL:(NSURL *)url completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:completed:`"); 203 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:completed:`"); 204 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:options:completed:`"); 205 | - (void)setImageWithURL:(NSURL *)url placeholderImage:(UIImage *)placeholder options:(SDWebImageOptions)options progress:(SDWebImageDownloaderProgressBlock)progressBlock completed:(SDWebImageCompletedBlock)completedBlock __deprecated_msg("Method deprecated. Use `sd_setImageWithURL:placeholderImage:options:progress:completed:`"); 206 | 207 | - (void)setAnimationImagesWithURLs:(NSArray *)arrayOfURLs __deprecated_msg("Use `sd_setAnimationImagesWithURLs:`"); 208 | 209 | - (void)cancelCurrentArrayLoad __deprecated_msg("Use `sd_cancelCurrentAnimationImagesLoad`"); 210 | 211 | - (void)cancelCurrentImageLoad __deprecated_msg("Use `sd_cancelCurrentImageLoad`"); 212 | 213 | @end 214 | -------------------------------------------------------------------------------- /Demo2/MJRefresh/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年 itcast. All rights reserved. 8 | // 9 | 10 | #import "MJRefreshFooter.h" 11 | #import "MJRefreshConst.h" 12 | #import "UIScrollView+MJExtension.h" 13 | #import "MJRefreshHeader.h" 14 | #import "UIView+MJExtension.h" 15 | #import "UIScrollView+MJRefresh.h" 16 | #import 17 | 18 | @interface MJRefreshFooter() 19 | /** 显示状态文字的标签 */ 20 | @property (weak, nonatomic) UILabel *stateLabel; 21 | /** 点击可以加载更多 */ 22 | @property (weak, nonatomic) UIButton *loadMoreButton; 23 | /** 没有更多的数据 */ 24 | @property (weak, nonatomic) UILabel *noMoreLabel; 25 | /** 即将要执行的代码 */ 26 | @property (strong, nonatomic) NSMutableArray *willExecuteBlocks; 27 | @end 28 | 29 | @implementation MJRefreshFooter 30 | #pragma mark - 懒加载 31 | - (NSMutableArray *)willExecuteBlocks 32 | { 33 | if (!_willExecuteBlocks) { 34 | self.willExecuteBlocks = [NSMutableArray array]; 35 | } 36 | return _willExecuteBlocks; 37 | } 38 | 39 | - (UIButton *)loadMoreButton 40 | { 41 | if (!_loadMoreButton) { 42 | UIButton *loadMoreButton = [[UIButton alloc] init]; 43 | loadMoreButton.backgroundColor = [UIColor clearColor]; 44 | [loadMoreButton addTarget:self action:@selector(buttonClick) forControlEvents:UIControlEventTouchUpInside]; 45 | [self addSubview:_loadMoreButton = loadMoreButton]; 46 | } 47 | return _loadMoreButton; 48 | } 49 | 50 | - (UILabel *)noMoreLabel 51 | { 52 | if (!_noMoreLabel) { 53 | UILabel *noMoreLabel = [[UILabel alloc] init]; 54 | noMoreLabel.backgroundColor = [UIColor clearColor]; 55 | noMoreLabel.textAlignment = NSTextAlignmentCenter; 56 | [self addSubview:_noMoreLabel = noMoreLabel]; 57 | } 58 | return _noMoreLabel; 59 | } 60 | 61 | - (UILabel *)stateLabel 62 | { 63 | if (!_stateLabel) { 64 | UILabel *stateLabel = [[UILabel alloc] init]; 65 | stateLabel.backgroundColor = [UIColor clearColor]; 66 | stateLabel.textAlignment = NSTextAlignmentCenter; 67 | [self addSubview:_stateLabel = stateLabel]; 68 | } 69 | return _stateLabel; 70 | } 71 | 72 | #pragma mark - 初始化方法 73 | - (instancetype)initWithFrame:(CGRect)frame { 74 | if (self = [super initWithFrame:frame]) { 75 | // 默认底部控件100%出现时才会自动刷新 76 | self.appearencePercentTriggerAutoRefresh = 1.0; 77 | 78 | // 设置为默认状态 79 | self.automaticallyRefresh = YES; 80 | self.state = MJRefreshFooterStateIdle; 81 | 82 | // 初始化文字 83 | [self setTitle:MJRefreshFooterStateIdleText forState:MJRefreshFooterStateIdle]; 84 | [self setTitle:MJRefreshFooterStateRefreshingText forState:MJRefreshFooterStateRefreshing]; 85 | [self setTitle:MJRefreshFooterStateNoMoreDataText forState:MJRefreshFooterStateNoMoreData]; 86 | } 87 | return self; 88 | } 89 | 90 | - (void)willMoveToSuperview:(UIView *)newSuperview 91 | { 92 | [super willMoveToSuperview:newSuperview]; 93 | 94 | // 旧的父控件 95 | [self.superview removeObserver:self forKeyPath:MJRefreshContentSize context:nil]; 96 | [self.superview removeObserver:self forKeyPath:MJRefreshPanState context:nil]; 97 | 98 | if (newSuperview) { // 新的父控件 99 | // 监听 100 | [newSuperview addObserver:self forKeyPath:MJRefreshContentSize options:NSKeyValueObservingOptionNew context:nil]; 101 | [newSuperview addObserver:self forKeyPath:MJRefreshPanState options:NSKeyValueObservingOptionNew context:nil]; 102 | 103 | self.mj_h = MJRefreshFooterHeight; 104 | _scrollView.mj_insetB += self.mj_h; 105 | 106 | // 重新调整frame 107 | [self adjustFrameWithContentSize]; 108 | } else { // 被移除了 109 | _scrollView.mj_insetB -= self.mj_h; 110 | } 111 | } 112 | 113 | - (void)layoutSubviews 114 | { 115 | [super layoutSubviews]; 116 | 117 | self.loadMoreButton.frame = self.bounds; 118 | self.stateLabel.frame = self.bounds; 119 | self.noMoreLabel.frame = self.bounds; 120 | } 121 | 122 | #pragma mark - 私有方法 123 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 124 | { 125 | // 遇到这些情况就直接返回 126 | if (!self.userInteractionEnabled || self.alpha <= 0.01 || self.hidden) return; 127 | 128 | if (self.state == MJRefreshFooterStateIdle) { 129 | // 当是Idle状态时,才需要检测是否要进入刷新状态 130 | if ([keyPath isEqualToString:MJRefreshPanState]) { 131 | if (_scrollView.panGestureRecognizer.state == UIGestureRecognizerStateEnded) {// 手松开 132 | if (_scrollView.mj_insetT + _scrollView.mj_contentSizeH <= _scrollView.mj_h) { // 不够一个屏幕 133 | if (_scrollView.mj_offsetY > - _scrollView.mj_insetT) { // 向上拽 134 | [self beginRefreshing]; 135 | } 136 | } else { // 超出一个屏幕 137 | if (_scrollView.mj_offsetY > _scrollView.mj_contentSizeH + _scrollView.mj_insetB - _scrollView.mj_h) { 138 | [self beginRefreshing]; 139 | } 140 | } 141 | } 142 | } else if ([keyPath isEqualToString:MJRefreshContentOffset]) { 143 | if (self.state != MJRefreshFooterStateRefreshing && self.automaticallyRefresh) { 144 | // 根据contentOffset调整state 145 | [self adjustStateWithContentOffset]; 146 | } 147 | } 148 | } 149 | 150 | // 不管是什么状态,都要调整位置 151 | if ([keyPath isEqualToString:MJRefreshContentSize]) { 152 | [self adjustFrameWithContentSize]; 153 | } 154 | } 155 | 156 | #pragma mark 根据contentOffset调整state 157 | - (void)adjustStateWithContentOffset 158 | { 159 | if (self.mj_y == 0) return; 160 | 161 | if (_scrollView.mj_insetT + _scrollView.mj_contentSizeH > _scrollView.mj_h) { // 内容超过一个屏幕 162 | // 这里的_scrollView.mj_contentSizeH替换掉self.mj_y更为合理 163 | if (_scrollView.mj_offsetY > _scrollView.mj_contentSizeH - _scrollView.mj_h + self.mj_h * self.appearencePercentTriggerAutoRefresh + _scrollView.mj_insetB - self.mj_h) { 164 | // 当底部刷新控件完全出现时,才刷新 165 | [self beginRefreshing]; 166 | } 167 | } 168 | } 169 | 170 | - (void)adjustFrameWithContentSize 171 | { 172 | // 设置位置 173 | self.mj_y = _scrollView.mj_contentSizeH; 174 | } 175 | 176 | - (void)buttonClick 177 | { 178 | [self beginRefreshing]; 179 | } 180 | 181 | #pragma mark - 公共方法 182 | - (void)setHidden:(BOOL)hidden 183 | { 184 | __weak __typeof(self) weakSelf = self; 185 | BOOL lastHidden = weakSelf.isHidden; 186 | CGFloat h = weakSelf.mj_h; 187 | [weakSelf.willExecuteBlocks addObject:^{ 188 | if (!lastHidden && hidden) { 189 | weakSelf.state = MJRefreshFooterStateIdle; 190 | _scrollView.mj_insetB -= h; 191 | } else if (lastHidden && !hidden) { 192 | _scrollView.mj_insetB += h; 193 | 194 | [weakSelf adjustFrameWithContentSize]; 195 | } 196 | }]; 197 | [weakSelf setNeedsDisplay]; // 放到drawRect是为了延迟执行,防止因为修改了inset,导致循环调用数据源方法 198 | 199 | [super setHidden:hidden]; 200 | } 201 | 202 | - (void)drawRect:(CGRect)rect 203 | { 204 | [super drawRect:rect]; 205 | 206 | for (void (^block)() in self.willExecuteBlocks) { 207 | block(); 208 | } 209 | [self.willExecuteBlocks removeAllObjects]; 210 | } 211 | 212 | - (void)beginRefreshing 213 | { 214 | self.state = MJRefreshFooterStateRefreshing; 215 | } 216 | 217 | - (void)endRefreshing 218 | { 219 | self.state = MJRefreshFooterStateIdle; 220 | } 221 | 222 | - (BOOL)isRefreshing 223 | { 224 | return self.state == MJRefreshFooterStateRefreshing; 225 | } 226 | 227 | - (void)noticeNoMoreData 228 | { 229 | self.state = MJRefreshFooterStateNoMoreData; 230 | } 231 | 232 | - (void)resetNoMoreData 233 | { 234 | self.state = MJRefreshFooterStateIdle; 235 | } 236 | 237 | - (void)setTitle:(NSString *)title forState:(MJRefreshFooterState)state 238 | { 239 | if (title == nil) return; 240 | 241 | // 刷新当前状态的文字 242 | switch (state) { 243 | case MJRefreshFooterStateIdle: 244 | [self.loadMoreButton setTitle:title forState:UIControlStateNormal]; 245 | break; 246 | 247 | case MJRefreshFooterStateRefreshing: 248 | self.stateLabel.text = title; 249 | break; 250 | 251 | case MJRefreshFooterStateNoMoreData: 252 | self.noMoreLabel.text = title; 253 | break; 254 | 255 | default: 256 | break; 257 | } 258 | } 259 | 260 | - (void)setState:(MJRefreshFooterState)state 261 | { 262 | if (_state == state) return; 263 | 264 | _state = state; 265 | 266 | switch (state) { 267 | case MJRefreshFooterStateIdle:{ 268 | self.noMoreLabel.hidden = YES; 269 | self.stateLabel.hidden = YES; 270 | self.loadMoreButton.hidden = YES; 271 | 272 | //修复传统上拉加载更多在 UITableView 使用 '- (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation;'方法加载更多数据时露出按钮的的问题 273 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 274 | self.loadMoreButton.hidden = self.state != MJRefreshFooterStateIdle; 275 | }); 276 | } 277 | break; 278 | 279 | case MJRefreshFooterStateRefreshing: 280 | { 281 | self.loadMoreButton.hidden = YES; 282 | self.noMoreLabel.hidden = YES; 283 | if (!self.stateHidden) self.stateLabel.hidden = NO; 284 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 285 | if (self.refreshingBlock) { 286 | self.refreshingBlock(); 287 | } 288 | if ([self.refreshingTarget respondsToSelector:self.refreshingAction]) { 289 | msgSend(msgTarget(self.refreshingTarget), self.refreshingAction, self); 290 | } 291 | }); 292 | } 293 | break; 294 | 295 | case MJRefreshFooterStateNoMoreData: 296 | self.loadMoreButton.hidden = YES; 297 | self.noMoreLabel.hidden = NO; 298 | self.stateLabel.hidden = YES; 299 | break; 300 | 301 | default: 302 | break; 303 | } 304 | } 305 | 306 | - (void)setTextColor:(UIColor *)textColor 307 | { 308 | [super setTextColor:textColor]; 309 | 310 | self.stateLabel.textColor = textColor; 311 | [self.loadMoreButton setTitleColor:textColor forState:UIControlStateNormal]; 312 | self.noMoreLabel.textColor = textColor; 313 | } 314 | 315 | - (void)setFont:(UIFont *)font 316 | { 317 | [super setFont:font]; 318 | 319 | self.loadMoreButton.titleLabel.font = font; 320 | self.noMoreLabel.font = font; 321 | self.stateLabel.font = font; 322 | } 323 | 324 | - (void)setStateHidden:(BOOL)stateHidden 325 | { 326 | _stateHidden = stateHidden; 327 | 328 | self.stateLabel.hidden = stateHidden; 329 | [self setNeedsLayout]; 330 | } 331 | @end 332 | --------------------------------------------------------------------------------