iOS - 关于点击小图查看大图的封装(包含单击、双击、捏合手势)

这篇博客介绍了如何在iOS应用中封装一个图片浏览功能,包括使用UICollectionView展示图片、实现单击返回、双击放大/缩小以及捏合手势放大/缩小图片。主要涉及三个类:ImageScanController、ScrollImageView和ImageScanCell。ImageScanController作为控制器,处理数据源和手势处理;ScrollImageView是自定义的UIScrollView子类,实现了图片的缩放功能;ImageScanCell是UICollectionViewCell的子类,用于展示图片。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这次的封装,最终效果就是可以滑动查看所有图片,单击返回、双击放大/缩小、捏合放大/缩小的手势。在此,封装了三个类。如下所示:

第一个类(我们直接要使用的类):

#import "ImageScanCell.h"


@interface ImageScanController : BaseController


//1.图片数组 (一组图片, 是给collectionView现实的)

@property(nonatomic, strong)NSArray * imageURLStringArray;


//2.当前是 哪个item被点击,就显示哪个item的图片

//如何得知哪个item'被点击, 传递 当前item的索引位置

@property(nonatomic, strong)NSIndexPath * selectedIndexPath;


@property (nonatomic,assign) NSInteger currentPage;

@end


// .m中

#import "ImageScanController.h"


@interface ImageScanController ()<UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>

{

    //子视图

    UICollectionView * _collectionView;

    

    //取非

    BOOL  _isHidden;

    

    // 需要下载的图片

    UIImage * _myImage;

    

    UIPageControl *_page;

    

}

@end


static NSString * imageScanID = @"ImageScanCell";


@implementation ImageScanController


- (void)viewDidLoad {

    [super viewDidLoad];

    

    

    self.title = @"图片浏览";

    

    self.view.backgroundColor = [UIColor whiteColor];

    

    

    //创建子视图

    [self _loadSubViews];

    

    //创建 下载的按钮

    UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];

    [button setImage:[UIImage imageNamed:@"img_download_p"] forState:UIControlStateNormal];

    [button addTarget:self action:@selector(downloadImageAction:) forControlEvents:UIControlEventTouchUpInside];

    button.frame = CGRectMake(kScreenWidth - 60 - 20, kScreenHeight - 60 - 64 - 30, 60, 60);

    [self.view addSubview:button];

    

    //注册成为kNavigationBarHideOrNot这条通知的观察者

    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(hideNavigationOrNot:) name:@"HideOrNot" object:nil];

    

}


#pragma mark - button action


- (void)downloadImageAction:(UIButton *)sender{

    //实现下载 图片 到相册 (保存)

    

    //C语言有一个函数

    //参数一:要保存哪张图片

    //参数二:回调目标, 当这个函数走完之后,会由 哪个对象(当前这个参数), 去调用一个什么方法(后面参数三的方法)

    //参数三:@selector  方法签名, 是要被调用的方法的名字(文档中有给定的方法)

    //参数四:指 要传递的信息,一般是NULL

    

    //回调方法注意看文档。

    UIImageWriteToSavedPhotosAlbum(_myImage, self, @selector(image: didFinishSavingWithError:contextInfo:), NULL);

    

}



- (void)               image: (UIImage *) image

    didFinishSavingWithError: (NSError *) error

                 contextInfo: (void *) contextInfo{

    

    //根据不同的 情况,让 提示视图 提示消息显示不同的内容。

    NSString * message = nil;


    if (error == nil ) {

        

        message = @"保存成功";

    } else{

        

        message = @"保存失败";

    }

    

    // 创建提示视图, 通知用户是否保存成功

    UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"提示" message:message delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil];

    

    [alertView show];


}



#pragma mark - notification Action

- (void)hideNavigationOrNot:(NSNotification *)notification{

    _isHidden = !_isHidden;

    

    // 隐藏  显示导航栏

    [self.navigationController setNavigationBarHidden:_isHidden animated:YES];

    

    [self dismissViewControllerAnimated:NO completion:nil];

}


#pragma mark - remove observer

- (void)dealloc{

    

    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"HideOrNot" object:nil];

}



#pragma mark - private action


