Commit a0c1ef468ed3f27ed7cb3b33a0b86802650ce821
1 parent
e5408852
0.1.3 YBImageBrowser 通过pod 形式集成
Showing
69 changed files
with
6 additions
and
6323 deletions
CNLiveOrganizationValidationModule.podspec
| ... | ... | @@ -8,7 +8,7 @@ |
| 8 | 8 | |
| 9 | 9 | Pod::Spec.new do |s| |
| 10 | 10 | s.name = 'CNLiveOrganizationValidationModule' |
| 11 | - s.version = '0.1.2' | |
| 11 | + s.version = '0.1.3' | |
| 12 | 12 | s.summary = '机构认证模块' |
| 13 | 13 | |
| 14 | 14 | # This description is used to generate tags and improve search results. |
| ... | ... | @@ -78,7 +78,7 @@ Pod::Spec.new do |s| |
| 78 | 78 | ######################################## |
| 79 | 79 | s.dependency 'CNLiveNewTripartiteManagement/RSKImageCropper' |
| 80 | 80 | # #相册展示 |
| 81 | -# s.dependency 'YBImageBrowser' | |
| 81 | + s.dependency 'YBImageBrowser' | |
| 82 | 82 | |
| 83 | 83 | |
| 84 | 84 | ... | ... |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/Controller/CNLiveBOraganizationDetailController.m
| ... | ... | @@ -20,8 +20,8 @@ |
| 20 | 20 | #import <QMUIKit/QMUIKit.h> |
| 21 | 21 | //#import <YYKit/YYKit.h> |
| 22 | 22 | #import <objc/runtime.h> |
| 23 | -#import "YBImageBrowser.h" | |
| 24 | -#import "YBIBImageData.h" | |
| 23 | +#import <YBImageBrowser/YBImageBrowser.h> | |
| 24 | +//#import "YBIBImageData.h" | |
| 25 | 25 | #import "UIImage+OrganizationValidation.h" |
| 26 | 26 | |
| 27 | 27 | ... | ... |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/AuxiliaryView/YBIBAuxiliaryViewHandler.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBAuxiliaryViewHandler.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/27. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@protocol YBIBAuxiliaryViewHandler <NSObject> | |
| 14 | - | |
| 15 | -@required | |
| 16 | - | |
| 17 | -/// 展示正确情况的提示 | |
| 18 | -- (void)yb_showCorrectToastWithContainer:(UIView *)container text:(NSString *)text; | |
| 19 | -/// 展示错误情况的提示 | |
| 20 | -- (void)yb_showIncorrectToastWithContainer:(UIView *)container text:(NSString *)text; | |
| 21 | -/// 隐藏所有提示 | |
| 22 | -- (void)yb_hideToastWithContainer:(UIView *)container; | |
| 23 | - | |
| 24 | -/// 展示加载视图 | |
| 25 | -- (void)yb_showLoadingWithContainer:(UIView *)container; | |
| 26 | -/// 展示带进度的加载视图 | |
| 27 | -- (void)yb_showLoadingWithContainer:(UIView *)container progress:(CGFloat)progress; | |
| 28 | -/// 展示带文字的视图 | |
| 29 | -- (void)yb_showLoadingWithContainer:(UIView *)container text:(NSString *)text; | |
| 30 | -/// 隐藏所有视图 | |
| 31 | -- (void)yb_hideLoadingWithContainer:(UIView *)container; | |
| 32 | - | |
| 33 | -@end | |
| 34 | - | |
| 35 | -@interface YBIBAuxiliaryViewHandler : NSObject <YBIBAuxiliaryViewHandler> | |
| 36 | - | |
| 37 | -@end | |
| 38 | - | |
| 39 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/AuxiliaryView/YBIBAuxiliaryViewHandler.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBAuxiliaryViewHandler.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/27. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBAuxiliaryViewHandler.h" | |
| 10 | -#import "YBIBToastView.h" | |
| 11 | -#import "YBIBLoadingView.h" | |
| 12 | - | |
| 13 | -@implementation YBIBAuxiliaryViewHandler | |
| 14 | - | |
| 15 | -#pragma mark - <YBIBAuxiliaryViewHandler> | |
| 16 | - | |
| 17 | -- (void)yb_showCorrectToastWithContainer:(UIView *)container text:(NSString *)text { | |
| 18 | - [container ybib_showHookToast:text]; | |
| 19 | -} | |
| 20 | - | |
| 21 | -- (void)yb_showIncorrectToastWithContainer:(UIView *)container text:(NSString *)text { | |
| 22 | - [container ybib_showForkToast:text]; | |
| 23 | -} | |
| 24 | - | |
| 25 | -- (void)yb_hideToastWithContainer:(UIView *)container { | |
| 26 | - [container ybib_hideToast]; | |
| 27 | -} | |
| 28 | - | |
| 29 | -- (void)yb_showLoadingWithContainer:(UIView *)container { | |
| 30 | - [container ybib_showLoading]; | |
| 31 | -} | |
| 32 | - | |
| 33 | -- (void)yb_showLoadingWithContainer:(UIView *)container progress:(CGFloat)progress { | |
| 34 | - [container ybib_showLoadingWithProgress:progress]; | |
| 35 | -} | |
| 36 | - | |
| 37 | -- (void)yb_showLoadingWithContainer:(UIView *)container text:(NSString *)text { | |
| 38 | - [container ybib_showLoadingWithText:text click:nil]; | |
| 39 | -} | |
| 40 | - | |
| 41 | -- (void)yb_hideLoadingWithContainer:(UIView *)container { | |
| 42 | - [container ybib_hideLoading]; | |
| 43 | -} | |
| 44 | - | |
| 45 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/AuxiliaryView/YBIBLoadingView.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBLoadingView.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/9/1. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface UIView (YBIBLoading) | |
| 14 | - | |
| 15 | -- (void)ybib_showLoading; | |
| 16 | - | |
| 17 | -- (void)ybib_showLoadingWithProgress:(CGFloat)progress; | |
| 18 | - | |
| 19 | -- (void)ybib_showLoadingWithText:(NSString *)text click:(nullable void(^)(void))click; | |
| 20 | - | |
| 21 | -- (void)ybib_hideLoading; | |
| 22 | - | |
| 23 | -@end | |
| 24 | - | |
| 25 | - | |
| 26 | -@interface YBIBLoadingView : UIView | |
| 27 | - | |
| 28 | -- (void)show; | |
| 29 | - | |
| 30 | -- (void)showProgress:(CGFloat)progress; | |
| 31 | - | |
| 32 | -- (void)showText:(NSString *)text click:(void(^)(void))click; | |
| 33 | - | |
| 34 | -@end | |
| 35 | - | |
| 36 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/AuxiliaryView/YBIBLoadingView.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBLoadingView.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/9/1. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBLoadingView.h" | |
| 10 | -#import "YBIBIconManager.h" | |
| 11 | -#import <objc/runtime.h> | |
| 12 | - | |
| 13 | -@interface UIView () | |
| 14 | -@property (nonatomic, strong, readonly) YBIBLoadingView *ybib_loading; | |
| 15 | -@end | |
| 16 | - | |
| 17 | -@implementation UIView (YBIBLoading) | |
| 18 | - | |
| 19 | -- (void)ybib_showLoadingWithProgress:(CGFloat)progress { | |
| 20 | - [self ybib_addLoadingView]; | |
| 21 | - [self.ybib_loading showProgress:progress]; | |
| 22 | -} | |
| 23 | - | |
| 24 | -- (void)ybib_showLoading { | |
| 25 | - [self ybib_addLoadingView]; | |
| 26 | - [self.ybib_loading show]; | |
| 27 | -} | |
| 28 | - | |
| 29 | -- (void)ybib_showLoadingWithText:(NSString *)text click:(void (^)(void))click { | |
| 30 | - [self ybib_addLoadingView]; | |
| 31 | - [self.ybib_loading showText:text click:click]; | |
| 32 | -} | |
| 33 | - | |
| 34 | -- (void)ybib_addLoadingView { | |
| 35 | - YBIBLoadingView *loading = self.ybib_loading; | |
| 36 | - if (!loading.superview) { | |
| 37 | - [self addSubview:loading]; | |
| 38 | - loading.translatesAutoresizingMaskIntoConstraints = NO; | |
| 39 | - NSLayoutConstraint *layA = [NSLayoutConstraint constraintWithItem:loading attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:0]; | |
| 40 | - NSLayoutConstraint *layB = [NSLayoutConstraint constraintWithItem:loading attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:0]; | |
| 41 | - NSLayoutConstraint *layC = [NSLayoutConstraint constraintWithItem:loading attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:0]; | |
| 42 | - NSLayoutConstraint *layD = [NSLayoutConstraint constraintWithItem:loading attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1 constant:0]; | |
| 43 | - [self addConstraints:@[layA, layB, layC, layD]]; | |
| 44 | - } | |
| 45 | -} | |
| 46 | - | |
| 47 | -- (void)ybib_hideLoading { | |
| 48 | - YBIBLoadingView *loading = self.ybib_loading; | |
| 49 | - if (loading && loading.superview) { | |
| 50 | - [loading removeFromSuperview]; | |
| 51 | - } | |
| 52 | -} | |
| 53 | - | |
| 54 | -static void *YBIBLoadingKey = &YBIBLoadingKey; | |
| 55 | -- (void)setYbib_loading:(YBIBLoadingView *)ybib_loading { | |
| 56 | - objc_setAssociatedObject(self, YBIBLoadingKey, ybib_loading, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
| 57 | -} | |
| 58 | -- (YBIBLoadingView *)ybib_loading { | |
| 59 | - YBIBLoadingView *loading = objc_getAssociatedObject(self, YBIBLoadingKey); | |
| 60 | - if (!loading) { | |
| 61 | - loading = [YBIBLoadingView new]; | |
| 62 | - self.ybib_loading = loading; | |
| 63 | - } | |
| 64 | - return loading; | |
| 65 | -} | |
| 66 | - | |
| 67 | -@end | |
| 68 | - | |
| 69 | - | |
| 70 | -@interface YBIBProgressDrawView : UIView | |
| 71 | -@property (nonatomic, assign) CGFloat progress; | |
| 72 | -@end | |
| 73 | -@implementation YBIBProgressDrawView | |
| 74 | -- (void)drawRect:(CGRect)rect { | |
| 75 | - if (self.isHidden) return; | |
| 76 | - | |
| 77 | - CGFloat progress = (isnan(_progress) || isinf(_progress) || _progress < 0) ? 0 : _progress; | |
| 78 | - | |
| 79 | - CGFloat radius = 17; | |
| 80 | - CGFloat strokeWidth = 3; | |
| 81 | - CGPoint center = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); | |
| 82 | - | |
| 83 | - [[UIColor lightGrayColor] setStroke]; | |
| 84 | - UIBezierPath *bottomPath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:M_PI * 2 clockwise:YES]; | |
| 85 | - bottomPath.lineWidth = 4.0; | |
| 86 | - bottomPath.lineCapStyle = kCGLineCapRound; | |
| 87 | - bottomPath.lineJoinStyle = kCGLineCapRound; | |
| 88 | - [bottomPath stroke]; | |
| 89 | - | |
| 90 | - [[UIColor whiteColor] setStroke]; | |
| 91 | - UIBezierPath *activePath = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:-M_PI / 2.0 endAngle:M_PI * 2 * progress - M_PI / 2.0 clockwise:true]; | |
| 92 | - activePath.lineWidth = strokeWidth; | |
| 93 | - activePath.lineCapStyle = kCGLineCapRound; | |
| 94 | - activePath.lineJoinStyle = kCGLineCapRound; | |
| 95 | - [activePath stroke]; | |
| 96 | - | |
| 97 | - NSShadow *shadow = [NSShadow new]; | |
| 98 | - shadow.shadowBlurRadius = 4; | |
| 99 | - shadow.shadowOffset = CGSizeMake(0, 1); | |
| 100 | - shadow.shadowColor = UIColor.darkGrayColor; | |
| 101 | - NSString *string = [NSString stringWithFormat:@"%.0lf%@", progress * 100, @"%"]; | |
| 102 | - NSMutableAttributedString *atts = [[NSMutableAttributedString alloc] initWithString:string attributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:10], NSForegroundColorAttributeName:[UIColor whiteColor], NSShadowAttributeName:shadow}]; | |
| 103 | - CGSize size = atts.size; | |
| 104 | - [atts drawAtPoint:CGPointMake(center.x - size.width / 2.0, center.y - size.height / 2.0)]; | |
| 105 | -} | |
| 106 | -@end | |
| 107 | - | |
| 108 | - | |
| 109 | -typedef NS_ENUM(NSUInteger, YBImageBrowserProgressType) { | |
| 110 | - YBImageBrowserProgressTypeProgress, | |
| 111 | - YBImageBrowserProgressTypeLoad, | |
| 112 | - YBImageBrowserProgressTypeText | |
| 113 | -}; | |
| 114 | - | |
| 115 | -@interface YBIBLoadingView () { | |
| 116 | - YBImageBrowserProgressType _type; | |
| 117 | -} | |
| 118 | -@property (nonatomic, strong) UILabel *textLabel; | |
| 119 | -@property (nonatomic, strong) UIImageView *imageView; | |
| 120 | -@property (nonatomic, strong) YBIBProgressDrawView *drawView; | |
| 121 | -@property (nonatomic, copy) void(^clickTextLabelBlock)(void); | |
| 122 | -@end | |
| 123 | - | |
| 124 | -@implementation YBIBLoadingView | |
| 125 | - | |
| 126 | -#pragma mark life cycle | |
| 127 | - | |
| 128 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 129 | - self = [super initWithFrame:frame]; | |
| 130 | - if (self) { | |
| 131 | - self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0]; | |
| 132 | - self.userInteractionEnabled = NO; | |
| 133 | - | |
| 134 | - [self addSubview:self.drawView]; | |
| 135 | - [self addSubview:self.textLabel]; | |
| 136 | - [self addSubview:self.imageView]; | |
| 137 | - } | |
| 138 | - return self; | |
| 139 | -} | |
| 140 | - | |
| 141 | -- (void)updateConstraints { | |
| 142 | - self.textLabel.translatesAutoresizingMaskIntoConstraints = NO; | |
| 143 | - NSLayoutConstraint *layA = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:20]; | |
| 144 | - NSLayoutConstraint *layB = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:-20]; | |
| 145 | - NSLayoutConstraint *layC = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; | |
| 146 | - | |
| 147 | - self.imageView.translatesAutoresizingMaskIntoConstraints = NO; | |
| 148 | - NSLayoutConstraint *layE = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]; | |
| 149 | - NSLayoutConstraint *layF = [NSLayoutConstraint constraintWithItem:self.imageView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; | |
| 150 | - | |
| 151 | - self.drawView.translatesAutoresizingMaskIntoConstraints = NO; | |
| 152 | - NSLayoutConstraint *layG = [NSLayoutConstraint constraintWithItem:self.drawView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]; | |
| 153 | - NSLayoutConstraint *layH = [NSLayoutConstraint constraintWithItem:self.drawView attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; | |
| 154 | - NSLayoutConstraint *layI = [NSLayoutConstraint constraintWithItem:self.drawView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50]; | |
| 155 | - NSLayoutConstraint *layJ = [NSLayoutConstraint constraintWithItem:self.drawView attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:50]; | |
| 156 | - | |
| 157 | - [self addConstraints:@[layA, layB, layC, layE, layF, layG, layH, layI, layJ]]; | |
| 158 | - [super updateConstraints]; | |
| 159 | -} | |
| 160 | - | |
| 161 | -#pragma mark public | |
| 162 | - | |
| 163 | -- (void)showProgress:(CGFloat)progress { | |
| 164 | - self.userInteractionEnabled = NO; | |
| 165 | - _type = YBImageBrowserProgressTypeProgress; | |
| 166 | - self.drawView.hidden = NO; | |
| 167 | - self.textLabel.hidden = YES; | |
| 168 | - self.imageView.hidden = YES; | |
| 169 | - [self stopImageViewAnimation]; | |
| 170 | - | |
| 171 | - self.drawView.progress = progress; | |
| 172 | - [self.drawView setNeedsDisplay]; | |
| 173 | -} | |
| 174 | - | |
| 175 | -- (void)show { | |
| 176 | - self.userInteractionEnabled = NO; | |
| 177 | - _type = YBImageBrowserProgressTypeLoad; | |
| 178 | - self.drawView.hidden = YES; | |
| 179 | - self.textLabel.hidden = YES; | |
| 180 | - self.imageView.hidden = NO; | |
| 181 | - | |
| 182 | - [self startImageViewAnimation]; | |
| 183 | - [self.drawView setNeedsDisplay]; | |
| 184 | -} | |
| 185 | - | |
| 186 | -- (void)startImageViewAnimation { | |
| 187 | - CABasicAnimation *ra = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"]; | |
| 188 | - ra.toValue = [NSNumber numberWithFloat:M_PI * 2]; | |
| 189 | - ra.duration = 1; | |
| 190 | - ra.cumulative = YES; | |
| 191 | - ra.repeatCount = HUGE_VALF; | |
| 192 | - ra.removedOnCompletion = NO; | |
| 193 | - ra.fillMode = kCAFillModeForwards; | |
| 194 | - [self.imageView.layer addAnimation:ra forKey:@"ra"]; | |
| 195 | -} | |
| 196 | - | |
| 197 | -- (void)stopImageViewAnimation { | |
| 198 | - [self.imageView.layer removeAllAnimations]; | |
| 199 | -} | |
| 200 | - | |
| 201 | -- (void)showText:(NSString *)text click:(void (^)(void))click { | |
| 202 | - self.userInteractionEnabled = click ? YES : NO; | |
| 203 | - _type = YBImageBrowserProgressTypeText; | |
| 204 | - self.drawView.hidden = YES; | |
| 205 | - self.textLabel.hidden = NO; | |
| 206 | - self.imageView.hidden = YES; | |
| 207 | - [self stopImageViewAnimation]; | |
| 208 | - | |
| 209 | - self.textLabel.text = text; | |
| 210 | - self.clickTextLabelBlock = click; | |
| 211 | - [self.drawView setNeedsDisplay]; | |
| 212 | -} | |
| 213 | - | |
| 214 | -#pragma mark - touch event | |
| 215 | - | |
| 216 | -- (void)respondsToTapTextlabel { | |
| 217 | - if (self.clickTextLabelBlock) { | |
| 218 | - self.clickTextLabelBlock(); | |
| 219 | - } | |
| 220 | -} | |
| 221 | - | |
| 222 | -#pragma mark - getter | |
| 223 | - | |
| 224 | -- (YBIBProgressDrawView *)drawView { | |
| 225 | - if (!_drawView) { | |
| 226 | - _drawView = [YBIBProgressDrawView new]; | |
| 227 | - _drawView.backgroundColor = [UIColor clearColor]; | |
| 228 | - } | |
| 229 | - return _drawView; | |
| 230 | -} | |
| 231 | - | |
| 232 | -- (UILabel *)textLabel { | |
| 233 | - if (!_textLabel) { | |
| 234 | - _textLabel = [UILabel new]; | |
| 235 | - _textLabel.textColor = [UIColor whiteColor]; | |
| 236 | - _textLabel.numberOfLines = 0; | |
| 237 | - _textLabel.font = [UIFont systemFontOfSize:14]; | |
| 238 | - _textLabel.textAlignment = NSTextAlignmentCenter; | |
| 239 | - UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToTapTextlabel)]; | |
| 240 | - [_textLabel addGestureRecognizer:tapGesture]; | |
| 241 | - _textLabel.userInteractionEnabled = YES; | |
| 242 | - } | |
| 243 | - return _textLabel; | |
| 244 | -} | |
| 245 | - | |
| 246 | -- (UIImageView *)imageView { | |
| 247 | - if (!_imageView) { | |
| 248 | - _imageView = [UIImageView new]; | |
| 249 | - _imageView.image = [YBIBIconManager sharedManager].loadingImage(); | |
| 250 | - _imageView.layer.shadowColor = UIColor.darkGrayColor.CGColor; | |
| 251 | - _imageView.layer.shadowOffset = CGSizeMake(0, 1); | |
| 252 | - _imageView.layer.shadowOpacity = 1; | |
| 253 | - _imageView.layer.shadowRadius = 4; | |
| 254 | - } | |
| 255 | - return _imageView; | |
| 256 | -} | |
| 257 | - | |
| 258 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/AuxiliaryView/YBIBToastView.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBToastView.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/20. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface UIView (YBIBToast) | |
| 14 | - | |
| 15 | -- (void)ybib_showHookToast:(NSString *)text; | |
| 16 | - | |
| 17 | -- (void)ybib_showForkToast:(NSString *)text; | |
| 18 | - | |
| 19 | -- (void)ybib_hideToast; | |
| 20 | - | |
| 21 | -@end | |
| 22 | - | |
| 23 | - | |
| 24 | -typedef NS_ENUM(NSInteger, YBIBToastType) { | |
| 25 | - YBIBToastTypeNone, | |
| 26 | - YBIBToastTypeHook, | |
| 27 | - YBIBToastTypeFork | |
| 28 | -}; | |
| 29 | - | |
| 30 | -@interface YBIBToastView : UIView | |
| 31 | - | |
| 32 | -- (void)showWithText:(NSString *)text type:(YBIBToastType)type; | |
| 33 | - | |
| 34 | -@end | |
| 35 | - | |
| 36 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/AuxiliaryView/YBIBToastView.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBToastView.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/20. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBToastView.h" | |
| 10 | -#import <objc/runtime.h> | |
| 11 | - | |
| 12 | -@interface UIView () | |
| 13 | -@property (nonatomic, strong, readonly) YBIBToastView *ybib_toast; | |
| 14 | -@end | |
| 15 | - | |
| 16 | -@implementation UIView (YBIBToast) | |
| 17 | - | |
| 18 | -- (void)ybib_showHookToast:(NSString *)text { | |
| 19 | - [self ybib_showToastWithText:text type:YBIBToastTypeHook hideAfterDelay:1.7]; | |
| 20 | -} | |
| 21 | - | |
| 22 | -- (void)ybib_showForkToast:(NSString *)text { | |
| 23 | - [self ybib_showToastWithText:text type:YBIBToastTypeFork hideAfterDelay:1.7]; | |
| 24 | -} | |
| 25 | - | |
| 26 | -- (void)ybib_showToastWithText:(NSString *)text type:(YBIBToastType)type hideAfterDelay:(NSTimeInterval)delay { | |
| 27 | - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(ybib_hideToast) object:nil]; | |
| 28 | - | |
| 29 | - YBIBToastView *toast = self.ybib_toast; | |
| 30 | - if (!toast.superview) { | |
| 31 | - [self addSubview:toast]; | |
| 32 | - toast.translatesAutoresizingMaskIntoConstraints = NO; | |
| 33 | - NSLayoutConstraint *layA = [NSLayoutConstraint constraintWithItem:toast attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]; | |
| 34 | - NSLayoutConstraint *layB = [NSLayoutConstraint constraintWithItem:toast attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]; | |
| 35 | - NSLayoutConstraint *layC = [NSLayoutConstraint constraintWithItem:toast attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:40]; | |
| 36 | - NSLayoutConstraint *layD = [NSLayoutConstraint constraintWithItem:toast attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationLessThanOrEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:-40]; | |
| 37 | - [self addConstraints:@[layA, layB, layC, layD]]; | |
| 38 | - } | |
| 39 | - | |
| 40 | - [toast showWithText:text type:type]; | |
| 41 | - [self performSelector:@selector(ybib_hideToast) withObject:nil afterDelay:delay]; | |
| 42 | -} | |
| 43 | - | |
| 44 | -- (void)ybib_hideToast { | |
| 45 | - YBIBToastView *toast = self.ybib_toast; | |
| 46 | - if (toast && toast.superview) { | |
| 47 | - [UIView animateWithDuration:0.25 animations:^{ | |
| 48 | - toast.alpha = 0; | |
| 49 | - } completion:^(BOOL finished) { | |
| 50 | - [toast removeFromSuperview]; | |
| 51 | - toast.alpha = 1; | |
| 52 | - }]; | |
| 53 | - } | |
| 54 | -} | |
| 55 | - | |
| 56 | -static void *YBIBToastKey = &YBIBToastKey; | |
| 57 | -- (void)setYbib_toast:(YBIBToastView *)ybib_toast { | |
| 58 | - objc_setAssociatedObject(self, YBIBToastKey, ybib_toast, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
| 59 | -} | |
| 60 | -- (YBIBToastView *)ybib_toast { | |
| 61 | - YBIBToastView *toast = objc_getAssociatedObject(self, YBIBToastKey); | |
| 62 | - if (!toast) { | |
| 63 | - toast = [YBIBToastView new]; | |
| 64 | - self.ybib_toast = toast; | |
| 65 | - } | |
| 66 | - return toast; | |
| 67 | -} | |
| 68 | - | |
| 69 | -@end | |
| 70 | - | |
| 71 | - | |
| 72 | -@interface YBIBToastView () { | |
| 73 | - YBIBToastType _type; | |
| 74 | - CAShapeLayer *_shapeLayer; | |
| 75 | -} | |
| 76 | -@property (nonatomic, strong) UILabel *textLabel; | |
| 77 | -@end | |
| 78 | - | |
| 79 | -@implementation YBIBToastView | |
| 80 | - | |
| 81 | -#pragma mark - life cycle | |
| 82 | - | |
| 83 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 84 | - self = [super initWithFrame:frame]; | |
| 85 | - if (self) { | |
| 86 | - self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.8]; | |
| 87 | - self.userInteractionEnabled = NO; | |
| 88 | - self.layer.cornerRadius = 7; | |
| 89 | - | |
| 90 | - [self addSubview:self.textLabel]; | |
| 91 | - } | |
| 92 | - return self; | |
| 93 | -} | |
| 94 | - | |
| 95 | -- (void)updateConstraints { | |
| 96 | - self.textLabel.translatesAutoresizingMaskIntoConstraints = NO; | |
| 97 | - NSLayoutConstraint *layA = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeLeft multiplier:1 constant:20]; | |
| 98 | - NSLayoutConstraint *layB = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeRight multiplier:1 constant:-20]; | |
| 99 | - NSLayoutConstraint *layC = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeBottom multiplier:1 constant:-15]; | |
| 100 | - NSLayoutConstraint *layD = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:self attribute:NSLayoutAttributeTop multiplier:1 constant:70]; | |
| 101 | - NSLayoutConstraint *layE = [NSLayoutConstraint constraintWithItem:self.textLabel attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationGreaterThanOrEqual toItem:nil attribute:NSLayoutAttributeNotAnAttribute multiplier:1 constant:60]; | |
| 102 | - [self addConstraints:@[layA, layB, layC, layD, layE]]; | |
| 103 | - [super updateConstraints]; | |
| 104 | -} | |
| 105 | - | |
| 106 | -- (void)layoutSubviews { | |
| 107 | - [super layoutSubviews]; | |
| 108 | - [self startAnimation]; | |
| 109 | -} | |
| 110 | - | |
| 111 | -#pragma mark - animation | |
| 112 | - | |
| 113 | -- (void)showWithText:(NSString *)text type:(YBIBToastType)type { | |
| 114 | - self.textLabel.text = text; | |
| 115 | - _type = type; | |
| 116 | - [self setNeedsLayout]; | |
| 117 | -} | |
| 118 | - | |
| 119 | -- (void)startAnimation { | |
| 120 | - if (_shapeLayer && _shapeLayer.superlayer) { | |
| 121 | - [_shapeLayer removeFromSuperlayer]; | |
| 122 | - } | |
| 123 | - _shapeLayer = [CAShapeLayer layer]; | |
| 124 | - _shapeLayer.strokeColor = [UIColor whiteColor].CGColor; | |
| 125 | - _shapeLayer.fillColor = [UIColor clearColor].CGColor; | |
| 126 | - _shapeLayer.lineWidth = 5.0; | |
| 127 | - _shapeLayer.lineCap = @"round"; | |
| 128 | - _shapeLayer.lineJoin = @"round"; | |
| 129 | - _shapeLayer.strokeStart = 0.0; | |
| 130 | - _shapeLayer.strokeEnd = 0.0; | |
| 131 | - | |
| 132 | - UIBezierPath *bezierPath = [UIBezierPath bezierPath]; | |
| 133 | - CGFloat r = 13.0; | |
| 134 | - CGFloat x = self.bounds.size.width / 2.0; | |
| 135 | - CGFloat y = 38.0; | |
| 136 | - switch (_type) { | |
| 137 | - case YBIBToastTypeHook: { | |
| 138 | - [bezierPath moveToPoint:CGPointMake(x - r - r / 2, y)]; | |
| 139 | - [bezierPath addLineToPoint:CGPointMake(x - r / 2, y + r)]; | |
| 140 | - [bezierPath addLineToPoint:CGPointMake(x + r * 2 - r / 2, y - r)]; | |
| 141 | - } | |
| 142 | - break; | |
| 143 | - case YBIBToastTypeFork: { | |
| 144 | - [bezierPath moveToPoint:CGPointMake(x - r, y - r)]; | |
| 145 | - [bezierPath addLineToPoint:CGPointMake(x + r, y + r)]; | |
| 146 | - [bezierPath moveToPoint:CGPointMake(x - r, y + r)]; | |
| 147 | - [bezierPath addLineToPoint:CGPointMake(x + r, y - r)]; | |
| 148 | - } | |
| 149 | - break; | |
| 150 | - default:break; | |
| 151 | - } | |
| 152 | - | |
| 153 | - CABasicAnimation *baseAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"]; | |
| 154 | - [baseAnimation setFromValue:@0.0]; | |
| 155 | - [baseAnimation setToValue:@1.0]; | |
| 156 | - [baseAnimation setDuration:0.3]; | |
| 157 | - baseAnimation.removedOnCompletion = NO; | |
| 158 | - baseAnimation.fillMode = kCAFillModeBoth; | |
| 159 | - | |
| 160 | - _shapeLayer.path = bezierPath.CGPath; | |
| 161 | - [self.layer addSublayer:_shapeLayer]; | |
| 162 | - [_shapeLayer addAnimation:baseAnimation forKey:@"strokeEnd"]; | |
| 163 | -} | |
| 164 | - | |
| 165 | -#pragma mark - getter | |
| 166 | - | |
| 167 | -- (UILabel *)textLabel { | |
| 168 | - if (!_textLabel) { | |
| 169 | - _textLabel = [UILabel new]; | |
| 170 | - _textLabel.textColor = [UIColor whiteColor]; | |
| 171 | - _textLabel.font = [UIFont systemFontOfSize:14]; | |
| 172 | - _textLabel.textAlignment = NSTextAlignmentCenter; | |
| 173 | - _textLabel.numberOfLines = 0; | |
| 174 | - } | |
| 175 | - return _textLabel; | |
| 176 | -} | |
| 177 | - | |
| 178 | -@end | |
| 179 | - |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/NSObject+YBImageBrowser.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// NSObject+YBImageBrowser.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/9/26. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface NSObject (YBImageBrowser) | |
| 14 | - | |
| 15 | -@property (nonatomic, assign) CGFloat ybib_originAlpha; | |
| 16 | - | |
| 17 | -@end | |
| 18 | - | |
| 19 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/NSObject+YBImageBrowser.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// NSObject+YBImageBrowser.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/9/26. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "NSObject+YBImageBrowser.h" | |
| 10 | -#import <objc/runtime.h> | |
| 11 | - | |
| 12 | -@implementation NSObject (YBImageBrowser) | |
| 13 | - | |
| 14 | -static void *YBIBOriginAlphaKey = &YBIBOriginAlphaKey; | |
| 15 | -- (void)setYbib_originAlpha:(CGFloat)ybib_originAlpha { | |
| 16 | - objc_setAssociatedObject(self, YBIBOriginAlphaKey, @(ybib_originAlpha), OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
| 17 | -} | |
| 18 | -- (CGFloat)ybib_originAlpha { | |
| 19 | - NSNumber *alpha = objc_getAssociatedObject(self, YBIBOriginAlphaKey); | |
| 20 | - return alpha ? alpha.floatValue : 1; | |
| 21 | -} | |
| 22 | - | |
| 23 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBAnimatedTransition.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBAnimatedTransition.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/6. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@protocol YBIBAnimatedTransition <NSObject> | |
| 14 | -@required | |
| 15 | - | |
| 16 | -- (void)yb_showTransitioningWithContainer:(UIView *)container startView:(nullable __kindof UIView *)startView startImage:(nullable UIImage *)startImage endFrame:(CGRect)endFrame orientation:(UIDeviceOrientation)orientation completion:(void(^)(void))completion; | |
| 17 | - | |
| 18 | -- (void)yb_hideTransitioningWithContainer:(UIView *)container startView:(nullable __kindof UIView *)startView endView:(UIView *)endView orientation:(UIDeviceOrientation)orientation completion:(void(^)(void))completion; | |
| 19 | - | |
| 20 | -@end | |
| 21 | - | |
| 22 | - | |
| 23 | -typedef NS_ENUM(NSInteger, YBIBTransitionType) { | |
| 24 | - /// 无动效 | |
| 25 | - YBIBTransitionTypeNone, | |
| 26 | - /// 渐隐 | |
| 27 | - YBIBTransitionTypeFade, | |
| 28 | - /// 连贯移动 | |
| 29 | - YBIBTransitionTypeCoherent | |
| 30 | -}; | |
| 31 | - | |
| 32 | -@interface YBIBAnimatedTransition : NSObject <YBIBAnimatedTransition> | |
| 33 | - | |
| 34 | -/// 入场动效类型 | |
| 35 | -@property (nonatomic, assign) YBIBTransitionType showType; | |
| 36 | -/// 出场动效类型 | |
| 37 | -@property (nonatomic, assign) YBIBTransitionType hideType; | |
| 38 | - | |
| 39 | -/// 入场动效持续时间 | |
| 40 | -@property (nonatomic, assign) NSTimeInterval showDuration; | |
| 41 | -/// 出场动效持续时间 | |
| 42 | -@property (nonatomic, assign) NSTimeInterval hideDuration; | |
| 43 | - | |
| 44 | -@end | |
| 45 | - | |
| 46 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBAnimatedTransition.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBAnimatedTransition.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/6. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBAnimatedTransition.h" | |
| 10 | - | |
| 11 | -extern CGFloat YBIBRotationAngle(UIDeviceOrientation startOrientation, UIDeviceOrientation endOrientation); | |
| 12 | - | |
| 13 | -@implementation YBIBAnimatedTransition | |
| 14 | - | |
| 15 | -#pragma mark - life cycle | |
| 16 | - | |
| 17 | -- (instancetype)init { | |
| 18 | - self = [super init]; | |
| 19 | - if (self) { | |
| 20 | - _showType = _hideType = YBIBTransitionTypeCoherent; | |
| 21 | - _showDuration = _hideDuration = 0.25; | |
| 22 | - } | |
| 23 | - return self; | |
| 24 | -} | |
| 25 | - | |
| 26 | -#pragma mark - <YBIBAnimationHandler> | |
| 27 | - | |
| 28 | -- (void)yb_showTransitioningWithContainer:(UIView *)container startView:(__kindof UIView *)startView startImage:(UIImage *)startImage endFrame:(CGRect)endFrame orientation:(UIDeviceOrientation)orientation completion:(void (^)(void))completion { | |
| 29 | - YBIBTransitionType type = self.showType; | |
| 30 | - if (type == YBIBTransitionTypeCoherent) { | |
| 31 | - if (CGRectIsEmpty(endFrame) || !startView || orientation != (UIDeviceOrientation)UIApplication.sharedApplication.statusBarOrientation) { | |
| 32 | - type = YBIBTransitionTypeFade; | |
| 33 | - } | |
| 34 | - } | |
| 35 | - | |
| 36 | - switch (type) { | |
| 37 | - case YBIBTransitionTypeNone: { | |
| 38 | - completion(); | |
| 39 | - } | |
| 40 | - break; | |
| 41 | - case YBIBTransitionTypeFade: { | |
| 42 | - | |
| 43 | - BOOL animateValid = !CGRectIsEmpty(endFrame) && startView; | |
| 44 | - | |
| 45 | - UIImageView *animateImageView; | |
| 46 | - if (animateValid) { | |
| 47 | - animateImageView = [self imageViewAssimilateToView:startView]; | |
| 48 | - animateImageView.frame = endFrame; | |
| 49 | - animateImageView.image = startImage; | |
| 50 | - [container addSubview:animateImageView]; | |
| 51 | - } | |
| 52 | - | |
| 53 | - CGFloat rawAlpha = container.alpha; | |
| 54 | - container.alpha = 0; | |
| 55 | - | |
| 56 | - if (!animateValid) completion(); | |
| 57 | - | |
| 58 | - [UIView animateWithDuration:self.showDuration animations:^{ | |
| 59 | - container.alpha = rawAlpha; | |
| 60 | - } completion:^(BOOL finished) { | |
| 61 | - if (animateValid) { | |
| 62 | - [animateImageView removeFromSuperview]; | |
| 63 | - completion(); | |
| 64 | - } | |
| 65 | - }]; | |
| 66 | - | |
| 67 | - } | |
| 68 | - break; | |
| 69 | - case YBIBTransitionTypeCoherent: { | |
| 70 | - | |
| 71 | - UIImageView *animateImageView = [self imageViewAssimilateToView:startView]; | |
| 72 | - animateImageView.frame = [startView convertRect:startView.bounds toView:container]; | |
| 73 | - animateImageView.image = startImage; | |
| 74 | - | |
| 75 | - [container addSubview:animateImageView]; | |
| 76 | - | |
| 77 | - UIColor *rawBackgroundColor = container.backgroundColor; | |
| 78 | - container.backgroundColor = [rawBackgroundColor colorWithAlphaComponent:0]; | |
| 79 | - | |
| 80 | - [UIView animateWithDuration:self.showDuration animations:^{ | |
| 81 | - animateImageView.frame = endFrame; | |
| 82 | - container.backgroundColor = rawBackgroundColor; | |
| 83 | - } completion:^(BOOL finished) { | |
| 84 | - completion(); | |
| 85 | - // Disappear smoothly. | |
| 86 | - [UIView animateWithDuration:0.2 animations:^{ | |
| 87 | - animateImageView.alpha = 0; | |
| 88 | - } completion:^(BOOL finished) { | |
| 89 | - [animateImageView removeFromSuperview]; | |
| 90 | - }]; | |
| 91 | - }]; | |
| 92 | - | |
| 93 | - } | |
| 94 | - break; | |
| 95 | - } | |
| 96 | -} | |
| 97 | - | |
| 98 | -- (void)yb_hideTransitioningWithContainer:(UIView *)container startView:(__kindof UIView *)startView endView:(UIView *)endView orientation:(UIDeviceOrientation)orientation completion:(void (^)(void))completion { | |
| 99 | - YBIBTransitionType type = self.hideType; | |
| 100 | - if (type == YBIBTransitionTypeCoherent && (!startView || !endView)) { | |
| 101 | - type = YBIBTransitionTypeFade; | |
| 102 | - } | |
| 103 | - | |
| 104 | - switch (type) { | |
| 105 | - case YBIBTransitionTypeNone: { | |
| 106 | - completion(); | |
| 107 | - } | |
| 108 | - break; | |
| 109 | - case YBIBTransitionTypeFade: { | |
| 110 | - | |
| 111 | - CGFloat rawAlpha = container.alpha; | |
| 112 | - | |
| 113 | - [UIView animateWithDuration:self.hideDuration animations:^{ | |
| 114 | - container.alpha = 0; | |
| 115 | - } completion:^(BOOL finished) { | |
| 116 | - completion(); | |
| 117 | - container.alpha = rawAlpha; | |
| 118 | - }]; | |
| 119 | - | |
| 120 | - } | |
| 121 | - break; | |
| 122 | - case YBIBTransitionTypeCoherent: { | |
| 123 | - | |
| 124 | - CGRect startFrame = startView.frame; | |
| 125 | - CGRect endFrame = [endView convertRect:endView.bounds toView:startView.superview]; | |
| 126 | - | |
| 127 | - UIColor *rawBackgroundColor = container.backgroundColor; | |
| 128 | - | |
| 129 | - [UIView animateWithDuration:self.hideDuration animations:^{ | |
| 130 | - | |
| 131 | - container.backgroundColor = [rawBackgroundColor colorWithAlphaComponent:0]; | |
| 132 | - | |
| 133 | - startView.contentMode = endView.contentMode; | |
| 134 | - | |
| 135 | - CGAffineTransform transform = startView.transform; | |
| 136 | - UIDeviceOrientation statusBarOrientation = (UIDeviceOrientation)UIApplication.sharedApplication.statusBarOrientation; | |
| 137 | - if (orientation != statusBarOrientation) { | |
| 138 | - transform = CGAffineTransformRotate(transform, YBIBRotationAngle(orientation, statusBarOrientation)); | |
| 139 | - } | |
| 140 | - | |
| 141 | - if ([startView isKindOfClass:UIImageView.self]) { | |
| 142 | - startView.frame = endFrame; | |
| 143 | - startView.transform = transform; | |
| 144 | - } else { | |
| 145 | - CGFloat scale = MAX(endFrame.size.width / startFrame.size.width, endFrame.size.height / startFrame.size.height); | |
| 146 | - startView.center = CGPointMake(endFrame.size.width * startView.layer.anchorPoint.x + endFrame.origin.x, endFrame.size.height * startView.layer.anchorPoint.y + endFrame.origin.y); | |
| 147 | - startView.transform = CGAffineTransformScale(transform, scale, scale); | |
| 148 | - } | |
| 149 | - | |
| 150 | - } completion:^(BOOL finished) { | |
| 151 | - completion(); | |
| 152 | - container.backgroundColor = rawBackgroundColor; | |
| 153 | - }]; | |
| 154 | - | |
| 155 | - } | |
| 156 | - break; | |
| 157 | - } | |
| 158 | -} | |
| 159 | - | |
| 160 | -#pragma mark - private | |
| 161 | - | |
| 162 | -- (UIImageView *)imageViewAssimilateToView:(nullable __kindof UIView *)view { | |
| 163 | - UIImageView *animateImageView = [UIImageView new]; | |
| 164 | - if ([view isKindOfClass:UIImageView.self]) { | |
| 165 | - animateImageView.contentMode = view.contentMode; | |
| 166 | - } else { | |
| 167 | - animateImageView.contentMode = UIViewContentModeScaleAspectFill; | |
| 168 | - } | |
| 169 | - animateImageView.layer.masksToBounds = view.layer.masksToBounds; | |
| 170 | - animateImageView.layer.cornerRadius = view.layer.cornerRadius; | |
| 171 | - animateImageView.layer.backgroundColor = view.layer.backgroundColor; | |
| 172 | - return animateImageView; | |
| 173 | -} | |
| 174 | - | |
| 175 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBCollectionView.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBCollectionView.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/6. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBCollectionViewLayout.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface YBIBCollectionView : UICollectionView | |
| 14 | - | |
| 15 | -@property (nonatomic, strong, readonly) YBIBCollectionViewLayout *layout; | |
| 16 | - | |
| 17 | -- (NSString *)reuseIdentifierForCellClass:(Class)cellClass; | |
| 18 | - | |
| 19 | -- (nullable UICollectionViewCell *)centerCell; | |
| 20 | - | |
| 21 | -- (void)scrollToPage:(NSInteger)page; | |
| 22 | - | |
| 23 | -@end | |
| 24 | - | |
| 25 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBCollectionView.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBCollectionView.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/6. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBCollectionView.h" | |
| 10 | - | |
| 11 | -@implementation YBIBCollectionView { | |
| 12 | - NSMutableSet *_reuseSet; | |
| 13 | -} | |
| 14 | - | |
| 15 | -#pragma mark - life cycle | |
| 16 | - | |
| 17 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 18 | - _layout = [YBIBCollectionViewLayout new]; | |
| 19 | - return [self initWithFrame:frame collectionViewLayout:_layout]; | |
| 20 | -} | |
| 21 | - | |
| 22 | -- (instancetype)initWithFrame:(CGRect)frame collectionViewLayout:(nonnull UICollectionViewLayout *)layout { | |
| 23 | - self = [super initWithFrame:frame collectionViewLayout:layout]; | |
| 24 | - if (self) { | |
| 25 | - self.backgroundColor = [UIColor clearColor]; | |
| 26 | - self.pagingEnabled = YES; | |
| 27 | - self.showsHorizontalScrollIndicator = NO; | |
| 28 | - self.showsVerticalScrollIndicator = NO; | |
| 29 | - self.alwaysBounceVertical = NO; | |
| 30 | - self.alwaysBounceHorizontal = NO; | |
| 31 | - self.decelerationRate = UIScrollViewDecelerationRateFast; | |
| 32 | - if (@available(iOS 11.0, *)) { | |
| 33 | - self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; | |
| 34 | - } | |
| 35 | - _reuseSet = [NSMutableSet set]; | |
| 36 | - } | |
| 37 | - return self; | |
| 38 | -} | |
| 39 | - | |
| 40 | -#pragma mark - public | |
| 41 | - | |
| 42 | -- (NSString *)reuseIdentifierForCellClass:(Class)cellClass { | |
| 43 | - NSString *identifier = NSStringFromClass(cellClass); | |
| 44 | - if (![_reuseSet containsObject:identifier]) { | |
| 45 | - NSString *path = [[NSBundle mainBundle] pathForResource:identifier ofType:@"nib"]; | |
| 46 | - if (path) { | |
| 47 | - [self registerNib:[UINib nibWithNibName:identifier bundle:nil] forCellWithReuseIdentifier:identifier]; | |
| 48 | - } else { | |
| 49 | - [self registerClass:cellClass forCellWithReuseIdentifier:identifier]; | |
| 50 | - } | |
| 51 | - [_reuseSet addObject:identifier]; | |
| 52 | - } | |
| 53 | - return identifier; | |
| 54 | -} | |
| 55 | - | |
| 56 | -- (UICollectionViewCell *)centerCell { | |
| 57 | - NSArray<UICollectionViewCell *> *cells = [self visibleCells]; | |
| 58 | - if (cells.count == 0) return nil; | |
| 59 | - | |
| 60 | - UICollectionViewCell *res = cells[0]; | |
| 61 | - CGFloat centerX = self.contentOffset.x + (self.bounds.size.width / 2.0); | |
| 62 | - for (int i = 1; i < cells.count; ++i) { | |
| 63 | - if (ABS(cells[i].center.x - centerX) < ABS(res.center.x - centerX)) { | |
| 64 | - res = cells[i]; | |
| 65 | - } | |
| 66 | - } | |
| 67 | - return res; | |
| 68 | -} | |
| 69 | - | |
| 70 | -- (void)scrollToPage:(NSInteger)page { | |
| 71 | - [self setContentOffset:CGPointMake(self.bounds.size.width * page, 0)]; | |
| 72 | -} | |
| 73 | - | |
| 74 | -#pragma mark - hit test | |
| 75 | - | |
| 76 | -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { | |
| 77 | - UIView *view = [super hitTest:point withEvent:event]; | |
| 78 | - // When the hit-test view is 'UISlider', set '_scrollEnabled' to 'NO', avoid gesture conflicts. | |
| 79 | - self.scrollEnabled = ![view isKindOfClass:UISlider.class]; | |
| 80 | - return view; | |
| 81 | -} | |
| 82 | - | |
| 83 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBCollectionViewLayout.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBCollectionViewLayout.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 杨少 on 2018/4/17. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -@interface YBIBCollectionViewLayout : UICollectionViewFlowLayout | |
| 12 | - | |
| 13 | -@property (nonatomic, assign) CGFloat distanceBetweenPages; | |
| 14 | - | |
| 15 | -@end | |
| 16 | - |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBCollectionViewLayout.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBCollectionViewLayout.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 杨少 on 2018/4/17. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBCollectionViewLayout.h" | |
| 10 | - | |
| 11 | -@implementation YBIBCollectionViewLayout | |
| 12 | - | |
| 13 | -- (instancetype)init { | |
| 14 | - self = [super init]; | |
| 15 | - if (self) { | |
| 16 | - self.minimumLineSpacing = 0; | |
| 17 | - self.minimumInteritemSpacing = 0; | |
| 18 | - self.sectionInset = UIEdgeInsetsZero; | |
| 19 | - self.scrollDirection = UICollectionViewScrollDirectionHorizontal; | |
| 20 | - _distanceBetweenPages = 20; | |
| 21 | - } | |
| 22 | - return self; | |
| 23 | -} | |
| 24 | - | |
| 25 | -- (void)prepareLayout { | |
| 26 | - [super prepareLayout]; | |
| 27 | - self.itemSize = self.collectionView.bounds.size; | |
| 28 | -} | |
| 29 | - | |
| 30 | -- (NSArray<UICollectionViewLayoutAttributes *> *)layoutAttributesForElementsInRect:(CGRect)rect { | |
| 31 | - NSArray<UICollectionViewLayoutAttributes *> *layoutAttsArray = [[NSArray alloc] initWithArray:[super layoutAttributesForElementsInRect:rect] copyItems:YES]; | |
| 32 | - CGFloat halfWidth = self.collectionView.bounds.size.width / 2.0; | |
| 33 | - CGFloat centerX = self.collectionView.contentOffset.x + halfWidth; | |
| 34 | - [layoutAttsArray enumerateObjectsUsingBlock:^(UICollectionViewLayoutAttributes * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { | |
| 35 | - obj.center = CGPointMake(obj.center.x + (obj.center.x - centerX) / halfWidth * self.distanceBetweenPages / 2, obj.center.y); | |
| 36 | - }]; | |
| 37 | - return layoutAttsArray; | |
| 38 | -} | |
| 39 | - | |
| 40 | -- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds { | |
| 41 | - return YES; | |
| 42 | -} | |
| 43 | - | |
| 44 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBContainerView.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBContainerView.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/11. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface YBIBContainerView : UIView | |
| 14 | - | |
| 15 | -@end | |
| 16 | - | |
| 17 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBContainerView.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBContainerView.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/11. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBContainerView.h" | |
| 10 | - | |
| 11 | -@implementation YBIBContainerView | |
| 12 | - | |
| 13 | -- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { | |
| 14 | - UIView *originView = [super hitTest:point withEvent:event]; | |
| 15 | - if ([originView isKindOfClass:self.class]) { | |
| 16 | - // Continue hit-testing if the view is kind of 'self.class'. | |
| 17 | - return nil; | |
| 18 | - } | |
| 19 | - return originView; | |
| 20 | -} | |
| 21 | - | |
| 22 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBDataMediator.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBDataMediator.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/6. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBImageBrowser.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface YBIBDataMediator : NSObject | |
| 14 | - | |
| 15 | -- (instancetype)initWithBrowser:(YBImageBrowser *)browser; | |
| 16 | - | |
| 17 | -@property (nonatomic, assign) NSUInteger dataCacheCountLimit; | |
| 18 | - | |
| 19 | -- (NSInteger)numberOfCells; | |
| 20 | - | |
| 21 | -- (id<YBIBDataProtocol>)dataForCellAtIndex:(NSInteger)index; | |
| 22 | - | |
| 23 | -- (void)clear; | |
| 24 | - | |
| 25 | -@property (nonatomic, assign) NSUInteger preloadCount; | |
| 26 | - | |
| 27 | -- (void)preloadWithPage:(NSInteger)page; | |
| 28 | - | |
| 29 | -@end | |
| 30 | - | |
| 31 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBDataMediator.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBDataMediator.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/6. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBDataMediator.h" | |
| 10 | -#import "YBImageBrowser+Internal.h" | |
| 11 | - | |
| 12 | -@implementation YBIBDataMediator { | |
| 13 | - __weak YBImageBrowser *_browser; | |
| 14 | - NSCache<NSNumber *, id<YBIBDataProtocol>> *_dataCache; | |
| 15 | -} | |
| 16 | - | |
| 17 | -#pragma mark - life cycle | |
| 18 | - | |
| 19 | -- (instancetype)initWithBrowser:(YBImageBrowser *)browser { | |
| 20 | - if (self = [super init]) { | |
| 21 | - _browser = browser; | |
| 22 | - _dataCache = [NSCache new]; | |
| 23 | - } | |
| 24 | - return self; | |
| 25 | -} | |
| 26 | - | |
| 27 | -#pragma mark - public | |
| 28 | - | |
| 29 | -- (NSInteger)numberOfCells { | |
| 30 | - return _browser.dataSource ? [_browser.dataSource yb_numberOfCellsInImageBrowser:_browser] : _browser.dataSourceArray.count; | |
| 31 | -} | |
| 32 | - | |
| 33 | -- (id<YBIBDataProtocol>)dataForCellAtIndex:(NSInteger)index { | |
| 34 | - if (index < 0 || index > self.numberOfCells - 1) return nil; | |
| 35 | - | |
| 36 | - id<YBIBDataProtocol> data = [_dataCache objectForKey:@(index)]; | |
| 37 | - if (!data) { | |
| 38 | - data = _browser.dataSource ? [_browser.dataSource yb_imageBrowser:_browser dataForCellAtIndex:index] : _browser.dataSourceArray[index]; | |
| 39 | - [_dataCache setObject:data forKey:@(index)]; | |
| 40 | - [_browser implementGetBaseInfoProtocol:data]; | |
| 41 | - } | |
| 42 | - return data; | |
| 43 | -} | |
| 44 | - | |
| 45 | -- (void)clear { | |
| 46 | - [_dataCache removeAllObjects]; | |
| 47 | -} | |
| 48 | - | |
| 49 | -- (void)preloadWithPage:(NSInteger)page { | |
| 50 | - if (_preloadCount == 0) return; | |
| 51 | - | |
| 52 | - NSInteger left = -(_preloadCount / 2), right = _preloadCount - ABS(left); | |
| 53 | - for (NSInteger i = left; i <= right; ++i) { | |
| 54 | - if (i == 0) continue; | |
| 55 | - id<YBIBDataProtocol> targetData = [self dataForCellAtIndex:page + i]; | |
| 56 | - if ([targetData respondsToSelector:@selector(yb_preload)]) { | |
| 57 | - [targetData yb_preload]; | |
| 58 | - } | |
| 59 | - } | |
| 60 | -} | |
| 61 | - | |
| 62 | -#pragma mark - getters & setters | |
| 63 | - | |
| 64 | -- (void)setDataCacheCountLimit:(NSUInteger)dataCacheCountLimit { | |
| 65 | - _dataCacheCountLimit = dataCacheCountLimit; | |
| 66 | - _dataCache.countLimit = dataCacheCountLimit; | |
| 67 | -} | |
| 68 | - | |
| 69 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBScreenRotationHandler.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBScreenRotationHandler.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/8. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBImageBrowser.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface YBIBScreenRotationHandler : NSObject | |
| 14 | - | |
| 15 | -- (instancetype)initWithBrowser:(YBImageBrowser *)browser; | |
| 16 | - | |
| 17 | -- (void)startObserveStatusBarOrientation; | |
| 18 | - | |
| 19 | -- (void)startObserveDeviceOrientation; | |
| 20 | - | |
| 21 | -- (void)clear; | |
| 22 | - | |
| 23 | -- (void)configContainerSize:(CGSize)size; | |
| 24 | - | |
| 25 | -- (CGSize)containerSizeWithOrientation:(UIDeviceOrientation)orientation; | |
| 26 | - | |
| 27 | -@property (nonatomic, assign, readonly, getter=isRotating) BOOL rotating; | |
| 28 | - | |
| 29 | -@property (nonatomic, assign, readonly) UIDeviceOrientation currentOrientation; | |
| 30 | - | |
| 31 | -@property (nonatomic, assign) UIInterfaceOrientationMask supportedOrientations; | |
| 32 | - | |
| 33 | -@property (nonatomic, assign) NSTimeInterval rotationDuration; | |
| 34 | - | |
| 35 | -@end | |
| 36 | - | |
| 37 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBIBScreenRotationHandler.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBScreenRotationHandler.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/8. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBScreenRotationHandler.h" | |
| 10 | -#import "YBIBUtilities.h" | |
| 11 | -#import "YBIBCellProtocol.h" | |
| 12 | -#import "YBImageBrowser+Internal.h" | |
| 13 | - | |
| 14 | -BOOL YBIBValidDeviceOrientation(UIDeviceOrientation orientation) { | |
| 15 | - static NSSet *validSet; | |
| 16 | - static dispatch_once_t onceToken; | |
| 17 | - dispatch_once(&onceToken, ^{ | |
| 18 | - validSet = [NSSet setWithObjects:@(UIDeviceOrientationPortrait), @(UIDeviceOrientationPortraitUpsideDown), @(UIDeviceOrientationLandscapeLeft), @(UIDeviceOrientationLandscapeRight), nil]; | |
| 19 | - }); | |
| 20 | - return [validSet containsObject:@(orientation)]; | |
| 21 | -} | |
| 22 | - | |
| 23 | -CGFloat YBIBRotationAngle(UIDeviceOrientation startOrientation, UIDeviceOrientation endOrientation) { | |
| 24 | - static NSDictionary<NSNumber*, NSNumber*> *angleMap; | |
| 25 | - static dispatch_once_t onceToken; | |
| 26 | - dispatch_once(&onceToken, ^{ | |
| 27 | - angleMap = @{@(UIDeviceOrientationPortrait):@(0), @(UIDeviceOrientationPortraitUpsideDown):@(M_PI), @(UIDeviceOrientationLandscapeLeft):@(M_PI_2), @(UIDeviceOrientationLandscapeRight): @(-M_PI_2)}; | |
| 28 | - }); | |
| 29 | - NSNumber *start = angleMap[@(startOrientation)], *end = angleMap[@(endOrientation)]; | |
| 30 | - CGFloat res = CGFLOAT_IS_DOUBLE ? end.doubleValue - start.doubleValue : end.floatValue - start.floatValue; | |
| 31 | - if (ABS(res) > M_PI) { | |
| 32 | - return res > 0 ? res - M_PI * 2 : M_PI * 2 + res; | |
| 33 | - } | |
| 34 | - return res; | |
| 35 | -} | |
| 36 | - | |
| 37 | - | |
| 38 | -static NSUInteger const kMaskNull = 10000; | |
| 39 | - | |
| 40 | -@interface YBIBScreenRotationHandler () | |
| 41 | -@property (nonatomic, assign) BOOL rotating; | |
| 42 | -@property (nonatomic, assign) UIDeviceOrientation currentOrientation; | |
| 43 | -@end | |
| 44 | - | |
| 45 | -@implementation YBIBScreenRotationHandler { | |
| 46 | - __weak YBImageBrowser *_browser; | |
| 47 | - CGSize _verticalContainerSize; | |
| 48 | - CGSize _horizontalContainerSize; | |
| 49 | - NSInteger _recordPage; | |
| 50 | -} | |
| 51 | - | |
| 52 | -#pragma mark - life cycle | |
| 53 | - | |
| 54 | -- (void)dealloc { | |
| 55 | - [self clear]; | |
| 56 | -} | |
| 57 | - | |
| 58 | -- (instancetype)initWithBrowser:(YBImageBrowser *)browser { | |
| 59 | - if (self = [super init]) { | |
| 60 | - _browser = browser; | |
| 61 | - _rotating = NO; | |
| 62 | - _supportedOrientations = UIInterfaceOrientationMaskAllButUpsideDown; | |
| 63 | - _rotationDuration = 0.25; | |
| 64 | - } | |
| 65 | - return self; | |
| 66 | -} | |
| 67 | - | |
| 68 | -#pragma mark - public | |
| 69 | - | |
| 70 | -- (void)startObserveStatusBarOrientation { | |
| 71 | - self.currentOrientation = (UIDeviceOrientation)UIApplication.sharedApplication.statusBarOrientation; | |
| 72 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationDidChangedStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; | |
| 73 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillChangeStatusBarOrientationNotification:) name:UIApplicationWillChangeStatusBarOrientationNotification object:nil]; | |
| 74 | -} | |
| 75 | - | |
| 76 | -- (void)startObserveDeviceOrientation { | |
| 77 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChangeNotification:) name:UIDeviceOrientationDidChangeNotification object:nil]; | |
| 78 | -} | |
| 79 | - | |
| 80 | -- (void)clear { | |
| 81 | - [[NSNotificationCenter defaultCenter] removeObserver:self]; | |
| 82 | -} | |
| 83 | - | |
| 84 | -- (void)configContainerSize:(CGSize)size { | |
| 85 | - if (UIDeviceOrientationIsLandscape(self.currentOrientation)) { | |
| 86 | - // Now is horizontal. | |
| 87 | - _verticalContainerSize = CGSizeMake(size.height, size.width); | |
| 88 | - _horizontalContainerSize = size; | |
| 89 | - } else { | |
| 90 | - // Now is vertical. | |
| 91 | - _verticalContainerSize = size; | |
| 92 | - _horizontalContainerSize = CGSizeMake(size.height, size.width); | |
| 93 | - } | |
| 94 | -} | |
| 95 | - | |
| 96 | -- (CGSize)containerSizeWithOrientation:(UIDeviceOrientation)orientation { | |
| 97 | - return UIDeviceOrientationIsLandscape(orientation) ? _horizontalContainerSize : _verticalContainerSize; | |
| 98 | -} | |
| 99 | - | |
| 100 | -#pragma mark - private | |
| 101 | - | |
| 102 | -- (BOOL)supportedOfOrientation:(UIDeviceOrientation)orientation { | |
| 103 | - if (!YBIBValidDeviceOrientation(orientation)) return NO; | |
| 104 | - NSMutableSet *set = [NSMutableSet set]; | |
| 105 | - if (_supportedOrientations & UIInterfaceOrientationMaskPortrait) [set addObject:@(UIDeviceOrientationPortrait)]; | |
| 106 | - if (_supportedOrientations & UIInterfaceOrientationMaskPortraitUpsideDown) [set addObject:@(UIDeviceOrientationPortraitUpsideDown)]; | |
| 107 | - if (_supportedOrientations & UIInterfaceOrientationMaskLandscapeRight) [set addObject:@(UIDeviceOrientationLandscapeLeft)]; | |
| 108 | - if (_supportedOrientations & UIInterfaceOrientationMaskLandscapeLeft) [set addObject:@(UIDeviceOrientationLandscapeRight)]; | |
| 109 | - return [set containsObject:@(orientation)]; | |
| 110 | -} | |
| 111 | - | |
| 112 | -- (BOOL)supportedOnlyOneSystemOrientation { | |
| 113 | - UIInterfaceOrientationMask mask = [self supportSystemOrientationMask]; | |
| 114 | - return mask == (mask & (-mask)); | |
| 115 | -} | |
| 116 | - | |
| 117 | -- (void)orientationWillChangeWithExpectOrientation:(UIDeviceOrientation)orientation centerCell:(UICollectionViewCell<YBIBCellProtocol> *)centerCell { | |
| 118 | - if ([centerCell respondsToSelector:@selector(yb_orientationWillChangeWithExpectOrientation:)]) { | |
| 119 | - [centerCell yb_orientationWillChangeWithExpectOrientation:orientation]; | |
| 120 | - } | |
| 121 | - for (id<YBIBToolViewHandler> handler in _browser.toolViewHandlers) { | |
| 122 | - if ([handler respondsToSelector:@selector(yb_orientationWillChangeWithExpectOrientation:)]) { | |
| 123 | - [handler yb_orientationWillChangeWithExpectOrientation:orientation]; | |
| 124 | - } | |
| 125 | - } | |
| 126 | -} | |
| 127 | - | |
| 128 | -- (void)orientationChangeAnimationWithExpectOrientation:(UIDeviceOrientation)orientation centerCell:(UICollectionViewCell<YBIBCellProtocol> *)centerCell { | |
| 129 | - if ([centerCell respondsToSelector:@selector(yb_orientationChangeAnimationWithExpectOrientation:)]) { | |
| 130 | - [centerCell yb_orientationChangeAnimationWithExpectOrientation:orientation]; | |
| 131 | - [centerCell layoutIfNeeded]; // Compatible with autolayout. | |
| 132 | - } | |
| 133 | - for (id<YBIBToolViewHandler> handler in _browser.toolViewHandlers) { | |
| 134 | - if ([handler respondsToSelector:@selector(yb_orientationChangeAnimationWithExpectOrientation:)]) { | |
| 135 | - [handler yb_orientationChangeAnimationWithExpectOrientation:orientation]; | |
| 136 | - } | |
| 137 | - } | |
| 138 | -} | |
| 139 | - | |
| 140 | -- (void)orientationDidChangedWithOrientation:(UIDeviceOrientation)orientation centerCell:(UICollectionViewCell<YBIBCellProtocol> *)centerCell { | |
| 141 | - if ([centerCell respondsToSelector:@selector(yb_orientationDidChangedWithOrientation:)]) { | |
| 142 | - [centerCell yb_orientationDidChangedWithOrientation:orientation]; | |
| 143 | - } | |
| 144 | - for (id<YBIBToolViewHandler> handler in _browser.toolViewHandlers) { | |
| 145 | - if ([handler respondsToSelector:@selector(yb_orientationDidChangedWithOrientation:)]) { | |
| 146 | - [handler yb_orientationDidChangedWithOrientation:orientation]; | |
| 147 | - } | |
| 148 | - } | |
| 149 | -} | |
| 150 | - | |
| 151 | -#pragma mark - event | |
| 152 | - | |
| 153 | -- (void)deviceOrientationDidChangeNotification:(NSNotification *)note { | |
| 154 | - if (![self supportedOnlyOneSystemOrientation]) return; | |
| 155 | - if (_browser.isTransitioning || self.rotating) return; | |
| 156 | - | |
| 157 | - UIDeviceOrientation expectOrientation = [UIDevice currentDevice].orientation; | |
| 158 | - if (expectOrientation == self.currentOrientation || ![self supportedOfOrientation:expectOrientation]) return; | |
| 159 | - | |
| 160 | - self.rotating = YES; | |
| 161 | - | |
| 162 | - // Align. | |
| 163 | - [_browser.collectionView scrollToPage:_browser.currentPage]; | |
| 164 | - // Record current page number before transforming. | |
| 165 | - NSInteger currentPage = _browser.currentPage; | |
| 166 | - | |
| 167 | - UIDeviceOrientation statusBarOrientation = (UIDeviceOrientation)UIApplication.sharedApplication.statusBarOrientation; | |
| 168 | - CGFloat angleStatusBarToExpect = YBIBRotationAngle(statusBarOrientation, expectOrientation); | |
| 169 | - CGFloat angleCurrentToExpect = YBIBRotationAngle(_currentOrientation, expectOrientation); | |
| 170 | - CGRect expectBounds = (CGRect){CGPointZero, [self containerSizeWithOrientation:expectOrientation]}; | |
| 171 | - UICollectionViewCell<YBIBCellProtocol> *centerCell = (UICollectionViewCell<YBIBCellProtocol> *)self->_browser.collectionView.centerCell; | |
| 172 | - // Animate smoothly if bigger rotation angle. | |
| 173 | - NSTimeInterval duration = self.rotationDuration * (ABS(angleCurrentToExpect) > M_PI_2 ? 2 : 1); | |
| 174 | - | |
| 175 | - // 'collectionView' transformation. | |
| 176 | - self->_browser.collectionView.bounds = expectBounds; | |
| 177 | - self->_browser.collectionView.transform = CGAffineTransformMakeRotation(angleStatusBarToExpect); | |
| 178 | - centerCell.contentView.transform = CGAffineTransformMakeRotation(-angleCurrentToExpect); | |
| 179 | - | |
| 180 | - // Reset to prevent the page number change after transforming. | |
| 181 | - [self->_browser.collectionView scrollToPage:currentPage]; | |
| 182 | - | |
| 183 | - [self orientationWillChangeWithExpectOrientation:expectOrientation centerCell:centerCell]; | |
| 184 | - | |
| 185 | - [UIView animateWithDuration:duration delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ | |
| 186 | - | |
| 187 | - // Maybe the internal UI need to transform. | |
| 188 | - [self orientationChangeAnimationWithExpectOrientation:expectOrientation centerCell:centerCell]; | |
| 189 | - | |
| 190 | - centerCell.contentView.bounds = expectBounds; | |
| 191 | - centerCell.contentView.transform = CGAffineTransformIdentity; | |
| 192 | - | |
| 193 | - self->_browser.containerView.bounds = expectBounds; | |
| 194 | - self->_browser.containerView.transform = CGAffineTransformMakeRotation(angleStatusBarToExpect); | |
| 195 | - | |
| 196 | - } completion:^(BOOL finished) { | |
| 197 | - self.currentOrientation = expectOrientation; | |
| 198 | - self.rotating = NO; | |
| 199 | - | |
| 200 | - [self orientationDidChangedWithOrientation:expectOrientation centerCell:centerCell]; | |
| 201 | - }]; | |
| 202 | -} | |
| 203 | - | |
| 204 | -- (void)applicationWillChangeStatusBarOrientationNotification:(NSNotification *)noti { | |
| 205 | - if ([self supportedOnlyOneSystemOrientation]) return; | |
| 206 | - | |
| 207 | - self.rotating = YES; | |
| 208 | - // Record current page number before transforming. | |
| 209 | - _recordPage = _browser.currentPage; | |
| 210 | - | |
| 211 | - UICollectionViewCell<YBIBCellProtocol> *centerCell = (UICollectionViewCell<YBIBCellProtocol> *)self->_browser.collectionView.centerCell; | |
| 212 | - UIDeviceOrientation expectOrientation = ((NSNumber *)noti.userInfo[UIApplicationStatusBarOrientationUserInfoKey]).integerValue; | |
| 213 | - [self orientationWillChangeWithExpectOrientation:expectOrientation centerCell:centerCell]; | |
| 214 | -} | |
| 215 | - | |
| 216 | -- (void)applicationDidChangedStatusBarOrientationNotification:(NSNotification *)noti { | |
| 217 | - if ([self supportedOnlyOneSystemOrientation]) return; | |
| 218 | - | |
| 219 | - UIDeviceOrientation expectOrientation = (UIDeviceOrientation)UIApplication.sharedApplication.statusBarOrientation; | |
| 220 | - UICollectionViewCell<YBIBCellProtocol> *centerCell = (UICollectionViewCell<YBIBCellProtocol> *)self->_browser.collectionView.centerCell; | |
| 221 | - | |
| 222 | - [self orientationChangeAnimationWithExpectOrientation:expectOrientation centerCell:centerCell]; | |
| 223 | - | |
| 224 | - CGRect expectBounds = (CGRect){CGPointZero, [self containerSizeWithOrientation:expectOrientation]}; | |
| 225 | - self->_browser.collectionView.layout.itemSize = expectBounds.size; | |
| 226 | - | |
| 227 | - // Reset to prevent the page number change after transforming. | |
| 228 | - [_browser.collectionView scrollToPage:_recordPage]; | |
| 229 | - | |
| 230 | - self.currentOrientation = expectOrientation; | |
| 231 | - self.rotating = NO; | |
| 232 | - | |
| 233 | - [self orientationDidChangedWithOrientation:expectOrientation centerCell:centerCell]; | |
| 234 | -} | |
| 235 | - | |
| 236 | -#pragma mark - getters & setters | |
| 237 | - | |
| 238 | -- (void)setRotating:(BOOL)rotating { | |
| 239 | - _rotating = rotating; | |
| 240 | - _browser.containerView.userInteractionEnabled = !rotating; | |
| 241 | - _browser.collectionView.userInteractionEnabled = !rotating; | |
| 242 | - _browser.collectionView.panGestureRecognizer.enabled = !rotating; | |
| 243 | -} | |
| 244 | - | |
| 245 | -#pragma mark - calculate supported orientation of system | |
| 246 | - | |
| 247 | -- (UIInterfaceOrientationMask)supportSystemOrientationMask { | |
| 248 | - UIInterfaceOrientationMask limitMask = 0; | |
| 249 | - // IphoneX series do not support UIInterfaceOrientationMaskPortraitUpsideDown, except selector '-application:supportedInterfaceOrientationsForWindow:' of '[UIApplication sharedApplication].delegate' return 0. Maybe it is BUG of Apple. | |
| 250 | - BOOL ignoreUpsideDownIfIphoneX = YES; | |
| 251 | - UIInterfaceOrientationMask delegateMask = [self maskOfApplicationDelegate]; | |
| 252 | - if (delegateMask != kMaskNull) { | |
| 253 | - if (delegateMask == 0) { | |
| 254 | - // Apple do. | |
| 255 | - limitMask = UIInterfaceOrientationMaskAll; | |
| 256 | - ignoreUpsideDownIfIphoneX = NO; | |
| 257 | - } else { | |
| 258 | - limitMask = delegateMask; | |
| 259 | - } | |
| 260 | - } else { | |
| 261 | - // Lower priority. | |
| 262 | - limitMask = [self maskOfInfoPlist]; | |
| 263 | - } | |
| 264 | - | |
| 265 | - UIInterfaceOrientationMask supportMask = limitMask & [self maskOfViewController]; | |
| 266 | - | |
| 267 | - if (ignoreUpsideDownIfIphoneX && YBIBIsIphoneXSeries() && (supportMask & UIInterfaceOrientationMaskPortraitUpsideDown)) { | |
| 268 | - supportMask ^= UIInterfaceOrientationMaskPortraitUpsideDown; | |
| 269 | - } | |
| 270 | - return supportMask; | |
| 271 | -} | |
| 272 | - | |
| 273 | -- (UIInterfaceOrientationMask)maskOfInfoPlist { | |
| 274 | - // 'Info.plist' will not change in a process. | |
| 275 | - static UIInterfaceOrientationMask mask = 0; | |
| 276 | - static dispatch_once_t onceToken; | |
| 277 | - dispatch_once(&onceToken, ^{ | |
| 278 | - NSString *path = [[NSBundle mainBundle] pathForResource:@"Info" ofType:@"plist"]; | |
| 279 | - NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:path]; | |
| 280 | - NSArray *array = dict[@"UISupportedInterfaceOrientations"]; | |
| 281 | - NSSet *set = [NSSet setWithArray:array]; | |
| 282 | - if ([set containsObject:@"UIInterfaceOrientationPortrait"]) mask |= UIInterfaceOrientationMaskPortrait; | |
| 283 | - if ([set containsObject:@"UIInterfaceOrientationLandscapeRight"]) mask |= UIInterfaceOrientationMaskLandscapeRight; | |
| 284 | - if ([set containsObject:@"UIInterfaceOrientationLandscapeLeft"]) mask |= UIInterfaceOrientationMaskLandscapeLeft; | |
| 285 | - if ([set containsObject:@"UIInterfaceOrientationPortraitUpsideDown"]) mask |= UIInterfaceOrientationMaskPortraitUpsideDown; | |
| 286 | - }); | |
| 287 | - return mask == 0 ? kMaskNull : mask; | |
| 288 | -} | |
| 289 | - | |
| 290 | -- (UIInterfaceOrientationMask)maskOfApplicationDelegate { | |
| 291 | - UIInterfaceOrientationMask mask = kMaskNull; | |
| 292 | - id<UIApplicationDelegate> delegate = [UIApplication sharedApplication].delegate; | |
| 293 | - if ([delegate respondsToSelector:@selector(application:supportedInterfaceOrientationsForWindow:)]) { | |
| 294 | - mask = [delegate application:[UIApplication sharedApplication] supportedInterfaceOrientationsForWindow:_browser.window]; | |
| 295 | - } | |
| 296 | - return mask; | |
| 297 | -} | |
| 298 | - | |
| 299 | -- (UIInterfaceOrientationMask)maskOfViewController { | |
| 300 | - UIInterfaceOrientationMask mask = kMaskNull; | |
| 301 | - | |
| 302 | - // Find the UIViewController whitch 'browser' followed. | |
| 303 | - UIViewController *target = nil; | |
| 304 | - id next = _browser; | |
| 305 | - while (next) { | |
| 306 | - if ([next isKindOfClass:UIViewController.self]) { | |
| 307 | - target = next; | |
| 308 | - break; | |
| 309 | - } | |
| 310 | - if ([next isKindOfClass:UIWindow.self]) { | |
| 311 | - target = YBIBTopControllerByWindow(next); | |
| 312 | - break; | |
| 313 | - } | |
| 314 | - next = [next nextResponder]; | |
| 315 | - } | |
| 316 | - | |
| 317 | - // Cover directly. | |
| 318 | - if (target.tabBarController) { | |
| 319 | - mask = target.tabBarController.shouldAutorotate ? target.tabBarController.supportedInterfaceOrientations : 0; | |
| 320 | - } else if (target.navigationController) { | |
| 321 | - mask = target.navigationController.shouldAutorotate ? target.navigationController.supportedInterfaceOrientations : 0; | |
| 322 | - } else { | |
| 323 | - mask = target.shouldAutorotate ? target.supportedInterfaceOrientations : 0; | |
| 324 | - } | |
| 325 | - return mask; | |
| 326 | -} | |
| 327 | - | |
| 328 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Base/YBImageBrowser+Internal.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBImageBrowser+Internal.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/1. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBImageBrowser.h" | |
| 10 | -#import "YBIBContainerView.h" | |
| 11 | - | |
| 12 | -NS_ASSUME_NONNULL_BEGIN | |
| 13 | - | |
| 14 | -@interface YBImageBrowser () | |
| 15 | - | |
| 16 | -@property (nonatomic, strong) YBIBContainerView *containerView; | |
| 17 | - | |
| 18 | -- (void)implementGetBaseInfoProtocol:(id<YBIBGetBaseInfoProtocol>)obj; | |
| 19 | - | |
| 20 | -@property (nonatomic, weak, nullable) NSObject *hiddenProjectiveView; | |
| 21 | - | |
| 22 | -@end | |
| 23 | - | |
| 24 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBCopywriter.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBCopywriter.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/9/13. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <Foundation/Foundation.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -typedef NS_ENUM(NSInteger, YBIBCopywriterType) { | |
| 14 | - /// 简体中文 | |
| 15 | - YBIBCopywriterTypeSimplifiedChinese, | |
| 16 | - /// 英文 | |
| 17 | - YBIBCopywriterTypeEnglish | |
| 18 | -}; | |
| 19 | - | |
| 20 | -/** | |
| 21 | - 文案管理类 | |
| 22 | - */ | |
| 23 | -@interface YBIBCopywriter : NSObject | |
| 24 | - | |
| 25 | -/** | |
| 26 | - 唯一有效单例 | |
| 27 | - */ | |
| 28 | -+ (instancetype)sharedCopywriter; | |
| 29 | - | |
| 30 | -/// 语言类型 | |
| 31 | -@property (nonatomic, assign) YBIBCopywriterType type; | |
| 32 | - | |
| 33 | -#pragma - 以下文案可更改 | |
| 34 | - | |
| 35 | -@property (nonatomic, copy) NSString *videoIsInvalid; | |
| 36 | - | |
| 37 | -@property (nonatomic, copy) NSString *videoError; | |
| 38 | - | |
| 39 | -@property (nonatomic, copy) NSString *unableToSave; | |
| 40 | - | |
| 41 | -@property (nonatomic, copy) NSString *imageIsInvalid; | |
| 42 | - | |
| 43 | -@property (nonatomic, copy) NSString *downloadFailed; | |
| 44 | - | |
| 45 | -@property (nonatomic, copy) NSString *getPhotoAlbumAuthorizationFailed; | |
| 46 | - | |
| 47 | -@property (nonatomic, copy) NSString *saveToPhotoAlbumSuccess; | |
| 48 | - | |
| 49 | -@property (nonatomic, copy) NSString *saveToPhotoAlbumFailed; | |
| 50 | - | |
| 51 | -@property (nonatomic, copy) NSString *saveToPhotoAlbum; | |
| 52 | - | |
| 53 | -@property (nonatomic, copy) NSString *cancel; | |
| 54 | - | |
| 55 | -@end | |
| 56 | - | |
| 57 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBCopywriter.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBCopywriter.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/9/13. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBCopywriter.h" | |
| 10 | - | |
| 11 | -@implementation YBIBCopywriter | |
| 12 | - | |
| 13 | -#pragma mark - life cycle | |
| 14 | - | |
| 15 | -+ (instancetype)sharedCopywriter { | |
| 16 | - static YBIBCopywriter *copywriter = nil; | |
| 17 | - static dispatch_once_t onceToken; | |
| 18 | - dispatch_once(&onceToken, ^{ | |
| 19 | - copywriter = [YBIBCopywriter new]; | |
| 20 | - }); | |
| 21 | - return copywriter; | |
| 22 | -} | |
| 23 | - | |
| 24 | -- (instancetype)init { | |
| 25 | - self = [super init]; | |
| 26 | - if (self) { | |
| 27 | - _type = YBIBCopywriterTypeSimplifiedChinese; | |
| 28 | - NSArray *appleLanguages = [[NSUserDefaults standardUserDefaults] objectForKey:@"AppleLanguages"]; | |
| 29 | - if (appleLanguages && appleLanguages.count > 0) { | |
| 30 | - NSString *languages = appleLanguages[0]; | |
| 31 | - if (![languages hasPrefix:@"zh-Hans"]) { | |
| 32 | - _type = YBIBCopywriterTypeEnglish; | |
| 33 | - } | |
| 34 | - } | |
| 35 | - | |
| 36 | - [self initCopy]; | |
| 37 | - } | |
| 38 | - return self; | |
| 39 | -} | |
| 40 | - | |
| 41 | -#pragma mark - private | |
| 42 | - | |
| 43 | -- (void)initCopy { | |
| 44 | - BOOL en = self.type == YBIBCopywriterTypeEnglish; | |
| 45 | - | |
| 46 | - self.videoIsInvalid = en ? @"Video is invalid" : @"视频无效"; | |
| 47 | - self.videoError = en ? @"Video error" : @"视频错误"; | |
| 48 | - self.unableToSave = en ? @"Unable to save" : @"无法保存"; | |
| 49 | - self.imageIsInvalid = en ? @"Image is invalid" : @"图片无效"; | |
| 50 | - self.downloadFailed = en ? @"Download failed" : @"加载图片失败"; | |
| 51 | - self.getPhotoAlbumAuthorizationFailed = en ? @"Failed to get album authorization" : @"获取相册权限失败"; | |
| 52 | - self.saveToPhotoAlbumSuccess = en ? @"Save successful" : @"已保存到系统相册"; | |
| 53 | - self.saveToPhotoAlbumFailed = en ? @"Save failed" : @"保存失败"; | |
| 54 | - self.saveToPhotoAlbum = en ? @"Save" : @"保存到相册"; | |
| 55 | - self.cancel = en ? @"Cancel" : @"取消"; | |
| 56 | -} | |
| 57 | - | |
| 58 | -#pragma mark - public | |
| 59 | - | |
| 60 | -- (void)setType:(YBIBCopywriterType)type { | |
| 61 | - _type = type; | |
| 62 | - [self initCopy]; | |
| 63 | -} | |
| 64 | - | |
| 65 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBIconManager.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBIconManager.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/8/29. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface UIImage (YBImageBrowser) | |
| 14 | - | |
| 15 | -/** | |
| 16 | - 获取图片便利构造方法 | |
| 17 | - | |
| 18 | - @param name 图片名字 | |
| 19 | - @param bundle 资源对象 | |
| 20 | - @return 图片实例 | |
| 21 | - */ | |
| 22 | -+ (instancetype)ybib_imageNamed:(NSString *)name bundle:(NSBundle *)bundle; | |
| 23 | - | |
| 24 | -@end | |
| 25 | - | |
| 26 | - | |
| 27 | -/// 获取图片闭包 | |
| 28 | -typedef UIImage * _Nullable (^YBIBIconBlock)(void); | |
| 29 | - | |
| 30 | -/** | |
| 31 | - 图标管理类 | |
| 32 | - */ | |
| 33 | -@interface YBIBIconManager : NSObject | |
| 34 | - | |
| 35 | -/** | |
| 36 | - 唯一有效单例 | |
| 37 | - */ | |
| 38 | -+ (instancetype)sharedManager; | |
| 39 | - | |
| 40 | -#pragma - 以下图片可更改 | |
| 41 | - | |
| 42 | -/// 基本-加载 | |
| 43 | -@property (nonatomic, copy) YBIBIconBlock loadingImage; | |
| 44 | - | |
| 45 | -/// 工具视图-保存 | |
| 46 | -@property (nonatomic, copy) YBIBIconBlock toolSaveImage; | |
| 47 | -/// 工具视图-更多 | |
| 48 | -@property (nonatomic, copy) YBIBIconBlock toolMoreImage; | |
| 49 | - | |
| 50 | -/// 视频-播放 | |
| 51 | -@property (nonatomic, copy) YBIBIconBlock videoPlayImage; | |
| 52 | -/// 视频-暂停 | |
| 53 | -@property (nonatomic, copy) YBIBIconBlock videoPauseImage; | |
| 54 | -/// 视频-取消 | |
| 55 | -@property (nonatomic, copy) YBIBIconBlock videoCancelImage; | |
| 56 | -/// 视频-播放大图 | |
| 57 | -@property (nonatomic, copy) YBIBIconBlock videoBigPlayImage; | |
| 58 | -/// 视频-拖动圆点 | |
| 59 | -@property (nonatomic, copy) YBIBIconBlock videoDragCircleImage; | |
| 60 | - | |
| 61 | -@end | |
| 62 | - | |
| 63 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBIconManager.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBIconManager.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/8/29. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBIconManager.h" | |
| 10 | - | |
| 11 | -// The best order for path scale search. | |
| 12 | -static NSArray *_NSBundlePreferredScales() { | |
| 13 | - static NSArray *scales; | |
| 14 | - static dispatch_once_t onceToken; | |
| 15 | - dispatch_once(&onceToken, ^{ | |
| 16 | - CGFloat screenScale = [UIScreen mainScreen].scale; | |
| 17 | - if (screenScale <= 1) { | |
| 18 | - scales = @[@1,@2,@3]; | |
| 19 | - } else if (screenScale <= 2) { | |
| 20 | - scales = @[@2,@3,@1]; | |
| 21 | - } else { | |
| 22 | - scales = @[@3,@2,@1]; | |
| 23 | - } | |
| 24 | - }); | |
| 25 | - return scales; | |
| 26 | -} | |
| 27 | - | |
| 28 | -// Add scale modifier to the file name (without path extension), from @"name" to @"name@2x". | |
| 29 | -static NSString *_NSStringByAppendingNameScale(NSString *string, CGFloat scale) { | |
| 30 | - if (!string) return nil; | |
| 31 | - if (fabs(scale - 1) <= __FLT_EPSILON__ || string.length == 0 || [string hasSuffix:@"/"]) return string.copy; | |
| 32 | - return [string stringByAppendingFormat:@"@%@x", @(scale)]; | |
| 33 | -} | |
| 34 | - | |
| 35 | -@implementation UIImage (YBImageBrowser) | |
| 36 | - | |
| 37 | -+ (instancetype)ybib_imageNamed:(NSString *)name bundle:(NSBundle *)bundle { | |
| 38 | - if (name.length == 0) return nil; | |
| 39 | - if ([name hasSuffix:@"/"]) return nil; | |
| 40 | - | |
| 41 | - NSString *res = name.stringByDeletingPathExtension; | |
| 42 | - NSString *ext = name.pathExtension; | |
| 43 | - NSString *path = nil; | |
| 44 | - CGFloat scale = 1; | |
| 45 | - | |
| 46 | - // If no extension, guess by system supported (same as UIImage). | |
| 47 | - NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp", @"apng"]; | |
| 48 | - NSArray *scales = _NSBundlePreferredScales(); | |
| 49 | - for (int s = 0; s < scales.count; s++) { | |
| 50 | - scale = ((NSNumber *)scales[s]).floatValue; | |
| 51 | - NSString *scaledName = _NSStringByAppendingNameScale(res, scale); | |
| 52 | - for (NSString *e in exts) { | |
| 53 | - path = [bundle pathForResource:scaledName ofType:e]; | |
| 54 | - if (path) break; | |
| 55 | - } | |
| 56 | - if (path) break; | |
| 57 | - } | |
| 58 | - if (path.length == 0) { | |
| 59 | - // Assets.xcassets supported. | |
| 60 | - return [self imageNamed:name]; | |
| 61 | - } | |
| 62 | - | |
| 63 | - NSData *data = [NSData dataWithContentsOfFile:path]; | |
| 64 | - if (data.length == 0) return nil; | |
| 65 | - | |
| 66 | - return [[self alloc] initWithData:data scale:scale]; | |
| 67 | -} | |
| 68 | - | |
| 69 | -@end | |
| 70 | - | |
| 71 | - | |
| 72 | -NSBundle *YBIBDefaultBundle(void) { | |
| 73 | - static NSBundle *bundle = nil; | |
| 74 | - static dispatch_once_t onceToken; | |
| 75 | - dispatch_once(&onceToken, ^{ | |
| 76 | - NSBundle *_bundle = [NSBundle bundleForClass:NSClassFromString(@"YBImageBrowser")]; | |
| 77 | - NSString *path = [_bundle pathForResource:@"YBImageBrowser" ofType:@"bundle"]; | |
| 78 | - bundle = [NSBundle bundleWithPath:path]; | |
| 79 | - }); | |
| 80 | - return bundle; | |
| 81 | -} | |
| 82 | - | |
| 83 | -NSBundle *YBIBVideoBundle(void) { | |
| 84 | - static NSBundle *bundle = nil; | |
| 85 | - static dispatch_once_t onceToken; | |
| 86 | - dispatch_once(&onceToken, ^{ | |
| 87 | - NSBundle *_bundle = [NSBundle bundleForClass:NSClassFromString(@"YBImageBrowser")]; | |
| 88 | - NSString *path = [_bundle pathForResource:@"YBImageBrowserVideo" ofType:@"bundle"]; | |
| 89 | - bundle = [NSBundle bundleWithPath:path]; | |
| 90 | - }); | |
| 91 | - return bundle; | |
| 92 | -} | |
| 93 | - | |
| 94 | -@implementation YBIBIconManager | |
| 95 | - | |
| 96 | -+ (instancetype)sharedManager { | |
| 97 | - static YBIBIconManager *manager = nil; | |
| 98 | - static dispatch_once_t onceToken; | |
| 99 | - dispatch_once(&onceToken, ^{ | |
| 100 | - manager = [YBIBIconManager new]; | |
| 101 | - }); | |
| 102 | - return manager; | |
| 103 | -} | |
| 104 | - | |
| 105 | -- (instancetype)init { | |
| 106 | - self = [super init]; | |
| 107 | - if (self) { | |
| 108 | - _loadingImage = ^UIImage * _Nullable{ | |
| 109 | - return [UIImage ybib_imageNamed:@"ybib_loading" bundle:YBIBDefaultBundle()]; | |
| 110 | - }; | |
| 111 | - | |
| 112 | - _toolSaveImage = ^UIImage * _Nullable{ | |
| 113 | - return [UIImage ybib_imageNamed:@"ybib_save" bundle:YBIBDefaultBundle()]; | |
| 114 | - }; | |
| 115 | - _toolMoreImage = ^UIImage * _Nullable{ | |
| 116 | - return [UIImage ybib_imageNamed:@"ybib_more" bundle:YBIBDefaultBundle()]; | |
| 117 | - }; | |
| 118 | - | |
| 119 | - _videoPlayImage = ^UIImage * _Nullable{ | |
| 120 | - return [UIImage ybib_imageNamed:@"ybib_play" bundle:YBIBVideoBundle()]; | |
| 121 | - }; | |
| 122 | - _videoPauseImage = ^UIImage * _Nullable{ | |
| 123 | - return [UIImage ybib_imageNamed:@"ybib_pause" bundle:YBIBVideoBundle()]; | |
| 124 | - }; | |
| 125 | - _videoCancelImage = ^UIImage * _Nullable{ | |
| 126 | - return [UIImage ybib_imageNamed:@"ybib_cancel" bundle:YBIBVideoBundle()]; | |
| 127 | - }; | |
| 128 | - _videoBigPlayImage = ^UIImage * _Nullable{ | |
| 129 | - return [UIImage ybib_imageNamed:@"ybib_bigPlay" bundle:YBIBVideoBundle()]; | |
| 130 | - }; | |
| 131 | - _videoDragCircleImage = ^UIImage * _Nullable{ | |
| 132 | - return [UIImage ybib_imageNamed:@"ybib_circlePoint" bundle:YBIBVideoBundle()]; | |
| 133 | - }; | |
| 134 | - } | |
| 135 | - return self; | |
| 136 | -} | |
| 137 | - | |
| 138 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBPhotoAlbumManager.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBPhotoAlbumManager.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/8/28. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <Photos/Photos.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface YBIBPhotoAlbumManager : NSObject | |
| 14 | - | |
| 15 | -/** | |
| 16 | - Get photo album authorization. | |
| 17 | - */ | |
| 18 | -+ (void)getPhotoAlbumAuthorizationSuccess:(void(^)(void))success failed:(void(^)(void))failed; | |
| 19 | - | |
| 20 | -/** | |
| 21 | - Get 'AVAsset' by 'PHAsset' asynchronously, callback is in child thread. | |
| 22 | - */ | |
| 23 | -+ (void)getAVAssetWithPHAsset:(PHAsset *)phAsset completion:(void(^)(AVAsset * _Nullable asset))completion; | |
| 24 | - | |
| 25 | -/** | |
| 26 | - Get 'ImageData' by 'PHAsset' synchronously, callback is in child thread. | |
| 27 | - */ | |
| 28 | -+ (void)getImageDataWithPHAsset:(PHAsset *)phAsset completion:(void(^)(NSData * _Nullable data))completion; | |
| 29 | - | |
| 30 | -@end | |
| 31 | - | |
| 32 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBPhotoAlbumManager.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBPhotoAlbumManager.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/8/28. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBPhotoAlbumManager.h" | |
| 10 | -#import "YBIBUtilities.h" | |
| 11 | - | |
| 12 | -@implementation YBIBPhotoAlbumManager | |
| 13 | - | |
| 14 | -+ (void)getAVAssetWithPHAsset:(PHAsset *)phAsset completion:(nonnull void (^)(AVAsset * _Nullable))completion { | |
| 15 | - PHVideoRequestOptions *options = [PHVideoRequestOptions new]; | |
| 16 | - options.networkAccessAllowed = YES; | |
| 17 | - [[PHImageManager defaultManager] requestAVAssetForVideo:phAsset options:options resultHandler:^(AVAsset * _Nullable asset, AVAudioMix * _Nullable audioMix, NSDictionary * _Nullable info) { | |
| 18 | - completion(asset); | |
| 19 | - }]; | |
| 20 | -} | |
| 21 | - | |
| 22 | -+ (void)getImageDataWithPHAsset:(PHAsset *)phAsset completion:(nonnull void (^)(NSData * _Nullable))completion { | |
| 23 | - PHImageRequestOptions *options = [PHImageRequestOptions new]; | |
| 24 | - options.networkAccessAllowed = YES; | |
| 25 | - options.resizeMode = PHImageRequestOptionsResizeModeNone; | |
| 26 | - // Only when this property is YES, the callback will in child thread. | |
| 27 | - options.synchronous = YES; | |
| 28 | - [[PHImageManager defaultManager] requestImageDataForAsset:phAsset options:options resultHandler:^(NSData * _Nullable imageData, NSString * _Nullable dataUTI, UIImageOrientation orientation, NSDictionary * _Nullable info) { | |
| 29 | - BOOL complete = ![[info objectForKey:PHImageCancelledKey] boolValue] && ![info objectForKey:PHImageErrorKey] && ![[info objectForKey:PHImageResultIsDegradedKey] boolValue]; | |
| 30 | - if (complete && imageData) { | |
| 31 | - completion(imageData); | |
| 32 | - } else { | |
| 33 | - completion(nil); | |
| 34 | - } | |
| 35 | - }]; | |
| 36 | -} | |
| 37 | - | |
| 38 | -+ (void)getPhotoAlbumAuthorizationSuccess:(void(^)(void))success failed:(void(^)(void))failed { | |
| 39 | - PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; | |
| 40 | - switch (status) { | |
| 41 | - case PHAuthorizationStatusDenied: | |
| 42 | - if (failed) failed(); | |
| 43 | - break; | |
| 44 | - case PHAuthorizationStatusRestricted: | |
| 45 | - if (failed) failed(); | |
| 46 | - break; | |
| 47 | - case PHAuthorizationStatusNotDetermined: { | |
| 48 | - [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status){ | |
| 49 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 50 | - if (status == PHAuthorizationStatusAuthorized) { | |
| 51 | - if (success) success(); | |
| 52 | - } else { | |
| 53 | - if (failed) failed(); | |
| 54 | - } | |
| 55 | - }) | |
| 56 | - }]; | |
| 57 | - } | |
| 58 | - break; | |
| 59 | - case PHAuthorizationStatusAuthorized: | |
| 60 | - if (success) success(); | |
| 61 | - break; | |
| 62 | - } | |
| 63 | -} | |
| 64 | - | |
| 65 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBSentinel.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBSentinel.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/18. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <Foundation/Foundation.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -/** | |
| 14 | - Thread safe. | |
| 15 | - */ | |
| 16 | -@interface YBIBSentinel : NSObject | |
| 17 | - | |
| 18 | -/// Returns the current value of the counter. | |
| 19 | -@property (readonly) int32_t value; | |
| 20 | - | |
| 21 | -/** | |
| 22 | - Increase the value atomically. | |
| 23 | - @return The new value. | |
| 24 | - */ | |
| 25 | -- (int32_t)increase; | |
| 26 | - | |
| 27 | -@end | |
| 28 | - | |
| 29 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBSentinel.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBSentinel.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/18. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBSentinel.h" | |
| 10 | -#import <libkern/OSAtomic.h> | |
| 11 | - | |
| 12 | -@implementation YBIBSentinel { | |
| 13 | - int32_t _value; | |
| 14 | -} | |
| 15 | - | |
| 16 | -- (int32_t)value { | |
| 17 | - return _value; | |
| 18 | -} | |
| 19 | - | |
| 20 | -- (int32_t)increase { | |
| 21 | - return OSAtomicIncrement32(&_value); | |
| 22 | -} | |
| 23 | - | |
| 24 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBUtilities.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBUtilities.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 杨少 on 2018/4/11. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | - | |
| 14 | -#define YBIB_DISPATCH_ASYNC(queue, block)\ | |
| 15 | -if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(queue)) == 0) {\ | |
| 16 | -block();\ | |
| 17 | -} else {\ | |
| 18 | -dispatch_async(queue, block);\ | |
| 19 | -} | |
| 20 | - | |
| 21 | -#define YBIB_DISPATCH_ASYNC_MAIN(block) YBIB_DISPATCH_ASYNC(dispatch_get_main_queue(), block) | |
| 22 | - | |
| 23 | - | |
| 24 | -#define YBIB_CODE_EXEC_TIME(KEY, ...) \ | |
| 25 | -CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent(); \ | |
| 26 | -__VA_ARGS__ \ | |
| 27 | -CFAbsoluteTime linkTime = (CFAbsoluteTimeGetCurrent() - startTime); \ | |
| 28 | -NSLog(@"%@ Time-Consuming: %fms", KEY, linkTime * 1000.0); | |
| 29 | - | |
| 30 | - | |
| 31 | -UIWindow * _Nonnull YBIBNormalWindow(void); | |
| 32 | - | |
| 33 | -UIViewController * _Nullable YBIBTopController(void); | |
| 34 | -UIViewController * _Nullable YBIBTopControllerByWindow(UIWindow *); | |
| 35 | - | |
| 36 | -BOOL YBIBLowMemory(void); | |
| 37 | - | |
| 38 | -BOOL YBIBIsIphoneXSeries(void); | |
| 39 | -CGFloat YBIBStatusbarHeight(void); | |
| 40 | -CGFloat YBIBSafeAreaBottomHeight(void); | |
| 41 | - | |
| 42 | -UIImage *YBIBSnapshotView(UIView *); | |
| 43 | - | |
| 44 | -/// This is orientation of 'YBImageBrowser' not 'UIDevice'. | |
| 45 | -UIEdgeInsets YBIBPaddingByBrowserOrientation(UIDeviceOrientation); | |
| 46 | - | |
| 47 | - | |
| 48 | -@interface YBIBUtilities : NSObject | |
| 49 | - | |
| 50 | -@end | |
| 51 | - | |
| 52 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Helper/YBIBUtilities.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBUtilities.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 杨少 on 2018/4/11. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBUtilities.h" | |
| 10 | -#import <sys/utsname.h> | |
| 11 | - | |
| 12 | - | |
| 13 | -UIWindow * _Nullable YBIBNormalWindow(void) { | |
| 14 | - UIWindow *window = [[UIApplication sharedApplication] keyWindow]; | |
| 15 | - if (window.windowLevel != UIWindowLevelNormal) { | |
| 16 | - NSArray *windows = [[UIApplication sharedApplication] windows]; | |
| 17 | - for(UIWindow *temp in windows) { | |
| 18 | - if (temp.windowLevel == UIWindowLevelNormal) { | |
| 19 | - return temp; | |
| 20 | - } | |
| 21 | - } | |
| 22 | - } | |
| 23 | - return window; | |
| 24 | -} | |
| 25 | - | |
| 26 | -UIViewController * _Nullable YBIBTopController(void) { | |
| 27 | - return YBIBTopControllerByWindow(YBIBNormalWindow()); | |
| 28 | -} | |
| 29 | - | |
| 30 | -UIViewController * _Nullable YBIBTopControllerByWindow(UIWindow *window) { | |
| 31 | - if (!window) return nil; | |
| 32 | - | |
| 33 | - UIViewController *top = nil; | |
| 34 | - id nextResponder; | |
| 35 | - if (window.subviews.count > 0) { | |
| 36 | - UIView *frontView = [window.subviews objectAtIndex:0]; | |
| 37 | - nextResponder = frontView.nextResponder; | |
| 38 | - } | |
| 39 | - if (nextResponder && [nextResponder isKindOfClass:UIViewController.class]) { | |
| 40 | - top = nextResponder; | |
| 41 | - } else { | |
| 42 | - top = window.rootViewController; | |
| 43 | - } | |
| 44 | - | |
| 45 | - while ([top isKindOfClass:UITabBarController.class] || [top isKindOfClass:UINavigationController.class] || top.presentedViewController) { | |
| 46 | - if ([top isKindOfClass:UITabBarController.class]) { | |
| 47 | - top = ((UITabBarController *)top).selectedViewController; | |
| 48 | - } else if ([top isKindOfClass:UINavigationController.class]) { | |
| 49 | - top = ((UINavigationController *)top).topViewController; | |
| 50 | - } else if (top.presentedViewController) { | |
| 51 | - top = top.presentedViewController; | |
| 52 | - } | |
| 53 | - } | |
| 54 | - return top; | |
| 55 | -} | |
| 56 | - | |
| 57 | -BOOL YBIBLowMemory(void) { | |
| 58 | - static BOOL lowMemory = NO; | |
| 59 | - static dispatch_once_t onceToken; | |
| 60 | - dispatch_once(&onceToken, ^{ | |
| 61 | - unsigned long long physicalMemory = [[NSProcessInfo processInfo] physicalMemory]; | |
| 62 | - lowMemory = physicalMemory > 0 && physicalMemory < 1024 * 1024 * 1500; | |
| 63 | - }); | |
| 64 | - return lowMemory; | |
| 65 | -} | |
| 66 | - | |
| 67 | -BOOL YBIBIsIphoneXSeries(void) { | |
| 68 | - return YBIBStatusbarHeight() > 20; | |
| 69 | -} | |
| 70 | - | |
| 71 | -CGFloat YBIBStatusbarHeight(void) { | |
| 72 | - CGFloat height = 0; | |
| 73 | - if (@available(iOS 11.0, *)) { | |
| 74 | - height = UIApplication.sharedApplication.delegate.window.safeAreaInsets.top; | |
| 75 | - } | |
| 76 | - if (height <= 0) { | |
| 77 | - height = UIApplication.sharedApplication.statusBarFrame.size.height; | |
| 78 | - } | |
| 79 | - if (height <= 0) { | |
| 80 | - height = 20; | |
| 81 | - } | |
| 82 | - return height; | |
| 83 | -} | |
| 84 | - | |
| 85 | -CGFloat YBIBSafeAreaBottomHeight(void) { | |
| 86 | - CGFloat bottom = 0; | |
| 87 | - if (@available(iOS 11.0, *)) { | |
| 88 | - bottom = UIApplication.sharedApplication.delegate.window.safeAreaInsets.bottom; | |
| 89 | - } | |
| 90 | - return bottom; | |
| 91 | -} | |
| 92 | - | |
| 93 | -UIImage *YBIBSnapshotView(UIView *view) { | |
| 94 | - UIGraphicsBeginImageContextWithOptions(view.bounds.size, YES, [UIScreen mainScreen].scale); | |
| 95 | - [view drawViewHierarchyInRect:view.bounds afterScreenUpdates:NO]; | |
| 96 | - UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); | |
| 97 | - UIGraphicsEndImageContext(); | |
| 98 | - return image; | |
| 99 | -} | |
| 100 | - | |
| 101 | -UIEdgeInsets YBIBPaddingByBrowserOrientation(UIDeviceOrientation orientation) { | |
| 102 | - UIEdgeInsets padding = UIEdgeInsetsZero; | |
| 103 | - if (!YBIBIsIphoneXSeries()) return padding; | |
| 104 | - | |
| 105 | - UIDeviceOrientation barOrientation = (UIDeviceOrientation)UIApplication.sharedApplication.statusBarOrientation; | |
| 106 | - | |
| 107 | - if (UIDeviceOrientationIsLandscape(orientation)) { | |
| 108 | - BOOL same = orientation == barOrientation; | |
| 109 | - BOOL reverse = !same && UIDeviceOrientationIsLandscape(barOrientation); | |
| 110 | - if (same) { | |
| 111 | - padding.bottom = YBIBSafeAreaBottomHeight(); | |
| 112 | - padding.top = 0; | |
| 113 | - } else if (reverse) { | |
| 114 | - padding.top = YBIBSafeAreaBottomHeight(); | |
| 115 | - padding.bottom = 0; | |
| 116 | - } | |
| 117 | - padding.left = padding.right = MAX(YBIBSafeAreaBottomHeight(), YBIBStatusbarHeight()); | |
| 118 | - } else { | |
| 119 | - if (orientation == UIDeviceOrientationPortrait) { | |
| 120 | - padding.top = YBIBStatusbarHeight(); | |
| 121 | - padding.bottom = barOrientation == UIDeviceOrientationPortrait ? YBIBSafeAreaBottomHeight() : 0; | |
| 122 | - } else { | |
| 123 | - padding.bottom = YBIBStatusbarHeight(); | |
| 124 | - padding.top = barOrientation == UIDeviceOrientationPortrait ? YBIBSafeAreaBottomHeight() : 0; | |
| 125 | - } | |
| 126 | - padding.left = padding.right = UIDeviceOrientationIsLandscape(barOrientation) ? YBIBSafeAreaBottomHeight() : 0 ; | |
| 127 | - } | |
| 128 | - return padding; | |
| 129 | -} | |
| 130 | - | |
| 131 | - | |
| 132 | -@implementation YBIBUtilities | |
| 133 | - | |
| 134 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageCache+Internal.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageCache+Internal.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/13. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBImageCache.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -typedef NS_ENUM(NSInteger, YBIBImageCacheType) { | |
| 14 | - YBIBImageCacheTypeOrigin, | |
| 15 | - YBIBImageCacheTypeCompressed | |
| 16 | -}; | |
| 17 | - | |
| 18 | -/** | |
| 19 | - Not thread safe. | |
| 20 | - */ | |
| 21 | -@interface YBIBImageCache () | |
| 22 | - | |
| 23 | -- (void)setImage:(UIImage *)image type:(YBIBImageCacheType)type forKey:(NSString *)key resident:(BOOL)resident; | |
| 24 | - | |
| 25 | -- (nullable UIImage *)imageForKey:(NSString *)key type:(YBIBImageCacheType)type; | |
| 26 | - | |
| 27 | -- (void)removeForKey:(NSString *)key; | |
| 28 | - | |
| 29 | -- (void)removeResidentForKey:(NSString *)key; | |
| 30 | - | |
| 31 | -@end | |
| 32 | - | |
| 33 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageCache.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageCache.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/13. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@class YBIBImageCache; | |
| 14 | - | |
| 15 | -@interface NSObject (YBIBImageCache) | |
| 16 | - | |
| 17 | -/// 图片浏览器持有的图片缓存管理类 | |
| 18 | -@property (nonatomic, strong, readonly) YBIBImageCache *ybib_imageCache; | |
| 19 | - | |
| 20 | -@end | |
| 21 | - | |
| 22 | - | |
| 23 | -@interface YBIBImageCache : NSObject | |
| 24 | - | |
| 25 | -/// 缓存数量限制(一个单位表示一个 YBIBImageData 产生的所有图片数据) | |
| 26 | -@property (nonatomic, assign) NSUInteger imageCacheCountLimit; | |
| 27 | - | |
| 28 | -@end | |
| 29 | - | |
| 30 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageCache.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageCache.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/13. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBImageCache.h" | |
| 10 | -#import "YBIBImageCache+Internal.h" | |
| 11 | -#import "YBIBUtilities.h" | |
| 12 | -#import <objc/runtime.h> | |
| 13 | - | |
| 14 | - | |
| 15 | -@implementation NSObject (YBIBImageCache) | |
| 16 | -static void *YBIBImageCacheKey = &YBIBImageCacheKey; | |
| 17 | -- (void)setYbib_imageCache:(YBIBImageCache *)ybib_imageCache { | |
| 18 | - objc_setAssociatedObject(self, YBIBImageCacheKey, ybib_imageCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC); | |
| 19 | -} | |
| 20 | -- (YBIBImageCache *)ybib_imageCache { | |
| 21 | - YBIBImageCache *cache = objc_getAssociatedObject(self, YBIBImageCacheKey); | |
| 22 | - if (!cache) { | |
| 23 | - cache = [YBIBImageCache new]; | |
| 24 | - self.ybib_imageCache = cache; | |
| 25 | - } | |
| 26 | - return cache; | |
| 27 | -} | |
| 28 | -@end | |
| 29 | - | |
| 30 | - | |
| 31 | -@interface YBIBImageCachePack : NSObject | |
| 32 | -@property (nonatomic, strong) UIImage *originImage; | |
| 33 | -@property (nonatomic, strong) UIImage *compressedImage; | |
| 34 | -@end | |
| 35 | -@implementation YBIBImageCachePack | |
| 36 | -@end | |
| 37 | - | |
| 38 | - | |
| 39 | -@implementation YBIBImageCache { | |
| 40 | - NSCache<NSString *, YBIBImageCachePack *> *_imageCache; | |
| 41 | - NSMutableDictionary<NSString *, YBIBImageCachePack *> *_residentCache; | |
| 42 | -} | |
| 43 | - | |
| 44 | -#pragma mark - life cycle | |
| 45 | - | |
| 46 | -- (void)dealloc { | |
| 47 | - [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; | |
| 48 | -} | |
| 49 | - | |
| 50 | -- (instancetype)init { | |
| 51 | - self = [super init]; | |
| 52 | - if (self) { | |
| 53 | - _imageCache = [NSCache new]; | |
| 54 | - _imageCache.countLimit = _imageCacheCountLimit = YBIBLowMemory() ? 6 : 12; | |
| 55 | - _residentCache = [NSMutableDictionary dictionary]; | |
| 56 | - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didReceiveMemoryWarning:) name:UIApplicationDidReceiveMemoryWarningNotification object:nil]; | |
| 57 | - } | |
| 58 | - return self; | |
| 59 | -} | |
| 60 | - | |
| 61 | -#pragma mark - event | |
| 62 | - | |
| 63 | -- (void)didReceiveMemoryWarning:(NSNotification *)notification { | |
| 64 | - [_imageCache removeAllObjects]; | |
| 65 | - [_residentCache removeAllObjects]; | |
| 66 | -} | |
| 67 | - | |
| 68 | -#pragma mark - public | |
| 69 | - | |
| 70 | -- (void)setImage:(UIImage *)image type:(YBIBImageCacheType)type forKey:(NSString *)key resident:(BOOL)resident { | |
| 71 | - YBIBImageCachePack *pack = [_imageCache objectForKey:key]; | |
| 72 | - if (!pack) { | |
| 73 | - pack = [YBIBImageCachePack new]; | |
| 74 | - [_imageCache setObject:pack forKey:key]; | |
| 75 | - } | |
| 76 | - switch (type) { | |
| 77 | - case YBIBImageCacheTypeOrigin: | |
| 78 | - pack.originImage = image; | |
| 79 | - break; | |
| 80 | - case YBIBImageCacheTypeCompressed: | |
| 81 | - pack.compressedImage = image; | |
| 82 | - break; | |
| 83 | - } | |
| 84 | - [_residentCache setObject:pack forKey:key]; | |
| 85 | -} | |
| 86 | - | |
| 87 | -- (UIImage *)imageForKey:(NSString *)key type:(YBIBImageCacheType)type { | |
| 88 | - YBIBImageCachePack *pack = [_imageCache objectForKey:key] ?: [_residentCache objectForKey:key]; | |
| 89 | - switch (type) { | |
| 90 | - case YBIBImageCacheTypeOrigin: return pack.originImage; | |
| 91 | - case YBIBImageCacheTypeCompressed: return pack.compressedImage; | |
| 92 | - default: return nil; | |
| 93 | - } | |
| 94 | -} | |
| 95 | - | |
| 96 | -- (void)removeForKey:(NSString *)key { | |
| 97 | - [_imageCache removeObjectForKey:key]; | |
| 98 | - [_residentCache removeObjectForKey:key]; | |
| 99 | -} | |
| 100 | - | |
| 101 | -- (void)removeResidentForKey:(NSString *)key { | |
| 102 | - [_residentCache removeObjectForKey:key]; | |
| 103 | -} | |
| 104 | - | |
| 105 | -#pragma mark - setter | |
| 106 | - | |
| 107 | -- (void)setImageCacheCountLimit:(NSUInteger)imageCacheCountLimit { | |
| 108 | - _imageCacheCountLimit = imageCacheCountLimit; | |
| 109 | - _imageCache.countLimit = imageCacheCountLimit; | |
| 110 | -} | |
| 111 | - | |
| 112 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageCell+Internal.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageCell+Internal.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/12/23. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBImageCell.h" | |
| 10 | -#import "YBIBImageScrollView.h" | |
| 11 | - | |
| 12 | -NS_ASSUME_NONNULL_BEGIN | |
| 13 | - | |
| 14 | -@interface YBIBImageCell () | |
| 15 | - | |
| 16 | -@property (nonatomic, strong) YBIBImageScrollView *imageScrollView; | |
| 17 | - | |
| 18 | -@property (nonatomic, strong) UIImageView *tailoringImageView; | |
| 19 | - | |
| 20 | -@end | |
| 21 | - | |
| 22 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageCell.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageCell.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/5. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBCellProtocol.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface YBIBImageCell : UICollectionViewCell <YBIBCellProtocol> | |
| 14 | - | |
| 15 | -@end | |
| 16 | - | |
| 17 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageCell.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageCell.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/5. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBImageCell.h" | |
| 10 | -#import "YBIBImageData.h" | |
| 11 | -#import "YBIBIconManager.h" | |
| 12 | -#import "YBIBImageCell+Internal.h" | |
| 13 | -#import "YBIBImageData+Internal.h" | |
| 14 | -#import "YBIBCopywriter.h" | |
| 15 | -#import "YBIBUtilities.h" | |
| 16 | - | |
| 17 | -@interface YBIBImageCell () <YBIBImageDataDelegate, UIScrollViewDelegate, UIGestureRecognizerDelegate> | |
| 18 | -@end | |
| 19 | - | |
| 20 | -@implementation YBIBImageCell { | |
| 21 | - CGPoint _interactStartPoint; | |
| 22 | - BOOL _interacting; | |
| 23 | -} | |
| 24 | - | |
| 25 | -#pragma mark - life cycle | |
| 26 | - | |
| 27 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 28 | - self = [super initWithFrame:frame]; | |
| 29 | - if (self) { | |
| 30 | - [self initValue]; | |
| 31 | - [self.contentView addSubview:self.imageScrollView]; | |
| 32 | - [self addGesture]; | |
| 33 | - } | |
| 34 | - return self; | |
| 35 | -} | |
| 36 | - | |
| 37 | -- (void)layoutSubviews { | |
| 38 | - [super layoutSubviews]; | |
| 39 | - self.imageScrollView.frame = self.bounds; | |
| 40 | -} | |
| 41 | - | |
| 42 | -- (void)initValue { | |
| 43 | - _interactStartPoint = CGPointZero; | |
| 44 | - _interacting = NO; | |
| 45 | -} | |
| 46 | - | |
| 47 | -- (void)prepareForReuse { | |
| 48 | - ((YBIBImageData *)self.yb_cellData).delegate = nil; | |
| 49 | - [self.imageScrollView reset]; | |
| 50 | - [self hideTailoringImageView]; | |
| 51 | - [self hideAuxiliaryView]; | |
| 52 | - [super prepareForReuse]; | |
| 53 | -} | |
| 54 | - | |
| 55 | -#pragma mark - <YBIBCellProtocol> | |
| 56 | - | |
| 57 | -@synthesize yb_currentOrientation = _yb_currentOrientation; | |
| 58 | -@synthesize yb_containerSize = _yb_containerSize; | |
| 59 | -@synthesize yb_backView = _yb_backView; | |
| 60 | -@synthesize yb_collectionView = _yb_collectionView; | |
| 61 | -@synthesize yb_isTransitioning = _yb_isTransitioning; | |
| 62 | -@synthesize yb_isRotating = _yb_isRotating; | |
| 63 | -@synthesize yb_auxiliaryViewHandler = _yb_auxiliaryViewHandler; | |
| 64 | -@synthesize yb_hideStatusBar = _yb_hideStatusBar; | |
| 65 | -@synthesize yb_hideBrowser = _yb_hideBrowser; | |
| 66 | -@synthesize yb_hideToolViews = _yb_hideToolViews; | |
| 67 | -@synthesize yb_cellData = _yb_cellData; | |
| 68 | -@synthesize yb_cellIsInCenter = _yb_cellIsInCenter; | |
| 69 | -@synthesize yb_selfPage = _yb_selfPage; | |
| 70 | -@synthesize yb_currentPage = _yb_currentPage; | |
| 71 | - | |
| 72 | -- (void)setYb_cellData:(id<YBIBDataProtocol>)yb_cellData { | |
| 73 | - _yb_cellData = yb_cellData; | |
| 74 | - ((YBIBImageData *)yb_cellData).delegate = self; | |
| 75 | -} | |
| 76 | - | |
| 77 | -- (UIView *)yb_foregroundView { | |
| 78 | - return self.imageScrollView.imageView; | |
| 79 | -} | |
| 80 | - | |
| 81 | -- (void)yb_orientationWillChangeWithExpectOrientation:(UIDeviceOrientation)orientation { | |
| 82 | - [self hideTailoringImageView]; | |
| 83 | -} | |
| 84 | - | |
| 85 | -- (void)yb_orientationChangeAnimationWithExpectOrientation:(UIDeviceOrientation)orientation { | |
| 86 | - [self updateImageLayoutWithOrientation:orientation previousImageSize:self.imageScrollView.imageView.image.size]; | |
| 87 | -} | |
| 88 | - | |
| 89 | -#pragma mark - private | |
| 90 | - | |
| 91 | -- (CGSize)contentSizeWithContainerSize:(CGSize)containerSize imageViewFrame:(CGRect)imageViewFrame { | |
| 92 | - return CGSizeMake(MAX(containerSize.width, imageViewFrame.size.width), MAX(containerSize.height, imageViewFrame.size.height)); | |
| 93 | -} | |
| 94 | - | |
| 95 | -- (void)updateImageLayoutWithOrientation:(UIDeviceOrientation)orientation previousImageSize:(CGSize)previousImageSize { | |
| 96 | - if (_interacting) [self restoreInteractionWithDuration:0]; | |
| 97 | - | |
| 98 | - YBIBImageData *data = self.yb_cellData; | |
| 99 | - | |
| 100 | - CGSize imageSize; | |
| 101 | - | |
| 102 | - UIImage *image = self.imageScrollView.imageView.image; | |
| 103 | - YBIBScrollImageType imageType = self.imageScrollView.imageType; | |
| 104 | - if (imageType == YBIBScrollImageTypeCompressed) { | |
| 105 | - imageSize = data.originImage ? data.originImage.size : image.size; | |
| 106 | - } else { | |
| 107 | - imageSize = image.size; | |
| 108 | - } | |
| 109 | - | |
| 110 | - CGSize containerSize = self.yb_containerSize(orientation); | |
| 111 | - CGRect imageViewFrame = [data.layout yb_imageViewFrameWithContainerSize:containerSize imageSize:imageSize orientation:orientation]; | |
| 112 | - CGSize contentSize = [self contentSizeWithContainerSize:containerSize imageViewFrame:imageViewFrame]; | |
| 113 | - CGFloat maxZoomScale = imageType == YBIBScrollImageTypeThumb ? 1 : [data.layout yb_maximumZoomScaleWithContainerSize:containerSize imageSize:imageSize orientation:orientation]; | |
| 114 | - | |
| 115 | - // 'zoomScale' must set before 'contentSize' and 'imageView.frame'. | |
| 116 | - self.imageScrollView.zoomScale = 1; | |
| 117 | - self.imageScrollView.contentSize = contentSize; | |
| 118 | - self.imageScrollView.minimumZoomScale = 1; | |
| 119 | - self.imageScrollView.maximumZoomScale = maxZoomScale; | |
| 120 | - | |
| 121 | - CGFloat scale; | |
| 122 | - if (previousImageSize.width > 0 && previousImageSize.height > 0) { | |
| 123 | - scale = imageSize.width / imageSize.height - previousImageSize.width / previousImageSize.height; | |
| 124 | - } else { | |
| 125 | - scale = 0; | |
| 126 | - } | |
| 127 | - // '0.001' is admissible error. | |
| 128 | - if (ABS(scale) <= 0.001) { | |
| 129 | - self.imageScrollView.imageView.frame = imageViewFrame; | |
| 130 | - } else { | |
| 131 | - [UIView animateWithDuration:0.25 animations:^{ | |
| 132 | - self.imageScrollView.imageView.frame = imageViewFrame; | |
| 133 | - }]; | |
| 134 | - } | |
| 135 | -} | |
| 136 | - | |
| 137 | -- (void)cuttingImage { | |
| 138 | - // This method has been delayed called, so 'browser' may be in transit now. | |
| 139 | - if (self.yb_isTransitioning()) return; | |
| 140 | - if (_interacting) return; | |
| 141 | - | |
| 142 | - YBIBImageData *data = self.yb_cellData; | |
| 143 | - if (!data.originImage) return; | |
| 144 | - | |
| 145 | - if (self.imageScrollView.zoomScale < data.cuttingZoomScale) return; | |
| 146 | - | |
| 147 | - if ([data shouldCompress]) { | |
| 148 | - [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(cuttingImage_) object:nil]; | |
| 149 | - [self performSelector:@selector(cuttingImage_) withObject:nil afterDelay:0.15]; | |
| 150 | - } | |
| 151 | -} | |
| 152 | -- (void)cuttingImage_ { | |
| 153 | - YBIBImageData *data = self.yb_cellData; | |
| 154 | - if (!data.originImage) return; | |
| 155 | - | |
| 156 | - CGFloat scale = data.originImage.size.width / self.imageScrollView.contentSize.width; | |
| 157 | - CGFloat x = self.imageScrollView.contentOffset.x * scale, | |
| 158 | - y = self.imageScrollView.contentOffset.y * scale, | |
| 159 | - width = self.imageScrollView.bounds.size.width * scale, | |
| 160 | - height = self.imageScrollView.bounds.size.height * scale; | |
| 161 | - | |
| 162 | - __weak typeof(self) wSelf = self; | |
| 163 | - [data cuttingImageToRect:CGRectMake(x, y, width, height) complete:^(UIImage *image) { | |
| 164 | - if (!image) return; | |
| 165 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 166 | - __strong typeof(wSelf) self = wSelf; | |
| 167 | - if (!self) return; | |
| 168 | - if (data == self.yb_cellData && !self.imageScrollView.isDragging && !self->_interacting && !self.yb_isTransitioning()) { | |
| 169 | - [self showTailoringImageView:image]; | |
| 170 | - } | |
| 171 | - }) | |
| 172 | - }]; | |
| 173 | -} | |
| 174 | - | |
| 175 | -- (void)showTailoringImageView:(UIImage *)image { | |
| 176 | - CGSize containerSize = self.yb_containerSize(self.yb_currentOrientation()); | |
| 177 | - if (!self.tailoringImageView.superview) { | |
| 178 | - [self.contentView addSubview:self.tailoringImageView]; | |
| 179 | - } | |
| 180 | - self.tailoringImageView.frame = CGRectMake(0, 0, containerSize.width, containerSize.height); | |
| 181 | - self.tailoringImageView.hidden = NO; | |
| 182 | - self.tailoringImageView.image = image; | |
| 183 | -} | |
| 184 | - | |
| 185 | -- (void)hideTailoringImageView { | |
| 186 | - // Don't use 'getter' method, because it's according to the need to load. | |
| 187 | - if (_tailoringImageView) { | |
| 188 | - self.tailoringImageView.hidden = YES; | |
| 189 | - } | |
| 190 | -} | |
| 191 | - | |
| 192 | -- (void)hideAuxiliaryView { | |
| 193 | - [self.yb_auxiliaryViewHandler() yb_hideLoadingWithContainer:self]; | |
| 194 | - [self.yb_auxiliaryViewHandler() yb_hideToastWithContainer:self]; | |
| 195 | -} | |
| 196 | - | |
| 197 | -- (void)hideBrowser { | |
| 198 | - ((YBIBImageData *)self.yb_cellData).delegate = nil; | |
| 199 | - [self hideTailoringImageView]; | |
| 200 | - [self hideAuxiliaryView]; | |
| 201 | - self.yb_hideBrowser(); | |
| 202 | - _interacting = NO; | |
| 203 | -} | |
| 204 | - | |
| 205 | -#pragma mark - <YBIBImageDataDelegate> | |
| 206 | - | |
| 207 | -- (void)yb_imageData:(YBIBImageData *)data startLoadingWithStatus:(YBIBImageLoadingStatus)status { | |
| 208 | - switch (status) { | |
| 209 | - case YBIBImageLoadingStatusDecoding: { | |
| 210 | - if (!self.imageScrollView.imageView.image) { | |
| 211 | - [self.yb_auxiliaryViewHandler() yb_showLoadingWithContainer:self]; | |
| 212 | - } | |
| 213 | - } | |
| 214 | - break; | |
| 215 | - case YBIBImageLoadingStatusProcessing: { | |
| 216 | - if (!self.imageScrollView.imageView.image) { | |
| 217 | - [self.yb_auxiliaryViewHandler() yb_showLoadingWithContainer:self]; | |
| 218 | - } | |
| 219 | - } | |
| 220 | - break; | |
| 221 | - case YBIBImageLoadingStatusCompressing: { | |
| 222 | - if (!self.imageScrollView.imageView.image) { | |
| 223 | - [self.yb_auxiliaryViewHandler() yb_showLoadingWithContainer:self]; | |
| 224 | - } | |
| 225 | - } | |
| 226 | - break; | |
| 227 | - case YBIBImageLoadingStatusReadingPHAsset: { | |
| 228 | - if (!self.imageScrollView.imageView.image) { | |
| 229 | - [self.yb_auxiliaryViewHandler() yb_showLoadingWithContainer:self]; | |
| 230 | - } | |
| 231 | - } | |
| 232 | - break; | |
| 233 | - case YBIBImageLoadingStatusNone: { | |
| 234 | - [self hideAuxiliaryView]; | |
| 235 | - } | |
| 236 | - break; | |
| 237 | - default: | |
| 238 | - break; | |
| 239 | - } | |
| 240 | -} | |
| 241 | - | |
| 242 | -- (void)yb_imageData:(YBIBImageData *)data readyForImage:(__kindof UIImage *)image { | |
| 243 | - [self.yb_auxiliaryViewHandler() yb_hideLoadingWithContainer:self]; | |
| 244 | - if (self.imageScrollView.imageView.image == image) return; | |
| 245 | - | |
| 246 | - CGSize size = self.imageScrollView.imageView.image.size; | |
| 247 | - [self.imageScrollView setImage:image type:YBIBScrollImageTypeOriginal]; | |
| 248 | - [self updateImageLayoutWithOrientation:self.yb_currentOrientation() previousImageSize:size]; | |
| 249 | -} | |
| 250 | - | |
| 251 | -- (void)yb_imageData:(YBIBImageData *)data readyForCompressedImage:(__kindof UIImage *)image { | |
| 252 | - [self.yb_auxiliaryViewHandler() yb_hideLoadingWithContainer:self]; | |
| 253 | - if (self.imageScrollView.imageView.image == image) return; | |
| 254 | - | |
| 255 | - CGSize size = self.imageScrollView.imageView.image.size; | |
| 256 | - [self.imageScrollView setImage:image type:YBIBScrollImageTypeCompressed]; | |
| 257 | - [self updateImageLayoutWithOrientation:self.yb_currentOrientation() previousImageSize:size]; | |
| 258 | -} | |
| 259 | - | |
| 260 | -- (void)yb_imageData:(YBIBImageData *)data readyForThumbImage:(__kindof UIImage *)image { | |
| 261 | - if (self.imageScrollView.imageView.image) return; | |
| 262 | - | |
| 263 | - [self.imageScrollView setImage:image type:YBIBScrollImageTypeThumb]; | |
| 264 | - [self updateImageLayoutWithOrientation:self.yb_currentOrientation() previousImageSize:image.size]; | |
| 265 | -} | |
| 266 | - | |
| 267 | -- (void)yb_imageIsInvalidForData:(YBIBImageData *)data { | |
| 268 | - [self.yb_auxiliaryViewHandler() yb_hideLoadingWithContainer:self]; | |
| 269 | - NSString *imageIsInvalid = [YBIBCopywriter sharedCopywriter].imageIsInvalid; | |
| 270 | - if (self.imageScrollView.imageView.image) { | |
| 271 | - [self.yb_auxiliaryViewHandler() yb_showIncorrectToastWithContainer:self text:imageIsInvalid]; | |
| 272 | - } else { | |
| 273 | - [self.yb_auxiliaryViewHandler() yb_showLoadingWithContainer:self text:imageIsInvalid]; | |
| 274 | - } | |
| 275 | -} | |
| 276 | - | |
| 277 | -- (void)yb_imageData:(YBIBImageData *)data downloadProgress:(CGFloat)progress { | |
| 278 | - [self.yb_auxiliaryViewHandler() yb_showLoadingWithContainer:self progress:progress]; | |
| 279 | -} | |
| 280 | - | |
| 281 | -- (void)yb_imageDownloadFailedForData:(YBIBImageData *)data { | |
| 282 | - if (self.imageScrollView.imageView.image) { | |
| 283 | - [self.yb_auxiliaryViewHandler() yb_hideLoadingWithContainer:self]; | |
| 284 | - [self.yb_auxiliaryViewHandler() yb_showIncorrectToastWithContainer:self text:[YBIBCopywriter sharedCopywriter].downloadFailed]; | |
| 285 | - } else { | |
| 286 | - [self.yb_auxiliaryViewHandler() yb_showLoadingWithContainer:self text:[YBIBCopywriter sharedCopywriter].downloadFailed]; | |
| 287 | - } | |
| 288 | -} | |
| 289 | - | |
| 290 | -#pragma mark - gesture | |
| 291 | - | |
| 292 | -- (void)addGesture { | |
| 293 | - UITapGestureRecognizer *tapSingle = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToTapSingle:)]; | |
| 294 | - tapSingle.numberOfTapsRequired = 1; | |
| 295 | - UITapGestureRecognizer *tapDouble = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToTapDouble:)]; | |
| 296 | - tapDouble.numberOfTapsRequired = 2; | |
| 297 | - UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToPan:)]; | |
| 298 | - pan.maximumNumberOfTouches = 1; | |
| 299 | - pan.delegate = self; | |
| 300 | - | |
| 301 | - [tapSingle requireGestureRecognizerToFail:tapDouble]; | |
| 302 | - [tapSingle requireGestureRecognizerToFail:pan]; | |
| 303 | - [tapDouble requireGestureRecognizerToFail:pan]; | |
| 304 | - | |
| 305 | - [self addGestureRecognizer:tapSingle]; | |
| 306 | - [self addGestureRecognizer:tapDouble]; | |
| 307 | - [self addGestureRecognizer:pan]; | |
| 308 | -} | |
| 309 | - | |
| 310 | -- (void)respondsToTapSingle:(UITapGestureRecognizer *)tap { | |
| 311 | - if (self.yb_isRotating()) return; | |
| 312 | - | |
| 313 | - YBIBImageData *data = self.yb_cellData; | |
| 314 | - if (data.singleTouchBlock) { | |
| 315 | - data.singleTouchBlock(data); | |
| 316 | - } else { | |
| 317 | - [self hideTailoringImageView]; | |
| 318 | - [self hideAuxiliaryView]; | |
| 319 | - self.yb_hideBrowser(); | |
| 320 | - } | |
| 321 | -} | |
| 322 | - | |
| 323 | -- (void)respondsToTapDouble:(UITapGestureRecognizer *)tap { | |
| 324 | - if (self.yb_isRotating()) return; | |
| 325 | - | |
| 326 | - [self hideTailoringImageView]; | |
| 327 | - | |
| 328 | - UIScrollView *scrollView = self.imageScrollView; | |
| 329 | - UIView *zoomView = [self viewForZoomingInScrollView:scrollView]; | |
| 330 | - CGPoint point = [tap locationInView:zoomView]; | |
| 331 | - if (!CGRectContainsPoint(zoomView.bounds, point)) return; | |
| 332 | - if (scrollView.zoomScale == scrollView.maximumZoomScale) { | |
| 333 | - [scrollView setZoomScale:1 animated:YES]; | |
| 334 | - } else { | |
| 335 | - [scrollView zoomToRect:CGRectMake(point.x, point.y, 1, 1) animated:YES]; | |
| 336 | - } | |
| 337 | -} | |
| 338 | - | |
| 339 | -- (void)respondsToPan:(UIPanGestureRecognizer *)pan { | |
| 340 | - if (self.yb_isRotating()) return; | |
| 341 | - | |
| 342 | - YBIBInteractionProfile *profile = ((YBIBImageData *)self.yb_cellData).interactionProfile; | |
| 343 | - if (profile.disable) return; | |
| 344 | - if ((CGRectIsEmpty(self.imageScrollView.imageView.frame) || !self.imageScrollView.imageView.image)) return; | |
| 345 | - | |
| 346 | - CGPoint point = [pan locationInView:self]; | |
| 347 | - CGSize containerSize = self.yb_containerSize(self.yb_currentOrientation()); | |
| 348 | - | |
| 349 | - if (pan.state == UIGestureRecognizerStateBegan) { | |
| 350 | - _interactStartPoint = point; | |
| 351 | - } else if (pan.state == UIGestureRecognizerStateCancelled || pan.state == UIGestureRecognizerStateEnded || pan.state == UIGestureRecognizerStateRecognized || pan.state == UIGestureRecognizerStateFailed) { | |
| 352 | - | |
| 353 | - // End. | |
| 354 | - if (_interacting) { | |
| 355 | - CGPoint velocity = [pan velocityInView:self.imageScrollView]; | |
| 356 | - | |
| 357 | - BOOL velocityArrive = ABS(velocity.y) > profile.dismissVelocityY; | |
| 358 | - BOOL distanceArrive = ABS(point.y - _interactStartPoint.y) > containerSize.height * profile.dismissScale; | |
| 359 | - | |
| 360 | - BOOL shouldDismiss = distanceArrive || velocityArrive; | |
| 361 | - if (shouldDismiss) { | |
| 362 | - [self hideBrowser]; | |
| 363 | - } else { | |
| 364 | - [self restoreInteractionWithDuration:profile.restoreDuration]; | |
| 365 | - } | |
| 366 | - } | |
| 367 | - | |
| 368 | - } else if (pan.state == UIGestureRecognizerStateChanged) { | |
| 369 | - if (_interacting) { | |
| 370 | - | |
| 371 | - // Change. | |
| 372 | - self.imageScrollView.center = point; | |
| 373 | - CGFloat scale = 1 - ABS(point.y - _interactStartPoint.y) / (containerSize.height * 1.2); | |
| 374 | - if (scale > 1) scale = 1; | |
| 375 | - if (scale < 0.35) scale = 0.35; | |
| 376 | - self.imageScrollView.transform = CGAffineTransformMakeScale(scale, scale); | |
| 377 | - | |
| 378 | - CGFloat alpha = 1 - ABS(point.y - _interactStartPoint.y) / (containerSize.height * 0.7); | |
| 379 | - if (alpha > 1) alpha = 1; | |
| 380 | - if (alpha < 0) alpha = 0; | |
| 381 | - self.yb_backView.backgroundColor = [self.yb_backView.backgroundColor colorWithAlphaComponent:alpha]; | |
| 382 | - | |
| 383 | - } else { | |
| 384 | - | |
| 385 | - // Start. | |
| 386 | - if (CGPointEqualToPoint(_interactStartPoint, CGPointZero) || self.yb_currentPage() != self.yb_selfPage() || !self.yb_cellIsInCenter() || self.imageScrollView.isZooming) return; | |
| 387 | - | |
| 388 | - CGPoint velocity = [pan velocityInView:self.imageScrollView]; | |
| 389 | - CGFloat triggerDistance = profile.triggerDistance; | |
| 390 | - CGFloat offsetY = self.imageScrollView.contentOffset.y, height = self.imageScrollView.bounds.size.height; | |
| 391 | - | |
| 392 | - BOOL distanceArrive = ABS(point.x - _interactStartPoint.x) < triggerDistance && ABS(velocity.x) < 500; | |
| 393 | - BOOL upArrive = point.y - _interactStartPoint.y > triggerDistance && offsetY <= 1; | |
| 394 | - BOOL downArrive = point.y - _interactStartPoint.y < -triggerDistance && offsetY + height >= MAX(self.imageScrollView.contentSize.height, height) - 1; | |
| 395 | - | |
| 396 | - BOOL shouldStart = (upArrive || downArrive) && distanceArrive; | |
| 397 | - if (!shouldStart) return; | |
| 398 | - | |
| 399 | - _interactStartPoint = point; | |
| 400 | - | |
| 401 | - CGRect startFrame = self.imageScrollView.frame; | |
| 402 | - CGFloat anchorX = point.x / startFrame.size.width, anchorY = point.y / startFrame.size.height; | |
| 403 | - self.imageScrollView.layer.anchorPoint = CGPointMake(anchorX, anchorY); | |
| 404 | - self.imageScrollView.userInteractionEnabled = NO; | |
| 405 | - self.imageScrollView.scrollEnabled = NO; | |
| 406 | - self.imageScrollView.center = point; | |
| 407 | - | |
| 408 | - self.yb_hideToolViews(YES); | |
| 409 | - self.yb_hideStatusBar(NO); | |
| 410 | - self.yb_collectionView().scrollEnabled = NO; | |
| 411 | - [self hideTailoringImageView]; | |
| 412 | - | |
| 413 | - _interacting = YES; | |
| 414 | - } | |
| 415 | - } | |
| 416 | -} | |
| 417 | - | |
| 418 | -- (void)restoreInteractionWithDuration:(NSTimeInterval)duration { | |
| 419 | - CGSize containerSize = self.yb_containerSize(self.yb_currentOrientation()); | |
| 420 | - | |
| 421 | - void (^animations)(void) = ^{ | |
| 422 | - self.yb_backView.backgroundColor = [self.yb_backView.backgroundColor colorWithAlphaComponent:1]; | |
| 423 | - | |
| 424 | - CGPoint anchorPoint = self.imageScrollView.layer.anchorPoint; | |
| 425 | - self.imageScrollView.center = CGPointMake(containerSize.width * anchorPoint.x, containerSize.height * anchorPoint.y); | |
| 426 | - self.imageScrollView.transform = CGAffineTransformIdentity; | |
| 427 | - }; | |
| 428 | - void (^completion)(BOOL finished) = ^(BOOL finished){ | |
| 429 | - self.imageScrollView.layer.anchorPoint = CGPointMake(0.5, 0.5); | |
| 430 | - self.imageScrollView.center = CGPointMake(containerSize.width * 0.5, containerSize.height * 0.5); | |
| 431 | - self.imageScrollView.userInteractionEnabled = YES; | |
| 432 | - self.imageScrollView.scrollEnabled = YES; | |
| 433 | - | |
| 434 | - self.yb_hideToolViews(NO); | |
| 435 | - self.yb_hideStatusBar(YES); | |
| 436 | - self.yb_collectionView().scrollEnabled = YES; | |
| 437 | - [self cuttingImage]; | |
| 438 | - | |
| 439 | - self->_interactStartPoint = CGPointZero; | |
| 440 | - self->_interacting = NO; | |
| 441 | - }; | |
| 442 | - | |
| 443 | - if (duration <= 0) { | |
| 444 | - animations(); | |
| 445 | - completion(NO); | |
| 446 | - } else { | |
| 447 | - [UIView animateWithDuration:duration animations:animations completion:completion]; | |
| 448 | - } | |
| 449 | -} | |
| 450 | - | |
| 451 | -#pragma mark - <UIScrollViewDelegate> | |
| 452 | - | |
| 453 | -- (void)scrollViewDidZoom:(UIScrollView *)scrollView { | |
| 454 | - YBIBImageData *data = self.yb_cellData; | |
| 455 | - if (data.imageDidZoomBlock) { | |
| 456 | - data.imageDidZoomBlock(data, scrollView); | |
| 457 | - } | |
| 458 | - | |
| 459 | - CGRect imageViewFrame = self.imageScrollView.imageView.frame; | |
| 460 | - CGFloat width = imageViewFrame.size.width, | |
| 461 | - height = imageViewFrame.size.height, | |
| 462 | - sHeight = scrollView.bounds.size.height, | |
| 463 | - sWidth = scrollView.bounds.size.width; | |
| 464 | - if (height > sHeight) { | |
| 465 | - imageViewFrame.origin.y = 0; | |
| 466 | - } else { | |
| 467 | - imageViewFrame.origin.y = (sHeight - height) / 2.0; | |
| 468 | - } | |
| 469 | - if (width > sWidth) { | |
| 470 | - imageViewFrame.origin.x = 0; | |
| 471 | - } else { | |
| 472 | - imageViewFrame.origin.x = (sWidth - width) / 2.0; | |
| 473 | - } | |
| 474 | - self.imageScrollView.imageView.frame = imageViewFrame; | |
| 475 | -} | |
| 476 | - | |
| 477 | -- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView { | |
| 478 | - return self.imageScrollView.imageView; | |
| 479 | -} | |
| 480 | - | |
| 481 | -- (void)scrollViewDidScroll:(UIScrollView *)scrollView { | |
| 482 | - YBIBImageData *data = self.yb_cellData; | |
| 483 | - if (data.imageDidScrollBlock) { | |
| 484 | - data.imageDidScrollBlock(data, scrollView); | |
| 485 | - } | |
| 486 | - | |
| 487 | - [self cuttingImage]; | |
| 488 | -} | |
| 489 | - | |
| 490 | -- (void)scrollViewWillBeginZooming:(UIScrollView *)scrollView withView:(UIView *)view { | |
| 491 | - [self hideTailoringImageView]; | |
| 492 | -} | |
| 493 | - | |
| 494 | -- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { | |
| 495 | - [self hideTailoringImageView]; | |
| 496 | -} | |
| 497 | - | |
| 498 | -#pragma mark - <UIGestureRecognizerDelegate> | |
| 499 | - | |
| 500 | -- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { | |
| 501 | - return YES; | |
| 502 | -} | |
| 503 | - | |
| 504 | -#pragma mark - getters | |
| 505 | - | |
| 506 | -- (YBIBImageScrollView *)imageScrollView { | |
| 507 | - if (!_imageScrollView) { | |
| 508 | - _imageScrollView = [YBIBImageScrollView new]; | |
| 509 | - _imageScrollView.delegate = self; | |
| 510 | - } | |
| 511 | - return _imageScrollView; | |
| 512 | -} | |
| 513 | - | |
| 514 | -- (UIImageView *)tailoringImageView { | |
| 515 | - if (!_tailoringImageView) { | |
| 516 | - _tailoringImageView = [UIImageView new]; | |
| 517 | - _tailoringImageView.contentMode = UIViewContentModeScaleAspectFit; | |
| 518 | - } | |
| 519 | - return _tailoringImageView; | |
| 520 | -} | |
| 521 | - | |
| 522 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageData+Internal.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageData+Internal.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/12. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBImageData.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -typedef NS_ENUM(NSInteger, YBIBImageLoadingStatus) { | |
| 14 | - YBIBImageLoadingStatusNone, | |
| 15 | - YBIBImageLoadingStatusCompressing, | |
| 16 | - YBIBImageLoadingStatusDecoding, | |
| 17 | - YBIBImageLoadingStatusQuerying, | |
| 18 | - YBIBImageLoadingStatusProcessing, | |
| 19 | - YBIBImageLoadingStatusDownloading, | |
| 20 | - YBIBImageLoadingStatusReadingPHAsset, | |
| 21 | -}; | |
| 22 | - | |
| 23 | -@class YBIBImageData; | |
| 24 | - | |
| 25 | -@protocol YBIBImageDataDelegate <NSObject> | |
| 26 | -@required | |
| 27 | - | |
| 28 | -- (void)yb_imageData:(YBIBImageData *)data startLoadingWithStatus:(YBIBImageLoadingStatus)status; | |
| 29 | - | |
| 30 | -- (void)yb_imageIsInvalidForData:(YBIBImageData *)data; | |
| 31 | - | |
| 32 | -- (void)yb_imageData:(YBIBImageData *)data readyForImage:(__kindof UIImage *)image; | |
| 33 | - | |
| 34 | -- (void)yb_imageData:(YBIBImageData *)data readyForThumbImage:(__kindof UIImage *)image; | |
| 35 | - | |
| 36 | -- (void)yb_imageData:(YBIBImageData *)data readyForCompressedImage:(__kindof UIImage *)image; | |
| 37 | - | |
| 38 | -- (void)yb_imageData:(YBIBImageData *)data downloadProgress:(CGFloat)progress; | |
| 39 | - | |
| 40 | -- (void)yb_imageDownloadFailedForData:(YBIBImageData *)data; | |
| 41 | - | |
| 42 | -@end | |
| 43 | - | |
| 44 | -@interface YBIBImageData () | |
| 45 | - | |
| 46 | -@property (nonatomic, weak) id<YBIBImageDataDelegate> delegate; | |
| 47 | - | |
| 48 | -/// The status of asynchronous tasks. | |
| 49 | -@property (nonatomic, assign) YBIBImageLoadingStatus loadingStatus; | |
| 50 | - | |
| 51 | -/// The origin image. | |
| 52 | -@property (nonatomic, strong) UIImage *originImage; | |
| 53 | - | |
| 54 | -/// The image compressed by 'originImage' if need. | |
| 55 | -@property (nonatomic, strong) UIImage *compressedImage; | |
| 56 | - | |
| 57 | -- (BOOL)shouldCompress; | |
| 58 | - | |
| 59 | -- (void)cuttingImageToRect:(CGRect)rect complete:(void(^)(UIImage * _Nullable image))complete; | |
| 60 | - | |
| 61 | -@end | |
| 62 | - | |
| 63 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageData.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageData.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/5. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <Photos/Photos.h> | |
| 10 | -#import "YBIBDataProtocol.h" | |
| 11 | -#import "YBIBImageLayout.h" | |
| 12 | -#import "YBIBImageCache.h" | |
| 13 | -#import "YBIBInteractionProfile.h" | |
| 14 | - | |
| 15 | -NS_ASSUME_NONNULL_BEGIN | |
| 16 | - | |
| 17 | -@class YBIBImageData; | |
| 18 | - | |
| 19 | -/// 获取 NSData 的闭包 | |
| 20 | -typedef NSData * _Nullable (^YBIBImageDataBlock)(void); | |
| 21 | - | |
| 22 | -/// 获取 UIImage 的闭包 | |
| 23 | -typedef UIImage * _Nullable (^YBIBImageBlock)(void); | |
| 24 | - | |
| 25 | -/// 修改 NSURLRequest 并返回的闭包 | |
| 26 | -typedef NSURLRequest * _Nullable (^YBIBRequestModifierBlock)(YBIBImageData *imageData, NSURLRequest *request); | |
| 27 | - | |
| 28 | -/// 根据图片逻辑像素和 scale 判断是否需要预解码的闭包 | |
| 29 | -typedef BOOL (^YBIBPreDecodeDecisionBlock)(YBIBImageData *imageData, CGSize imageSize, CGFloat scale); | |
| 30 | - | |
| 31 | -/// 修改 UIImage 并返回的闭包 | |
| 32 | -typedef void (^YBIBImageModifierBlock)(YBIBImageData *imageData, UIImage *image, void(^completion)(UIImage *processedImage)); | |
| 33 | - | |
| 34 | -/// 单击事件的处理闭包 | |
| 35 | -typedef void (^YBIBImageSingleTouchBlock)(YBIBImageData *imageData); | |
| 36 | - | |
| 37 | -/// 内部图片滚动视图状态回调闭包 | |
| 38 | -typedef void (^YBIBImageScrollViewStatusBlock)(YBIBImageData *imageData, UIScrollView *scrollView); | |
| 39 | - | |
| 40 | - | |
| 41 | -/** | |
| 42 | - 图片数据类,承担配置数据和处理数据的责任 | |
| 43 | - */ | |
| 44 | -@interface YBIBImageData : NSObject <YBIBDataProtocol> | |
| 45 | - | |
| 46 | -/// 本地图片名字 | |
| 47 | -@property (nonatomic, copy, nullable) NSString *imageName; | |
| 48 | - | |
| 49 | -/// 本地图片路径 | |
| 50 | -@property (nonatomic, copy, nullable) NSString *imagePath; | |
| 51 | - | |
| 52 | -/// 本地图片字节码,返回 NSData | |
| 53 | -@property (nonatomic, copy, nullable) YBIBImageDataBlock imageData; | |
| 54 | - | |
| 55 | -/// 本地图片,返回 UIImage 及其衍生类 (若不是遵循'YYAnimatedImage'协议的类型,将失去对动图和拓展格式的支持) | |
| 56 | -@property (nonatomic, copy, nullable) YBIBImageBlock image; | |
| 57 | - | |
| 58 | -/// 网络图片资源 | |
| 59 | -@property (nonatomic, copy, nullable) NSURL *imageURL; | |
| 60 | - | |
| 61 | -/// 修改 NSURLRequest 并返回 | |
| 62 | -@property (nonatomic, copy, nullable) YBIBRequestModifierBlock requestModifier; | |
| 63 | - | |
| 64 | -/// 相册图片资源 | |
| 65 | -@property (nonatomic, strong, nullable) PHAsset *imagePHAsset; | |
| 66 | - | |
| 67 | -/// 投影视图,当前数据模型对应外界业务的 UIView (通常为 UIImageView),做转场动效用 | |
| 68 | -@property (nonatomic, weak, nullable) __kindof UIView *projectiveView; | |
| 69 | - | |
| 70 | -/// 预览图/缩约图,注意若这个图片过大会导致内存压力(若 projectiveView 存在且是 UIImageView 类型将会自动获取缩约图) | |
| 71 | -@property (nonatomic, strong, nullable) UIImage *thumbImage; | |
| 72 | - | |
| 73 | -/// 预览图/缩约图 URL,缓存中未找到则忽略(若 projectiveView 存在且是 UIImageView 类型将会自动获取缩约图) | |
| 74 | -@property (nonatomic, copy, nullable) NSURL *thumbURL; | |
| 75 | - | |
| 76 | -/// 是否允许保存到相册 | |
| 77 | -@property (nonatomic, assign) BOOL allowSaveToPhotoAlbum; | |
| 78 | - | |
| 79 | -/// 根据图片信息判断是否需要预解码 | |
| 80 | -@property (nonatomic, copy, nullable) YBIBPreDecodeDecisionBlock preDecodeDecision; | |
| 81 | - | |
| 82 | -/// 是否异步预解码,默认为 YES | |
| 83 | -@property (nonatomic, assign) BOOL shouldPreDecodeAsync; | |
| 84 | - | |
| 85 | -/// 压缩物理像素界限大小,当图片超过这个值将会被压缩显示,默认为 4096*4096 | |
| 86 | -@property (nonatomic, assign) CGFloat compressingSize; | |
| 87 | - | |
| 88 | -/// 触发裁剪的缩放比例,必须大于等于 1,默认情况内部会动态计算 (仅当图片需要压缩显示时有效) | |
| 89 | -@property (nonatomic, assign) CGFloat cuttingZoomScale; | |
| 90 | - | |
| 91 | -/** | |
| 92 | - 判断图片是否需要压缩显示 | |
| 93 | - */ | |
| 94 | -- (BOOL)shouldCompressWithImage:(UIImage *)image; | |
| 95 | - | |
| 96 | -/** | |
| 97 | - 修改原始图片并返回处理后的图片 (特别注意当 image 是大图的时候,避免 OOM) | |
| 98 | - Example: | |
| 99 | - [... setImageModifier:^(YBIBImageData *imageData, UIImage * _Nonnull image, void (^ _Nonnull completion)(UIImage * _Nonnull)) { | |
| 100 | - //step 1 : Add watermark, trademark, etc. (Sync or async). | |
| 101 | - ... processing code ... | |
| 102 | - //step 2 : Return the processed UIImage. | |
| 103 | - completion(image); | |
| 104 | - }]; | |
| 105 | - */ | |
| 106 | -@property (nonatomic, copy, nullable) YBIBImageModifierBlock originImageModifier; | |
| 107 | - | |
| 108 | -/// 修改压缩图片并返回处理后的图片 (仅在当前图片需要被压缩时有效) | |
| 109 | -@property (nonatomic, copy, nullable) YBIBImageModifierBlock compressedImageModifier; | |
| 110 | - | |
| 111 | -/// 修改裁剪图片并返回处理后的图片 (仅在当前图片需要被裁剪时有效) | |
| 112 | -@property (nonatomic, copy, nullable) YBIBImageModifierBlock cuttedImageModifier; | |
| 113 | - | |
| 114 | -/// 预留属性可随意使用 | |
| 115 | -@property (nonatomic, strong, nullable) id extraData; | |
| 116 | - | |
| 117 | -/// 手势交互动效配置文件 | |
| 118 | -@property (nonatomic, strong) YBIBInteractionProfile *interactionProfile; | |
| 119 | - | |
| 120 | -/// 单击的处理,默认是退出图片浏览器 | |
| 121 | -@property (nonatomic, copy, nullable) YBIBImageSingleTouchBlock singleTouchBlock; | |
| 122 | - | |
| 123 | -/// 图片滚动的回调 | |
| 124 | -@property (nonatomic, copy, nullable) YBIBImageScrollViewStatusBlock imageDidScrollBlock; | |
| 125 | - | |
| 126 | -/// 图片缩放的回调 | |
| 127 | -@property (nonatomic, copy, nullable) YBIBImageScrollViewStatusBlock imageDidZoomBlock; | |
| 128 | - | |
| 129 | -/// 图片布局类 (赋值可自定义) | |
| 130 | -@property (nonatomic, strong) id<YBIBImageLayout> layout; | |
| 131 | -/// 默认图片布局类 (可配置其属性) | |
| 132 | -@property (nonatomic, weak, readonly) YBIBImageLayout *defaultLayout; | |
| 133 | - | |
| 134 | -/** | |
| 135 | - 终止处理数据程序 | |
| 136 | - */ | |
| 137 | -- (void)stopLoading; | |
| 138 | - | |
| 139 | -/** | |
| 140 | - 清除缓存的数据 | |
| 141 | - */ | |
| 142 | -- (void)clearCache; | |
| 143 | - | |
| 144 | -/** | |
| 145 | - 加载数据,一般不需要调用这个方法,当该数据对象做了数据更新时调用 | |
| 146 | - */ | |
| 147 | -- (void)loadData; | |
| 148 | - | |
| 149 | -/// 处理后的原始图片 | |
| 150 | -@property (nonatomic, strong, readonly) UIImage *originImage; | |
| 151 | - | |
| 152 | -/// 处理后的压缩图片 | |
| 153 | -@property (nonatomic, strong, readonly) UIImage *compressedImage; | |
| 154 | - | |
| 155 | -@end | |
| 156 | - | |
| 157 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageData.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageData.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/5. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBImage.h" | |
| 10 | -#import "YBIBImageData.h" | |
| 11 | -#import "YBIBImageCell.h" | |
| 12 | -#import "YBIBPhotoAlbumManager.h" | |
| 13 | -#import "YBIBImageData+Internal.h" | |
| 14 | -#import "YBIBUtilities.h" | |
| 15 | -#import "YBIBImageCache+Internal.h" | |
| 16 | -#import "YBIBSentinel.h" | |
| 17 | -#import "YBIBCopywriter.h" | |
| 18 | -#import <AssetsLibrary/AssetsLibrary.h> | |
| 19 | - | |
| 20 | -extern CGImageRef YYCGImageCreateDecodedCopy(CGImageRef imageRef, BOOL decodeForDisplay); | |
| 21 | - | |
| 22 | -static dispatch_queue_t YBIBImageProcessingQueue(void) { | |
| 23 | - static dispatch_queue_t queue; | |
| 24 | - static dispatch_once_t onceToken; | |
| 25 | - dispatch_once(&onceToken, ^{ | |
| 26 | - queue = dispatch_queue_create("com.yangbo.imagebrowser.imageprocessing", DISPATCH_QUEUE_CONCURRENT); | |
| 27 | - }); | |
| 28 | - return queue; | |
| 29 | -} | |
| 30 | - | |
| 31 | -@implementation YBIBImageData { | |
| 32 | - __weak id _downloadToken; | |
| 33 | - YBIBSentinel *_cuttingSentinel; | |
| 34 | - /// Stop processing tasks when in freeze. | |
| 35 | - BOOL _freezing; | |
| 36 | -} | |
| 37 | - | |
| 38 | -#pragma mark - life cycle | |
| 39 | - | |
| 40 | -- (void)dealloc { | |
| 41 | - if (_downloadToken && [self.yb_webImageMediator() respondsToSelector:@selector(yb_cancelTaskWithDownloadToken:)]) { | |
| 42 | - [self.yb_webImageMediator() yb_cancelTaskWithDownloadToken:_downloadToken]; | |
| 43 | - } | |
| 44 | - [self.imageCache removeForKey:self.cacheKey]; | |
| 45 | -} | |
| 46 | - | |
| 47 | -- (instancetype)init { | |
| 48 | - self = [super init]; | |
| 49 | - if (self) { | |
| 50 | - [self initValue]; | |
| 51 | - } | |
| 52 | - return self; | |
| 53 | -} | |
| 54 | - | |
| 55 | -- (void)initValue { | |
| 56 | - _defaultLayout = _layout = [YBIBImageLayout new]; | |
| 57 | - _loadingStatus = YBIBImageLoadingStatusNone; | |
| 58 | - _compressingSize = 4096 * 4096; | |
| 59 | - _shouldPreDecodeAsync = YES; | |
| 60 | - _freezing = NO; | |
| 61 | - _cuttingSentinel = [YBIBSentinel new]; | |
| 62 | - _interactionProfile = [YBIBInteractionProfile new]; | |
| 63 | - _allowSaveToPhotoAlbum = YES; | |
| 64 | -} | |
| 65 | - | |
| 66 | -#pragma mark - load data | |
| 67 | - | |
| 68 | -- (void)loadData { | |
| 69 | - _freezing = NO; | |
| 70 | - | |
| 71 | - // Avoid handling asynchronous tasks repeatedly. | |
| 72 | - if (self.loadingStatus != YBIBImageLoadingStatusNone) { | |
| 73 | - [self loadThumbImage]; | |
| 74 | - self.loadingStatus = self.loadingStatus; | |
| 75 | - return; | |
| 76 | - } | |
| 77 | - | |
| 78 | - if (self.originImage) { | |
| 79 | - [self loadOriginImage]; | |
| 80 | - } else if (self.imageName || self.imagePath || self.imageData) { | |
| 81 | - [self loadYBImage]; | |
| 82 | - } else if (self.image) { | |
| 83 | - [self loadImageBlock]; | |
| 84 | - } else if (self.imageURL) { | |
| 85 | - [self loadThumbImage]; | |
| 86 | - [self loadURL]; | |
| 87 | - } else if (self.imagePHAsset) { | |
| 88 | - [self loadThumbImage]; | |
| 89 | - [self loadPHAsset]; | |
| 90 | - } else { | |
| 91 | - [self.delegate yb_imageIsInvalidForData:self]; | |
| 92 | - } | |
| 93 | -} | |
| 94 | - | |
| 95 | -- (void)loadOriginImage { | |
| 96 | - if (_freezing) return; | |
| 97 | - if (!self.originImage) return; | |
| 98 | - | |
| 99 | - if ([self shouldCompress]) { | |
| 100 | - if (self.compressedImage) { | |
| 101 | - [self.delegate yb_imageData:self readyForCompressedImage:self.compressedImage]; | |
| 102 | - } else { | |
| 103 | - [self loadThumbImage]; | |
| 104 | - [self loadOriginImage_compress]; | |
| 105 | - } | |
| 106 | - } else { | |
| 107 | - [self.delegate yb_imageData:self readyForImage:self.originImage]; | |
| 108 | - } | |
| 109 | -} | |
| 110 | -- (void)loadOriginImage_compress { | |
| 111 | - if (_freezing) return; | |
| 112 | - if (!self.originImage) return; | |
| 113 | - | |
| 114 | - self.loadingStatus = YBIBImageLoadingStatusCompressing; | |
| 115 | - __weak typeof(self) wSelf = self; | |
| 116 | - CGSize size = [self bestSizeOfCompressing]; | |
| 117 | - | |
| 118 | - YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{ | |
| 119 | - if (self->_freezing) { | |
| 120 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 121 | - return; | |
| 122 | - } | |
| 123 | - // Ensure the best display effect. | |
| 124 | - UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale); | |
| 125 | - [self.originImage drawInRect:CGRectMake(0, 0, size.width, size.height)]; | |
| 126 | - if (self->_freezing) { | |
| 127 | - UIGraphicsEndImageContext(); | |
| 128 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 129 | - return; | |
| 130 | - } | |
| 131 | - UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); | |
| 132 | - UIGraphicsEndImageContext(); | |
| 133 | - | |
| 134 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 135 | - __strong typeof(wSelf) self = wSelf; | |
| 136 | - if (!self) return; | |
| 137 | - | |
| 138 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 139 | - | |
| 140 | - [self modifyImageWithModifier:self.compressedImageModifier image:resultImage completion:^(UIImage *processedImage) { | |
| 141 | - __strong typeof(wSelf) self = wSelf; | |
| 142 | - if (!self) return; | |
| 143 | - self.compressedImage = processedImage ?: self.originImage; | |
| 144 | - [self.delegate yb_imageData:self readyForCompressedImage:self.compressedImage]; | |
| 145 | - }]; | |
| 146 | - }) | |
| 147 | - }) | |
| 148 | -} | |
| 149 | - | |
| 150 | -- (void)loadYBImage { | |
| 151 | - if (_freezing) return; | |
| 152 | - NSString *name = self.imageName.copy; | |
| 153 | - NSString *path = self.imagePath.copy; | |
| 154 | - NSData *data = self.imageData ? self.imageData().copy : nil; | |
| 155 | - if (name.length == 0 && path.length == 0 && data.length == 0) return; | |
| 156 | - | |
| 157 | - YBImageDecodeDecision decision = [self defaultDecodeDecision]; | |
| 158 | - | |
| 159 | - __block YBImage *image; | |
| 160 | - __weak typeof(self) wSelf = self; | |
| 161 | - void(^dealBlock)(void) = ^{ | |
| 162 | - if (name.length > 0) { | |
| 163 | - image = [YBImage imageNamed:name decodeDecision:decision]; | |
| 164 | - } else if (path.length > 0) { | |
| 165 | - image = [YBImage imageWithContentsOfFile:path decodeDecision:decision]; | |
| 166 | - } else if (data.length > 0) { | |
| 167 | - image = [YBImage imageWithData:data scale:UIScreen.mainScreen.scale decodeDecision:decision]; | |
| 168 | - } | |
| 169 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 170 | - __strong typeof(wSelf) self = wSelf; | |
| 171 | - if (!self) return; | |
| 172 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 173 | - if (image) { | |
| 174 | - [self setOriginImageAndLoadWithImage:image]; | |
| 175 | - } else { | |
| 176 | - [self.delegate yb_imageIsInvalidForData:self]; | |
| 177 | - } | |
| 178 | - }) | |
| 179 | - }; | |
| 180 | - | |
| 181 | - if (self.shouldPreDecodeAsync) { | |
| 182 | - [self loadThumbImage]; | |
| 183 | - self.loadingStatus = YBIBImageLoadingStatusDecoding; | |
| 184 | - YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), dealBlock) | |
| 185 | - } else { | |
| 186 | - self.loadingStatus = YBIBImageLoadingStatusDecoding; | |
| 187 | - dealBlock(); | |
| 188 | - } | |
| 189 | -} | |
| 190 | - | |
| 191 | -- (void)loadImageBlock { | |
| 192 | - if (_freezing) return; | |
| 193 | - __block UIImage *image = self.image ? self.image() : nil; | |
| 194 | - if (!image) return; | |
| 195 | - | |
| 196 | - BOOL shouldPreDecode = self.preDecodeDecision ? self.preDecodeDecision(self, image.size, image.scale) : ![self shouldCompressWithImage:image]; | |
| 197 | - | |
| 198 | - __weak typeof(self) wSelf = self; | |
| 199 | - void(^dealBlock)(void) = ^{ | |
| 200 | - // Do not need to decode If 'image' conformed 'YYAnimatedImage'. (Not entirely accurate.) | |
| 201 | - if (![image conformsToProtocol:@protocol(YYAnimatedImage)]) { | |
| 202 | - CGImageRef cgImage = YYCGImageCreateDecodedCopy(image.CGImage, shouldPreDecode); | |
| 203 | - image = [UIImage imageWithCGImage:cgImage scale:image.scale orientation:image.imageOrientation]; | |
| 204 | - if (cgImage) CGImageRelease(cgImage); | |
| 205 | - } | |
| 206 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 207 | - __strong typeof(wSelf) self = wSelf; | |
| 208 | - if (!self) return; | |
| 209 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 210 | - [self setOriginImageAndLoadWithImage:image]; | |
| 211 | - }) | |
| 212 | - }; | |
| 213 | - | |
| 214 | - if (self.shouldPreDecodeAsync) { | |
| 215 | - [self loadThumbImage]; | |
| 216 | - self.loadingStatus = YBIBImageLoadingStatusDecoding; | |
| 217 | - YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), dealBlock) | |
| 218 | - } else { | |
| 219 | - self.loadingStatus = YBIBImageLoadingStatusDecoding; | |
| 220 | - dealBlock(); | |
| 221 | - } | |
| 222 | -} | |
| 223 | - | |
| 224 | -- (void)loadURL { | |
| 225 | - if (!self.imageURL || self.imageURL.absoluteString.length == 0) return; | |
| 226 | - [self loadURL_queryCache]; | |
| 227 | -} | |
| 228 | -- (void)loadURL_queryCache { | |
| 229 | - if (_freezing) return; | |
| 230 | - if (!self.imageURL || self.imageURL.absoluteString.length == 0) return; | |
| 231 | - | |
| 232 | - YBImageDecodeDecision decision = [self defaultDecodeDecision]; | |
| 233 | - | |
| 234 | - self.loadingStatus = YBIBImageLoadingStatusQuerying; | |
| 235 | - [self.yb_webImageMediator() yb_queryCacheOperationForKey:self.imageURL completed:^(UIImage * _Nullable image, NSData * _Nullable imageData) { | |
| 236 | - if (!imageData || imageData.length == 0) { | |
| 237 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 238 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 239 | - [self loadURL_download]; | |
| 240 | - }) | |
| 241 | - return; | |
| 242 | - } | |
| 243 | - | |
| 244 | - YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{ | |
| 245 | - if (self->_freezing) { | |
| 246 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 247 | - return; | |
| 248 | - } | |
| 249 | - YBImage *image = [YBImage imageWithData:imageData scale:UIScreen.mainScreen.scale decodeDecision:decision]; | |
| 250 | - __weak typeof(self) wSelf = self; | |
| 251 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 252 | - __strong typeof(wSelf) self = wSelf; | |
| 253 | - if (!self) return; | |
| 254 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 255 | - if (image) { // Maybe the image data is invalid. | |
| 256 | - [self setOriginImageAndLoadWithImage:image]; | |
| 257 | - } else { | |
| 258 | - [self loadURL_download]; | |
| 259 | - } | |
| 260 | - }) | |
| 261 | - }) | |
| 262 | - }]; | |
| 263 | -} | |
| 264 | -- (void)loadURL_download { | |
| 265 | - if (_freezing) return; | |
| 266 | - if (!self.imageURL || self.imageURL.absoluteString.length == 0) return; | |
| 267 | - | |
| 268 | - YBImageDecodeDecision decision = [self defaultDecodeDecision]; | |
| 269 | - | |
| 270 | - self.loadingStatus = YBIBImageLoadingStatusDownloading; | |
| 271 | - __weak typeof(self) wSelf = self; | |
| 272 | - _downloadToken = [self.yb_webImageMediator() yb_downloadImageWithURL:self.imageURL requestModifier:^NSURLRequest * _Nullable(NSURLRequest * _Nonnull request) { | |
| 273 | - return self.requestModifier ? self.requestModifier(self, request) : request; | |
| 274 | - } progress:^(NSInteger receivedSize, NSInteger expectedSize) { | |
| 275 | - CGFloat progress = receivedSize * 1.0 / expectedSize ?: 0; | |
| 276 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 277 | - __strong typeof(wSelf) self = wSelf; | |
| 278 | - if (!self) return; | |
| 279 | - [self.delegate yb_imageData:self downloadProgress:progress]; | |
| 280 | - }) | |
| 281 | - } success:^(NSData * _Nullable imageData, BOOL finished) { | |
| 282 | - if (!finished) return; | |
| 283 | - | |
| 284 | - YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{ | |
| 285 | - if (self->_freezing) { | |
| 286 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 287 | - return; | |
| 288 | - } | |
| 289 | - YBImage *image = [YBImage imageWithData:imageData scale:UIScreen.mainScreen.scale decodeDecision:decision]; | |
| 290 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 291 | - __strong typeof(wSelf) self = wSelf; | |
| 292 | - if (!self) return; | |
| 293 | - [self.yb_webImageMediator() yb_storeToDiskWithImageData:imageData forKey:self.imageURL]; | |
| 294 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 295 | - if (image) { | |
| 296 | - [self setOriginImageAndLoadWithImage:image]; | |
| 297 | - } else { | |
| 298 | - [self.delegate yb_imageIsInvalidForData:self]; | |
| 299 | - } | |
| 300 | - }) | |
| 301 | - }) | |
| 302 | - } failed:^(NSError * _Nullable error, BOOL finished) { | |
| 303 | - if (!finished) return; | |
| 304 | - __strong typeof(wSelf) self = wSelf; | |
| 305 | - if (!self) return; | |
| 306 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 307 | - [self.delegate yb_imageDownloadFailedForData:self]; | |
| 308 | - }]; | |
| 309 | -} | |
| 310 | - | |
| 311 | -- (void)loadPHAsset { | |
| 312 | - if (_freezing) return; | |
| 313 | - if (!self.imagePHAsset) return; | |
| 314 | - | |
| 315 | - YBImageDecodeDecision decision = [self defaultDecodeDecision]; | |
| 316 | - | |
| 317 | - self.loadingStatus = YBIBImageLoadingStatusReadingPHAsset; | |
| 318 | - YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{ | |
| 319 | - [YBIBPhotoAlbumManager getImageDataWithPHAsset:self.imagePHAsset completion:^(NSData * _Nullable data) { | |
| 320 | - if (self->_freezing) { | |
| 321 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 322 | - return; | |
| 323 | - } | |
| 324 | - YBImage *image = [YBImage imageWithData:data scale:UIScreen.mainScreen.scale decodeDecision:decision]; | |
| 325 | - __weak typeof(self) wSelf = self; | |
| 326 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 327 | - __strong typeof(wSelf) self = wSelf; | |
| 328 | - if (!self) return; | |
| 329 | - | |
| 330 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 331 | - if (image) { | |
| 332 | - [self setOriginImageAndLoadWithImage:image]; | |
| 333 | - } else { | |
| 334 | - [self.delegate yb_imageIsInvalidForData:self]; | |
| 335 | - } | |
| 336 | - }) | |
| 337 | - }]; | |
| 338 | - }) | |
| 339 | -} | |
| 340 | - | |
| 341 | -- (void)loadThumbImage { | |
| 342 | - if (_freezing) return; | |
| 343 | - if (self.thumbImage) { | |
| 344 | - [self.delegate yb_imageData:self readyForThumbImage:self.thumbImage]; | |
| 345 | - } else if (self.thumbURL) { | |
| 346 | - __weak typeof(self) wSelf = self; | |
| 347 | - [self.yb_webImageMediator() yb_queryCacheOperationForKey:self.thumbURL completed:^(UIImage * _Nullable image, NSData * _Nullable imageData) { | |
| 348 | - __strong typeof(wSelf) self = wSelf; | |
| 349 | - if (!self) return; | |
| 350 | - | |
| 351 | - UIImage *thumbImage; | |
| 352 | - if (image) { | |
| 353 | - thumbImage = image; | |
| 354 | - } else if (imageData) { | |
| 355 | - thumbImage = [UIImage imageWithData:imageData]; | |
| 356 | - } | |
| 357 | - // If the target image is ready, ignore the thumb image. | |
| 358 | - BOOL shouldIgnore = [self shouldCompress] ? (self.compressedImage != nil) : (self.originImage != nil); | |
| 359 | - if (!shouldIgnore && thumbImage) { | |
| 360 | - [self.delegate yb_imageData:self readyForThumbImage:thumbImage]; | |
| 361 | - } | |
| 362 | - }]; | |
| 363 | - } else if (self.projectiveView && [self.projectiveView isKindOfClass:UIImageView.self] && ((UIImageView *)self.projectiveView).image) { | |
| 364 | - UIImage *thumbImage = ((UIImageView *)self.projectiveView).image; | |
| 365 | - [self.delegate yb_imageData:self readyForThumbImage:thumbImage]; | |
| 366 | - } | |
| 367 | -} | |
| 368 | - | |
| 369 | -#pragma mark - internal | |
| 370 | - | |
| 371 | -- (void)cuttingImageToRect:(CGRect)rect complete:(void (^)(UIImage * _Nullable))complete { | |
| 372 | - if (_freezing) return; | |
| 373 | - if (!self.originImage) return; | |
| 374 | - | |
| 375 | - int32_t value = [_cuttingSentinel increase]; | |
| 376 | - BOOL (^isCancelled)(void) = ^BOOL(void) { | |
| 377 | - if (self->_freezing) return YES; | |
| 378 | - return value != self->_cuttingSentinel.value; | |
| 379 | - }; | |
| 380 | - | |
| 381 | - YBIB_DISPATCH_ASYNC(YBIBImageProcessingQueue(), ^{ | |
| 382 | - if (isCancelled()) { | |
| 383 | - complete(nil); | |
| 384 | - return; | |
| 385 | - } | |
| 386 | - CGFloat scale = self.originImage.scale; | |
| 387 | - CGFloat width = self.originImage.size.width; | |
| 388 | - CGFloat height = self.originImage.size.height; | |
| 389 | - | |
| 390 | - BOOL reverseWidthHeight = NO; | |
| 391 | - CGAffineTransform transform = CGAffineTransformIdentity; | |
| 392 | - switch (self.originImage.imageOrientation) { | |
| 393 | - case UIImageOrientationDown: | |
| 394 | - case UIImageOrientationDownMirrored: | |
| 395 | - CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI), -width, -height); | |
| 396 | - break; | |
| 397 | - case UIImageOrientationLeft: | |
| 398 | - case UIImageOrientationLeftMirrored: | |
| 399 | - transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(M_PI_2), 0, -height); | |
| 400 | - reverseWidthHeight = YES; | |
| 401 | - break; | |
| 402 | - case UIImageOrientationRight: | |
| 403 | - case UIImageOrientationRightMirrored: | |
| 404 | - transform = CGAffineTransformTranslate(CGAffineTransformMakeRotation(-M_PI_2), -width, 0); | |
| 405 | - reverseWidthHeight = YES; | |
| 406 | - break; | |
| 407 | - default: break; | |
| 408 | - } | |
| 409 | - transform = CGAffineTransformScale(transform, scale, scale); | |
| 410 | - CGRect correctRect = CGRectApplyAffineTransform(rect, transform); | |
| 411 | - CGImageRef cgImage = CGImageCreateWithImageInRect(self.originImage.CGImage, correctRect); | |
| 412 | - | |
| 413 | - if (isCancelled()) { | |
| 414 | - complete(nil); | |
| 415 | - if (cgImage) CGImageRelease(cgImage); | |
| 416 | - return; | |
| 417 | - } | |
| 418 | - CGFloat cgWidth = reverseWidthHeight ? CGImageGetHeight(cgImage) : CGImageGetWidth(cgImage); | |
| 419 | - CGFloat cgHeight = reverseWidthHeight ? CGImageGetWidth(cgImage) : CGImageGetHeight(cgImage); | |
| 420 | - CGSize size = [self bestSizeOfCuttingWithOriginSize:CGSizeMake(cgWidth / scale, cgHeight / scale)]; | |
| 421 | - UIImage *tmpImage = [UIImage imageWithCGImage:cgImage scale:self.originImage.scale orientation:self.originImage.imageOrientation]; | |
| 422 | - if (isCancelled()) { | |
| 423 | - complete(nil); | |
| 424 | - if (cgImage) CGImageRelease(cgImage); | |
| 425 | - return; | |
| 426 | - } | |
| 427 | - | |
| 428 | - // Ensure the best display effect. | |
| 429 | - UIGraphicsBeginImageContextWithOptions(size, NO, UIScreen.mainScreen.scale); | |
| 430 | - [tmpImage drawInRect:CGRectMake(0, 0, size.width, size.height)]; | |
| 431 | - if (isCancelled()) { | |
| 432 | - complete(nil); | |
| 433 | - UIGraphicsEndImageContext(); | |
| 434 | - if (cgImage) CGImageRelease(cgImage); | |
| 435 | - return; | |
| 436 | - } | |
| 437 | - UIImage *resultImage = UIGraphicsGetImageFromCurrentImageContext(); | |
| 438 | - UIGraphicsEndImageContext(); | |
| 439 | - if (cgImage) CGImageRelease(cgImage); | |
| 440 | - | |
| 441 | - __weak typeof(self) wSelf = self; | |
| 442 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 443 | - __strong typeof(wSelf) self = wSelf; | |
| 444 | - if (!self) return; | |
| 445 | - | |
| 446 | - [self modifyImageWithModifier:self.cuttedImageModifier image:resultImage completion:^(UIImage *image) { | |
| 447 | - __strong typeof(wSelf) self = wSelf; | |
| 448 | - if (!self) return; | |
| 449 | - complete(image); | |
| 450 | - }]; | |
| 451 | - }) | |
| 452 | - }) | |
| 453 | -} | |
| 454 | - | |
| 455 | -- (BOOL)shouldCompress { | |
| 456 | - return [self shouldCompressWithImage:self.originImage]; | |
| 457 | -} | |
| 458 | - | |
| 459 | -#pragma mark - public | |
| 460 | - | |
| 461 | -- (BOOL)shouldCompressWithImage:(UIImage *)image { | |
| 462 | - if (!image) return NO; | |
| 463 | - return [self shouldCompressWithImageSize:image.size scale:image.scale]; | |
| 464 | -} | |
| 465 | - | |
| 466 | -- (void)stopLoading { | |
| 467 | - _freezing = YES; | |
| 468 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 469 | -} | |
| 470 | - | |
| 471 | -- (void)clearCache { | |
| 472 | - [self.imageCache removeForKey:self.cacheKey]; | |
| 473 | -} | |
| 474 | - | |
| 475 | -#pragma mark - private | |
| 476 | - | |
| 477 | -/// 'size': logic pixel. | |
| 478 | -- (BOOL)shouldCompressWithImageSize:(CGSize)size scale:(CGFloat)scale { | |
| 479 | - return size.width * scale * size.height * scale > self.compressingSize; | |
| 480 | -} | |
| 481 | - | |
| 482 | -/// Logic pixel. | |
| 483 | -- (CGSize)bestSizeOfCompressing { | |
| 484 | - if (!self.originImage) return CGSizeZero; | |
| 485 | - UIDeviceOrientation orientation = self.yb_currentOrientation(); | |
| 486 | - CGRect imageViewFrame = [self.layout yb_imageViewFrameWithContainerSize:self.yb_containerSize(orientation) imageSize:self.originImage.size orientation:orientation]; | |
| 487 | - return imageViewFrame.size; | |
| 488 | -} | |
| 489 | - | |
| 490 | -/// Logic pixel. | |
| 491 | -- (CGSize)bestSizeOfCuttingWithOriginSize:(CGSize)originSize { | |
| 492 | - CGSize containerSize = self.yb_containerSize(self.yb_currentOrientation()); | |
| 493 | - CGFloat maxWidth = containerSize.width, maxHeight = containerSize.height; | |
| 494 | - CGFloat oWidth = originSize.width, oHeight = originSize.height; | |
| 495 | - if (maxWidth <= 0 || maxHeight <= 0 || oWidth <= 0 || oHeight <= 0) return CGSizeZero; | |
| 496 | - | |
| 497 | - if (oWidth <= maxWidth && oHeight <= maxHeight) { | |
| 498 | - return originSize; | |
| 499 | - } | |
| 500 | - CGFloat rWidth = 0, rHeight = 0; | |
| 501 | - if (oWidth / maxWidth < oHeight / maxHeight) { | |
| 502 | - rHeight = maxHeight; | |
| 503 | - rWidth = oWidth / oHeight * rHeight; | |
| 504 | - } else { | |
| 505 | - rWidth = maxWidth; | |
| 506 | - rHeight = oHeight / oWidth * rWidth; | |
| 507 | - } | |
| 508 | - return CGSizeMake(rWidth, rHeight); | |
| 509 | -} | |
| 510 | - | |
| 511 | -- (YBImageDecodeDecision)defaultDecodeDecision { | |
| 512 | - __weak typeof(self) wSelf = self; | |
| 513 | - return ^BOOL(CGSize imageSize, CGFloat scale) { | |
| 514 | - __strong typeof(wSelf) self = wSelf; | |
| 515 | - if (!self) return NO; | |
| 516 | - CGSize logicSize = CGSizeMake(imageSize.width / scale, imageSize.height / scale); | |
| 517 | - if (self.preDecodeDecision) return self.preDecodeDecision(self, logicSize, scale); | |
| 518 | - if ([self shouldCompressWithImageSize:logicSize scale:scale]) return NO; | |
| 519 | - return YES; | |
| 520 | - }; | |
| 521 | -} | |
| 522 | - | |
| 523 | -- (void)modifyImageWithModifier:(YBIBImageModifierBlock)modifier image:(UIImage *)image completion:(void(^)(UIImage *processedImage))completion { | |
| 524 | - if (modifier) { | |
| 525 | - self.loadingStatus = YBIBImageLoadingStatusProcessing; | |
| 526 | - __weak typeof(self) wSelf = self; | |
| 527 | - modifier(self, image, ^(UIImage *processedImage){ | |
| 528 | - // This step is necessary, maybe 'self' is already 'dealloc' if processing code takes too much time. | |
| 529 | - __strong typeof(wSelf) self = wSelf; | |
| 530 | - if (!self) return; | |
| 531 | - self.loadingStatus = YBIBImageLoadingStatusNone; | |
| 532 | - completion(processedImage); | |
| 533 | - }); | |
| 534 | - } else { | |
| 535 | - completion(image); | |
| 536 | - } | |
| 537 | -} | |
| 538 | - | |
| 539 | -- (void)setOriginImageAndLoadWithImage:(UIImage *)image { | |
| 540 | - __weak typeof(self) wSelf = self; | |
| 541 | - [self modifyImageWithModifier:self.originImageModifier image:image completion:^(UIImage *processedImage) { | |
| 542 | - __strong typeof(wSelf) self = wSelf; | |
| 543 | - if (!self) return; | |
| 544 | - self.originImage = processedImage; | |
| 545 | - [self loadOriginImage]; | |
| 546 | - }]; | |
| 547 | -} | |
| 548 | - | |
| 549 | -- (void)saveToPhotoAlbumCompleteWithError:(nullable NSError *)error { | |
| 550 | - if (error) { | |
| 551 | - [self.yb_auxiliaryViewHandler() yb_showIncorrectToastWithContainer:self.yb_containerView text:[YBIBCopywriter sharedCopywriter].saveToPhotoAlbumFailed]; | |
| 552 | - } else { | |
| 553 | - [self.yb_auxiliaryViewHandler() yb_showCorrectToastWithContainer:self.yb_containerView text:[YBIBCopywriter sharedCopywriter].saveToPhotoAlbumSuccess]; | |
| 554 | - } | |
| 555 | -} | |
| 556 | - | |
| 557 | -- (void)UIImageWriteToSavedPhotosAlbum_completedWithImage:(UIImage *)image error:(NSError *)error context:(void *)context { | |
| 558 | - [self saveToPhotoAlbumCompleteWithError:error]; | |
| 559 | -} | |
| 560 | - | |
| 561 | -- (YBIBImageCache *)imageCache { | |
| 562 | - return self.yb_backView.ybib_imageCache; | |
| 563 | -} | |
| 564 | - | |
| 565 | -#pragma mark - <YBIBDataProtocol> | |
| 566 | - | |
| 567 | -@synthesize yb_isHideTransitioning = _yb_isHideTransitioning; | |
| 568 | -@synthesize yb_currentOrientation = _yb_currentOrientation; | |
| 569 | -@synthesize yb_containerSize = _yb_containerSize; | |
| 570 | -@synthesize yb_containerView = _yb_containerView; | |
| 571 | -@synthesize yb_auxiliaryViewHandler = _yb_auxiliaryViewHandler; | |
| 572 | -@synthesize yb_webImageMediator = _yb_webImageMediator; | |
| 573 | -@synthesize yb_backView = _yb_backView; | |
| 574 | - | |
| 575 | -- (nonnull Class)yb_classOfCell { | |
| 576 | - return YBIBImageCell.self; | |
| 577 | -} | |
| 578 | - | |
| 579 | -- (UIView *)yb_projectiveView { | |
| 580 | - return self.projectiveView; | |
| 581 | -} | |
| 582 | - | |
| 583 | -- (CGRect)yb_imageViewFrameWithContainerSize:(CGSize)containerSize imageSize:(CGSize)imageSize orientation:(UIDeviceOrientation)orientation { | |
| 584 | - return [self.layout yb_imageViewFrameWithContainerSize:containerSize imageSize:imageSize orientation:orientation]; | |
| 585 | -} | |
| 586 | - | |
| 587 | -- (void)yb_preload { | |
| 588 | - if (!self.delegate) { | |
| 589 | - [self loadData]; | |
| 590 | - } | |
| 591 | -} | |
| 592 | - | |
| 593 | -- (BOOL)yb_allowSaveToPhotoAlbum { | |
| 594 | - return self.allowSaveToPhotoAlbum; | |
| 595 | -} | |
| 596 | - | |
| 597 | -- (void)yb_saveToPhotoAlbum { | |
| 598 | - void(^saveData)(NSData *) = ^(NSData * _Nonnull data){ | |
| 599 | - [[ALAssetsLibrary new] writeImageDataToSavedPhotosAlbum:data metadata:nil completionBlock:^(NSURL *assetURL, NSError *error) { | |
| 600 | - [self saveToPhotoAlbumCompleteWithError:error]; | |
| 601 | - }]; | |
| 602 | - }; | |
| 603 | - void(^saveImage)(UIImage *) = ^(UIImage * _Nonnull image){ | |
| 604 | - UIImageWriteToSavedPhotosAlbum(image, self, @selector(UIImageWriteToSavedPhotosAlbum_completedWithImage:error:context:), NULL); | |
| 605 | - }; | |
| 606 | - void(^unableToSave)(void) = ^(){ | |
| 607 | - [self.yb_auxiliaryViewHandler() yb_showIncorrectToastWithContainer:self.yb_containerView text:[YBIBCopywriter sharedCopywriter].unableToSave]; | |
| 608 | - }; | |
| 609 | - | |
| 610 | - [YBIBPhotoAlbumManager getPhotoAlbumAuthorizationSuccess:^{ | |
| 611 | - if ([self.originImage conformsToProtocol:@protocol(YYAnimatedImage)] && [self.originImage respondsToSelector:@selector(animatedImageData)] && [self.originImage performSelector:@selector(animatedImageData)]) { | |
| 612 | - NSData *data = [self.originImage performSelector:@selector(animatedImageData)]; | |
| 613 | - data ? saveData(data) : unableToSave(); | |
| 614 | - } else if (self.originImage) { | |
| 615 | - saveImage(self.originImage); | |
| 616 | - } else if (self.imageURL) { | |
| 617 | - [self.yb_webImageMediator() yb_queryCacheOperationForKey:self.imageURL completed:^(UIImage * _Nullable image, NSData * _Nullable data) { | |
| 618 | - if (data) { | |
| 619 | - saveData(data); | |
| 620 | - } else if (image) { | |
| 621 | - saveImage(image); | |
| 622 | - } else { | |
| 623 | - unableToSave(); | |
| 624 | - } | |
| 625 | - }]; | |
| 626 | - } else { | |
| 627 | - unableToSave(); | |
| 628 | - } | |
| 629 | - } failed:^{ | |
| 630 | - [self.yb_auxiliaryViewHandler() yb_showIncorrectToastWithContainer:self.yb_containerView text:[YBIBCopywriter sharedCopywriter].getPhotoAlbumAuthorizationFailed]; | |
| 631 | - }]; | |
| 632 | -} | |
| 633 | - | |
| 634 | -#pragma mark - getters & setters | |
| 635 | - | |
| 636 | -@synthesize delegate = _delegate; | |
| 637 | -- (void)setDelegate:(id<YBIBImageDataDelegate>)delegate { | |
| 638 | - _delegate = delegate; | |
| 639 | - if (delegate) { | |
| 640 | - [self loadData]; | |
| 641 | - } else { | |
| 642 | - _freezing = YES; | |
| 643 | - // Remove the resident cache if '_delegate' is nil. | |
| 644 | - [self.imageCache removeResidentForKey:self.cacheKey]; | |
| 645 | - } | |
| 646 | -} | |
| 647 | -- (id<YBIBImageDataDelegate>)delegate { | |
| 648 | - // Stop sending data to the '_delegate' if it is transiting. | |
| 649 | - return self.yb_isHideTransitioning() ? nil : _delegate; | |
| 650 | -} | |
| 651 | - | |
| 652 | -- (void)setImageURL:(NSURL *)imageURL { | |
| 653 | - _imageURL = [imageURL isKindOfClass:NSString.class] ? [NSURL URLWithString:(NSString *)imageURL] : imageURL; | |
| 654 | -} | |
| 655 | - | |
| 656 | -- (NSString *)cacheKey { | |
| 657 | - return [NSString stringWithFormat:@"%p", self]; | |
| 658 | -} | |
| 659 | - | |
| 660 | -- (void)setOriginImage:(__kindof UIImage *)originImage { | |
| 661 | - // 'image' should be resident if '_delegate' exists. | |
| 662 | - [self.imageCache setImage:originImage type:YBIBImageCacheTypeOrigin forKey:self.cacheKey resident:self->_delegate != nil]; | |
| 663 | -} | |
| 664 | -- (UIImage *)originImage { | |
| 665 | - return [self.imageCache imageForKey:self.cacheKey type:YBIBImageCacheTypeOrigin]; | |
| 666 | -} | |
| 667 | - | |
| 668 | -- (void)setCompressedImage:(UIImage *)compressedImage { | |
| 669 | - // 'image' should be resident if '_delegate' exists. | |
| 670 | - [self.imageCache setImage:compressedImage type:YBIBImageCacheTypeCompressed forKey:self.cacheKey resident:_delegate != nil]; | |
| 671 | -} | |
| 672 | -- (UIImage *)compressedImage { | |
| 673 | - return [self.imageCache imageForKey:self.cacheKey type:YBIBImageCacheTypeCompressed]; | |
| 674 | -} | |
| 675 | - | |
| 676 | -- (void)setLoadingStatus:(YBIBImageLoadingStatus)loadingStatus { | |
| 677 | - // Ensure thread safety. | |
| 678 | - YBIB_DISPATCH_ASYNC_MAIN(^{ | |
| 679 | - self->_loadingStatus = loadingStatus; | |
| 680 | - [self.delegate yb_imageData:self startLoadingWithStatus:loadingStatus]; | |
| 681 | - }); | |
| 682 | -} | |
| 683 | - | |
| 684 | -- (CGFloat)cuttingZoomScale { | |
| 685 | - if (_cuttingZoomScale >= 1) return _cuttingZoomScale; | |
| 686 | - _cuttingZoomScale = 1.1; | |
| 687 | - if (!self.originImage) return _cuttingZoomScale; | |
| 688 | - CGFloat imagePixel = self.originImage.size.width * self.originImage.size.height * self.originImage.scale * self.originImage.scale; | |
| 689 | - // The larger the image size, the larger the '_cuttingZoomScale', in order to reduce the burden of CPU and memory. | |
| 690 | - CGFloat scale = YBIBLowMemory() ? 0.28 : 0.19; | |
| 691 | - _cuttingZoomScale += (imagePixel / self.compressingSize * scale); | |
| 692 | - return _cuttingZoomScale; | |
| 693 | -} | |
| 694 | - | |
| 695 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageLayout.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageLayout.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/12. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@protocol YBIBImageLayout <NSObject> | |
| 14 | -@required | |
| 15 | - | |
| 16 | -/** | |
| 17 | - 计算图片展示的位置 | |
| 18 | - | |
| 19 | - @param containerSize 容器大小 | |
| 20 | - @param imageSize 图片大小 (逻辑像素) | |
| 21 | - @param orientation 图片浏览器的方向 | |
| 22 | - @return 图片展示的位置 (frame) | |
| 23 | - */ | |
| 24 | -- (CGRect)yb_imageViewFrameWithContainerSize:(CGSize)containerSize imageSize:(CGSize)imageSize orientation:(UIDeviceOrientation)orientation; | |
| 25 | - | |
| 26 | -/** | |
| 27 | - 计算最大缩放比例 | |
| 28 | - | |
| 29 | - @param containerSize 容器大小 | |
| 30 | - @param imageSize 图片大小 (逻辑像素) | |
| 31 | - @param orientation 图片浏览器的方向 | |
| 32 | - @return 最大缩放比例 | |
| 33 | - */ | |
| 34 | -- (CGFloat)yb_maximumZoomScaleWithContainerSize:(CGSize)containerSize imageSize:(CGSize)imageSize orientation:(UIDeviceOrientation)orientation; | |
| 35 | - | |
| 36 | -@end | |
| 37 | - | |
| 38 | -typedef NS_ENUM(NSUInteger, YBIBImageFillType) { | |
| 39 | - /// 宽度优先填充满 | |
| 40 | - YBIBImageFillTypeFullWidth, | |
| 41 | - /// 完整显示 | |
| 42 | - YBIBImageFillTypeCompletely | |
| 43 | -}; | |
| 44 | - | |
| 45 | -@interface YBIBImageLayout : NSObject <YBIBImageLayout> | |
| 46 | - | |
| 47 | -/// 纵向的填充方式,默认 YBIBImageFillTypeCompletely | |
| 48 | -@property (nonatomic, assign) YBIBImageFillType verticalFillType; | |
| 49 | - | |
| 50 | -/// 横向的填充方式,默认 YBIBImageFillTypeFullWidth | |
| 51 | -@property (nonatomic, assign) YBIBImageFillType horizontalFillType; | |
| 52 | - | |
| 53 | -/// 最大缩放比例 (必须大于 1 才有效,若不指定内部会自动计算) | |
| 54 | -@property (nonatomic, assign) CGFloat maxZoomScale; | |
| 55 | - | |
| 56 | -/// 自动计算严格缩放比例后,再乘以这个值作为最终缩放比例,默认 1.5 | |
| 57 | -@property (nonatomic, assign) CGFloat zoomScaleSurplus; | |
| 58 | - | |
| 59 | -@end | |
| 60 | - | |
| 61 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageLayout.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageLayout.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/12. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBImageLayout.h" | |
| 10 | - | |
| 11 | -@implementation YBIBImageLayout | |
| 12 | - | |
| 13 | -#pragma mark - life cycle | |
| 14 | - | |
| 15 | -- (instancetype)init { | |
| 16 | - self = [super init]; | |
| 17 | - if (self) { | |
| 18 | - _verticalFillType = YBIBImageFillTypeCompletely; | |
| 19 | - _horizontalFillType = YBIBImageFillTypeFullWidth; | |
| 20 | - _zoomScaleSurplus = 1.5; | |
| 21 | - } | |
| 22 | - return self; | |
| 23 | -} | |
| 24 | - | |
| 25 | -#pragma mark - private | |
| 26 | - | |
| 27 | -- (YBIBImageFillType)fillTypeByOrientation:(UIDeviceOrientation)orientation { | |
| 28 | - return UIDeviceOrientationIsLandscape(orientation) ? self.horizontalFillType : self.verticalFillType; | |
| 29 | -} | |
| 30 | - | |
| 31 | -#pragma mark - <YBIBImageLayout> | |
| 32 | - | |
| 33 | -- (CGRect)yb_imageViewFrameWithContainerSize:(CGSize)containerSize imageSize:(CGSize)imageSize orientation:(UIDeviceOrientation)orientation { | |
| 34 | - if (containerSize.width <= 0 || containerSize.height <= 0 || imageSize.width <= 0 || imageSize.height <= 0) return CGRectZero; | |
| 35 | - | |
| 36 | - CGFloat x = 0, y = 0, width = 0, height = 0; | |
| 37 | - switch ([self fillTypeByOrientation:orientation]) { | |
| 38 | - case YBIBImageFillTypeFullWidth: { | |
| 39 | - x = 0; | |
| 40 | - width = containerSize.width; | |
| 41 | - height = containerSize.width * (imageSize.height / imageSize.width); | |
| 42 | - if (imageSize.width / imageSize.height >= containerSize.width / containerSize.height) | |
| 43 | - y = (containerSize.height - height) / 2.0; | |
| 44 | - else | |
| 45 | - y = 0; | |
| 46 | - } | |
| 47 | - break; | |
| 48 | - case YBIBImageFillTypeCompletely: { | |
| 49 | - if (imageSize.width / imageSize.height >= containerSize.width / containerSize.height) { | |
| 50 | - width = containerSize.width; | |
| 51 | - height = containerSize.width * (imageSize.height / imageSize.width); | |
| 52 | - x = 0; | |
| 53 | - y = (containerSize.height - height) / 2.0; | |
| 54 | - } else { | |
| 55 | - height = containerSize.height; | |
| 56 | - width = containerSize.height * (imageSize.width / imageSize.height); | |
| 57 | - x = (containerSize.width - width) / 2.0; | |
| 58 | - y = 0; | |
| 59 | - } | |
| 60 | - } | |
| 61 | - break; | |
| 62 | - default: return CGRectZero; | |
| 63 | - } | |
| 64 | - return CGRectMake(x, y, width, height); | |
| 65 | -} | |
| 66 | - | |
| 67 | -- (CGFloat)yb_maximumZoomScaleWithContainerSize:(CGSize)containerSize imageSize:(CGSize)imageSize orientation:(UIDeviceOrientation)orientation { | |
| 68 | - if (self.maxZoomScale >= 1) return self.maxZoomScale; | |
| 69 | - | |
| 70 | - if (containerSize.width <= 0 || containerSize.height <= 0) return 0; | |
| 71 | - | |
| 72 | - CGFloat scale = [UIScreen mainScreen].scale; | |
| 73 | - if (scale <= 0) return 0; | |
| 74 | - | |
| 75 | - CGFloat widthScale = imageSize.width / scale / containerSize.width, | |
| 76 | - heightScale = imageSize.height / scale / containerSize.height, | |
| 77 | - maxScale = 1; | |
| 78 | - switch ([self fillTypeByOrientation:orientation]) { | |
| 79 | - case YBIBImageFillTypeFullWidth: | |
| 80 | - maxScale = widthScale; | |
| 81 | - break; | |
| 82 | - case YBIBImageFillTypeCompletely: | |
| 83 | - maxScale = MAX(widthScale, heightScale); | |
| 84 | - break; | |
| 85 | - default: return 0; | |
| 86 | - } | |
| 87 | - return MAX(maxScale, 1) * self.zoomScaleSurplus; | |
| 88 | -} | |
| 89 | - | |
| 90 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageScrollView.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageScrollView.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/10. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBImage.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -typedef NS_ENUM(NSInteger, YBIBScrollImageType) { | |
| 14 | - YBIBScrollImageTypeNone, | |
| 15 | - YBIBScrollImageTypeOriginal, | |
| 16 | - YBIBScrollImageTypeCompressed, | |
| 17 | - YBIBScrollImageTypeThumb | |
| 18 | -}; | |
| 19 | - | |
| 20 | -@interface YBIBImageScrollView : UIScrollView | |
| 21 | - | |
| 22 | -- (void)setImage:(__kindof UIImage *)image type:(YBIBScrollImageType)type; | |
| 23 | - | |
| 24 | -@property (nonatomic, strong, readonly) YYAnimatedImageView *imageView; | |
| 25 | - | |
| 26 | -@property (nonatomic, assign) YBIBScrollImageType imageType; | |
| 27 | - | |
| 28 | -- (void)reset; | |
| 29 | - | |
| 30 | -@end | |
| 31 | - | |
| 32 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBImageScrollView.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBImageScrollView.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/10. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBImageScrollView.h" | |
| 10 | - | |
| 11 | -@interface YBIBImageScrollView () | |
| 12 | -@property (nonatomic, strong) YYAnimatedImageView *imageView; | |
| 13 | -@end | |
| 14 | - | |
| 15 | -@implementation YBIBImageScrollView | |
| 16 | - | |
| 17 | -#pragma mark - life cycle | |
| 18 | - | |
| 19 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 20 | - self = [super initWithFrame:frame]; | |
| 21 | - if (self) { | |
| 22 | - self.showsHorizontalScrollIndicator = NO; | |
| 23 | - self.showsVerticalScrollIndicator = NO; | |
| 24 | - self.decelerationRate = UIScrollViewDecelerationRateFast; | |
| 25 | - self.maximumZoomScale = 1; | |
| 26 | - self.minimumZoomScale = 1; | |
| 27 | - self.alwaysBounceHorizontal = NO; | |
| 28 | - self.alwaysBounceVertical = NO; | |
| 29 | - self.layer.masksToBounds = NO; | |
| 30 | - if (@available(iOS 11.0, *)) { | |
| 31 | - self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; | |
| 32 | - } | |
| 33 | - | |
| 34 | - [self addSubview:self.imageView]; | |
| 35 | - } | |
| 36 | - return self; | |
| 37 | -} | |
| 38 | - | |
| 39 | -#pragma mark - public | |
| 40 | - | |
| 41 | -- (void)setImage:(__kindof UIImage *)image type:(YBIBScrollImageType)type { | |
| 42 | - self.imageView.image = image; | |
| 43 | - self.imageType = type; | |
| 44 | -} | |
| 45 | - | |
| 46 | -- (void)reset { | |
| 47 | - self.zoomScale = 1; | |
| 48 | - self.imageView.image = nil; | |
| 49 | - self.imageView.frame = CGRectZero; | |
| 50 | - self.imageType = YBIBScrollImageTypeNone; | |
| 51 | -} | |
| 52 | - | |
| 53 | -#pragma mark - getters | |
| 54 | - | |
| 55 | -- (YYAnimatedImageView *)imageView { | |
| 56 | - if (!_imageView) { | |
| 57 | - _imageView = [YYAnimatedImageView new]; | |
| 58 | - _imageView.contentMode = UIViewContentModeScaleAspectFill; | |
| 59 | - _imageView.layer.masksToBounds = YES; | |
| 60 | - } | |
| 61 | - return _imageView; | |
| 62 | -} | |
| 63 | - | |
| 64 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBInteractionProfile.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBInteractionProfile.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/30. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface YBIBInteractionProfile : NSObject | |
| 14 | - | |
| 15 | -/// 是否取消手势交互动效 | |
| 16 | -@property (nonatomic, assign) BOOL disable; | |
| 17 | - | |
| 18 | -/// 拖动的距离与最大高度的比例,达到这个比例就会出场 | |
| 19 | -@property (nonatomic, assign) CGFloat dismissScale; | |
| 20 | - | |
| 21 | -/// 拖动的速度,达到这个值就会出场 | |
| 22 | -@property (nonatomic, assign) CGFloat dismissVelocityY; | |
| 23 | - | |
| 24 | -/// 拖动动效复位时的时长 | |
| 25 | -@property (nonatomic, assign) CGFloat restoreDuration; | |
| 26 | - | |
| 27 | -/// 拖动触发手势交互动效的起始距离 | |
| 28 | -@property (nonatomic, assign) CGFloat triggerDistance; | |
| 29 | - | |
| 30 | -@end | |
| 31 | - | |
| 32 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBIBInteractionProfile.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBInteractionProfile.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/30. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBInteractionProfile.h" | |
| 10 | - | |
| 11 | -@implementation YBIBInteractionProfile | |
| 12 | - | |
| 13 | -- (instancetype)init { | |
| 14 | - self = [super init]; | |
| 15 | - if (self) { | |
| 16 | - _disable = NO; | |
| 17 | - _dismissScale = 0.22; | |
| 18 | - _dismissVelocityY = 800; | |
| 19 | - _restoreDuration = 0.15; | |
| 20 | - _triggerDistance = 3; | |
| 21 | - } | |
| 22 | - return self; | |
| 23 | -} | |
| 24 | - | |
| 25 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBImage.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBImage.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/8/31. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#if __has_include(<YYImage/YYImage.h>) | |
| 10 | -#import <YYImage/YYFrameImage.h> | |
| 11 | -#import <YYImage/YYSpriteSheetImage.h> | |
| 12 | -#import <YYImage/YYImageCoder.h> | |
| 13 | -#import <YYImage/YYAnimatedImageView.h> | |
| 14 | -#elif __has_include(<YYWebImage/YYImage.h>) | |
| 15 | -#import <YYWebImage/YYFrameImage.h> | |
| 16 | -#import <YYWebImage/YYSpriteSheetImage.h> | |
| 17 | -#import <YYWebImage/YYImageCoder.h> | |
| 18 | -#import <YYWebImage/YYAnimatedImageView.h> | |
| 19 | -#else | |
| 20 | -#import "YYFrameImage.h" | |
| 21 | -#import "YYSpriteSheetImage.h" | |
| 22 | -#import "YYImageCoder.h" | |
| 23 | -#import "YYAnimatedImageView.h" | |
| 24 | -#endif | |
| 25 | - | |
| 26 | -NS_ASSUME_NONNULL_BEGIN | |
| 27 | - | |
| 28 | -/// 🙄波儿菜:Decide whether should to decode by image size. ('imageSize': physical pixel) | |
| 29 | -typedef BOOL(^YBImageDecodeDecision)(CGSize imageSize, CGFloat scale); | |
| 30 | - | |
| 31 | -/** | |
| 32 | - It is a fully compatible `UIImage` subclass. It extends the UIImage | |
| 33 | - to support animated WebP, APNG and GIF format image data decoding. It also | |
| 34 | - support NSCoding protocol to archive and unarchive multi-frame image data. | |
| 35 | - | |
| 36 | - If the image is created from multi-frame image data, and you want to play the | |
| 37 | - animation, try replace UIImageView with `YYAnimatedImageView`. | |
| 38 | - | |
| 39 | - 🙄波儿菜:Copied from 'YYImage' and made some extensions. | |
| 40 | - */ | |
| 41 | - | |
| 42 | -@interface YBImage : UIImage <YYAnimatedImage> | |
| 43 | - | |
| 44 | -+ (nullable __kindof UIImage *)imageNamed:(NSString *)name; // no cache! | |
| 45 | -+ (nullable YBImage *)imageWithContentsOfFile:(NSString *)path; | |
| 46 | -+ (nullable YBImage *)imageWithData:(NSData *)data; | |
| 47 | -+ (nullable YBImage *)imageWithData:(NSData *)data scale:(CGFloat)scale; | |
| 48 | - | |
| 49 | -/// 🙄波儿菜:Expand methodes. | |
| 50 | -/// Start -> | |
| 51 | -+ (nullable __kindof UIImage *)imageNamed:(NSString *)name decodeDecision:(nullable YBImageDecodeDecision)decodeDecision; | |
| 52 | -+ (nullable YBImage *)imageWithContentsOfFile:(NSString *)path decodeDecision:(nullable YBImageDecodeDecision)decodeDecision; | |
| 53 | -+ (nullable YBImage *)imageWithData:(NSData *)data decodeDecision:(nullable YBImageDecodeDecision)decodeDecision; | |
| 54 | -+ (nullable YBImage *)imageWithData:(NSData *)data scale:(CGFloat)scale decodeDecision:(nullable YBImageDecodeDecision)decodeDecision; | |
| 55 | -/// <- End | |
| 56 | - | |
| 57 | -/** | |
| 58 | - If the image is created from data or file, then the value indicates the data type. | |
| 59 | - */ | |
| 60 | -@property (nonatomic, readonly) YYImageType animatedImageType; | |
| 61 | - | |
| 62 | -/** | |
| 63 | - If the image is created from animated image data (multi-frame GIF/APNG/WebP), | |
| 64 | - this property stores the original image data. | |
| 65 | - */ | |
| 66 | -@property (nullable, nonatomic, readonly) NSData *animatedImageData; | |
| 67 | - | |
| 68 | -/** | |
| 69 | - The total memory usage (in bytes) if all frame images was loaded into memory. | |
| 70 | - The value is 0 if the image is not created from a multi-frame image data. | |
| 71 | - */ | |
| 72 | -@property (nonatomic, readonly) NSUInteger animatedImageMemorySize; | |
| 73 | - | |
| 74 | -/** | |
| 75 | - Preload all frame image to memory. | |
| 76 | - | |
| 77 | - @discussion Set this property to `YES` will block the calling thread to decode | |
| 78 | - all animation frame image to memory, set to `NO` will release the preloaded frames. | |
| 79 | - If the image is shared by lots of image views (such as emoticon), preload all | |
| 80 | - frames will reduce the CPU cost. | |
| 81 | - | |
| 82 | - See `animatedImageMemorySize` for memory cost. | |
| 83 | - */ | |
| 84 | -@property (nonatomic) BOOL preloadAllAnimatedImageFrames; | |
| 85 | - | |
| 86 | - | |
| 87 | -@end | |
| 88 | - | |
| 89 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Image/YBImage.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBImage.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/8/31. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBImage.h" | |
| 10 | -#import "YBIBImageData.h" | |
| 11 | -#import "YBIBUtilities.h" | |
| 12 | - | |
| 13 | -/** | |
| 14 | - An array of NSNumber objects, shows the best order for path scale search. | |
| 15 | - e.g. iPhone3GS:@[@1,@2,@3] iPhone5:@[@2,@3,@1] iPhone6 Plus:@[@3,@2,@1] | |
| 16 | - */ | |
| 17 | -static NSArray *_NSBundlePreferredScales() { | |
| 18 | - static NSArray *scales; | |
| 19 | - static dispatch_once_t onceToken; | |
| 20 | - dispatch_once(&onceToken, ^{ | |
| 21 | - CGFloat screenScale = [UIScreen mainScreen].scale; | |
| 22 | - if (screenScale <= 1) { | |
| 23 | - scales = @[@1,@2,@3]; | |
| 24 | - } else if (screenScale <= 2) { | |
| 25 | - scales = @[@2,@3,@1]; | |
| 26 | - } else { | |
| 27 | - scales = @[@3,@2,@1]; | |
| 28 | - } | |
| 29 | - }); | |
| 30 | - return scales; | |
| 31 | -} | |
| 32 | - | |
| 33 | -/** | |
| 34 | - Add scale modifier to the file name (without path extension), | |
| 35 | - From @"name" to @"name@2x". | |
| 36 | - | |
| 37 | - e.g. | |
| 38 | - <table> | |
| 39 | - <tr><th>Before </th><th>After(scale:2)</th></tr> | |
| 40 | - <tr><td>"icon" </td><td>"icon@2x" </td></tr> | |
| 41 | - <tr><td>"icon " </td><td>"icon @2x" </td></tr> | |
| 42 | - <tr><td>"icon.top" </td><td>"icon.top@2x" </td></tr> | |
| 43 | - <tr><td>"/p/name" </td><td>"/p/name@2x" </td></tr> | |
| 44 | - <tr><td>"/path/" </td><td>"/path/" </td></tr> | |
| 45 | - </table> | |
| 46 | - | |
| 47 | - @param scale Resource scale. | |
| 48 | - @return String by add scale modifier, or just return if it's not end with file name. | |
| 49 | - */ | |
| 50 | -static NSString *_NSStringByAppendingNameScale(NSString *string, CGFloat scale) { | |
| 51 | - if (!string) return nil; | |
| 52 | - if (fabs(scale - 1) <= __FLT_EPSILON__ || string.length == 0 || [string hasSuffix:@"/"]) return string.copy; | |
| 53 | - return [string stringByAppendingFormat:@"@%@x", @(scale)]; | |
| 54 | -} | |
| 55 | - | |
| 56 | -/** | |
| 57 | - Return the path scale. | |
| 58 | - | |
| 59 | - e.g. | |
| 60 | - <table> | |
| 61 | - <tr><th>Path </th><th>Scale </th></tr> | |
| 62 | - <tr><td>"icon.png" </td><td>1 </td></tr> | |
| 63 | - <tr><td>"icon@2x.png" </td><td>2 </td></tr> | |
| 64 | - <tr><td>"icon@2.5x.png" </td><td>2.5 </td></tr> | |
| 65 | - <tr><td>"icon@2x" </td><td>1 </td></tr> | |
| 66 | - <tr><td>"icon@2x..png" </td><td>1 </td></tr> | |
| 67 | - <tr><td>"icon@2x.png/" </td><td>1 </td></tr> | |
| 68 | - </table> | |
| 69 | - */ | |
| 70 | -static CGFloat _NSStringPathScale(NSString *string) { | |
| 71 | - if (string.length == 0 || [string hasSuffix:@"/"]) return 1; | |
| 72 | - NSString *name = string.stringByDeletingPathExtension; | |
| 73 | - __block CGFloat scale = 1; | |
| 74 | - | |
| 75 | - NSRegularExpression *pattern = [NSRegularExpression regularExpressionWithPattern:@"@[0-9]+\\.?[0-9]*x$" options:NSRegularExpressionAnchorsMatchLines error:nil]; | |
| 76 | - [pattern enumerateMatchesInString:name options:kNilOptions range:NSMakeRange(0, name.length) usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) { | |
| 77 | - if (result.range.location >= 3) { | |
| 78 | - scale = [string substringWithRange:NSMakeRange(result.range.location + 1, result.range.length - 2)].doubleValue; | |
| 79 | - } | |
| 80 | - }]; | |
| 81 | - | |
| 82 | - return scale; | |
| 83 | -} | |
| 84 | - | |
| 85 | - | |
| 86 | -@implementation YBImage { | |
| 87 | - YYImageDecoder *_decoder; | |
| 88 | - NSArray *_preloadedFrames; | |
| 89 | - dispatch_semaphore_t _preloadedLock; | |
| 90 | - NSUInteger _bytesPerFrame; | |
| 91 | -} | |
| 92 | - | |
| 93 | -+ (__kindof UIImage *)imageNamed:(NSString *)name { | |
| 94 | - return [self imageNamed:name decodeDecision:nil]; | |
| 95 | -} | |
| 96 | -+ (__kindof UIImage *)imageNamed:(NSString *)name decodeDecision:(nullable YBImageDecodeDecision)decodeDecision { | |
| 97 | - if (name.length == 0) return nil; | |
| 98 | - if ([name hasSuffix:@"/"]) return nil; | |
| 99 | - | |
| 100 | - NSString *res = name.stringByDeletingPathExtension; | |
| 101 | - NSString *ext = name.pathExtension; | |
| 102 | - NSString *path = nil; | |
| 103 | - CGFloat scale = 1; | |
| 104 | - | |
| 105 | - // If no extension, guess by system supported (same as UIImage). | |
| 106 | - NSArray *exts = ext.length > 0 ? @[ext] : @[@"", @"png", @"jpeg", @"jpg", @"gif", @"webp", @"apng"]; | |
| 107 | - NSArray *scales = _NSBundlePreferredScales(); | |
| 108 | - for (int s = 0; s < scales.count; s++) { | |
| 109 | - scale = ((NSNumber *)scales[s]).floatValue; | |
| 110 | - NSString *scaledName = _NSStringByAppendingNameScale(res, scale); | |
| 111 | - for (NSString *e in exts) { | |
| 112 | - path = [[NSBundle mainBundle] pathForResource:scaledName ofType:e]; | |
| 113 | - if (path) break; | |
| 114 | - } | |
| 115 | - if (path) break; | |
| 116 | - } | |
| 117 | - if (path.length == 0) { | |
| 118 | - // 🙄波儿菜:Assets.xcassets supported. | |
| 119 | - return [super imageNamed:name]; | |
| 120 | - } | |
| 121 | - | |
| 122 | - NSData *data = [NSData dataWithContentsOfFile:path]; | |
| 123 | - if (data.length == 0) return nil; | |
| 124 | - | |
| 125 | - return [[self alloc] initWithData:data scale:scale decodeDecision:decodeDecision]; | |
| 126 | -} | |
| 127 | - | |
| 128 | -+ (YBImage *)imageWithContentsOfFile:(NSString *)path { | |
| 129 | - return [self imageWithContentsOfFile:path decodeDecision:nil]; | |
| 130 | -} | |
| 131 | -+ (YBImage *)imageWithContentsOfFile:(NSString *)path decodeDecision:(nullable YBImageDecodeDecision)decodeDecision { | |
| 132 | - return [[self alloc] initWithContentsOfFile:path decodeDecision:decodeDecision]; | |
| 133 | -} | |
| 134 | - | |
| 135 | -+ (YBImage *)imageWithData:(NSData *)data { | |
| 136 | - return [self imageWithData:data decodeDecision:nil]; | |
| 137 | -} | |
| 138 | -+ (YBImage *)imageWithData:(NSData *)data decodeDecision:(nullable YBImageDecodeDecision)decodeDecision { | |
| 139 | - return [[self alloc] initWithData:data decodeDecision:decodeDecision]; | |
| 140 | -} | |
| 141 | - | |
| 142 | -+ (YBImage *)imageWithData:(NSData *)data scale:(CGFloat)scale { | |
| 143 | - return [self imageWithData:data scale:scale decodeDecision:nil]; | |
| 144 | -} | |
| 145 | -+ (YBImage *)imageWithData:(NSData *)data scale:(CGFloat)scale decodeDecision:(nullable YBImageDecodeDecision)decodeDecision { | |
| 146 | - return [[self alloc] initWithData:data scale:scale decodeDecision:decodeDecision]; | |
| 147 | -} | |
| 148 | - | |
| 149 | -- (instancetype)initWithContentsOfFile:(NSString *)path { | |
| 150 | - return [self initWithContentsOfFile:path decodeDecision:nil]; | |
| 151 | -} | |
| 152 | -- (instancetype)initWithContentsOfFile:(NSString *)path decodeDecision:(nullable YBImageDecodeDecision)decodeDecision { | |
| 153 | - NSData *data = [NSData dataWithContentsOfFile:path]; | |
| 154 | - return [self initWithData:data scale:_NSStringPathScale(path) decodeDecision:decodeDecision]; | |
| 155 | -} | |
| 156 | - | |
| 157 | -- (instancetype)initWithData:(NSData *)data { | |
| 158 | - return [self initWithData:data decodeDecision:nil]; | |
| 159 | -} | |
| 160 | -- (instancetype)initWithData:(NSData *)data decodeDecision:(nullable YBImageDecodeDecision)decodeDecision { | |
| 161 | - return [self initWithData:data scale:1 decodeDecision:decodeDecision]; | |
| 162 | -} | |
| 163 | - | |
| 164 | -- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale { | |
| 165 | - return [self initWithData:data scale:scale decodeDecision:nil]; | |
| 166 | -} | |
| 167 | -- (instancetype)initWithData:(NSData *)data scale:(CGFloat)scale decodeDecision:(nullable YBImageDecodeDecision)decodeDecision { | |
| 168 | - if (data.length == 0) return nil; | |
| 169 | - if (scale <= 0) scale = [UIScreen mainScreen].scale; | |
| 170 | - _preloadedLock = dispatch_semaphore_create(1); | |
| 171 | - @autoreleasepool { | |
| 172 | - YYImageDecoder *decoder = [YYImageDecoder decoderWithData:data scale:scale]; | |
| 173 | - | |
| 174 | - // 🙄波儿菜:Determine whether should to decode. | |
| 175 | - BOOL decodeForDisplay = YES; | |
| 176 | - if (decodeDecision) { | |
| 177 | - decodeForDisplay = decodeDecision(CGSizeMake(decoder.width, decoder.height), decoder.scale ?: 1); | |
| 178 | - } | |
| 179 | - | |
| 180 | - YYImageFrame *frame = [decoder frameAtIndex:0 decodeForDisplay:decodeForDisplay]; | |
| 181 | - UIImage *image = frame.image; | |
| 182 | - if (!image) return nil; | |
| 183 | - self = [self initWithCGImage:image.CGImage scale:decoder.scale orientation:image.imageOrientation]; | |
| 184 | - if (!self) return nil; | |
| 185 | - _animatedImageType = decoder.type; | |
| 186 | - if (decoder.frameCount > 1) { | |
| 187 | - _decoder = decoder; | |
| 188 | - _bytesPerFrame = CGImageGetBytesPerRow(image.CGImage) * CGImageGetHeight(image.CGImage); | |
| 189 | - _animatedImageMemorySize = _bytesPerFrame * decoder.frameCount; | |
| 190 | - } | |
| 191 | - self.yy_isDecodedForDisplay = YES; | |
| 192 | - } | |
| 193 | - return self; | |
| 194 | -} | |
| 195 | - | |
| 196 | -- (NSData *)animatedImageData { | |
| 197 | - return _decoder.data; | |
| 198 | -} | |
| 199 | - | |
| 200 | -- (void)setPreloadAllAnimatedImageFrames:(BOOL)preloadAllAnimatedImageFrames { | |
| 201 | - if (_preloadAllAnimatedImageFrames != preloadAllAnimatedImageFrames) { | |
| 202 | - if (preloadAllAnimatedImageFrames && _decoder.frameCount > 0) { | |
| 203 | - NSMutableArray *frames = [NSMutableArray new]; | |
| 204 | - for (NSUInteger i = 0, max = _decoder.frameCount; i < max; i++) { | |
| 205 | - UIImage *img = [self animatedImageFrameAtIndex:i]; | |
| 206 | - if (img) { | |
| 207 | - [frames addObject:img]; | |
| 208 | - } else { | |
| 209 | - [frames addObject:[NSNull null]]; | |
| 210 | - } | |
| 211 | - } | |
| 212 | - dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); | |
| 213 | - _preloadedFrames = frames; | |
| 214 | - dispatch_semaphore_signal(_preloadedLock); | |
| 215 | - } else { | |
| 216 | - dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); | |
| 217 | - _preloadedFrames = nil; | |
| 218 | - dispatch_semaphore_signal(_preloadedLock); | |
| 219 | - } | |
| 220 | - } | |
| 221 | -} | |
| 222 | - | |
| 223 | -#pragma mark - protocol NSCoding | |
| 224 | - | |
| 225 | -- (instancetype)initWithCoder:(NSCoder *)aDecoder { | |
| 226 | - NSNumber *scale = [aDecoder decodeObjectForKey:@"YYImageScale"]; | |
| 227 | - NSData *data = [aDecoder decodeObjectForKey:@"YYImageData"]; | |
| 228 | - if (data.length) { | |
| 229 | - self = [self initWithData:data scale:scale.doubleValue]; | |
| 230 | - } else { | |
| 231 | - self = [super initWithCoder:aDecoder]; | |
| 232 | - } | |
| 233 | - return self; | |
| 234 | -} | |
| 235 | - | |
| 236 | -- (void)encodeWithCoder:(NSCoder *)aCoder { | |
| 237 | - if (_decoder.data.length) { | |
| 238 | - [aCoder encodeObject:@(self.scale) forKey:@"YYImageScale"]; | |
| 239 | - [aCoder encodeObject:_decoder.data forKey:@"YYImageData"]; | |
| 240 | - } else { | |
| 241 | - [super encodeWithCoder:aCoder]; // Apple use UIImagePNGRepresentation() to encode UIImage. | |
| 242 | - } | |
| 243 | -} | |
| 244 | - | |
| 245 | -#pragma mark - protocol YYAnimatedImage | |
| 246 | - | |
| 247 | -- (NSUInteger)animatedImageFrameCount { | |
| 248 | - return _decoder.frameCount; | |
| 249 | -} | |
| 250 | - | |
| 251 | -- (NSUInteger)animatedImageLoopCount { | |
| 252 | - return _decoder.loopCount; | |
| 253 | -} | |
| 254 | - | |
| 255 | -- (NSUInteger)animatedImageBytesPerFrame { | |
| 256 | - return _bytesPerFrame; | |
| 257 | -} | |
| 258 | - | |
| 259 | -- (UIImage *)animatedImageFrameAtIndex:(NSUInteger)index { | |
| 260 | - if (index >= _decoder.frameCount) return nil; | |
| 261 | - dispatch_semaphore_wait(_preloadedLock, DISPATCH_TIME_FOREVER); | |
| 262 | - UIImage *image = _preloadedFrames[index]; | |
| 263 | - dispatch_semaphore_signal(_preloadedLock); | |
| 264 | - if (image) return image == (id)[NSNull null] ? nil : image; | |
| 265 | - return [_decoder frameAtIndex:index decodeForDisplay:YES].image; | |
| 266 | -} | |
| 267 | - | |
| 268 | -- (NSTimeInterval)animatedImageDurationAtIndex:(NSUInteger)index { | |
| 269 | - NSTimeInterval duration = [_decoder frameDurationAtIndex:index]; | |
| 270 | - | |
| 271 | - /* | |
| 272 | - http://opensource.apple.com/source/WebCore/WebCore-7600.1.25/platform/graphics/cg/ImageSourceCG.cpp | |
| 273 | - Many annoying ads specify a 0 duration to make an image flash as quickly as | |
| 274 | - possible. We follow Safari and Firefox's behavior and use a duration of 100 ms | |
| 275 | - for any frames that specify a duration of <= 10 ms. | |
| 276 | - See <rdar://problem/7689300> and <http://webkit.org/b/36082> for more information. | |
| 277 | - | |
| 278 | - See also: http://nullsleep.tumblr.com/post/16524517190/animated-gif-minimum-frame-delay-browser. | |
| 279 | - */ | |
| 280 | - if (duration < 0.011f) return 0.100f; | |
| 281 | - return duration; | |
| 282 | -} | |
| 283 | - | |
| 284 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Protocol/YBIBCellProtocol.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBCellProtocol.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/5. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBGetBaseInfoProtocol.h" | |
| 10 | -#import "YBIBOrientationReceiveProtocol.h" | |
| 11 | -#import "YBIBOperateBrowserProtocol.h" | |
| 12 | - | |
| 13 | -@protocol YBIBDataProtocol; | |
| 14 | - | |
| 15 | -NS_ASSUME_NONNULL_BEGIN | |
| 16 | - | |
| 17 | -@protocol YBIBCellProtocol <YBIBGetBaseInfoProtocol, YBIBOperateBrowserProtocol, YBIBOrientationReceiveProtocol> | |
| 18 | - | |
| 19 | -@required | |
| 20 | - | |
| 21 | -/// Cell 对应的 Data | |
| 22 | -@property (nonatomic, strong) id<YBIBDataProtocol> yb_cellData; | |
| 23 | - | |
| 24 | -@optional | |
| 25 | - | |
| 26 | -/** | |
| 27 | - 获取前景视图,出入场时需要用这个返回值做动效 | |
| 28 | - | |
| 29 | - @return 前景视图 | |
| 30 | - */ | |
| 31 | -- (__kindof UIView *)yb_foregroundView; | |
| 32 | - | |
| 33 | -/** | |
| 34 | - 页码变化了 | |
| 35 | - */ | |
| 36 | -- (void)yb_pageChanged; | |
| 37 | - | |
| 38 | -/// 当前 Cell 的页码 | |
| 39 | -@property (nonatomic, copy) NSInteger(^yb_selfPage)(void); | |
| 40 | - | |
| 41 | -@end | |
| 42 | - | |
| 43 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Protocol/YBIBDataProtocol.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBDataProtocol.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/5. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBGetBaseInfoProtocol.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@protocol YBIBDataProtocol <YBIBGetBaseInfoProtocol> | |
| 14 | - | |
| 15 | -@required | |
| 16 | - | |
| 17 | -/** | |
| 18 | - 当前 Data 对应 Cell 的类类型 | |
| 19 | - | |
| 20 | - @return Class 类型 | |
| 21 | - */ | |
| 22 | -- (Class)yb_classOfCell; | |
| 23 | - | |
| 24 | -@optional | |
| 25 | - | |
| 26 | -/** | |
| 27 | - 获取投影视图,当前数据模型对应外界业务的 UIView (通常为 UIImageView),做转场动效用 | |
| 28 | - | |
| 29 | - 这个方法会在做出入场动效时调用,若未实现时将无法进行平滑的入场 | |
| 30 | - | |
| 31 | - @return 投影视图 | |
| 32 | - */ | |
| 33 | -- (__kindof UIView *)yb_projectiveView; | |
| 34 | - | |
| 35 | -/** | |
| 36 | - 通过一系列数据,计算并返回图片视图在容器中的 frame | |
| 37 | - | |
| 38 | - 这个方法会在做入场动效时调用,若未实现时将无法进行平滑的入场 | |
| 39 | - | |
| 40 | - @param containerSize 容器大小 | |
| 41 | - @param imageSize 图片大小 (逻辑像素) | |
| 42 | - @param orientation 图片浏览器的方向 | |
| 43 | - @return 计算好的 frame | |
| 44 | - */ | |
| 45 | -- (CGRect)yb_imageViewFrameWithContainerSize:(CGSize)containerSize imageSize:(CGSize)imageSize orientation:(UIDeviceOrientation)orientation; | |
| 46 | - | |
| 47 | -/** | |
| 48 | - 预加载数据,有效的预加载能提高性能,请注意管理内存 | |
| 49 | - */ | |
| 50 | -- (void)yb_preload; | |
| 51 | - | |
| 52 | -/** | |
| 53 | - 保存到相册 | |
| 54 | - */ | |
| 55 | -- (void)yb_saveToPhotoAlbum; | |
| 56 | - | |
| 57 | -/** | |
| 58 | - 是否允许保存到相册 | |
| 59 | - */ | |
| 60 | -- (BOOL)yb_allowSaveToPhotoAlbum; | |
| 61 | - | |
| 62 | -@end | |
| 63 | - | |
| 64 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Protocol/YBIBGetBaseInfoProtocol.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBGetBaseInfoProtocol.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/23. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | -#import "YBIBAuxiliaryViewHandler.h" | |
| 11 | -#import "YBIBWebImageMediator.h" | |
| 12 | - | |
| 13 | -NS_ASSUME_NONNULL_BEGIN | |
| 14 | - | |
| 15 | -@protocol YBIBGetBaseInfoProtocol <NSObject> | |
| 16 | - | |
| 17 | -@optional | |
| 18 | - | |
| 19 | -/// 当前的方向 | |
| 20 | -@property (nonatomic, copy) UIDeviceOrientation(^yb_currentOrientation)(void); | |
| 21 | - | |
| 22 | -/// 根据方向获取容器大小 | |
| 23 | -@property (nonatomic, copy) CGSize(^yb_containerSize)(UIDeviceOrientation orientation); | |
| 24 | - | |
| 25 | -/// 容器视图 (可在上面添加子视图) | |
| 26 | -@property (nonatomic, weak) UIView *yb_containerView; | |
| 27 | - | |
| 28 | -/// 辅助视图处理器 | |
| 29 | -@property (nonatomic, copy) id<YBIBAuxiliaryViewHandler>(^yb_auxiliaryViewHandler)(void); | |
| 30 | - | |
| 31 | -/// 图片下载缓存相关中介者 | |
| 32 | -@property (nonatomic, copy) id<YBIBWebImageMediator>(^yb_webImageMediator)(void); | |
| 33 | - | |
| 34 | -/// 当前页码 | |
| 35 | -@property (nonatomic, copy) NSInteger(^yb_currentPage)(void); | |
| 36 | - | |
| 37 | -/// 总页码数量 | |
| 38 | -@property (nonatomic, copy) NSInteger(^yb_totalPage)(void); | |
| 39 | - | |
| 40 | -/// 判断当前展示的 cell 是否恰好在屏幕中间 | |
| 41 | -@property (nonatomic, copy) BOOL(^yb_cellIsInCenter)(void); | |
| 42 | - | |
| 43 | -/// 是否正在转场 | |
| 44 | -@property (nonatomic, copy) BOOL(^yb_isTransitioning)(void); | |
| 45 | -/// 是否正在展示过程转场 | |
| 46 | -@property (nonatomic, copy) BOOL(^yb_isShowTransitioning)(void); | |
| 47 | -/// 是否正在隐藏过程转场 | |
| 48 | -@property (nonatomic, copy) BOOL(^yb_isHideTransitioning)(void); | |
| 49 | - | |
| 50 | -/// 是否正在旋转 | |
| 51 | -@property (nonatomic, copy) BOOL(^yb_isRotating)(void); | |
| 52 | - | |
| 53 | -/// 背景视图 (也就是 YBImageBrower 对象,不可在上面添加子视图。作用:一是可以更改透明度和颜色,入场和出场动效有用;二是可以用来比较内存指针,在做不同实例差异化功能时可能有用,虽然不提倡这么做) | |
| 54 | -@property (nonatomic, weak) __kindof UIView *yb_backView; | |
| 55 | - | |
| 56 | -/// 集合视图 | |
| 57 | -@property (nonatomic, copy) __kindof UICollectionView *(^yb_collectionView)(void); | |
| 58 | - | |
| 59 | -@end | |
| 60 | - | |
| 61 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Protocol/YBIBOperateBrowserProtocol.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBOperateBrowserProtocol.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/8. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <Foundation/Foundation.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@protocol YBIBOperateBrowserProtocol <NSObject> | |
| 14 | - | |
| 15 | -@optional | |
| 16 | - | |
| 17 | -/// 隐藏图片浏览器 | |
| 18 | -@property (nonatomic, copy) void(^yb_hideBrowser)(void); | |
| 19 | - | |
| 20 | -/// 是否隐藏状态栏 | |
| 21 | -@property (nonatomic, copy) void(^yb_hideStatusBar)(BOOL); | |
| 22 | - | |
| 23 | -/// 是否隐藏工具视图 | |
| 24 | -@property (nonatomic, copy) void(^yb_hideToolViews)(BOOL); | |
| 25 | - | |
| 26 | -@end | |
| 27 | - | |
| 28 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Protocol/YBIBOrientationReceiveProtocol.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBOrientationReceiveProtocol.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/8. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@protocol YBIBOrientationReceiveProtocol <NSObject> | |
| 14 | - | |
| 15 | -@optional | |
| 16 | - | |
| 17 | -/** | |
| 18 | - 图片浏览器的方向将要变化 | |
| 19 | - | |
| 20 | - @param orientation 期望的方向 | |
| 21 | - */ | |
| 22 | -- (void)yb_orientationWillChangeWithExpectOrientation:(UIDeviceOrientation)orientation; | |
| 23 | - | |
| 24 | -/** | |
| 25 | - 图片浏览器的方向变化动效调用,实现的变化会自动转换为动画 | |
| 26 | - | |
| 27 | - @param orientation 期望的方向 | |
| 28 | - */ | |
| 29 | -- (void)yb_orientationChangeAnimationWithExpectOrientation:(UIDeviceOrientation)orientation; | |
| 30 | - | |
| 31 | -/** | |
| 32 | - 图片浏览器的方向已经变化 | |
| 33 | - | |
| 34 | - @param orientation 当前的方向 | |
| 35 | - */ | |
| 36 | -- (void)yb_orientationDidChangedWithOrientation:(UIDeviceOrientation)orientation; | |
| 37 | - | |
| 38 | -@end | |
| 39 | - | |
| 40 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Protocol/YBImageBrowserDataSource.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBImageBrowserDataSource.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2018/8/25. | |
| 6 | -// Copyright © 2018年 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBDataProtocol.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@class YBImageBrowser; | |
| 14 | - | |
| 15 | -@protocol YBImageBrowserDataSource <NSObject> | |
| 16 | - | |
| 17 | -@required | |
| 18 | - | |
| 19 | -/** | |
| 20 | - 返回数据源数量 | |
| 21 | - | |
| 22 | - @param imageBrowser 图片浏览器 | |
| 23 | - @return 数量 | |
| 24 | - */ | |
| 25 | -- (NSInteger)yb_numberOfCellsInImageBrowser:(YBImageBrowser *)imageBrowser; | |
| 26 | - | |
| 27 | -/** | |
| 28 | - 返回当前下标对应的数据 | |
| 29 | - | |
| 30 | - @param imageBrowser 图片浏览器 | |
| 31 | - @param index 当前下标 | |
| 32 | - @return 数据 | |
| 33 | - */ | |
| 34 | -- (id<YBIBDataProtocol>)yb_imageBrowser:(YBImageBrowser *)imageBrowser dataForCellAtIndex:(NSInteger)index; | |
| 35 | - | |
| 36 | -@end | |
| 37 | - | |
| 38 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/Protocol/YBImageBrowserDelegate.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBImageBrowserDelegate.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/9. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBDataProtocol.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@class YBImageBrowser; | |
| 14 | - | |
| 15 | -@protocol YBImageBrowserDelegate <NSObject> | |
| 16 | - | |
| 17 | -@optional | |
| 18 | - | |
| 19 | -/** | |
| 20 | - 页码变化 | |
| 21 | - | |
| 22 | - @param imageBrowser 图片浏览器 | |
| 23 | - @param page 当前页码 | |
| 24 | - @param data 数据 | |
| 25 | - */ | |
| 26 | -- (void)yb_imageBrowser:(YBImageBrowser *)imageBrowser pageChanged:(NSInteger)page data:(id<YBIBDataProtocol>)data; | |
| 27 | - | |
| 28 | -/** | |
| 29 | - 响应长按手势(若实现该方法将阻止其它地方捕获到长按事件) | |
| 30 | - | |
| 31 | - @param imageBrowser 图片浏览器 | |
| 32 | - @param data 数据 | |
| 33 | - */ | |
| 34 | -- (void)yb_imageBrowser:(YBImageBrowser *)imageBrowser respondsToLongPressWithData:(id<YBIBDataProtocol>)data; | |
| 35 | - | |
| 36 | -/** | |
| 37 | - 开始转场 | |
| 38 | - | |
| 39 | - @param imageBrowser 图片浏览器 | |
| 40 | - @param isShow YES 表示入场,NO 表示出场 | |
| 41 | - */ | |
| 42 | -- (void)yb_imageBrowser:(YBImageBrowser *)imageBrowser beginTransitioningWithIsShow:(BOOL)isShow; | |
| 43 | - | |
| 44 | -/** | |
| 45 | - 结束转场 | |
| 46 | - | |
| 47 | - @param imageBrowser 图片浏览器 | |
| 48 | - @param isShow YES 表示入场,NO 表示出场 | |
| 49 | - */ | |
| 50 | -- (void)yb_imageBrowser:(YBImageBrowser *)imageBrowser endTransitioningWithIsShow:(BOOL)isShow; | |
| 51 | - | |
| 52 | -@end | |
| 53 | - | |
| 54 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/ToolView/YBIBSheetView.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBSheetView.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/6. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@protocol YBIBDataProtocol; | |
| 14 | - | |
| 15 | -typedef void(^YBIBSheetActionBlock)(id<YBIBDataProtocol> data); | |
| 16 | - | |
| 17 | -@interface YBIBSheetAction : NSObject | |
| 18 | - | |
| 19 | -/// 显示的名字 | |
| 20 | -@property (nonatomic, copy) NSString *name; | |
| 21 | - | |
| 22 | -/// 点击回调闭包 | |
| 23 | -@property (nonatomic, copy, nullable) YBIBSheetActionBlock action; | |
| 24 | - | |
| 25 | -+ (instancetype)actionWithName:(NSString *)name action:(_Nullable YBIBSheetActionBlock)action; | |
| 26 | - | |
| 27 | -@end | |
| 28 | - | |
| 29 | - | |
| 30 | -@interface YBIBSheetView : UIView | |
| 31 | - | |
| 32 | -/// 数据源 (可自定义添加) | |
| 33 | -@property (nonatomic, strong) NSMutableArray<YBIBSheetAction *> *actions; | |
| 34 | - | |
| 35 | -/// 列表 Cell 的高度 | |
| 36 | -@property (nonatomic, assign) CGFloat cellHeight; | |
| 37 | - | |
| 38 | -/// 列表最大高度与容器高度的比例 | |
| 39 | -@property (nonatomic, assign) CGFloat maxHeightScale; | |
| 40 | - | |
| 41 | -/// 取消的文本 | |
| 42 | -@property (nonatomic, copy) NSString *cancelText; | |
| 43 | - | |
| 44 | -/// 显示动画持续时间 | |
| 45 | -@property (nonatomic, assign) NSTimeInterval showDuration; | |
| 46 | - | |
| 47 | -/// 隐藏动画持续时间 | |
| 48 | -@property (nonatomic, assign) NSTimeInterval hideDuration; | |
| 49 | - | |
| 50 | -/// 背景透明度 | |
| 51 | -@property (nonatomic, assign) CGFloat backAlpha; | |
| 52 | - | |
| 53 | -/** | |
| 54 | - 展示 | |
| 55 | - | |
| 56 | - @param view 指定父视图 | |
| 57 | - @param orientation 当前方向 | |
| 58 | - */ | |
| 59 | -- (void)showToView:(UIView *)view orientation:(UIDeviceOrientation)orientation; | |
| 60 | - | |
| 61 | -/** | |
| 62 | - 隐藏 | |
| 63 | - | |
| 64 | - @param animation 是否带动画 | |
| 65 | - */ | |
| 66 | -- (void)hideWithAnimation:(BOOL)animation; | |
| 67 | - | |
| 68 | -/// 获取当前数据的闭包 | |
| 69 | -@property (nonatomic, copy) id<YBIBDataProtocol>(^currentdata)(void); | |
| 70 | - | |
| 71 | -@end | |
| 72 | - | |
| 73 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/ToolView/YBIBSheetView.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBSheetView.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/6. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBSheetView.h" | |
| 10 | -#import "YBIBUtilities.h" | |
| 11 | -#import "YBIBCopywriter.h" | |
| 12 | - | |
| 13 | - | |
| 14 | -@implementation YBIBSheetAction | |
| 15 | -+ (instancetype)actionWithName:(NSString *)name action:(YBIBSheetActionBlock)action { | |
| 16 | - YBIBSheetAction *sheetAction = [YBIBSheetAction new]; | |
| 17 | - sheetAction.name = name; | |
| 18 | - sheetAction.action = action; | |
| 19 | - return sheetAction; | |
| 20 | -} | |
| 21 | -@end | |
| 22 | - | |
| 23 | - | |
| 24 | -@interface YBIBSheetCell : UITableViewCell | |
| 25 | -@property (nonatomic, strong) UILabel *titleLabel; | |
| 26 | -@property (nonatomic, strong) CALayer *line; | |
| 27 | -@end | |
| 28 | -@implementation YBIBSheetCell | |
| 29 | -- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { | |
| 30 | - if (self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]) { | |
| 31 | - self.selectionStyle = UITableViewCellSelectionStyleNone; | |
| 32 | - _titleLabel = [UILabel new]; | |
| 33 | - _titleLabel.textColor = UIColor.darkTextColor; | |
| 34 | - _titleLabel.font = [UIFont fontWithName:@"Avenir-Medium" size:16]; | |
| 35 | - _titleLabel.textAlignment = NSTextAlignmentCenter; | |
| 36 | - _line = [CALayer new]; | |
| 37 | - _line.backgroundColor = UIColor.groupTableViewBackgroundColor.CGColor; | |
| 38 | - [self.contentView addSubview:_titleLabel]; | |
| 39 | - [self.contentView.layer addSublayer:_line]; | |
| 40 | - } | |
| 41 | - return self; | |
| 42 | -} | |
| 43 | -- (void)layoutSubviews { | |
| 44 | - [super layoutSubviews]; | |
| 45 | - CGFloat width = self.contentView.bounds.size.width, height = self.contentView.bounds.size.height; | |
| 46 | - CGFloat lineHeight = 0.5; | |
| 47 | - _line.frame = CGRectMake(0, height - lineHeight, width, lineHeight); | |
| 48 | - CGFloat offset = 15; | |
| 49 | - _titleLabel.frame = CGRectMake(offset, 0, width - offset * 2, height); | |
| 50 | -} | |
| 51 | -@end | |
| 52 | - | |
| 53 | - | |
| 54 | -static CGFloat kOffsetSpace = 5; | |
| 55 | - | |
| 56 | -@interface YBIBSheetView () <UITableViewDelegate, UITableViewDataSource> | |
| 57 | -@property (nonatomic, strong) UITableView *tableView; | |
| 58 | -@end | |
| 59 | - | |
| 60 | -@implementation YBIBSheetView { | |
| 61 | - CGRect _tableShowFrame; | |
| 62 | - CGRect _tableHideFrame; | |
| 63 | -} | |
| 64 | - | |
| 65 | -#pragma mark - life cycle | |
| 66 | - | |
| 67 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 68 | - self = [super initWithFrame:frame]; | |
| 69 | - if (self) { | |
| 70 | - _cancelText = [YBIBCopywriter sharedCopywriter].cancel; | |
| 71 | - _maxHeightScale = 0.7; | |
| 72 | - _showDuration = 0.2; | |
| 73 | - _hideDuration = 0.1; | |
| 74 | - _cellHeight = 50; | |
| 75 | - _backAlpha = 0.3; | |
| 76 | - _actions = [NSMutableArray array]; | |
| 77 | - | |
| 78 | - [self addSubview:self.tableView]; | |
| 79 | - } | |
| 80 | - return self; | |
| 81 | -} | |
| 82 | - | |
| 83 | -#pragma mark - public | |
| 84 | - | |
| 85 | -- (void)showToView:(UIView *)view orientation:(UIDeviceOrientation)orientation { | |
| 86 | - if (self.actions.count == 0) return; | |
| 87 | - | |
| 88 | - [view addSubview:self]; | |
| 89 | - self.frame = view.bounds; | |
| 90 | - | |
| 91 | - UIEdgeInsets padding = YBIBPaddingByBrowserOrientation(orientation); | |
| 92 | - | |
| 93 | - CGFloat footerHeight = padding.bottom; | |
| 94 | - CGFloat tableHeight = self.cellHeight * (self.actions.count + 1) + kOffsetSpace + footerHeight; | |
| 95 | - | |
| 96 | - _tableShowFrame = self.frame; | |
| 97 | - _tableShowFrame.size.height = MIN(self.maxHeightScale * self.bounds.size.height, tableHeight); | |
| 98 | - _tableShowFrame.origin.y = self.bounds.size.height - _tableShowFrame.size.height; | |
| 99 | - | |
| 100 | - _tableHideFrame = _tableShowFrame; | |
| 101 | - _tableHideFrame.origin.y = self.bounds.size.height; | |
| 102 | - | |
| 103 | - self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0]; | |
| 104 | - self.tableView.frame = _tableHideFrame; | |
| 105 | - self.tableView.tableFooterView.bounds = CGRectMake(0, 0, self.tableView.frame.size.width, footerHeight); | |
| 106 | - [UIView animateWithDuration:self.showDuration animations:^{ | |
| 107 | - self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:self->_backAlpha]; | |
| 108 | - self.tableView.frame = self->_tableShowFrame; | |
| 109 | - }]; | |
| 110 | -} | |
| 111 | - | |
| 112 | -- (void)hideWithAnimation:(BOOL)animation { | |
| 113 | - if (!self.superview) return; | |
| 114 | - | |
| 115 | - void(^animationsBlock)(void) = ^{ | |
| 116 | - self.tableView.frame = self->_tableHideFrame; | |
| 117 | - self.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0]; | |
| 118 | - }; | |
| 119 | - void(^completionBlock)(BOOL n) = ^(BOOL n){ | |
| 120 | - [self removeFromSuperview]; | |
| 121 | - }; | |
| 122 | - if (animation) { | |
| 123 | - [UIView animateWithDuration:self.hideDuration animations:animationsBlock completion:completionBlock]; | |
| 124 | - } else { | |
| 125 | - animationsBlock(); | |
| 126 | - completionBlock(NO); | |
| 127 | - } | |
| 128 | -} | |
| 129 | - | |
| 130 | -#pragma mark - touch | |
| 131 | - | |
| 132 | -- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { | |
| 133 | - CGPoint point = [touches.anyObject locationInView:self]; | |
| 134 | - if (!CGRectContainsPoint(self.tableView.frame, point)) { | |
| 135 | - [self hideWithAnimation:YES]; | |
| 136 | - } | |
| 137 | -} | |
| 138 | - | |
| 139 | -#pragma mark - <UITableViewDataSource> | |
| 140 | - | |
| 141 | -- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { | |
| 142 | - return 2; | |
| 143 | -} | |
| 144 | - | |
| 145 | -- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { | |
| 146 | - return section == 0 ? self.actions.count : 1; | |
| 147 | -} | |
| 148 | - | |
| 149 | -- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { | |
| 150 | - return self.cellHeight; | |
| 151 | -} | |
| 152 | - | |
| 153 | -- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { | |
| 154 | - return section == 0 ? CGFLOAT_MIN : kOffsetSpace; | |
| 155 | -} | |
| 156 | - | |
| 157 | -- (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { | |
| 158 | - return CGFLOAT_MIN; | |
| 159 | -} | |
| 160 | - | |
| 161 | -- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { | |
| 162 | - YBIBSheetCell *cell = [tableView dequeueReusableCellWithIdentifier:NSStringFromClass(YBIBSheetCell.self)]; | |
| 163 | - if (indexPath.section == 0) { | |
| 164 | - cell.line.hidden = NO; | |
| 165 | - YBIBSheetAction *action = self.actions[indexPath.row]; | |
| 166 | - cell.titleLabel.text = action.name; | |
| 167 | - } else { | |
| 168 | - cell.line.hidden = YES; | |
| 169 | - cell.titleLabel.text = self.cancelText; | |
| 170 | - } | |
| 171 | - return cell; | |
| 172 | -} | |
| 173 | - | |
| 174 | -#pragma mark - <UITableViewDelegate> | |
| 175 | - | |
| 176 | -- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { | |
| 177 | - if (indexPath.section == 0) { | |
| 178 | - YBIBSheetAction *action = self.actions[indexPath.row]; | |
| 179 | - if (action.action) action.action(self.currentdata()); | |
| 180 | - } else { | |
| 181 | - [self hideWithAnimation:YES]; | |
| 182 | - } | |
| 183 | -} | |
| 184 | - | |
| 185 | -#pragma mark - getters | |
| 186 | - | |
| 187 | -- (UITableView *)tableView { | |
| 188 | - if (!_tableView) { | |
| 189 | - _tableView = [[UITableView alloc] initWithFrame:CGRectZero style:UITableViewStyleGrouped]; | |
| 190 | - _tableView.delegate = self; | |
| 191 | - _tableView.dataSource = self; | |
| 192 | - _tableView.estimatedRowHeight = 44; | |
| 193 | - _tableView.estimatedSectionFooterHeight = 0; | |
| 194 | - _tableView.estimatedSectionHeaderHeight = 0; | |
| 195 | - _tableView.backgroundColor = [UIColor clearColor]; | |
| 196 | - _tableView.alwaysBounceVertical = NO; | |
| 197 | - _tableView.separatorStyle = UITableViewCellSeparatorStyleNone; | |
| 198 | - if (@available(iOS 11.0, *)) { | |
| 199 | - _tableView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; | |
| 200 | - } | |
| 201 | - UIView *footer = [UIView new]; | |
| 202 | - footer.backgroundColor = UIColor.whiteColor; | |
| 203 | - _tableView.tableFooterView = footer; | |
| 204 | - [_tableView registerClass:YBIBSheetCell.self forCellReuseIdentifier:NSStringFromClass(YBIBSheetCell.self)]; | |
| 205 | - } | |
| 206 | - return _tableView; | |
| 207 | -} | |
| 208 | - | |
| 209 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/ToolView/YBIBToolViewHandler.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBToolViewHandler.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/7. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBSheetView.h" | |
| 10 | -#import "YBIBTopView.h" | |
| 11 | -#import "YBIBDataProtocol.h" | |
| 12 | -#import "YBIBOrientationReceiveProtocol.h" | |
| 13 | -#import "YBIBOperateBrowserProtocol.h" | |
| 14 | - | |
| 15 | -NS_ASSUME_NONNULL_BEGIN | |
| 16 | - | |
| 17 | -@protocol YBIBToolViewHandler <YBIBGetBaseInfoProtocol, YBIBOperateBrowserProtocol, YBIBOrientationReceiveProtocol> | |
| 18 | - | |
| 19 | -@required | |
| 20 | - | |
| 21 | -/** | |
| 22 | - 容器视图准备好了,可进行子视图的添加和布局 | |
| 23 | - */ | |
| 24 | -- (void)yb_containerViewIsReadied; | |
| 25 | - | |
| 26 | -/** | |
| 27 | - 隐藏视图 | |
| 28 | - | |
| 29 | - @param hide 是否隐藏 | |
| 30 | - */ | |
| 31 | -- (void)yb_hide:(BOOL)hide; | |
| 32 | - | |
| 33 | -@optional | |
| 34 | - | |
| 35 | -/// 当前数据 | |
| 36 | -@property (nonatomic, copy) id<YBIBDataProtocol>(^yb_currentData)(void); | |
| 37 | - | |
| 38 | -/** | |
| 39 | - 页码变化了 | |
| 40 | - */ | |
| 41 | -- (void)yb_pageChanged; | |
| 42 | - | |
| 43 | -/** | |
| 44 | - 偏移量变化了 | |
| 45 | - | |
| 46 | - @param offsetX 当前偏移量 | |
| 47 | - */ | |
| 48 | -- (void)yb_offsetXChanged:(CGFloat)offsetX; | |
| 49 | - | |
| 50 | -/** | |
| 51 | - 响应长按手势 | |
| 52 | - */ | |
| 53 | -- (void)yb_respondsToLongPress; | |
| 54 | - | |
| 55 | -@end | |
| 56 | - | |
| 57 | -@interface YBIBToolViewHandler : NSObject <YBIBToolViewHandler> | |
| 58 | - | |
| 59 | -/// 弹出表单视图 | |
| 60 | -@property (nonatomic, strong, readonly) YBIBSheetView *sheetView; | |
| 61 | - | |
| 62 | -/// 顶部显示页码视图 | |
| 63 | -@property (nonatomic, strong, readonly) YBIBTopView *topView; | |
| 64 | - | |
| 65 | -@end | |
| 66 | - | |
| 67 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/ToolView/YBIBToolViewHandler.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBToolViewHandler.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/7. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBToolViewHandler.h" | |
| 10 | -#import "YBIBCopywriter.h" | |
| 11 | -#import "YBIBUtilities.h" | |
| 12 | - | |
| 13 | -@interface YBIBToolViewHandler () | |
| 14 | -@property (nonatomic, strong) YBIBSheetView *sheetView; | |
| 15 | -@property (nonatomic, strong) YBIBSheetAction *saveAction; | |
| 16 | -@property (nonatomic, strong) YBIBTopView *topView; | |
| 17 | -@end | |
| 18 | - | |
| 19 | -@implementation YBIBToolViewHandler | |
| 20 | - | |
| 21 | -#pragma mark - <YBIBToolViewHandler> | |
| 22 | - | |
| 23 | -@synthesize yb_containerView = _yb_containerView; | |
| 24 | -@synthesize yb_containerSize = _yb_containerSize; | |
| 25 | -@synthesize yb_currentPage = _yb_currentPage; | |
| 26 | -@synthesize yb_totalPage = _yb_totalPage; | |
| 27 | -@synthesize yb_currentOrientation = _yb_currentOrientation; | |
| 28 | -@synthesize yb_currentData = _yb_currentData; | |
| 29 | - | |
| 30 | -- (void)yb_containerViewIsReadied { | |
| 31 | - [self.yb_containerView addSubview:self.topView]; | |
| 32 | - [self layoutWithExpectOrientation:self.yb_currentOrientation()]; | |
| 33 | -} | |
| 34 | - | |
| 35 | -- (void)yb_pageChanged { | |
| 36 | - if (self.topView.operationType == YBIBTopViewOperationTypeSave) { | |
| 37 | - self.topView.operationButton.hidden = [self currentDataShouldHideSaveButton]; | |
| 38 | - } | |
| 39 | - [self.topView setPage:self.yb_currentPage() totalPage:self.yb_totalPage()]; | |
| 40 | -} | |
| 41 | - | |
| 42 | -- (void)yb_respondsToLongPress { | |
| 43 | - [self showSheetView]; | |
| 44 | -} | |
| 45 | - | |
| 46 | -- (void)yb_hide:(BOOL)hide { | |
| 47 | - self.topView.hidden = hide; | |
| 48 | - [self.sheetView hideWithAnimation:NO]; | |
| 49 | -} | |
| 50 | - | |
| 51 | -- (void)yb_orientationWillChangeWithExpectOrientation:(UIDeviceOrientation)orientation { | |
| 52 | - [self.sheetView hideWithAnimation:NO]; | |
| 53 | -} | |
| 54 | - | |
| 55 | -- (void)yb_orientationChangeAnimationWithExpectOrientation:(UIDeviceOrientation)orientation { | |
| 56 | - [self layoutWithExpectOrientation:orientation]; | |
| 57 | -} | |
| 58 | - | |
| 59 | -#pragma mark - private | |
| 60 | - | |
| 61 | -- (BOOL)currentDataShouldHideSaveButton { | |
| 62 | - id<YBIBDataProtocol> data = self.yb_currentData(); | |
| 63 | - BOOL allow = [data respondsToSelector:@selector(yb_allowSaveToPhotoAlbum)] && [data yb_allowSaveToPhotoAlbum]; | |
| 64 | - BOOL can = [data respondsToSelector:@selector(yb_saveToPhotoAlbum)]; | |
| 65 | - return !(allow && can); | |
| 66 | -} | |
| 67 | - | |
| 68 | -- (void)layoutWithExpectOrientation:(UIDeviceOrientation)orientation { | |
| 69 | - CGSize containerSize = self.yb_containerSize(orientation); | |
| 70 | - UIEdgeInsets padding = YBIBPaddingByBrowserOrientation(orientation); | |
| 71 | - | |
| 72 | - self.topView.frame = CGRectMake(padding.left, padding.top, containerSize.width - padding.left - padding.right, [YBIBTopView defaultHeight]); | |
| 73 | -} | |
| 74 | - | |
| 75 | -- (void)showSheetView { | |
| 76 | - if ([self currentDataShouldHideSaveButton]) { | |
| 77 | - [self.sheetView.actions removeObject:self.saveAction]; | |
| 78 | - } else { | |
| 79 | - if (![self.sheetView.actions containsObject:self.saveAction]) { | |
| 80 | - [self.sheetView.actions addObject:self.saveAction]; | |
| 81 | - } | |
| 82 | - } | |
| 83 | - [self.sheetView showToView:self.yb_containerView orientation:self.yb_currentOrientation()]; | |
| 84 | -} | |
| 85 | - | |
| 86 | -#pragma mark - getters | |
| 87 | - | |
| 88 | -- (YBIBSheetView *)sheetView { | |
| 89 | - if (!_sheetView) { | |
| 90 | - _sheetView = [YBIBSheetView new]; | |
| 91 | - __weak typeof(self) wSelf = self; | |
| 92 | - [_sheetView setCurrentdata:^id<YBIBDataProtocol>{ | |
| 93 | - __strong typeof(wSelf) self = wSelf; | |
| 94 | - if (!self) return nil; | |
| 95 | - return self.yb_currentData(); | |
| 96 | - }]; | |
| 97 | - } | |
| 98 | - return _sheetView; | |
| 99 | -} | |
| 100 | - | |
| 101 | -- (YBIBSheetAction *)saveAction { | |
| 102 | - if (!_saveAction) { | |
| 103 | - __weak typeof(self) wSelf = self; | |
| 104 | - _saveAction = [YBIBSheetAction actionWithName:[YBIBCopywriter sharedCopywriter].saveToPhotoAlbum action:^(id<YBIBDataProtocol> data) { | |
| 105 | - __strong typeof(wSelf) self = wSelf; | |
| 106 | - if (!self) return; | |
| 107 | - if ([data respondsToSelector:@selector(yb_saveToPhotoAlbum)]) { | |
| 108 | - [data yb_saveToPhotoAlbum]; | |
| 109 | - } | |
| 110 | - [self.sheetView hideWithAnimation:YES]; | |
| 111 | - }]; | |
| 112 | - } | |
| 113 | - return _saveAction; | |
| 114 | -} | |
| 115 | - | |
| 116 | -- (YBIBTopView *)topView { | |
| 117 | - if (!_topView) { | |
| 118 | - _topView = [YBIBTopView new]; | |
| 119 | - _topView.operationType = YBIBTopViewOperationTypeMore; | |
| 120 | - __weak typeof(self) wSelf = self; | |
| 121 | - [_topView setClickOperation:^(YBIBTopViewOperationType type) { | |
| 122 | - __strong typeof(wSelf) self = wSelf; | |
| 123 | - if (!self) return; | |
| 124 | - switch (type) { | |
| 125 | - case YBIBTopViewOperationTypeSave: { | |
| 126 | - id<YBIBDataProtocol> data = self.yb_currentData(); | |
| 127 | - if ([data respondsToSelector:@selector(yb_saveToPhotoAlbum)]) { | |
| 128 | - [data yb_saveToPhotoAlbum]; | |
| 129 | - } | |
| 130 | - } | |
| 131 | - break; | |
| 132 | - case YBIBTopViewOperationTypeMore: { | |
| 133 | - [self showSheetView]; | |
| 134 | - } | |
| 135 | - break; | |
| 136 | - default: | |
| 137 | - break; | |
| 138 | - } | |
| 139 | - }]; | |
| 140 | - } | |
| 141 | - return _topView; | |
| 142 | -} | |
| 143 | - | |
| 144 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/ToolView/YBIBTopView.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBTopView.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/6. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -typedef NS_ENUM(NSInteger, YBIBTopViewOperationType) { | |
| 14 | - YBIBTopViewOperationTypeSave, //保存 | |
| 15 | - YBIBTopViewOperationTypeMore //更多 | |
| 16 | -}; | |
| 17 | - | |
| 18 | -@interface YBIBTopView : UIView | |
| 19 | - | |
| 20 | -/// 页码标签 | |
| 21 | -@property (nonatomic, strong, readonly) UILabel *pageLabel; | |
| 22 | - | |
| 23 | -/// 操作按钮(自定义:直接修改图片或文字,然后添加点击事件) | |
| 24 | -@property (nonatomic, strong, readonly) UIButton *operationButton; | |
| 25 | - | |
| 26 | -/// 按钮类型 | |
| 27 | -@property (nonatomic, assign) YBIBTopViewOperationType operationType; | |
| 28 | - | |
| 29 | -/** | |
| 30 | - 设置页码 | |
| 31 | - | |
| 32 | - @param page 当前页码 | |
| 33 | - @param totalPage 总页码数 | |
| 34 | - */ | |
| 35 | -- (void)setPage:(NSInteger)page totalPage:(NSInteger)totalPage; | |
| 36 | - | |
| 37 | -/// 点击操作按钮的回调 | |
| 38 | -@property (nonatomic, copy) void(^clickOperation)(YBIBTopViewOperationType type); | |
| 39 | - | |
| 40 | -+ (CGFloat)defaultHeight; | |
| 41 | - | |
| 42 | -@end | |
| 43 | - | |
| 44 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/ToolView/YBIBTopView.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBTopView.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/7/6. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBTopView.h" | |
| 10 | -#import "YBIBIconManager.h" | |
| 11 | -#import "YBIBUtilities.h" | |
| 12 | - | |
| 13 | -@interface YBIBTopView () | |
| 14 | -@property (nonatomic, strong) UILabel *pageLabel; | |
| 15 | -@property (nonatomic, strong) UIButton *operationButton; | |
| 16 | -@end | |
| 17 | - | |
| 18 | -@implementation YBIBTopView | |
| 19 | - | |
| 20 | -#pragma mark - life cycle | |
| 21 | - | |
| 22 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 23 | - self = [super initWithFrame:frame]; | |
| 24 | - if (self) { | |
| 25 | - [self addSubview:self.pageLabel]; | |
| 26 | - [self addSubview:self.operationButton]; | |
| 27 | - | |
| 28 | - [self setOperationType:YBIBTopViewOperationTypeMore]; | |
| 29 | - } | |
| 30 | - return self; | |
| 31 | -} | |
| 32 | - | |
| 33 | -- (void)layoutSubviews { | |
| 34 | - [super layoutSubviews]; | |
| 35 | - CGFloat height = self.bounds.size.height, width = self.bounds.size.width; | |
| 36 | - self.pageLabel.frame = CGRectMake(16, 0, width / 3, height); | |
| 37 | - CGFloat buttonWidth = 54; | |
| 38 | - self.operationButton.frame = CGRectMake(width - buttonWidth, 0, buttonWidth, height); | |
| 39 | -} | |
| 40 | - | |
| 41 | -#pragma mark - public | |
| 42 | - | |
| 43 | -+ (CGFloat)defaultHeight { | |
| 44 | - return 50; | |
| 45 | -} | |
| 46 | - | |
| 47 | -- (void)setPage:(NSInteger)page totalPage:(NSInteger)totalPage { | |
| 48 | - if (totalPage <= 1) { | |
| 49 | - self.pageLabel.hidden = YES; | |
| 50 | - } else { | |
| 51 | - self.pageLabel.hidden = NO; | |
| 52 | - | |
| 53 | - NSString *text = [NSString stringWithFormat:@"%ld/%ld", page + (NSInteger)1, totalPage]; | |
| 54 | - NSShadow *shadow = [NSShadow new]; | |
| 55 | - shadow.shadowBlurRadius = 4; | |
| 56 | - shadow.shadowOffset = CGSizeMake(0, 1); | |
| 57 | - shadow.shadowColor = UIColor.darkGrayColor; | |
| 58 | - NSMutableAttributedString *attr = [[NSMutableAttributedString alloc] initWithString:text attributes:@{NSShadowAttributeName:shadow}]; | |
| 59 | - self.pageLabel.attributedText = attr; | |
| 60 | - } | |
| 61 | -} | |
| 62 | - | |
| 63 | -#pragma mark - event | |
| 64 | - | |
| 65 | -- (void)clickOperationButton:(UIButton *)button { | |
| 66 | - if (self.clickOperation) self.clickOperation(self.operationType); | |
| 67 | -} | |
| 68 | - | |
| 69 | -#pragma mark - getters & setters | |
| 70 | - | |
| 71 | -- (void)setOperationType:(YBIBTopViewOperationType)operationType { | |
| 72 | - _operationType = operationType; | |
| 73 | - | |
| 74 | - UIImage *image = nil; | |
| 75 | - switch (operationType) { | |
| 76 | - case YBIBTopViewOperationTypeSave: | |
| 77 | - image = [YBIBIconManager sharedManager].toolSaveImage(); | |
| 78 | - break; | |
| 79 | - case YBIBTopViewOperationTypeMore: | |
| 80 | - image = [YBIBIconManager sharedManager].toolMoreImage(); | |
| 81 | - break; | |
| 82 | - } | |
| 83 | - | |
| 84 | - [self.operationButton setImage:image forState:UIControlStateNormal]; | |
| 85 | -} | |
| 86 | - | |
| 87 | -- (UILabel *)pageLabel { | |
| 88 | - if (!_pageLabel) { | |
| 89 | - _pageLabel = [UILabel new]; | |
| 90 | - _pageLabel.textColor = [UIColor whiteColor]; | |
| 91 | - _pageLabel.font = [UIFont boldSystemFontOfSize:16]; | |
| 92 | - _pageLabel.textAlignment = NSTextAlignmentLeft; | |
| 93 | - _pageLabel.adjustsFontSizeToFitWidth = YES; | |
| 94 | - } | |
| 95 | - return _pageLabel; | |
| 96 | -} | |
| 97 | - | |
| 98 | -- (UIButton *)operationButton { | |
| 99 | - if (!_operationButton) { | |
| 100 | - _operationButton = [UIButton buttonWithType:UIButtonTypeCustom]; | |
| 101 | - _operationButton.titleLabel.font = [UIFont boldSystemFontOfSize:16]; | |
| 102 | - _operationButton.titleLabel.adjustsFontSizeToFitWidth = YES; | |
| 103 | - [_operationButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; | |
| 104 | - [_operationButton addTarget:self action:@selector(clickOperationButton:) forControlEvents:UIControlEventTouchUpInside]; | |
| 105 | - _operationButton.layer.shadowColor = UIColor.darkGrayColor.CGColor; | |
| 106 | - _operationButton.layer.shadowOffset = CGSizeMake(0, 1); | |
| 107 | - _operationButton.layer.shadowOpacity = 1; | |
| 108 | - _operationButton.layer.shadowRadius = 4; | |
| 109 | - } | |
| 110 | - return _operationButton; | |
| 111 | -} | |
| 112 | - | |
| 113 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/WebImageMediator/YBIBDefaultWebImageMediator.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBDefaultWebImageMediator.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/8/27. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBWebImageMediator.h" | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -@interface YBIBDefaultWebImageMediator : NSObject <YBIBWebImageMediator> | |
| 14 | - | |
| 15 | -@end | |
| 16 | - | |
| 17 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/WebImageMediator/YBIBDefaultWebImageMediator.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBDefaultWebImageMediator.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/8/27. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBDefaultWebImageMediator.h" | |
| 10 | -#import "YBIBUtilities.h" | |
| 11 | -#if __has_include(<SDWebImage/SDWebImage.h>) | |
| 12 | -#import <SDWebImage/SDWebImage.h> | |
| 13 | -#else | |
| 14 | -#import "SDWebImage.h" | |
| 15 | -#endif | |
| 16 | - | |
| 17 | -@implementation YBIBDefaultWebImageMediator | |
| 18 | - | |
| 19 | -#pragma mark - <YBIBWebImageMediator> | |
| 20 | - | |
| 21 | -- (id)yb_downloadImageWithURL:(NSURL *)URL requestModifier:(nullable YBIBWebImageRequestModifierBlock)requestModifier progress:(nonnull YBIBWebImageProgressBlock)progress success:(nonnull YBIBWebImageSuccessBlock)success failed:(nonnull YBIBWebImageFailedBlock)failed { | |
| 22 | - if (!URL) return nil; | |
| 23 | - | |
| 24 | - SDWebImageContext *context = nil; | |
| 25 | - if (requestModifier) { | |
| 26 | - SDWebImageDownloaderRequestModifier *modifier = [SDWebImageDownloaderRequestModifier requestModifierWithBlock:requestModifier]; | |
| 27 | - context = @{SDWebImageContextDownloadRequestModifier:modifier}; | |
| 28 | - } | |
| 29 | - | |
| 30 | - SDWebImageDownloaderOptions options = SDWebImageDownloaderLowPriority | SDWebImageDownloaderAvoidDecodeImage; | |
| 31 | - | |
| 32 | - SDWebImageDownloadToken *token = [[SDWebImageDownloader sharedDownloader] downloadImageWithURL:URL options:options context:context progress:^(NSInteger receivedSize, NSInteger expectedSize, NSURL * _Nullable targetURL) { | |
| 33 | - if (progress) progress(receivedSize, expectedSize); | |
| 34 | - } completed:^(UIImage * _Nullable image, NSData * _Nullable data, NSError * _Nullable error, BOOL finished) { | |
| 35 | - if (error) { | |
| 36 | - if (failed) failed(error, finished); | |
| 37 | - } else { | |
| 38 | - if (success) success(data, finished); | |
| 39 | - } | |
| 40 | - }]; | |
| 41 | - return token; | |
| 42 | -} | |
| 43 | - | |
| 44 | -- (void)yb_cancelTaskWithDownloadToken:(id)token { | |
| 45 | - if (token && [token isKindOfClass:SDWebImageDownloadToken.class]) { | |
| 46 | - [((SDWebImageDownloadToken *)token) cancel]; | |
| 47 | - } | |
| 48 | -} | |
| 49 | - | |
| 50 | -- (void)yb_storeToDiskWithImageData:(NSData *)data forKey:(NSURL *)key { | |
| 51 | - if (!key) return; | |
| 52 | - NSString *cacheKey = [SDWebImageManager.sharedManager cacheKeyForURL:key]; | |
| 53 | - if (!cacheKey) return; | |
| 54 | - | |
| 55 | - YBIB_DISPATCH_ASYNC(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ | |
| 56 | - [[SDImageCache sharedImageCache] storeImageDataToDisk:data forKey:cacheKey]; | |
| 57 | - }) | |
| 58 | -} | |
| 59 | - | |
| 60 | -- (void)yb_queryCacheOperationForKey:(NSURL *)key completed:(YBIBWebImageCacheQueryCompletedBlock)completed { | |
| 61 | -#define QUERY_CACHE_FAILED if (completed) {completed(nil, nil); return;} | |
| 62 | - if (!key) QUERY_CACHE_FAILED | |
| 63 | - NSString *cacheKey = [SDWebImageManager.sharedManager cacheKeyForURL:key]; | |
| 64 | - if (!cacheKey) QUERY_CACHE_FAILED | |
| 65 | -#undef QUERY_CACHE_FAILED | |
| 66 | - | |
| 67 | - // 'NSData' of image must be read to ensure decoding correctly. | |
| 68 | - SDImageCacheOptions options = SDImageCacheQueryMemoryData | SDImageCacheAvoidDecodeImage; | |
| 69 | - [[SDImageCache sharedImageCache] queryCacheOperationForKey:cacheKey options:options done:^(UIImage * _Nullable image, NSData * _Nullable data, SDImageCacheType cacheType) { | |
| 70 | - if (completed) completed(image, data); | |
| 71 | - }]; | |
| 72 | -} | |
| 73 | - | |
| 74 | -@end |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/WebImageMediator/YBIBWebImageMediator.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBIBWebImageMediator.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/8/27. | |
| 6 | -// Copyright © 2019 杨波. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import <UIKit/UIKit.h> | |
| 10 | - | |
| 11 | -NS_ASSUME_NONNULL_BEGIN | |
| 12 | - | |
| 13 | -typedef NSURLRequest * _Nullable (^YBIBWebImageRequestModifierBlock)(NSURLRequest *request); | |
| 14 | -typedef void(^YBIBWebImageProgressBlock)(NSInteger receivedSize, NSInteger expectedSize); | |
| 15 | -typedef void(^YBIBWebImageSuccessBlock)(NSData * _Nullable imageData, BOOL finished); | |
| 16 | -typedef void(^YBIBWebImageFailedBlock)(NSError * _Nullable error, BOOL finished); | |
| 17 | -typedef void(^YBIBWebImageCacheQueryCompletedBlock)(UIImage * _Nullable image, NSData * _Nullable imageData); | |
| 18 | - | |
| 19 | -@protocol YBIBWebImageMediator <NSObject> | |
| 20 | - | |
| 21 | -@required | |
| 22 | - | |
| 23 | -/** | |
| 24 | - 下载图片 | |
| 25 | - | |
| 26 | - @param URL 图片地址 | |
| 27 | - @param requestModifier 修改默认 NSURLRequest 的闭包 | |
| 28 | - @param progress 进度回调 | |
| 29 | - @param success 成功回调 | |
| 30 | - @param failed 失败回调 | |
| 31 | - @return 下载 token (可为空) | |
| 32 | - */ | |
| 33 | -- (id)yb_downloadImageWithURL:(NSURL *)URL requestModifier:(nullable YBIBWebImageRequestModifierBlock)requestModifier progress:(YBIBWebImageProgressBlock)progress success:(YBIBWebImageSuccessBlock)success failed:(YBIBWebImageFailedBlock)failed; | |
| 34 | - | |
| 35 | -/** | |
| 36 | - 缓存图片数据到磁盘 | |
| 37 | - | |
| 38 | - @param data 图片数据 | |
| 39 | - @param key 缓存标识 | |
| 40 | - */ | |
| 41 | -- (void)yb_storeToDiskWithImageData:(nullable NSData *)data forKey:(NSURL *)key; | |
| 42 | - | |
| 43 | -/** | |
| 44 | - 读取图片数据 | |
| 45 | - | |
| 46 | - @param key 缓存标识 | |
| 47 | - @param completed 读取回调 | |
| 48 | - */ | |
| 49 | -- (void)yb_queryCacheOperationForKey:(NSURL *)key completed:(YBIBWebImageCacheQueryCompletedBlock)completed; | |
| 50 | - | |
| 51 | -@optional | |
| 52 | - | |
| 53 | -/** | |
| 54 | - 取消下载 | |
| 55 | - | |
| 56 | - @param token 下载 token | |
| 57 | - */ | |
| 58 | -- (void)yb_cancelTaskWithDownloadToken:(id)token; | |
| 59 | - | |
| 60 | -@end | |
| 61 | - | |
| 62 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/YBImageBrowser.h deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBImageBrowser.h | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/5. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBIBCollectionView.h" | |
| 10 | -#import "YBImageBrowserDataSource.h" | |
| 11 | -#import "YBImageBrowserDelegate.h" | |
| 12 | -#import "YBIBDataProtocol.h" | |
| 13 | -#import "YBIBCellProtocol.h" | |
| 14 | -#import "YBIBAnimatedTransition.h" | |
| 15 | -#import "YBIBAuxiliaryViewHandler.h" | |
| 16 | -#import "YBIBToolViewHandler.h" | |
| 17 | -#import "YBIBWebImageMediator.h" | |
| 18 | -#import "YBIBImageData.h" | |
| 19 | - | |
| 20 | -NS_ASSUME_NONNULL_BEGIN | |
| 21 | - | |
| 22 | -@interface YBImageBrowser : UIView | |
| 23 | - | |
| 24 | -/// 数据源数组 | |
| 25 | -@property (nonatomic, copy) NSArray<id<YBIBDataProtocol>> *dataSourceArray; | |
| 26 | - | |
| 27 | -/// 数据源代理 | |
| 28 | -@property (nonatomic, weak) id<YBImageBrowserDataSource> dataSource; | |
| 29 | - | |
| 30 | -/// 状态回调代理 | |
| 31 | -@property (nonatomic, weak) id<YBImageBrowserDelegate> delegate; | |
| 32 | - | |
| 33 | -/** | |
| 34 | - 展示图片浏览器 | |
| 35 | - | |
| 36 | - @param view 指定父视图(view 的大小不能为 CGSizeZero,但允许变化) | |
| 37 | - @param containerSize 容器大小(当 view 的大小允许变化时,必须指定确切的 containerSize) | |
| 38 | - */ | |
| 39 | -- (void)showToView:(UIView *)view containerSize:(CGSize)containerSize; | |
| 40 | -- (void)showToView:(UIView *)view; | |
| 41 | -- (void)show; | |
| 42 | - | |
| 43 | -/** | |
| 44 | - 隐藏图片浏览器(不建议外部持有图片浏览器重复使用) | |
| 45 | - */ | |
| 46 | -- (void)hide; | |
| 47 | - | |
| 48 | -/// 当前页码 | |
| 49 | -@property (nonatomic, assign) NSInteger currentPage; | |
| 50 | - | |
| 51 | -/// 分页间距 | |
| 52 | -@property (nonatomic, assign) CGFloat distanceBetweenPages; | |
| 53 | - | |
| 54 | -/// 当前图片浏览器的方向 | |
| 55 | -@property (nonatomic, assign, readonly) UIDeviceOrientation currentOrientation; | |
| 56 | - | |
| 57 | -/// 图片浏览器支持的方向 (仅当前控制器不支持旋转时有效,否则将跟随控制器旋转) | |
| 58 | -@property (nonatomic, assign) UIInterfaceOrientationMask supportedOrientations; | |
| 59 | - | |
| 60 | -/// 是否自动隐藏 id<YBIBImageData> 设置的映射视图,默认为 YES | |
| 61 | -@property (nonatomic, assign) BOOL autoHideProjectiveView; | |
| 62 | - | |
| 63 | -/// 是否正在转场 | |
| 64 | -@property (nonatomic, assign, readonly, getter=isTransitioning) BOOL transitioning; | |
| 65 | -/// 是否正在进行展示过程转场 | |
| 66 | -@property (nonatomic, assign, readonly, getter=isShowTransitioning) BOOL showTransitioning; | |
| 67 | -/// 是否正在进行隐藏过程转场 | |
| 68 | -@property (nonatomic, assign, readonly, getter=isHideTransitioning) BOOL hideTransitioning; | |
| 69 | - | |
| 70 | -/// 预加载数量 (默认为 2,低内存设备默认为 0) | |
| 71 | -@property (nonatomic, assign) NSUInteger preloadCount; | |
| 72 | - | |
| 73 | -/** | |
| 74 | - 重载数据,请保证数据源被正确修改 | |
| 75 | - */ | |
| 76 | -- (void)reloadData; | |
| 77 | - | |
| 78 | -/** | |
| 79 | - 获取当前展示的数据对象 | |
| 80 | - | |
| 81 | - @return 数据对象 | |
| 82 | - */ | |
| 83 | -- (id<YBIBDataProtocol>)currentData; | |
| 84 | - | |
| 85 | -/// 是否隐藏状态栏,默认为 YES(该值为 YES 时需要在 info.plist 中添加 View controller-based status bar appearance : NO 才能生效) | |
| 86 | -@property (nonatomic, assign) BOOL shouldHideStatusBar; | |
| 87 | - | |
| 88 | -/// 工具视图处理器 | |
| 89 | -/// 赋值可自定义,实现者可以直接用 UIView,或者创建一个中介者管理一系列的 UIView。 | |
| 90 | -/// 内部消息是按照数组下标顺序调度的,所以如果有多个处理器注意添加 UIView 的视图层级。 | |
| 91 | -@property (nonatomic, copy) NSArray<id<YBIBToolViewHandler>> *toolViewHandlers; | |
| 92 | -/// 默认工具视图处理器 | |
| 93 | -@property (nonatomic, weak, readonly) YBIBToolViewHandler *defaultToolViewHandler; | |
| 94 | - | |
| 95 | -/// Toast/Loading 处理器 (赋值可自定义) | |
| 96 | -@property (nonatomic, strong) id<YBIBAuxiliaryViewHandler> auxiliaryViewHandler; | |
| 97 | - | |
| 98 | -/// 转场实现类 (赋值可自定义) | |
| 99 | -@property (nonatomic, strong) id<YBIBAnimatedTransition> animatedTransition; | |
| 100 | -/// 默认转场实现类 (可配置其属性) | |
| 101 | -@property (nonatomic, weak, readonly) YBIBAnimatedTransition *defaultAnimatedTransition; | |
| 102 | - | |
| 103 | -/// 图片下载缓存相关的中介者(赋值可自定义) | |
| 104 | -@property (nonatomic, strong) id<YBIBWebImageMediator> webImageMediator; | |
| 105 | - | |
| 106 | -/// 核心集合视图 | |
| 107 | -@property (nonatomic, strong, readonly) YBIBCollectionView *collectionView; | |
| 108 | - | |
| 109 | -@end | |
| 110 | - | |
| 111 | -NS_ASSUME_NONNULL_END |
CNLiveOrganizationValidationModule/Classes/CNLiveOrganizationValidationModule/YBImageBrowser/YBImageBrowser.m deleted
100644 → 0
| 1 | -// | |
| 2 | -// YBImageBrowser.m | |
| 3 | -// YBImageBrowserDemo | |
| 4 | -// | |
| 5 | -// Created by 波儿菜 on 2019/6/5. | |
| 6 | -// Copyright © 2019 波儿菜. All rights reserved. | |
| 7 | -// | |
| 8 | - | |
| 9 | -#import "YBImageBrowser.h" | |
| 10 | -#import "YBIBUtilities.h" | |
| 11 | -#import "YBIBCellProtocol.h" | |
| 12 | -#import "YBIBDataMediator.h" | |
| 13 | -#import "YBIBScreenRotationHandler.h" | |
| 14 | -#import "NSObject+YBImageBrowser.h" | |
| 15 | -#import "YBImageBrowser+Internal.h" | |
| 16 | -#if __has_include("YBIBDefaultWebImageMediator.h") | |
| 17 | -#import "YBIBDefaultWebImageMediator.h" | |
| 18 | -#endif | |
| 19 | - | |
| 20 | -@interface YBImageBrowser () <UICollectionViewDelegate, UICollectionViewDataSource> | |
| 21 | -@property (nonatomic, strong) YBIBCollectionView *collectionView; | |
| 22 | -@property (nonatomic, strong) YBIBDataMediator *dataMediator; | |
| 23 | -@property (nonatomic, strong) YBIBScreenRotationHandler *rotationHandler; | |
| 24 | -@end | |
| 25 | - | |
| 26 | -@implementation YBImageBrowser { | |
| 27 | - BOOL _originStatusBarHidden; | |
| 28 | -} | |
| 29 | - | |
| 30 | -#pragma mark - life cycle | |
| 31 | - | |
| 32 | -- (void)dealloc { | |
| 33 | - self.hiddenProjectiveView = nil; | |
| 34 | - [self showStatusBar]; | |
| 35 | -} | |
| 36 | - | |
| 37 | -- (instancetype)initWithFrame:(CGRect)frame { | |
| 38 | - self = [super initWithFrame:frame]; | |
| 39 | - if (self) { | |
| 40 | - self.backgroundColor = UIColor.blackColor; | |
| 41 | - UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToLongPress:)]; | |
| 42 | - [self addGestureRecognizer:longPress]; | |
| 43 | - [self initValue]; | |
| 44 | - } | |
| 45 | - return self; | |
| 46 | -} | |
| 47 | - | |
| 48 | -- (void)initValue { | |
| 49 | - _transitioning = _showTransitioning = _hideTransitioning = NO; | |
| 50 | - _defaultAnimatedTransition = _animatedTransition = [YBIBAnimatedTransition new]; | |
| 51 | - _toolViewHandlers = @[[YBIBToolViewHandler new]]; | |
| 52 | - _defaultToolViewHandler = _toolViewHandlers[0]; | |
| 53 | - _auxiliaryViewHandler = [YBIBAuxiliaryViewHandler new]; | |
| 54 | - _shouldHideStatusBar = YES; | |
| 55 | - _autoHideProjectiveView = YES; | |
| 56 | -#if __has_include("YBIBDefaultWebImageMediator.h") | |
| 57 | - _webImageMediator = [YBIBDefaultWebImageMediator new]; | |
| 58 | -#endif | |
| 59 | -} | |
| 60 | - | |
| 61 | -#pragma mark - private | |
| 62 | - | |
| 63 | -- (void)build { | |
| 64 | - [self addSubview:self.collectionView]; | |
| 65 | - self.collectionView.frame = self.bounds; | |
| 66 | - self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | |
| 67 | - | |
| 68 | - [self addSubview:self.containerView]; | |
| 69 | - self.containerView.frame = self.bounds; | |
| 70 | - self.containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | |
| 71 | - | |
| 72 | - [self buildToolView]; | |
| 73 | - | |
| 74 | - [self layoutIfNeeded]; | |
| 75 | - | |
| 76 | - [self collectionViewScrollToPage:self.currentPage]; | |
| 77 | - [self.rotationHandler startObserveDeviceOrientation]; | |
| 78 | -} | |
| 79 | - | |
| 80 | -- (void)buildToolView { | |
| 81 | - for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) { | |
| 82 | - [self implementGetBaseInfoProtocol:handler]; | |
| 83 | - [self implementOperateBrowserProtocol:handler]; | |
| 84 | - __weak typeof(self) wSelf = self; | |
| 85 | - if ([handler respondsToSelector:@selector(setYb_currentData:)]) { | |
| 86 | - [handler setYb_currentData:^id<YBIBDataProtocol>{ | |
| 87 | - __strong typeof(wSelf) self = wSelf; | |
| 88 | - if (!self) return nil; | |
| 89 | - return self.currentData; | |
| 90 | - }]; | |
| 91 | - } | |
| 92 | - [handler yb_containerViewIsReadied]; | |
| 93 | - [handler yb_hide:NO]; | |
| 94 | - } | |
| 95 | -} | |
| 96 | - | |
| 97 | -- (void)rebuild { | |
| 98 | - self.hiddenProjectiveView = nil; | |
| 99 | - [self showStatusBar]; | |
| 100 | - [self.containerView removeFromSuperview]; | |
| 101 | - _containerView = nil; | |
| 102 | - [self.collectionView removeFromSuperview]; | |
| 103 | - _collectionView = nil; | |
| 104 | - [self.dataMediator clear]; | |
| 105 | - [self.rotationHandler clear]; | |
| 106 | -} | |
| 107 | - | |
| 108 | -- (void)collectionViewScrollToPage:(NSInteger)page { | |
| 109 | - [self.collectionView scrollToPage:page]; | |
| 110 | - [self pageNumberChanged]; | |
| 111 | -} | |
| 112 | - | |
| 113 | -- (void)pageNumberChanged { | |
| 114 | - id<YBIBDataProtocol> data = self.currentData; | |
| 115 | - UIView *projectiveView = nil; | |
| 116 | - if ([data respondsToSelector:@selector(yb_projectiveView)]) { | |
| 117 | - projectiveView = [data yb_projectiveView]; | |
| 118 | - } | |
| 119 | - self.hiddenProjectiveView = projectiveView; | |
| 120 | - | |
| 121 | - if (self.delegate && [self.delegate respondsToSelector:@selector(yb_imageBrowser:pageChanged:data:)]) { | |
| 122 | - [self.delegate yb_imageBrowser:self pageChanged:self.currentPage data:data]; | |
| 123 | - } | |
| 124 | - for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) { | |
| 125 | - if ([handler respondsToSelector:@selector(yb_pageChanged)]) { | |
| 126 | - [handler yb_pageChanged]; | |
| 127 | - } | |
| 128 | - } | |
| 129 | - NSArray *visibleCells = self.collectionView.visibleCells; | |
| 130 | - for (UICollectionViewCell<YBIBCellProtocol> *cell in visibleCells) { | |
| 131 | - if ([cell respondsToSelector:@selector(yb_pageChanged)]) { | |
| 132 | - [cell yb_pageChanged]; | |
| 133 | - } | |
| 134 | - } | |
| 135 | -} | |
| 136 | - | |
| 137 | -- (void)showStatusBar { | |
| 138 | - if (self.shouldHideStatusBar) { | |
| 139 | - [UIApplication sharedApplication].statusBarHidden = _originStatusBarHidden; | |
| 140 | - } | |
| 141 | -} | |
| 142 | - | |
| 143 | -- (void)hideStatusBar { | |
| 144 | - if (self.shouldHideStatusBar) { | |
| 145 | - [UIApplication sharedApplication].statusBarHidden = YES; | |
| 146 | - } | |
| 147 | -} | |
| 148 | - | |
| 149 | -#pragma mark - public | |
| 150 | - | |
| 151 | -- (void)show { | |
| 152 | - [self showToView:[UIApplication sharedApplication].keyWindow]; | |
| 153 | -} | |
| 154 | - | |
| 155 | -- (void)showToView:(UIView *)view { | |
| 156 | - [self showToView:view containerSize:view.bounds.size]; | |
| 157 | -} | |
| 158 | - | |
| 159 | -- (void)showToView:(UIView *)view containerSize:(CGSize)containerSize { | |
| 160 | - [self.rotationHandler startObserveStatusBarOrientation]; | |
| 161 | - | |
| 162 | - [view addSubview:self]; | |
| 163 | - self.frame = view.bounds; | |
| 164 | - self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | |
| 165 | - | |
| 166 | - _originStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden; | |
| 167 | - | |
| 168 | - [self.rotationHandler configContainerSize:containerSize]; | |
| 169 | - | |
| 170 | - [self.dataMediator preloadWithPage:self.currentPage]; | |
| 171 | - | |
| 172 | - __kindof UIView *startView; | |
| 173 | - UIImage *startImage; | |
| 174 | - CGRect endFrame = CGRectZero; | |
| 175 | - id<YBIBDataProtocol> data = [self.dataMediator dataForCellAtIndex:self.currentPage]; | |
| 176 | - if ([data respondsToSelector:@selector(yb_projectiveView)]) { | |
| 177 | - startView = data.yb_projectiveView; | |
| 178 | - self.hiddenProjectiveView = startView; | |
| 179 | - if ([startView isKindOfClass:UIImageView.class]) { | |
| 180 | - startImage = ((UIImageView *)startView).image; | |
| 181 | - } else { | |
| 182 | - startImage = YBIBSnapshotView(startView); | |
| 183 | - } | |
| 184 | - } | |
| 185 | - if ([data respondsToSelector:@selector(yb_imageViewFrameWithContainerSize:imageSize:orientation:)]) { | |
| 186 | - endFrame = [data yb_imageViewFrameWithContainerSize:self.bounds.size imageSize:startImage.size orientation:self.rotationHandler.currentOrientation]; | |
| 187 | - } | |
| 188 | - | |
| 189 | - [self setTransitioning:YES isShow:YES]; | |
| 190 | - [self.animatedTransition yb_showTransitioningWithContainer:self startView:startView startImage:startImage endFrame:endFrame orientation:self.rotationHandler.currentOrientation completion:^{ | |
| 191 | - [self hideStatusBar]; | |
| 192 | - [self build]; | |
| 193 | - [self setTransitioning:NO isShow:YES]; | |
| 194 | - }]; | |
| 195 | -} | |
| 196 | - | |
| 197 | -- (void)hide { | |
| 198 | - __kindof UIView *startView; | |
| 199 | - __kindof UIView *endView; | |
| 200 | - UICollectionViewCell<YBIBCellProtocol> *cell = (UICollectionViewCell<YBIBCellProtocol> *)self.collectionView.centerCell; | |
| 201 | - if ([cell respondsToSelector:@selector(yb_foregroundView)]) { | |
| 202 | - startView = cell.yb_foregroundView; | |
| 203 | - } | |
| 204 | - if ([cell.yb_cellData respondsToSelector:@selector(yb_projectiveView)]) { | |
| 205 | - endView = cell.yb_cellData.yb_projectiveView; | |
| 206 | - } | |
| 207 | - | |
| 208 | - for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) { | |
| 209 | - [handler yb_hide:YES]; | |
| 210 | - } | |
| 211 | - [self showStatusBar]; | |
| 212 | - | |
| 213 | - [self setTransitioning:YES isShow:NO]; | |
| 214 | - [self.animatedTransition yb_hideTransitioningWithContainer:self startView:startView endView:endView orientation:self.rotationHandler.currentOrientation completion:^{ | |
| 215 | - [self rebuild]; | |
| 216 | - [self removeFromSuperview]; | |
| 217 | - [self setTransitioning:NO isShow:NO]; | |
| 218 | - }]; | |
| 219 | -} | |
| 220 | - | |
| 221 | -- (void)reloadData { | |
| 222 | - [self.dataMediator clear]; | |
| 223 | - NSInteger page = self.currentPage; | |
| 224 | - [self.collectionView reloadData]; | |
| 225 | - self.currentPage = page; | |
| 226 | -} | |
| 227 | - | |
| 228 | -- (id<YBIBDataProtocol>)currentData { | |
| 229 | - return [self.dataMediator dataForCellAtIndex:self.currentPage]; | |
| 230 | -} | |
| 231 | - | |
| 232 | -#pragma mark - internal | |
| 233 | - | |
| 234 | -- (void)setHiddenProjectiveView:(NSObject *)hiddenProjectiveView { | |
| 235 | - if (_hiddenProjectiveView && [_hiddenProjectiveView respondsToSelector:@selector(setAlpha:)]) { | |
| 236 | - CGFloat originAlpha = _hiddenProjectiveView.ybib_originAlpha; | |
| 237 | - if (originAlpha != 1) { | |
| 238 | - [_hiddenProjectiveView setValue:@(1) forKey:@"alpha"]; | |
| 239 | - [UIView animateWithDuration:0.2 animations:^{ | |
| 240 | - [self->_hiddenProjectiveView setValue:@(originAlpha) forKey:@"alpha"]; | |
| 241 | - }]; | |
| 242 | - } else { | |
| 243 | - [_hiddenProjectiveView setValue:@(originAlpha) forKey:@"alpha"]; | |
| 244 | - } | |
| 245 | - } | |
| 246 | - _hiddenProjectiveView = hiddenProjectiveView; | |
| 247 | - | |
| 248 | - if (!self.autoHideProjectiveView) return; | |
| 249 | - | |
| 250 | - if (hiddenProjectiveView && [hiddenProjectiveView respondsToSelector:@selector(setAlpha:)]) { | |
| 251 | - hiddenProjectiveView.ybib_originAlpha = ((NSNumber *)[hiddenProjectiveView valueForKey:@"alpha"]).floatValue; | |
| 252 | - [hiddenProjectiveView setValue:@(0) forKey:@"alpha"]; | |
| 253 | - } | |
| 254 | -} | |
| 255 | - | |
| 256 | -- (void)implementOperateBrowserProtocol:(id<YBIBOperateBrowserProtocol>)obj { | |
| 257 | - __weak typeof(self) wSelf = self; | |
| 258 | - if ([obj respondsToSelector:@selector(setYb_hideBrowser:)]) { | |
| 259 | - [obj setYb_hideBrowser:^{ | |
| 260 | - __strong typeof(wSelf) self = wSelf; | |
| 261 | - if (!self) return; | |
| 262 | - [self hide]; | |
| 263 | - }]; | |
| 264 | - } | |
| 265 | - if ([obj respondsToSelector:@selector(setYb_hideStatusBar:)]) { | |
| 266 | - [obj setYb_hideStatusBar:^(BOOL hide) { | |
| 267 | - __strong typeof(wSelf) self = wSelf; | |
| 268 | - if (!self) return; | |
| 269 | - hide ? [self hideStatusBar] : [self showStatusBar]; | |
| 270 | - }]; | |
| 271 | - } | |
| 272 | - if ([obj respondsToSelector:@selector(setYb_hideToolViews:)]) { | |
| 273 | - [obj setYb_hideToolViews:^(BOOL hide) { | |
| 274 | - __strong typeof(wSelf) self = wSelf; | |
| 275 | - if (!self) return; | |
| 276 | - for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) { | |
| 277 | - [handler yb_hide:hide]; | |
| 278 | - } | |
| 279 | - }]; | |
| 280 | - } | |
| 281 | -} | |
| 282 | - | |
| 283 | -- (void)implementGetBaseInfoProtocol:(id<YBIBGetBaseInfoProtocol>)obj { | |
| 284 | - __weak typeof(self) wSelf = self; | |
| 285 | - if ([obj respondsToSelector:@selector(setYb_currentOrientation:)]) { | |
| 286 | - [obj setYb_currentOrientation:^UIDeviceOrientation{ | |
| 287 | - __strong typeof(wSelf) self = wSelf; | |
| 288 | - if (!self) return UIDeviceOrientationPortrait; | |
| 289 | - return self.rotationHandler.currentOrientation; | |
| 290 | - }]; | |
| 291 | - } | |
| 292 | - if ([obj respondsToSelector:@selector(setYb_containerSize:)]) { | |
| 293 | - [obj setYb_containerSize:^CGSize(UIDeviceOrientation orientation) { | |
| 294 | - __strong typeof(wSelf) self = wSelf; | |
| 295 | - if (!self) return CGSizeZero; | |
| 296 | - return [self.rotationHandler containerSizeWithOrientation:orientation]; | |
| 297 | - }]; | |
| 298 | - } | |
| 299 | - if ([obj respondsToSelector:@selector(setYb_auxiliaryViewHandler:)]) { | |
| 300 | - [obj setYb_auxiliaryViewHandler:^id<YBIBAuxiliaryViewHandler>{ | |
| 301 | - __strong typeof(wSelf) self = wSelf; | |
| 302 | - if (!self) return nil; | |
| 303 | - return self.auxiliaryViewHandler; | |
| 304 | - }]; | |
| 305 | - } | |
| 306 | - if ([obj respondsToSelector:@selector(setYb_webImageMediator:)]) { | |
| 307 | - [obj setYb_webImageMediator:^id<YBIBWebImageMediator> { | |
| 308 | - __strong typeof(wSelf) self = wSelf; | |
| 309 | - if (!self) return nil; | |
| 310 | - NSAssert(self.webImageMediator, @"'webImageMediator' should not be nil."); | |
| 311 | - return self.webImageMediator; | |
| 312 | - }]; | |
| 313 | - } | |
| 314 | - if ([obj respondsToSelector:@selector(setYb_currentPage:)]) { | |
| 315 | - [obj setYb_currentPage:^NSInteger{ | |
| 316 | - __strong typeof(wSelf) self = wSelf; | |
| 317 | - if (!self) return 0; | |
| 318 | - return self.currentPage; | |
| 319 | - }]; | |
| 320 | - } | |
| 321 | - if ([obj respondsToSelector:@selector(setYb_totalPage:)]) { | |
| 322 | - [obj setYb_totalPage:^NSInteger{ | |
| 323 | - __strong typeof(wSelf) self = wSelf; | |
| 324 | - if (!self) return 0; | |
| 325 | - return [self.dataMediator numberOfCells]; | |
| 326 | - }]; | |
| 327 | - } | |
| 328 | - if ([obj respondsToSelector:@selector(setYb_backView:)]) { | |
| 329 | - obj.yb_backView = self; | |
| 330 | - } | |
| 331 | - if ([obj respondsToSelector:@selector(setYb_containerView:)]) { | |
| 332 | - obj.yb_containerView = self.containerView; | |
| 333 | - } | |
| 334 | - if ([obj respondsToSelector:@selector(setYb_collectionView:)]) { | |
| 335 | - [obj setYb_collectionView:^__kindof UICollectionView *{ | |
| 336 | - __strong typeof(wSelf) self = wSelf; | |
| 337 | - if (!self) return nil; | |
| 338 | - return self.collectionView; | |
| 339 | - }]; | |
| 340 | - } | |
| 341 | - if ([obj respondsToSelector:@selector(setYb_cellIsInCenter:)]) { | |
| 342 | - [obj setYb_cellIsInCenter:^BOOL{ | |
| 343 | - __strong typeof(wSelf) self = wSelf; | |
| 344 | - CGFloat pageF = self.collectionView.contentOffset.x / self.collectionView.bounds.size.width; | |
| 345 | - // '0.001' is admissible error. | |
| 346 | - return ABS(pageF - (NSInteger)pageF) <= 0.001; | |
| 347 | - }]; | |
| 348 | - } | |
| 349 | - if ([obj respondsToSelector:@selector(setYb_isTransitioning:)]) { | |
| 350 | - [obj setYb_isTransitioning:^BOOL{ | |
| 351 | - __strong typeof(wSelf) self = wSelf; | |
| 352 | - if (!self) return NO; | |
| 353 | - return self.isTransitioning; | |
| 354 | - }]; | |
| 355 | - } | |
| 356 | - if ([obj respondsToSelector:@selector(setYb_isShowTransitioning:)]) { | |
| 357 | - [obj setYb_isShowTransitioning:^BOOL{ | |
| 358 | - __strong typeof(wSelf) self = wSelf; | |
| 359 | - if (!self) return NO; | |
| 360 | - return self.isShowTransitioning; | |
| 361 | - }]; | |
| 362 | - } | |
| 363 | - if ([obj respondsToSelector:@selector(setYb_isHideTransitioning:)]) { | |
| 364 | - [obj setYb_isHideTransitioning:^BOOL{ | |
| 365 | - __strong typeof(wSelf) self = wSelf; | |
| 366 | - if (!self) return NO; | |
| 367 | - return self.isHideTransitioning; | |
| 368 | - }]; | |
| 369 | - } | |
| 370 | - if ([obj respondsToSelector:@selector(setYb_isRotating:)]) { | |
| 371 | - [obj setYb_isRotating:^BOOL{ | |
| 372 | - __strong typeof(wSelf) self = wSelf; | |
| 373 | - if (!self) return NO; | |
| 374 | - return self.rotationHandler.isRotating; | |
| 375 | - }]; | |
| 376 | - } | |
| 377 | -} | |
| 378 | - | |
| 379 | -#pragma mark - <UICollectionViewDataSource> | |
| 380 | - | |
| 381 | -- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { | |
| 382 | - return [self.dataMediator numberOfCells]; | |
| 383 | -} | |
| 384 | - | |
| 385 | -- (UICollectionViewCell *)collectionView:(YBIBCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { | |
| 386 | - id<YBIBDataProtocol> data = [self.dataMediator dataForCellAtIndex:indexPath.row]; | |
| 387 | - | |
| 388 | - UICollectionViewCell<YBIBCellProtocol> *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[collectionView reuseIdentifierForCellClass:data.yb_classOfCell] forIndexPath:indexPath]; | |
| 389 | - | |
| 390 | - [self implementGetBaseInfoProtocol:cell]; | |
| 391 | - [self implementOperateBrowserProtocol:cell]; | |
| 392 | - | |
| 393 | - if ([cell respondsToSelector:@selector(setYb_selfPage:)]) { | |
| 394 | - [cell setYb_selfPage:^NSInteger{ | |
| 395 | - return indexPath.row; | |
| 396 | - }]; | |
| 397 | - } | |
| 398 | - | |
| 399 | - cell.yb_cellData = data; | |
| 400 | - | |
| 401 | - if ([cell respondsToSelector:@selector(yb_pageChanged)]) { | |
| 402 | - [cell yb_pageChanged]; | |
| 403 | - } | |
| 404 | - | |
| 405 | - [self.dataMediator preloadWithPage:indexPath.row]; | |
| 406 | - | |
| 407 | - return cell; | |
| 408 | -} | |
| 409 | - | |
| 410 | -#pragma mark - <UICollectionViewDelegate> | |
| 411 | - | |
| 412 | -- (void)scrollViewDidScroll:(UIScrollView *)scrollView { | |
| 413 | - CGFloat pageF = scrollView.contentOffset.x / scrollView.bounds.size.width; | |
| 414 | - NSInteger page = (NSInteger)(pageF + 0.5); | |
| 415 | - | |
| 416 | - for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) { | |
| 417 | - if ([handler respondsToSelector:@selector(yb_offsetXChanged:)]) { | |
| 418 | - [handler yb_offsetXChanged:pageF]; | |
| 419 | - } | |
| 420 | - } | |
| 421 | - | |
| 422 | - if (!scrollView.isDecelerating && !scrollView.isDragging) { | |
| 423 | - // Return if not scrolled by finger. | |
| 424 | - return; | |
| 425 | - } | |
| 426 | - if (page < 0 || page > [self.dataMediator numberOfCells] - 1) return; | |
| 427 | - if (self.rotationHandler.isRotating) return; | |
| 428 | - | |
| 429 | - if (page != _currentPage) { | |
| 430 | - _currentPage = page; | |
| 431 | - [self pageNumberChanged]; | |
| 432 | - } | |
| 433 | -} | |
| 434 | - | |
| 435 | -#pragma mark - event | |
| 436 | - | |
| 437 | -- (void)respondsToLongPress:(UILongPressGestureRecognizer *)sender { | |
| 438 | - if (sender.state == UIGestureRecognizerStateBegan) { | |
| 439 | - if ([self.delegate respondsToSelector:@selector(yb_imageBrowser:respondsToLongPressWithData:)]) { | |
| 440 | - [self.delegate yb_imageBrowser:self respondsToLongPressWithData:[self currentData]]; | |
| 441 | - } else { | |
| 442 | - for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) { | |
| 443 | - if ([handler respondsToSelector:@selector(yb_respondsToLongPress)]) { | |
| 444 | - [handler yb_respondsToLongPress]; | |
| 445 | - } | |
| 446 | - } | |
| 447 | - } | |
| 448 | - } | |
| 449 | -} | |
| 450 | - | |
| 451 | -#pragma mark - getters & setters | |
| 452 | - | |
| 453 | -- (YBIBContainerView *)containerView { | |
| 454 | - if (!_containerView) { | |
| 455 | - _containerView = [YBIBContainerView new]; | |
| 456 | - _containerView.backgroundColor = UIColor.clearColor; | |
| 457 | - _containerView.layer.masksToBounds = YES; | |
| 458 | - } | |
| 459 | - return _containerView; | |
| 460 | -} | |
| 461 | - | |
| 462 | -- (YBIBCollectionView *)collectionView { | |
| 463 | - if (!_collectionView) { | |
| 464 | - _collectionView = [YBIBCollectionView new]; | |
| 465 | - _collectionView.delegate = self; | |
| 466 | - _collectionView.dataSource = self; | |
| 467 | - } | |
| 468 | - return _collectionView; | |
| 469 | -} | |
| 470 | -- (void)setCurrentPage:(NSInteger)currentPage { | |
| 471 | - NSInteger maxPage = self.dataMediator.numberOfCells - 1; | |
| 472 | - if (currentPage > maxPage) { | |
| 473 | - currentPage = maxPage; | |
| 474 | - } | |
| 475 | - _currentPage = currentPage; | |
| 476 | - if (self.collectionView.superview) { | |
| 477 | - [self collectionViewScrollToPage:currentPage]; | |
| 478 | - } | |
| 479 | -} | |
| 480 | -- (void)setDistanceBetweenPages:(CGFloat)distanceBetweenPages { | |
| 481 | - self.collectionView.layout.distanceBetweenPages = distanceBetweenPages; | |
| 482 | -} | |
| 483 | -- (CGFloat)distanceBetweenPages { | |
| 484 | - return self.collectionView.layout.distanceBetweenPages; | |
| 485 | -} | |
| 486 | - | |
| 487 | -- (void)setTransitioning:(BOOL)transitioning isShow:(BOOL)isShow { | |
| 488 | - _transitioning = transitioning; | |
| 489 | - _showTransitioning = transitioning && isShow; | |
| 490 | - _hideTransitioning = transitioning && !isShow; | |
| 491 | - | |
| 492 | - // Make 'self.userInteractionEnabled' always 'YES' to block external interaction. | |
| 493 | - self.containerView.userInteractionEnabled = !transitioning; | |
| 494 | - self.collectionView.userInteractionEnabled = !transitioning; | |
| 495 | - | |
| 496 | - if (transitioning) { | |
| 497 | - if ([self.delegate respondsToSelector:@selector(yb_imageBrowser:beginTransitioningWithIsShow:)]) { | |
| 498 | - [self.delegate yb_imageBrowser:self beginTransitioningWithIsShow:isShow]; | |
| 499 | - } | |
| 500 | - } else { | |
| 501 | - if ([self.delegate respondsToSelector:@selector(yb_imageBrowser:endTransitioningWithIsShow:)]) { | |
| 502 | - [self.delegate yb_imageBrowser:self endTransitioningWithIsShow:isShow]; | |
| 503 | - } | |
| 504 | - } | |
| 505 | -} | |
| 506 | - | |
| 507 | -- (YBIBDataMediator *)dataMediator { | |
| 508 | - if (!_dataMediator) { | |
| 509 | - _dataMediator = [[YBIBDataMediator alloc] initWithBrowser:self]; | |
| 510 | - _dataMediator.dataCacheCountLimit = YBIBLowMemory() ? 9 : 27; | |
| 511 | - _dataMediator.preloadCount = YBIBLowMemory() ? 0 : 2; | |
| 512 | - } | |
| 513 | - return _dataMediator; | |
| 514 | -} | |
| 515 | -- (void)setPreloadCount:(NSUInteger)preloadCount { | |
| 516 | - self.dataMediator.preloadCount = preloadCount; | |
| 517 | -} | |
| 518 | -- (NSUInteger)preloadCount { | |
| 519 | - return self.dataMediator.preloadCount; | |
| 520 | -} | |
| 521 | - | |
| 522 | -- (YBIBScreenRotationHandler *)rotationHandler { | |
| 523 | - if (!_rotationHandler) { | |
| 524 | - _rotationHandler = [[YBIBScreenRotationHandler alloc] initWithBrowser:self]; | |
| 525 | - } | |
| 526 | - return _rotationHandler; | |
| 527 | -} | |
| 528 | -- (void)setSupportedOrientations:(UIInterfaceOrientationMask)supportedOrientations { | |
| 529 | - self.rotationHandler.supportedOrientations = supportedOrientations; | |
| 530 | -} | |
| 531 | -- (UIInterfaceOrientationMask)supportedOrientations { | |
| 532 | - return self.rotationHandler.supportedOrientations; | |
| 533 | -} | |
| 534 | -- (UIDeviceOrientation)currentOrientation { | |
| 535 | - return self.rotationHandler.currentOrientation; | |
| 536 | -} | |
| 537 | - | |
| 538 | -@end |
Example/CNLiveOrganizationValidationModule.xcodeproj/project.pbxproj
| ... | ... | @@ -396,6 +396,7 @@ |
| 396 | 396 | "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", |
| 397 | 397 | "${BUILT_PRODUCTS_DIR}/SSZipArchive/SSZipArchive.framework", |
| 398 | 398 | "${BUILT_PRODUCTS_DIR}/TZImagePickerController/TZImagePickerController.framework", |
| 399 | + "${BUILT_PRODUCTS_DIR}/YBImageBrowser/YBImageBrowser.framework", | |
| 399 | 400 | "${BUILT_PRODUCTS_DIR}/YYAsyncLayer/YYAsyncLayer.framework", |
| 400 | 401 | "${BUILT_PRODUCTS_DIR}/YYCache/YYCache.framework", |
| 401 | 402 | "${BUILT_PRODUCTS_DIR}/YYCategories/YYCategories.framework", |
| ... | ... | @@ -434,6 +435,7 @@ |
| 434 | 435 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SDWebImage.framework", |
| 435 | 436 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SSZipArchive.framework", |
| 436 | 437 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/TZImagePickerController.framework", |
| 438 | + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YBImageBrowser.framework", | |
| 437 | 439 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYAsyncLayer.framework", |
| 438 | 440 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYCache.framework", |
| 439 | 441 | "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYCategories.framework", | ... | ... |