XKZoomingView.h

#import <UIKit/UIKit.h>

@interface XKZoomingView : UIScrollView
/**
本地图片
*/
@property (nonatomic, strong) UIImage *mainImage; /**
图片显示
*/
@property (nonatomic, strong) UIImageView *mainImageView;
@end

XKZoomingView.m

#import "XKZoomingView.h"
@interface XKZoomingView()<UIScrollViewDelegate>
/**
当前图片偏移量
*/
@property (nonatomic,assign) CGPoint currPont;
@end
@implementation XKZoomingView - (instancetype)init{
self = [super init];
if (self) {
[self setup];
}
return self;
}
- (instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
[self setup];
}
return self;
}
- (void)setup{
self.backgroundColor = [[UIColor grayColor]colorWithAlphaComponent:0.2];
self.delegate = self;
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;
self.decelerationRate = UIScrollViewDecelerationRateFast;
self.maximumZoomScale = ;
self.minimumZoomScale = ;
self.alwaysBounceHorizontal = NO;
self.alwaysBounceVertical = NO;
self.layer.masksToBounds = YES;
if (@available(iOS 11.0, *)) {
self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
[self addSubview:self.mainImageView]; _currPont = CGPointZero; ///监听屏幕旋转
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(statusBarOrientationChange:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
///单击
UITapGestureRecognizer *tapSingle = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapSingleSponse:)];
//设置手势属性
tapSingle.numberOfTapsRequired = ;
tapSingle.delaysTouchesEnded = NO;
[self.mainImageView addGestureRecognizer:tapSingle];
///双击
UITapGestureRecognizer *tapDouble = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapDoubleSponse:)];
//设置手势属性
tapDouble.numberOfTapsRequired = ;
[self.mainImageView addGestureRecognizer:tapDouble];
///避免手势冲突
[tapSingle requireGestureRecognizerToFail:tapDouble];
} #pragma mark - layoutSubviews
- (void)layoutSubviews{
[super layoutSubviews];
///放大或缩小中
if (self.zooming || self.zoomScale != 1.0 || self.zoomBouncing) {
return;
} ///设置图片尺寸
if (_mainImage) {
CGRect imgRect = [self getImageViewFrame];
self.mainImageView.frame = imgRect;
///设置content size
if (CGRectGetHeight(imgRect) > CGRectGetHeight(self.frame)) {
[self setContentSize:CGSizeMake(CGRectGetWidth(self.frame), CGRectGetHeight(imgRect))];
}
else{
[self setContentSize:CGSizeMake(CGRectGetWidth(self.frame), CGRectGetHeight(self.frame))];
}
} }
- (void)setMainImage:(UIImage *)mainImage{
_mainImage = mainImage;
self.mainImageView.image = _mainImage;
[self setContentOffset:CGPointMake(, )];
[self setNeedsLayout];
} /**
根据图片原始大小,获取图片显示大小
@return CGRect
*/
- (CGRect)getImageViewFrame{
if (_mainImage) {
CGRect imageRect;
CGFloat scWidth = self.frame.size.width;
CGFloat scHeight = self.frame.size.height;
///width
if (_mainImage.size.width > scWidth) {
imageRect.size.width = scWidth;
CGFloat ratioHW = _mainImage.size.height/_mainImage.size.width;
imageRect.size.height = ratioHW * imageRect.size.width;
imageRect.origin.x = ;
}
else{
imageRect.size.width = _mainImage.size.width;
imageRect.size.height = _mainImage.size.height;
imageRect.origin.x = (scWidth - imageRect.size.width)/;
}
///height
if (imageRect.size.height > scHeight) { imageRect.origin.y = ;
}
else{
imageRect.origin.y = (scHeight - imageRect.size.height)/;
}
return imageRect;
}
return CGRectZero;
}
/**
获取点击位置后所需的偏移量【目的是呈现点击位置在试图上】 @param location 点击位置
*/
- (void)zoomingOffset:(CGPoint)location{
CGFloat lo_x = location.x * self.zoomScale;
CGFloat lo_y = location.y * self.zoomScale; CGFloat off_x;
CGFloat off_y;
///off_x
if (lo_x < CGRectGetWidth(self.frame)/) {
off_x = ;
}
else if (lo_x > self.contentSize.width - CGRectGetWidth(self.frame)/){
off_x = self.contentSize.width - CGRectGetWidth(self.frame);
}
else{
off_x = lo_x - CGRectGetWidth(self.frame)/;
} ///off_y
if (lo_y < CGRectGetHeight(self.frame)/) {
off_y = ;
}
else if (lo_y > self.contentSize.height - CGRectGetHeight(self.frame)/){
if (self.contentSize.height <= CGRectGetHeight(self.frame)) {
off_y = ;
}
else{
off_y = self.contentSize.height - CGRectGetHeight(self.frame);
} }
else{
off_y = lo_y - CGRectGetHeight(self.frame)/;
}
[self setContentOffset:CGPointMake(off_x, off_y)];
} #pragma mark - 重置图片
- (void)resetImageViewState{
self.zoomScale = ;
_mainImage = nil;;
self.mainImageView.image = nil; }
#pragma mark - 变量
- (UIImageView *)mainImageView {
if (!_mainImageView) {
_mainImageView = [UIImageView new];
_mainImageView.image = nil;
_mainImageView.contentMode = UIViewContentModeScaleAspectFit;
_mainImageView.userInteractionEnabled = YES;
}
return _mainImageView;
} #pragma mark - 单击
- (void)tapSingleSponse:(UITapGestureRecognizer *)singleTap{
if (!self.mainImageView.image) {
return;
} if (self.zoomScale != ) {
[UIView animateWithDuration:0.2 animations:^{
self.zoomScale = ;
} completion:^(BOOL finished) {
[self setContentOffset:_currPont animated:YES];
}];
}
}
#pragma mark - 双击
- (void)tapDoubleSponse:(UITapGestureRecognizer *)doubleTap{
if (!self.mainImageView.image) {
return;
}
CGPoint point = [doubleTap locationInView:self.mainImageView];
if (self.zoomScale == ) {
[UIView animateWithDuration:0.2 animations:^{
self.zoomScale = 2.0;
[self zoomingOffset:point];
}];
}
else{
[UIView animateWithDuration:0.2 animations:^{
self.zoomScale = ;
} completion:^(BOOL finished) {
[self setContentOffset:_currPont animated:YES];
}];
}
} #pragma mark - UIScrollViewDelegate
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
if (!self.mainImageView.image) {
return;
}
CGRect imageViewFrame = self.mainImageView.frame;
CGFloat width = imageViewFrame.size.width,
height = imageViewFrame.size.height,
sHeight = scrollView.bounds.size.height,
sWidth = scrollView.bounds.size.width;
if (height > sHeight) {
imageViewFrame.origin.y = ;
} else {
imageViewFrame.origin.y = (sHeight - height) / 2.0;
}
if (width > sWidth) {
imageViewFrame.origin.x = ;
} else {
imageViewFrame.origin.x = (sWidth - width) / 2.0;
}
self.mainImageView.frame = imageViewFrame;
} - (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.mainImageView;
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (self.isZooming || self.zoomScale != ) {
return;
}
_currPont = scrollView.contentOffset; }
#pragma mark - 监听屏幕旋转通知
- (void)statusBarOrientationChange:(NSNotification *)notification{
self.zoomScale = ;
}
- (void)dealloc{
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
} @end

