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. 用js控制 给一个input赋值之后,change事件不能捕获到,解决办法

    你用js给input赋值后要调用change方法 下面是jquery的写法 $('input#3').val("50"); $('input#3').change(); 自己试试吧

  2. day37 异步回调和协程

    异步回调 """ 异步任务使用场景 爬虫 1.从目标站点下载网页数据 本质就是HTML格式字符串 2.用re从字符串中提取出你需要的数据 ""&quo ...

  3. 利用travis自动化构建与部署(文档项目)

    背景 保持网站上文档的最新性有比较重要的意义, travis ci 提供了免费的解决方案,本文基于 latex 构建+ aliyun oss 部署对此作了尝试. 项目链接为 https://travi ...

  4. 腾讯云主机的公网无法访问,putty和FileZilla连接不上

    1.解决方法一(之前百度都是这种安全组忘了添加) 2.解决方案二(ps:我是用centos的,然后不知道为什么访问不了,端口也是全部开的) service network restart 重置网络命令 ...

  5. Python中操作Redis

    一 Rdis基本介绍 redis是一个key-value存储系统.它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set -- ...

  6. MongoDB、Hbase、Redis等NoSQL分析

    NoSQL的四大种类 NoSQL数据库在整个数据库领域的江湖地位已经不言而喻.在大数据时代,虽然RDBMS很优秀,但是面对快速增长的数据规模和日渐复杂的数据模型,RDBMS渐渐力不从心,无法应对很多数 ...

  7. 嵌入Python | 调用Python模块中无参数的函数

    开发环境 Python版本:3.6.4 (32-bit) 编辑器:Visual Studio Code C++环境:Visual Studio 2013 需求说明 在用VS2013编写的Win32程序 ...

  8. 让.net core 支持静态文件

    想不到默认的.net core竟然不支持静态文件,还需要额外配置中间件来支持 1.Nuget安装  Microsoft.aspnetcore.staticfiles 2.在Startup.cs中使用服 ...

  9. Gym - 100781G-Goblin Garden Guards

    题目链接:https://nanti.jisuanke.com/t/28882 解题思路:单纯的判断点是否在圆内,一一遍历圆外切正方形内的点即可,注意,该题要建个结构体数组存每个地精的位置,再bool ...

  10. java多线程系列12 ConcurrentHashMap CopyOnWriteArrayList 简介

    我们知道 ,hashmap 和 arraylist 是线程不安全的 在多线程环境下有数据安全问题, 当然 我们可以通过Collections的一些方法把他们变成线程安全的, Collections.s ...