123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538 |
- //
- // YBImageBrowser.m
- // YBImageBrowserDemo
- //
- // Created by 波儿菜 on 2019/6/5.
- // Copyright © 2019 波儿菜. All rights reserved.
- //
- #import "YBImageBrowser.h"
- #import "YBIBUtilities.h"
- #import "YBIBCellProtocol.h"
- #import "YBIBDataMediator.h"
- #import "YBIBScreenRotationHandler.h"
- #import "NSObject+YBImageBrowser.h"
- #import "YBImageBrowser+Internal.h"
- #if __has_include("YBIBDefaultWebImageMediator.h")
- #import "YBIBDefaultWebImageMediator.h"
- #endif
- @interface YBImageBrowser () <UICollectionViewDelegate, UICollectionViewDataSource>
- @property (nonatomic, strong) YBIBCollectionView *collectionView;
- @property (nonatomic, strong) YBIBDataMediator *dataMediator;
- @property (nonatomic, strong) YBIBScreenRotationHandler *rotationHandler;
- @end
- @implementation YBImageBrowser {
- BOOL _originStatusBarHidden;
- }
- #pragma mark - life cycle
- - (void)dealloc {
- self.hiddenProjectiveView = nil;
- [self showStatusBar];
- }
- - (instancetype)initWithFrame:(CGRect)frame {
- self = [super initWithFrame:frame];
- if (self) {
- self.backgroundColor = UIColor.blackColor;
- // UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(respondsToLongPress:)];
- // [self addGestureRecognizer:longPress];
- [self initValue];
- }
- return self;
- }
- - (void)initValue {
- _transitioning = _showTransitioning = _hideTransitioning = NO;
- _defaultAnimatedTransition = _animatedTransition = [YBIBAnimatedTransition new];
- _toolViewHandlers = @[[YBIBToolViewHandler new]];
- _defaultToolViewHandler = _toolViewHandlers[0];
- _auxiliaryViewHandler = [YBIBAuxiliaryViewHandler new];
- _shouldHideStatusBar = YES;
- _autoHideProjectiveView = YES;
- #if __has_include("YBIBDefaultWebImageMediator.h")
- _webImageMediator = [YBIBDefaultWebImageMediator new];
- #endif
- }
- #pragma mark - private
- - (void)build {
- [self addSubview:self.collectionView];
- self.collectionView.frame = self.bounds;
- self.collectionView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- [self addSubview:self.containerView];
- self.containerView.frame = self.bounds;
- self.containerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- [self buildToolView];
-
- [self layoutIfNeeded];
-
- [self collectionViewScrollToPage:self.currentPage];
- [self.rotationHandler startObserveDeviceOrientation];
- }
- - (void)buildToolView {
- for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) {
- [self implementGetBaseInfoProtocol:handler];
- [self implementOperateBrowserProtocol:handler];
- __weak typeof(self) wSelf = self;
- if ([handler respondsToSelector:@selector(setYb_currentData:)]) {
- [handler setYb_currentData:^id<YBIBDataProtocol>{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return nil;
- return self.currentData;
- }];
- }
- [handler yb_containerViewIsReadied];
- [handler yb_hide:NO];
- }
- }
- - (void)rebuild {
- self.hiddenProjectiveView = nil;
- [self showStatusBar];
- [self.containerView removeFromSuperview];
- _containerView = nil;
- [self.collectionView removeFromSuperview];
- _collectionView = nil;
- [self.dataMediator clear];
- [self.rotationHandler clear];
- }
- - (void)collectionViewScrollToPage:(NSInteger)page {
- [self.collectionView scrollToPage:page];
- [self pageNumberChanged];
- }
- - (void)pageNumberChanged {
- id<YBIBDataProtocol> data = self.currentData;
- UIView *projectiveView = nil;
- if ([data respondsToSelector:@selector(yb_projectiveView)]) {
- projectiveView = [data yb_projectiveView];
- }
- self.hiddenProjectiveView = projectiveView;
-
- if (self.delegate && [self.delegate respondsToSelector:@selector(yb_imageBrowser:pageChanged:data:)]) {
- [self.delegate yb_imageBrowser:self pageChanged:self.currentPage data:data];
- }
- for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) {
- if ([handler respondsToSelector:@selector(yb_pageChanged)]) {
- [handler yb_pageChanged];
- }
- }
- NSArray *visibleCells = self.collectionView.visibleCells;
- for (UICollectionViewCell<YBIBCellProtocol> *cell in visibleCells) {
- if ([cell respondsToSelector:@selector(yb_pageChanged)]) {
- [cell yb_pageChanged];
- }
- }
- }
- - (void)showStatusBar {
- if (self.shouldHideStatusBar) {
- [UIApplication sharedApplication].statusBarHidden = _originStatusBarHidden;
- }
- }
- - (void)hideStatusBar {
- if (self.shouldHideStatusBar) {
- [UIApplication sharedApplication].statusBarHidden = YES;
- }
- }
- #pragma mark - public
- - (void)show {
- [self showToView:[UIApplication sharedApplication].keyWindow];
- }
- - (void)showToView:(UIView *)view {
- [self showToView:view containerSize:view.bounds.size];
- }
- - (void)showToView:(UIView *)view containerSize:(CGSize)containerSize {
- [self.rotationHandler startObserveStatusBarOrientation];
-
- [view addSubview:self];
- self.frame = view.bounds;
- self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
-
- _originStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden;
-
- [self.rotationHandler configContainerSize:containerSize];
-
- [self.dataMediator preloadWithPage:self.currentPage];
-
- __kindof UIView *startView;
- UIImage *startImage;
- CGRect endFrame = CGRectZero;
- id<YBIBDataProtocol> data = [self.dataMediator dataForCellAtIndex:self.currentPage];
- if ([data respondsToSelector:@selector(yb_projectiveView)]) {
- startView = data.yb_projectiveView;
- self.hiddenProjectiveView = startView;
- if ([startView isKindOfClass:UIImageView.class]) {
- startImage = ((UIImageView *)startView).image;
- } else {
- startImage = YBIBSnapshotView(startView);
- }
- }
- if ([data respondsToSelector:@selector(yb_imageViewFrameWithContainerSize:imageSize:orientation:)]) {
- endFrame = [data yb_imageViewFrameWithContainerSize:self.bounds.size imageSize:startImage.size orientation:self.rotationHandler.currentOrientation];
- }
-
- [self setTransitioning:YES isShow:YES];
- [self.animatedTransition yb_showTransitioningWithContainer:self startView:startView startImage:startImage endFrame:endFrame orientation:self.rotationHandler.currentOrientation completion:^{
- [self hideStatusBar];
- [self build];
- [self setTransitioning:NO isShow:YES];
- }];
- }
- - (void)hide {
- __kindof UIView *startView;
- __kindof UIView *endView;
- UICollectionViewCell<YBIBCellProtocol> *cell = (UICollectionViewCell<YBIBCellProtocol> *)self.collectionView.centerCell;
- if ([cell respondsToSelector:@selector(yb_foregroundView)]) {
- startView = cell.yb_foregroundView;
- }
- if ([cell.yb_cellData respondsToSelector:@selector(yb_projectiveView)]) {
- endView = cell.yb_cellData.yb_projectiveView;
- }
-
- for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) {
- [handler yb_hide:YES];
- }
- [self showStatusBar];
-
- [self setTransitioning:YES isShow:NO];
- [self.animatedTransition yb_hideTransitioningWithContainer:self startView:startView endView:endView orientation:self.rotationHandler.currentOrientation completion:^{
- [self rebuild];
- [self removeFromSuperview];
- [self setTransitioning:NO isShow:NO];
- }];
- }
- - (void)reloadData {
- [self.dataMediator clear];
- NSInteger page = self.currentPage;
- [self.collectionView reloadData];
- self.currentPage = page;
- }
- - (id<YBIBDataProtocol>)currentData {
- return [self.dataMediator dataForCellAtIndex:self.currentPage];
- }
- #pragma mark - internal
- - (void)setHiddenProjectiveView:(NSObject *)hiddenProjectiveView {
- if (_hiddenProjectiveView && [_hiddenProjectiveView respondsToSelector:@selector(setAlpha:)]) {
- CGFloat originAlpha = _hiddenProjectiveView.ybib_originAlpha;
- if (originAlpha != 1) {
- [_hiddenProjectiveView setValue:@(1) forKey:@"alpha"];
- [UIView animateWithDuration:0.2 animations:^{
- [self->_hiddenProjectiveView setValue:@(originAlpha) forKey:@"alpha"];
- }];
- } else {
- [_hiddenProjectiveView setValue:@(originAlpha) forKey:@"alpha"];
- }
- }
- _hiddenProjectiveView = hiddenProjectiveView;
-
- if (!self.autoHideProjectiveView) return;
-
- if (hiddenProjectiveView && [hiddenProjectiveView respondsToSelector:@selector(setAlpha:)]) {
- hiddenProjectiveView.ybib_originAlpha = ((NSNumber *)[hiddenProjectiveView valueForKey:@"alpha"]).floatValue;
- [hiddenProjectiveView setValue:@(0) forKey:@"alpha"];
- }
- }
- - (void)implementOperateBrowserProtocol:(id<YBIBOperateBrowserProtocol>)obj {
- __weak typeof(self) wSelf = self;
- if ([obj respondsToSelector:@selector(setYb_hideBrowser:)]) {
- [obj setYb_hideBrowser:^{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- [self hide];
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_hideStatusBar:)]) {
- [obj setYb_hideStatusBar:^(BOOL hide) {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- hide ? [self hideStatusBar] : [self showStatusBar];
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_hideToolViews:)]) {
- [obj setYb_hideToolViews:^(BOOL hide) {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return;
- for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) {
- [handler yb_hide:hide];
- }
- }];
- }
- }
- - (void)implementGetBaseInfoProtocol:(id<YBIBGetBaseInfoProtocol>)obj {
- __weak typeof(self) wSelf = self;
- if ([obj respondsToSelector:@selector(setYb_currentOrientation:)]) {
- [obj setYb_currentOrientation:^UIDeviceOrientation{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return UIDeviceOrientationPortrait;
- return self.rotationHandler.currentOrientation;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_containerSize:)]) {
- [obj setYb_containerSize:^CGSize(UIDeviceOrientation orientation) {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return CGSizeZero;
- return [self.rotationHandler containerSizeWithOrientation:orientation];
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_auxiliaryViewHandler:)]) {
- [obj setYb_auxiliaryViewHandler:^id<YBIBAuxiliaryViewHandler>{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return nil;
- return self.auxiliaryViewHandler;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_webImageMediator:)]) {
- [obj setYb_webImageMediator:^id<YBIBWebImageMediator> {
- __strong typeof(wSelf) self = wSelf;
- if (!self) return nil;
- NSAssert(self.webImageMediator, @"'webImageMediator' should not be nil.");
- return self.webImageMediator;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_currentPage:)]) {
- [obj setYb_currentPage:^NSInteger{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return 0;
- return self.currentPage;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_totalPage:)]) {
- [obj setYb_totalPage:^NSInteger{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return 0;
- return [self.dataMediator numberOfCells];
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_backView:)]) {
- obj.yb_backView = self;
- }
- if ([obj respondsToSelector:@selector(setYb_containerView:)]) {
- obj.yb_containerView = self.containerView;
- }
- if ([obj respondsToSelector:@selector(setYb_collectionView:)]) {
- [obj setYb_collectionView:^__kindof UICollectionView *{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return nil;
- return self.collectionView;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_cellIsInCenter:)]) {
- [obj setYb_cellIsInCenter:^BOOL{
- __strong typeof(wSelf) self = wSelf;
- CGFloat pageF = self.collectionView.contentOffset.x / self.collectionView.bounds.size.width;
- // '0.001' is admissible error.
- return ABS(pageF - (NSInteger)pageF) <= 0.001;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_isTransitioning:)]) {
- [obj setYb_isTransitioning:^BOOL{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return NO;
- return self.isTransitioning;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_isShowTransitioning:)]) {
- [obj setYb_isShowTransitioning:^BOOL{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return NO;
- return self.isShowTransitioning;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_isHideTransitioning:)]) {
- [obj setYb_isHideTransitioning:^BOOL{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return NO;
- return self.isHideTransitioning;
- }];
- }
- if ([obj respondsToSelector:@selector(setYb_isRotating:)]) {
- [obj setYb_isRotating:^BOOL{
- __strong typeof(wSelf) self = wSelf;
- if (!self) return NO;
- return self.rotationHandler.isRotating;
- }];
- }
- }
- #pragma mark - <UICollectionViewDataSource>
- - (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
- return [self.dataMediator numberOfCells];
- }
- - (UICollectionViewCell *)collectionView:(YBIBCollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
- id<YBIBDataProtocol> data = [self.dataMediator dataForCellAtIndex:indexPath.row];
-
- UICollectionViewCell<YBIBCellProtocol> *cell = [collectionView dequeueReusableCellWithReuseIdentifier:[collectionView reuseIdentifierForCellClass:data.yb_classOfCell] forIndexPath:indexPath];
-
- [self implementGetBaseInfoProtocol:cell];
- [self implementOperateBrowserProtocol:cell];
-
- if ([cell respondsToSelector:@selector(setYb_selfPage:)]) {
- [cell setYb_selfPage:^NSInteger{
- return indexPath.row;
- }];
- }
-
- cell.yb_cellData = data;
-
- if ([cell respondsToSelector:@selector(yb_pageChanged)]) {
- [cell yb_pageChanged];
- }
-
- [self.dataMediator preloadWithPage:indexPath.row];
-
- return cell;
- }
- #pragma mark - <UICollectionViewDelegate>
- - (void)scrollViewDidScroll:(UIScrollView *)scrollView {
- CGFloat pageF = scrollView.contentOffset.x / scrollView.bounds.size.width;
- NSInteger page = (NSInteger)(pageF + 0.5);
-
- for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) {
- if ([handler respondsToSelector:@selector(yb_offsetXChanged:)]) {
- [handler yb_offsetXChanged:pageF];
- }
- }
-
- if (!scrollView.isDecelerating && !scrollView.isDragging) {
- // Return if not scrolled by finger.
- return;
- }
- if (page < 0 || page > [self.dataMediator numberOfCells] - 1) return;
- if (self.rotationHandler.isRotating) return;
-
- if (page != _currentPage) {
- _currentPage = page;
- [self pageNumberChanged];
- }
- }
- #pragma mark - event
- - (void)respondsToLongPress:(UILongPressGestureRecognizer *)sender {
- if (sender.state == UIGestureRecognizerStateBegan) {
- if ([self.delegate respondsToSelector:@selector(yb_imageBrowser:respondsToLongPressWithData:)]) {
- [self.delegate yb_imageBrowser:self respondsToLongPressWithData:[self currentData]];
- } else {
- for (id<YBIBToolViewHandler> handler in self.toolViewHandlers) {
- if ([handler respondsToSelector:@selector(yb_respondsToLongPress)]) {
- [handler yb_respondsToLongPress];
- }
- }
- }
- }
- }
- #pragma mark - getters & setters
- - (YBIBContainerView *)containerView {
- if (!_containerView) {
- _containerView = [YBIBContainerView new];
- _containerView.backgroundColor = UIColor.clearColor;
- _containerView.layer.masksToBounds = YES;
- }
- return _containerView;
- }
- - (YBIBCollectionView *)collectionView {
- if (!_collectionView) {
- _collectionView = [YBIBCollectionView new];
- _collectionView.delegate = self;
- _collectionView.dataSource = self;
- }
- return _collectionView;
- }
- - (void)setCurrentPage:(NSInteger)currentPage {
- NSInteger maxPage = self.dataMediator.numberOfCells - 1;
- if (currentPage > maxPage) {
- currentPage = maxPage;
- }
- _currentPage = currentPage;
- if (self.collectionView.superview) {
- [self collectionViewScrollToPage:currentPage];
- }
- }
- - (void)setDistanceBetweenPages:(CGFloat)distanceBetweenPages {
- self.collectionView.layout.distanceBetweenPages = distanceBetweenPages;
- }
- - (CGFloat)distanceBetweenPages {
- return self.collectionView.layout.distanceBetweenPages;
- }
- - (void)setTransitioning:(BOOL)transitioning isShow:(BOOL)isShow {
- _transitioning = transitioning;
- _showTransitioning = transitioning && isShow;
- _hideTransitioning = transitioning && !isShow;
-
- // Make 'self.userInteractionEnabled' always 'YES' to block external interaction.
- self.containerView.userInteractionEnabled = !transitioning;
- self.collectionView.userInteractionEnabled = !transitioning;
-
- if (transitioning) {
- if ([self.delegate respondsToSelector:@selector(yb_imageBrowser:beginTransitioningWithIsShow:)]) {
- [self.delegate yb_imageBrowser:self beginTransitioningWithIsShow:isShow];
- }
- } else {
- if ([self.delegate respondsToSelector:@selector(yb_imageBrowser:endTransitioningWithIsShow:)]) {
- [self.delegate yb_imageBrowser:self endTransitioningWithIsShow:isShow];
- }
- }
- }
- - (YBIBDataMediator *)dataMediator {
- if (!_dataMediator) {
- _dataMediator = [[YBIBDataMediator alloc] initWithBrowser:self];
- _dataMediator.dataCacheCountLimit = YBIBLowMemory() ? 9 : 27;
- _dataMediator.preloadCount = YBIBLowMemory() ? 0 : 2;
- }
- return _dataMediator;
- }
- - (void)setPreloadCount:(NSUInteger)preloadCount {
- self.dataMediator.preloadCount = preloadCount;
- }
- - (NSUInteger)preloadCount {
- return self.dataMediator.preloadCount;
- }
- - (YBIBScreenRotationHandler *)rotationHandler {
- if (!_rotationHandler) {
- _rotationHandler = [[YBIBScreenRotationHandler alloc] initWithBrowser:self];
- }
- return _rotationHandler;
- }
- - (void)setSupportedOrientations:(UIInterfaceOrientationMask)supportedOrientations {
- self.rotationHandler.supportedOrientations = supportedOrientations;
- }
- - (UIInterfaceOrientationMask)supportedOrientations {
- return self.rotationHandler.supportedOrientations;
- }
- - (UIDeviceOrientation)currentOrientation {
- return self.rotationHandler.currentOrientation;
- }
- @end
|