iOS小技能:查看大图浏览器(图片支持滑动切换)

659 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

引言

demo视频:live.csdn.net/v/embed/157…

从CSDN下载Demo源码:https://download.csdn.net/download/u011018979/16039540

  • 应用场景: 查看多张大图,比如查看风险商户的证明材料,图片支持滑动切换

  • 文章:blog.csdn.net/z929118967/…

  • 主要功能:进入查看器之后,可左右滑动查看上/下张,并支持下滑视图退出查看器

image.png

I 用法

/**
 初始化查看大图的controller

 @param imageUrls 所有大图的数组
 @param originImageViews 所有小图原始的imageView数组
 @param selectPage 选中的是第几个
 @return 大图的controller
 */
- (id)initWithUrlStr:(NSArray<NSString *>*)imageUrls originImageViews:(NSArray<UIImageView *>*)originImageViews selectPage:(NSInteger)selectPage;


此功能推荐采用UIModalPresentationOverCurrentContext

  • 用法一: 采用模型数据进行传递

避免多个数组下标不一致问题

//处理查看大图事件

- (void)showImageBrowser:(QCTCollectionModel*)m
{
    

        [self setupImageBrowserModels];

    
    KNImageBrowserViewController * imageBrowserViewController = [[KNImageBrowserViewController alloc] initWithImageBrowserModels:self.viewModel.ImageBrowserModels selectPage:m.selectPage];
    
//    KNImageBrowserViewController * imageBrowserViewController = [[KNImageBrowserViewController alloc] initWithUrlStr:imageUrls originImageViews:imageView4smalls selectPage:m.selectPage];
    
        
    
    [self presentViewController:imageBrowserViewController animated:YES completion:nil];
}


  • 用法二: 废弃
- (void)showImageBrowser {
    KNImageBrowserViewController * imageBrowserViewController = [[KNImageBrowserViewController alloc] initWithUrlStr:self.imageUrls originImageViews:self.originImageViews selectPage:self.selectPage];
    [self.controller presentViewController:imageBrowserViewController animated:YES completion:nil];
}

II demo

从CSDN下载Demo源码:https://download.csdn.net/download/u011018979/16039540

2.1 数据模型

@interface KNImageBrowserModel : NSObject
/**
大图的图片地址
*/
@property(nonatomic,copy)NSString * urlStr;
/**
小图原始的imageView,用于加载大图时的占位图片
*/
@property(nonatomic,weak)UIImageView * smallImageView;

/**
 选中的是第几个imageView
*/
@property(nonatomic,assign)NSInteger selectPage;

  • 构建数据模型:KNImageBrowserModel
        KNImageBrowserModel * imageBrowserModel = [[KNImageBrowserModel alloc] init];
        imageBrowserModel.smallImageView = imageView;
        
        
        
        
        imageBrowserModel.urlStr = urlStr;


- (void)setupImageBrowserModels{
    
    
//    NSArray *imageView4smalls = [self.viewModel.collectionDataArray valueForKeyPath:@"@distinctUnionOfObjects.imageView4small"];//arDistinct是一些含有originalAddress属性的对象集合

    //
//    NSArray *imageUrls = [self.viewModel.collectionDataArray valueForKeyPath:@"@distinctUnionOfObjects.originalAddress"];//arDistinct是一些含有originalAddress属性的对象集合

    self.viewModel.ImageBrowserModels  =  [NSMutableArray array];
    
    
    for ( QCTCollectionModel  *obj in  self.viewModel.collectionDataArray) {
        
        KNImageBrowserModel * imageBrowserModel = [[KNImageBrowserModel alloc] init];
        imageBrowserModel.smallImageView = obj.imageView4small;
        
        imageBrowserModel.urlStr = obj.originalAddress;

        [self.viewModel.ImageBrowserModels addObject:imageBrowserModel];

    }
    
    

}


2.2 向下滑动触发退出操作。

- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset {
    CGFloat contentOffsetY = scrollView.contentOffset.y;
    if ((contentOffsetY<0 && _touchFingerNumber==1) && (velocity.y<0 && fabs(velocity.y)>fabs(velocity.x))) {
        //如果是向下滑动才触发消失的操作。
        if ([self.delegate respondsToSelector:@selector(imageBrowserSubViewSingleTapWithModel:)]) {
            [self.delegate imageBrowserSubViewSingleTapWithModel:_imageBrowserModel];
        }
    } else {
        [self changeSizeCenterY:0.0];
        CGFloat offsetX = (scrollView.frame.size.width > scrollView.contentSize.width) ? (scrollView.frame.size.width - scrollView.contentSize.width) * 0.5 : 0.0;
        CGFloat offsetY = (scrollView.frame.size.height > scrollView.contentSize.height) ? (scrollView.frame.size.height - scrollView.contentSize.height) * 0.5 : 0.0;
        self.subImageView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX, scrollView.contentSize.height * 0.5 + offsetY);
    }
    _touchFingerNumber = 0;
    self.subScrollView.clipsToBounds = YES;
}

2.3 下载demo源码

[video(video-farK5uUD-1616404131406)(type-csdn)(url-live.csdn.net/v/embed/157…)]

从CSDN下载Demo源码:https://download.csdn.net/download/u011018979/16039540

  • 应用场景: 查看多张大图,比如查看风险商户的证明材料,图片支持滑动切换

  • 文章:blog.csdn.net/z929118967/…

  • 主要功能:进入查看器之后,可左右滑动查看上/下张,并支持下滑视图退出查看器