- (void)_loadSubViews{

    

    //创建布局对象

    UICollectionViewFlowLayout * flow = [[UICollectionViewFlowLayout alloc]init];

    

    flow.itemSize = CGSizeMake(kScreenWidth, kScreenHeight);

    flow.minimumLineSpacing = 0;

    flow.minimumInteritemSpacing = 0;

    

    flow.scrollDirection = UICollectionViewScrollDirectionHorizontal;

    

    //创建collectionView

    _collectionView = [[UICollectionView alloc]initWithFrame:[UIScreen mainScreen].bounds collectionViewLayout:flow];

    

    _collectionView.dataSource = self;

    _collectionView.delegate = self;

    

    _collectionView.pagingEnabled = YES;

    

    [self.view addSubview:_collectionView];

    

    //注册单元格

    [_collectionView registerClass:[ImageScanCell class] forCellWithReuseIdentifier:imageScanID];

    

    

    UIPageControl *page = [[UIPageControl alloc] initWithFrame:CGRectMake((self.view.frame.size.width-150)/2, self.view.frame.size.height-20, 150, 20)];

    page.numberOfPages = self.imageURLStringArray.count;

    page.backgroundColor = [UIColor clearColor];

    page.currentPageIndicatorTintColor = [UIColor whiteColor];

    page.pageIndicatorTintColor = [UIColor grayColor];

    [self.view addSubview:page];

    page.currentPage = self.currentPage;

    _page = page;


    

    

}


- (void)setImageURLStringArray:(NSArray *)imageURLStringArray{

    

    if (_imageURLStringArray != imageURLStringArray) {

        

        _imageURLStringArray = imageURLStringArray;

    }

    

    //[self _loadSubViews];

}


- (void)setSelectedIndexPath:(NSIndexPath *)selectedIndexPath{

    

    if (_selectedIndexPath != selectedIndexPath) {

        _selectedIndexPath = selectedIndexPath;

    }

}



#pragma mark - collection view  data source


- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{

    

    return _imageURLStringArray.count;

}



- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{

    

    //创建单元格

    ImageScanCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:imageScanID forIndexPath:indexPath];

    

    //cell.backgroundColor = [UIColor redColor];

    

    //传数据

    cell.imageURLString = _imageURLStringArray[indexPath.row];

    

    return cell;

}



//点击放大然后滑倒其他界面后, 让原本的界面上的图片变小

//结束 在界面显示的单元格的索引

- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{

    

    //NSLog(@"当前是第%ld个图片", indexPath.row);

    //判断这个 方法中的 indexPath 对应的 这个 滑动视图(图片), 是否有被放大

    

    //拿到 indexPath所对应的 单元格 上面的 滑动视图

    

    //根据参数 拿到这个单元格

    ImageScanCell * scanCell = (ImageScanCell *) cell;

//    if ( scanCell.imageScrollView.zoomScale > 1) {

//        

//        [scanCell.imageScrollView setZoomScale:1.0 animated:YES];

//    }else if(scanCell.imageScrollView.zoomScale < 1) {

//        

    [scanCell.imageScrollView setZoomScale:1.0 animated:YES];

    

//    }

    

}


//将要展示单元格 是哪个, 索引位置

- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath{


    //拿到当前显示的单元格对象

    ImageScanCell * myCell = (ImageScanCell *)cell;

    

    //拿到当前单元格显示的 图片

    _myImage =  myCell.imageScrollView.imgView.image;

    

    

}


- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {

    

    NSInteger pageCurrent = scrollView.contentOffset.x/kScreenWidth;

    

    _page.currentPage = pageCurrent;

}


#pragma mark - view life cycle

- (void)viewWillAppear:(BOOL)animated{

    

    [super viewWillAppear:animated];

    

    //视图将要出现, collectionView view子视图,我也要出现了,

    //本来是出现第0个索引位置的单元格

    

    //我们复写这个方法,改变 当前即将要现实的单元格

    

    //我们指定让collectionView滑动到 指定位置的单元格

    

    //参数一:指定的 单元格索引

    //参数二:滑动停止后的 视图显示位置(枚举值)

    [_collectionView scrollToItemAtIndexPath:_selectedIndexPath atScrollPosition:UICollectionViewScrollPositionCenteredHorizontally

     animated:YES];

}


第二个类:--------------------------------------------------------

#import <UIKit/UIKit.h>


@interface ScrollImageView : UIScrollView<UIScrollViewDelegate>


//1.子视图

@property(nonatomic, strong)UIImageView * imgView;


//2.显示数据

@property(nonatomic, copy)NSString * imageURLString;