USE

XKZoomingView *zoomView = [[XKZoomingView alloc]init];
zoomView.frame = self.view.bounds;
zoomView.mainImage = [UIImage imageNamed:@""];
[self.view addSubview:zoomView];

ELSE

iOS- XKZoomingView 简单的图片缩放预览,支持横屏、长图【手势:单击、双击、放大缩小】的更多相关文章

  1. Android仿微信图片上传,可以选择多张图片,缩放预览,拍照上传等

    仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...

  2. iOS HTML图片本地预览

    引言 相信用过苹果手机的童鞋,会发现很多新闻类的应用,都可以实现HTML图片本地预览,那么这是如何实现的呢?本文将深入阐述其中的原理. 关于此功能,我还实现了一个DEMO,大家可以点击此访问更详细内容 ...

  3. Android图片上传,可以选择多张图片,缩放预览,拍照上传等

    仿照微信,朋友圈分享图片功能 .可以进行图片的多张选择,拍照添加图片,以及进行图片的预览,预览时可以进行缩放,并且可以删除选中状态的图片 .很不错的源码,大家有需要可以下载看看 . 微信 微信 微信 ...

  4. Azure SQL 数据库的灵活缩放预览版简介

    Eron Kelly SQL Server 产品管理部门产品市场营销总经理 几天前,我们宣布了发布 Azure SQL 数据库的灵活缩放公共预览版.新增的灵活缩放功能通过简化开发和管理,简化了扩展和缩 ...

  5. Android 举例说明自己的定义Camera图片和预览,以及前后摄像头切换

    如何调用本地图片,并调用系统拍摄的图像上一博文解释(http://blog.csdn.net/a123demi/article/details/40003695)的功能. 而本博文将通过实例实现自己定 ...

  6. js实现FileUpload选择图片后预览功能

    当asp.net的FileUpload选择一个图片后不需要上传就能显示出图片的预览功能, 代码: <%@ Page Language="C#" AutoEventWireup ...

  7. 图片本地预览 flash html5

    dataURI 一种能够在页面嵌入外部资源的URI方案.能够降低图片或者样式表的http请求数量,提高效率. ie8把dataURI 的属性值限制在32k以内. 图片本地预览: 由于安全原因,通过fi ...

  8. 巧用weui.gallery(),点击图片后预览图片

    要在页面需要加载的JS文件: <script src="../js/libs/weui.min.js"></script> 可以去weui的文档中下载,这是 ...

  9. node.js平台下,cropper.js实现图片裁剪预览并转换为base64发送至服务端。

    一 .准备工作 1.首先需要先下载cropper,常规使用npm,进入项目路径后执行以下命令: npm install cropper 2. cropper基于jquery,在此不要忘记引入jq,同时 ...

随机推荐

  1. Curl 基本命令

    下载单个文件,默认将输出打印到标准输出中(STDOUT)中 curl http://www.centos.org 通过-o/-O选项保存下载的文件到指定的文件中:-o:将文件保存为命令行中指定的文件名 ...

  2. AI大道理头尾标识

    标题 点击上方“AI大道理”,选择“置顶”公众号 重磅干货,深入讲解AI大道理 —————— 正文 —————— 浅谈则止,深入理解AI大道理 扫描下方“AI大道理”,选择“关注”公众号 欢迎加入!

  3. HDU 6304 Chiaki Sequence Revisited

    题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=6304 多校contest1   Problem Description Chiaki is int ...

  4. OOm是否可以try catch ?

    只有在一种情况下,这样做是可行的: 在try语句中声明了很大的对象,导致OOM,并且可以确认OOM是由try语句中的对象声明导致的,那么在catch语句中,可以释放掉这些对象,解决OOM的问题,继续执 ...

  5. IP、TCP、DNS协议

    ·······················································IP协议························· 位于网络层,作用是把数据包传送 ...

  6. python 实践项目 强密码检测

    需求:写一个函数,它使用正则表达式,确保传入的口令字符串是强口令.强口令的定义是:长度不少于 8 个字符,同时包含大写和小写字符,至少有一位数字.你可能需要用多个正则表达式来测试该字符串,以保证它的强 ...

  7. Unable to instantiate Action, xxxAction, defined for 'xxxAction' in namespace '/'xxx

    最近写SSH2的项目时,遇到一些小问题,action得不到service实例,遂将struct2委托给spring进行管理,然后修改了bean的id和action的class,但是运行后发现找不到ac ...

  8. FJOI2018 部分题解

    领导集团问题 考虑对每一个点暴力dpdpdp:fi,jf_{i,j}fi,j​表示iii为根的子树选出来的点集最小值不小于jjj的点集元素个数最大值. 那么显然fi,j=∑max⁡{fv,k≥j}+1 ...

  9. 地址栏的路由输入不匹配时候,设置默认跳转页面(redirect)

    如果输入正确的路由,就会显示正确的页面. 如果输入错误的路由 ,则可以配置跳转到指定的页面. { redirect:"/', path:"*" ; }

  10. base operand of '->' has non-pointer type 'const Comple

    base operand of '->' has non-pointer type 'const Comple ->操作符前面的操作数类型不是指针类型 错误原因 函数(&对象) { ...