在这里插入图片描述

private projects

III 转场动画

  • UIModalPresentationStyle

        self.modalPresentationStyle = UIModalPresentationOverCurrentContext;
        self.transitioningDelegate = self;


typedef NS_ENUM(NSInteger, UIModalPresentationStyle) {
    UIModalPresentationFullScreen = 0,
    UIModalPresentationPageSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
    UIModalPresentationFormSheet API_AVAILABLE(ios(3.2)) API_UNAVAILABLE(tvos),
    UIModalPresentationCurrentContext API_AVAILABLE(ios(3.2)),
    UIModalPresentationCustom API_AVAILABLE(ios(7.0)),
    UIModalPresentationOverFullScreen API_AVAILABLE(ios(8.0)),
    UIModalPresentationOverCurrentContext API_AVAILABLE(ios(8.0)),
    UIModalPresentationPopover API_AVAILABLE(ios(8.0)) API_UNAVAILABLE(tvos),
    UIModalPresentationBlurOverFullScreen API_AVAILABLE(tvos(11.0)) API_UNAVAILABLE(ios) API_UNAVAILABLE(watchos),
    UIModalPresentationNone API_AVAILABLE(ios(7.0)) = -1,
    UIModalPresentationAutomatic API_AVAILABLE(ios(13.0)) = -2,
};

3.1 Modal 转场动画

此功能推荐采用UIModalPresentationOverCurrentContext

  • 实现代理方法UIViewControllerTransitioningDelegate

presentViewController 转场动画

#pragma mark --UIViewControllerTransitioningDelegate
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
    self.browserTranslation.isBrowserMainView = YES;// 进入
    return self.browserTranslation;
}

- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    self.browserTranslation.isBrowserMainView = NO;// 离开
    return self.browserTranslation;
}

  • 自定义UIViewControllerAnimatedTransitioning
@interface KNImageBrowserTranslation : NSObject<UIViewControllerAnimatedTransitioning>

/* 自定义转场动画 */
//动画时间
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
    return 0.3;
}
//转场动画
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
    
    
//    return ;
    
    NSMutableArray * dataM = [self.mainBrowserMainView dataSource];
    NSInteger currentIndex = [self.mainBrowserMainView selectPage];

    KNImageBrowserModel * currentModel = [dataM objectAtIndex:currentIndex];
    
    //转场过程中显示的view,所有动画控件都应该加在这上面
    UIView * containerView = [transitionContext containerView];
    //转场去往的控制器
    UIViewController * toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
    if (_isBrowserMainView) {
        //是进入
        [containerView addSubview:toViewController.view];
        
        CGRect frame = [currentModel smallImageViewframeOriginWindow];
        UIImage * image = [currentModel getCurrentImage];
        UIImageView * imageView = [self addShadowImageViewWithFrame:frame image:image];
        //隐藏子组件
        [self.mainBrowserMainView subViewHidden:YES];
        self.browserControllerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.0];
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            imageView.frame = [currentModel imageViewframeShowWindow];
            self.browserControllerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:1.0];
        } completion:^(BOOL finished) {
            if ([transitionContext transitionWasCancelled]) {
                [transitionContext completeTransition:NO];
            } else {
                [transitionContext completeTransition:YES];
                
                [self.mainBrowserMainView subViewHidden:NO];
                [imageView removeFromSuperview];
                
//                [toViewController.view removeFromSuperview];
            }
        }];
    } else {
        //是离开
        CGRect frame = [currentModel bigImageViewFrameOnScrollView];
        UIImage * image = [currentModel getCurrentImage];
        UIImageView * imageView = [self addShadowImageViewWithFrame:frame image:image];
        
        [self.mainBrowserMainView subViewHidden:YES];
        
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            imageView.frame = [currentModel smallImageViewframeOriginWindow];
            self.browserControllerView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.0];
        } completion:^(BOOL finished) {
            if ([transitionContext transitionWasCancelled]) {
                [transitionContext completeTransition:NO];
            } else {
                [transitionContext completeTransition:YES];
                [imageView removeFromSuperview];
            }
        }];
    }
}

- (UIImageView *)addShadowImageViewWithFrame:(CGRect)frame image:(UIImage *)image {
    UIImageView * imageView = [[UIImageView alloc] initWithFrame:frame];
    imageView.contentMode = UIViewContentModeScaleAspectFill;
    imageView.clipsToBounds = YES;
    imageView.image = image;
    [self.browserControllerView addSubview:imageView];
    return imageView;
}

@end

3.2 push 转场动画

    
    [UIView transitionWithView:self.navigationController.view duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
        
        [weakSelf.navigationController pushViewController:detail animated:NO];
        
    } completion:nil];

see also

iOS NSPredicate的应用:从数组搜索特定条件的元素https://kunnan.blog.csdn.net/article/details/113499172

通过 isSelected 筛选选中的规格数据

- (NSString *)SpecValIds{
    
    
    NSPredicate* predicate = [NSPredicate predicateWithFormat:@"isSelected == %d",YES];
    
    
    
    NSMutableArray *tmparr = [self.platProductAttributeAndSpecificationDto.ProductSpecificationDtos filteredArrayUsingPredicate:predicate];
        
    NSArray *editReturnedModeltmparr = [tmparr valueForKeyPath:@"@distinctUnionOfObjects.id"];
    
    NSString *string = [editReturnedModeltmparr componentsJoinedByString:@","];//     iOS 将数组中的元素用符号拼接字符串的方法

    

    return string;
    
}