@end





#import "ScrollImageView.h"


@implementation ScrollImageView

- (id)initWithFrame:(CGRect)frame{

    

    self = [super initWithFrame:frame];

    

    if (self) {

        

        //加载子视图


        _imgView = [[UIImageView alloc]initWithFrame:[UIScreen mainScreen].bounds];


        

        /**

         

          UIViewContentModeScaleToFill,

         UIViewContentModeRedraw,

        };


         */

         _imgView.contentMode = UIViewContentModeScaleToFill;


        

        

        //用户响应时间

        _imgView.userInteractionEnabled = YES;

       // _imgView.backgroundColor = [UIColor yellowColor];

        

        [self addSubview:_imgView];

        

        

        //自己的属性设置

        self.minimumZoomScale = 0.5;

        self.maximumZoomScale = 3.0;

        

        //设置代理(自己成为自己的代理,来实现缩放功能)

        self.delegate = self;

        

        

        //添加手势

        UITapGestureRecognizer * tapOnce = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(hidesOrNotAction:)];

        tapOnce.numberOfTapsRequired = 1; //默认是1,所以这行代码可省

        //添加到滑动视图上面(先把 imageView 用户交互事件打开)

        [self addGestureRecognizer:tapOnce];

        

        

        //双击手势

        UITapGestureRecognizer * doubleTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(doubleTapAction:)];

        doubleTap.numberOfTapsRequired = 2;

        

        [self addGestureRecognizer:doubleTap];


        //这个方法是为了 防止 两个手势的冲突当双击的时候,会冲突单击的方法,

        //让冲突的手势 不响应

        //当我们单击的时候,让双击不响应

        [tapOnce requireGestureRecognizerToFail:doubleTap];

        

    }

    

    return self;

}



- (void)setImageURLString:(NSString *)imageURLString{

    

    if (_imageURLString != imageURLString) {

        _imageURLString = imageURLString;

    }

    

    //赋值(图片)

    [_imgView setImageWithURL:[NSURL URLWithString:_imageURLString]];

    

    

    // 安全判断,如果没有图片的话,加载默认的图片

    if (!_imgView.image) {

        _imgView.image = [UIImage imageNamed:@"default_image.png"];

    }

    

}


#pragma mark - tap action

//隐藏导航栏

// 当前我们是在 滑动视图这个视图类中,,没有导航控制器

//导航控制器 -- 控制器容器

- (void)hidesOrNotAction:(UITapGestureRecognizer *)tap {

    

    //发通知 告诉 imageScanController ,你要隐藏 或者是显示 导航栏

    [[NSNotificationCenter defaultCenter] postNotificationName:@"HideOrNot" object:nil];

}


//双击实现放大或者缩小

- (void)doubleTapAction:(UITapGestureRecognizer *)tap{


    if (self.zoomScale > 1) {


        [self setZoomScale:1.0 animated:NO];

    } else{

        

        [self setZoomScale:2.0 animated:NO];

    }

    

}

#pragma mark - delegate

- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{


    return _imgView;

}



第三个类:----------------------------------------------------------------

#import <UIKit/UIKit.h>


#import "ScrollImageView.h"


@interface ImageScanCell : UICollectionViewCell

//子视图(自己封装的滑动视图)

//测试界面效果,我们先给一个imageView

@property(nonatomic, strong)ScrollImageView * imageScrollView;

//数据

@property(nonatomic, copy)NSString * imageURLString;


@end




#import "ImageScanCell.h"


@implementation ImageScanCell


//代码方式

- (id)initWithFrame:(CGRect)frame{

    

    self = [super initWithFrame:frame];

    

    if (self) {

        

    

        //加载子视图

        

        _imageScrollView = [[ScrollImageView alloc]initWithFrame:CGRectMake(0, 0, kScreenWidth, kScreenHeight)];

        _imageScrollView.pagingEnabled = NO;

        //_imageScrollView.backgroundColor = [UIColor greenColor];

        [self.contentView addSubview:_imageScrollView];

        

    }

    

    return self;

}


- (void)setImageURLString:(NSString *)imageURLString{

    

    if (_imageURLString != imageURLString) {

        

        _imageURLString = imageURLString;

    }

    

 

    //传递数据 滑动视图

    _imageScrollView.imageURLString = _imageURLString;

    

}


--------------OK,到此结束---------------------------
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值