iOS 实现点击微信头像效果
来源:伯乐在线 - 小良
如有好文章投稿,请点击 → 这里了解详情
如需转载,发送「转载」二字查看说明
公司产品需要实现点击个人主页头像可以放大头像、缩放头像、保存头像效果(和点击微信个人头像类似),故找个时间实现一下,记录下来,供自己查看,也给大家做个参考。
实现效果(GIF):
实现思路:
直接自定义 UIView(CYPhotoPreviewer),为了实现双击缩放,可以实现 UIScrollViewDelegate 对应的方法。如果需要模糊背景,可以在自定义的 UIView 中先添加模糊背景,再添加 UIScrollView,继而在 UIScrollView 中添加图片容器,这个容器就是要显示的图片的 superView,代码一目了然:
- (void)setup {
self.frame = [UIScreen mainScreen].bounds;
self.backgroundColor = [UIColor clearColor];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTap:)];
[self addGestureRecognizer:singleTap];
UITapGestureRecognizer *doubleTap = [[UITapGestureRecognizer alloc] initWithTarget:selfaction:@selector(doubleTap:)];
doubleTap.numberOfTapsRequired = 2;
[singleTap requireGestureRecognizerToFail:doubleTap];
[self addGestureRecognizer:doubleTap];
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:selfaction:@selector(longPress:)];
[self addGestureRecognizer:longPress];
// 设置模糊背景
self.blurBackground = [[UIVisualEffectView alloc] initWithEffect:[UIBlurEffecteffectWithStyle:UIBlurEffectStyleExtraLight]];
self.blurBackground.frame = self.frame;
[self addSubview:self.blurBackground];
// 设置 UIScrollView 相关属性
self.scrollView = [[UIScrollView alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.scrollView.delegate = self;
self.scrollView.bouncesZoom = YES;
self.scrollView.maximumZoomScale = 3.0;
self.scrollView.multipleTouchEnabled = YES;
self.scrollView.alwaysBounceVertical = NO;
self.scrollView.showsVerticalScrollIndicator = NO;
self.scrollView.showsHorizontalScrollIndicator = NO;
[self addSubview:self.scrollView];
// containerView
self.containerView = [[UIView alloc] init];
[self.scrollView addSubview:self.containerView];
// imageView
self.imageView = [[UIImageView alloc] init];
self.imageView.clipsToBounds = YES;
self.imageView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.5];
[self.containerView addSubview:self.imageView];
}
可以看到,我们给设置了模糊背景,给这个 CYPhotoPreviewer 添加了单击手势(关闭 PhotoPreviewer)、双击手势(缩放图片)、长按手势(使用 UIAlertController 菜单,比如保存图片等)。
好,确定了这个 CYPhotoPreviewer 中的显示内容,那么我们该如何显示这个 CYPhotoPreviewer 呢?
直接将这个 CYPhotoPreviewer 添加到 keyWindow 上
将这个 CYPhotoPreviewer 添加到控制器的 self.view 上
这两种方式的实现都差不多,不过如果使用第一种方式的话,会导致将 CYPhotoPreviewer 添加到 keyWindow 上之后,再长按继续将 UIAlertController 显示就比较麻烦了,因此,这里打算采用将 CYPhotoPreviewer 添加到控制器的 self.view 上,继而就可以很方便的显示 UIAlertController 了:
- (void)previewFromImageView:(UIImageView *)fromImageView inContainer:(UIView *)container {
_fromImageView = fromImageView;
fromImageView.hidden = YES;
[container addSubview:self]; // 将 CYPhotoPreviewer 添加到 container 上
self.containerView.origin = CGPointZero;
self.containerView.width = self.width; // containerView 的宽度是屏幕的宽度
UIImage *image = fromImageView.image;
// 计算 containerView 的高度
if (image.size.height / image.size.height > self.height / self.width) {
self.containerView.height = floor(image.size.height / (image.size.width / self.width));
} else {
CGFloat height = image.size.height / image.size.width * self.width;
if (height self.height && self.containerView.height - self.height
可以看到,我们将外面的图片 fromImageView 传递进来,是为了显示更好的动画效果;将控制器的 container(self.view)传递进来,是为了将 CYPhotoPreviewer 添加到 container 的细节不需要在调用处处理,即初始化 CYPhotoPreviewer 之后,CYPhotoPreviewer 就直接被 container 添加为 subview 了。动画很简单不再细说。
显示的效果已经做好,单击关闭 CYPhotoPreviewer 也比较好实现,只需要从父类移除 CYPhotoPreviewer 即可:
- (void)dismiss {
[UIView animateWithDuration:0.18 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
CGRect fromRect = [self.fromImageView convertRect:self.fromImageView.bounds toView:self.containerView];
self.imageView.contentMode = self.fromImageView.contentMode;
self.imageView.frame = fromRect;
self.blurBackground.alpha = 0.01;
} completion:^(BOOL finished) {
[UIView animateWithDuration:0.10 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
self.fromImageView.hidden = NO;
self.alpha = 0;
} completion:^(BOOL finished) {
[self removeFromSuperview];
}];
}];
}
好了,显示和关闭 CYPhotoPreviewer 都实现了,如果需要双击缩放图片效果,就得实现 UIScrollViewDelegate 的两个方法以及 CYPhotoPreviewer 的双击手势:
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView{
return self.containerView;
}
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
UIView *subView = self.containerView;
CGFloat offsetX = (scrollView.bounds.size.width > scrollView.contentSize.width)?
(scrollView.bounds.size.width - scrollView.contentSize.width) * 0.5 : 0.0;
CGFloat offsetY = (scrollView.bounds.size.height > scrollView.contentSize.height)?
(scrollView.bounds.size.height - scrollView.contentSize.height) * 0.5 : 0.0;
subView.center = CGPointMake(scrollView.contentSize.width * 0.5 + offsetX,
scrollView.contentSize.height * 0.5 + offsetY);
}
- (void)doubleTap:(UITapGestureRecognizer *)recognizer {
if (self.scrollView.zoomScale > 1.0) {
[self.scrollView setZoomScale:1.0 animated:YES];
} else {
CGPoint touchPoint = [recognizer locationInView:self.imageView];
CGFloat newZoomScale = self.scrollView.maximumZoomScale;
CGFloat xSize = self.width / newZoomScale;
CGFloat ySize = self.height / newZoomScale;
[self.scrollView zoomToRect:CGRectMake(touchPoint.x - xSize / 2, touchPoint.y - ySize / 2, xSize, ySize)animated:YES];
}
}
最后一个就是长按弹出菜单(UIAlertController)了:
- (void)longPress:(UILongPressGestureRecognizer *)recognizer {
// 为了避免弹警告:Warning: Attempt to present on which is already presenting ,最好加入状态判断
if (recognizer.state == UIGestureRecognizerStateBegan) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:@"QuoraDots" message:nilpreferredStyle:UIAlertControllerStyleActionSheet];
[alertController addAction:[UIAlertAction actionWithTitle:@"保存" style:UIAlertActionStyleDefault handler:nil]];
[alertController addAction:[UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleCancel handler:nil]];
UIViewController *vc = self.viewController;
[vc presentViewController:alertController animated:YES completion:nil];
}
}
注意一点,longPress: 这个方法会调用很频繁,因此,为了避免 Attempt to present xxx on xxx which is already presenting xxx 这个警告,我们需要判断手势的状态。
后话:
这个只是显示单张图片的大图,如果需要显示多张图片类似微信微博的九宫格图片的大图显示,则需要将这个 CYPhotoPreviewer 搞成 UICollectionView 的 item 即可,大家可以尝试尝试。最后,如果需要或者 CYPhotoPreviewer 源码,可以前往
相关文章:

HDU 4292 Food(dinic +拆点)
题目链接 我做的伤心了,不知是模版效率低,还是错了,交上就是TLE,找了份别人的代码,改了好几下终于过了。。 1 #include <cstdio>2 #include <cstring>3 #include <queue>4 #include <map>5 #i…

jQuery中用ajax访问php接口文件
js代码 function ajax_request(){var result;var articleId new Object();articleIdgetArticleId();$.ajax({url: "/topicPage/getComment.php",//请求php文件的路径data:{id:articleId},//请求中要传送的参数,会自动拼接成一个路径,在php中用get方式获取…

Python 数据库操作 psycopg2
文章目录安装基本使用安装 psycopg 是 Python 语言中 PostpreSQL数据库接口 安装环境: Python:v2.7, v3.4~3.8PostGreSQL:7.4~12 pip install psycopg2基本使用 import psycopg2def connect_db(host: str,port: int,database: str,user:…

Android logcat命令详解
一、logcat命令介绍 1.android log系统 2.logcat介绍 logcat是android中的一个命令行工具,可以用于得到程序的log信息 log类是一个日志类,可以在代码中使用logcat打印出消息 常见的日志纪录方法包括:方法 描述 v(String,String) (vervbose)显…

[iOS]如何重新架构 JPVideoPlayer ?
注意:此文为配合 JPVideoPlayer version 2.0 版本发布而写,如果你想了解 2.0 版本的更新内容和所有实现细节,请点击前往 GitHub。 导言:我几个月前写了一个在 UITableView 中滑动 UITableViewCell 播放视频的框架,类似…

函数项目一个超感人的故事:关于swfupload在某些环境下面session丢失的完美解决方案(看完我哭了)...
查了好多资料,发现还是不全,干脆自己整理吧,至少保证在我的做法正确的,以免误导读者,也是给自己做个记录吧! 标题吸引到你了吗? 先说一下这个题问成形的原因。大家都晓得 session是靠cookie中的…

【学习笔记】git 使用文档
安装 git # mac 环境 brew install git检查是否安装成功 ➜ ~ git --version git version 2.20.1 (Apple Git-117)卸载 git ➜ ~ which -a git /usr/bin/git ➜ ~ cd /usr/bin ➜ bin sudo rm -rf git*git init 命令 对一个空文件,git 初始化。文件名称增加…

UIBezierPath和CAShapeLayer创建不规则View(Swift 3.0)
最近一个朋友在做图片处理的 App,想要实现类似 MOLDIV App 拼图的UI效果(如何创建不规则的 view),就问我有什么想法。我首先想到的就是 UIBezierPathCAShapeLayer的方式,为了验证自己的想法,写了一个小 dem…

http响应状态
Servlet API: javax.servlet.http.HttpServletResponse 用于创建HTTP响应,包括HTTP协议的状态行、响应头以及消息体 HTTP状态码: 100-199:表示信息性代码,标示客户端应该采取的其他动作,请求正在进行。 200…

antlr.collections.AST.getLine()I问题的起因及解决
在我们的java web 项目中引入hibernate和struts,当我们使用HQL语句进行查询时会报 antlr.collections.AST.getLine()I的错误,导致程序无法继续运行,这并不是我们的程序写的有错误,出现这个异常的原因是因为我们使用的hibernate和s…

2018湖湘杯海选复赛Writeup
2018湖湘杯Writeup0x01 签到题0x02 MISC Flow0x03 WEB Code Check0x04 WEB Readflag0x05 WEB XmeO0x06 Reverse Replace0x07 MISC Disk0x08 Crypto Common Crypto0x09 Reverse HighwayHash640x10 Web Mynot0x01 签到题 关注合天智汇公众号,回复hxb2018得到flag。0x…

Operation Queues并发编程
并发、异步在我们的编程中,见到的太多了。在iOS中,实现并发的主要三个途径Operation Queues、Dispatch Queues、Dispatch Sources,今天我们就来详细介绍Operatin Queues的使用,花了两天时间写这一篇,值得一看。 为什么…

socket 服务器浏览器与服务器客户端实例
一、服务器与浏览器 // 取得本机的loopback网络地址,即127.0.0.1 IPAddress address IPAddress.Loopback; IPEndPoint endPoint new IPEndPoint(address, 49152); Socket socket new Socket(AddressFamily.InterNetwork, Socke…

匹配3位或4位区号的电话号码,其中区号可以用小括号括起来,也可以不用,区号与本地号间可以用连字号或空格间隔,也可以没有间隔...
public bool IsPhone(string input){string pattern "^\\(0\\d{2}\\)[- ]?\\d{8}$|^0\\d{2}[- ]?\\d{8}$|^\\(0\\d{3}\\)[- ]?\\d{7}$|^0\\d{3}[- ]?\\d{7}$";Regex regex new Regex(pattern);return regex.IsMatch(input);} 转载于:https://www.cnblogs.com/…

Mac MySQL配置环境变量的两种方法
第一种: 1.打开终端,输入: cd ~ 会进入~文件夹 2.然后输入:touch .bash_profile 回车执行后, 3.再输入:open -e .bash_profile 会在TextEdit中打开这个文件(如果以前没有配置过环境变量,那么这…

linux之x86裁剪移植---字符界面sdl开发入门
linux下有没有TurboC2.0那样的画点、线、圆的图形函数库,有没有grapihcs.h,或者与之相对应或相似的函数库是什么?有没有DirectX这样的游戏开发库?SDL就是其中之一。SDL(Simple DirectMedia Layer)是一个夸平…

iOS 视频捕获系列Swift之AVFoundation(一)
iOS 视频捕获系列之AVFoundation(一) AVCaptureMovieFileOutput系列 在iOS开发过程中,或多或少的都涉及视频的操作。 尤其在去年直播行业的带动下,移动端对视频的处理也愈来愈发要求严格。 本文也是在 这篇 中参考而来。 Swift 版本哦! 本文 …

C#做外挂常用API
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; //这个肯定要的 namespace WindowsApplication1 {class win32API{public const int OPEN_PROCESS_ALL 2035711;public const int PAGE_READWRITE 4;public con…

phpinfo 信息利用
0x01 基础信息 1.system info:提供详细的操作系统信息,为提权做准备。 2.extension_dir:php扩展的路径 3.$_SERVER[‘HTTP_HOST’]:网站真实IP、CDN什么的都不存在的,找到真实ip,扫一扫旁站,没准就拿下几个站。 4.$_SERVER[‘…

iOS三种录制视频方式详细对比
先附上参考资料 http://www.jianshu.com/p/16cb14f53933 https://developer.apple.com/library/content/samplecode/AVSimpleEditoriOS/Introduction/Intro.html https://github.com/objcio/VideoCaptureDemo https://github.com/gsixxxx/DTSmallVideo https://github.com/Andy…

C# 实现Oracle中的数据与Excel之间的转换
最近项目要求实现数据库之间数据在各个数据库之间导入导出,在此做个笔记 1. 将Oracle中的表导入到Excel中,反之亦然 private static readonly string connectionString ConfigurationManager.ConnectionStrings["OracleConnection"].Connecti…

【转】Word2007中不连续页码设置 多种页码设置
【转】Word2007中不连续页码设置 多种页码设置 页码是论文必不可少的部分。我们看一下如何添加页码,并且针对一些特殊的格式要求怎么应对: 如果是【毕业论文】有多种混合页码,有Ⅰ、Ⅱ、Ⅲ。。。还有1、2、3 。。。请直接看【第二种方法】。 …

vim编辑器异常退出产生备份文件
当非正常关闭vim编辑器时(比如直接关闭终端或者电脑断电),会生成一个.swp文件,这个文件是一个临时交换文件,用来备份缓冲区中的内容。 需要注意的是如果你并没有对文件进行修改,而只是读取文件,…

从0到1思考与实现iOS-Widget
讲述之前首先看下demo效果图: 基本的展开收起、本App本体交互然后再展示几个效果不错的 Widget app 毒物 && KeepESPNPCalcMusixmatchFantastical 2Carrot Weatherdemo 地址在此!欢迎star 比心一、Widget总览 Widget 是 iOS8 推出第一版&…
Android Studio 初体验
Google在I/O2013大会上发布了Android新的开发工具Android Studio,趁周末时间做了一下尝试。有需要的可以在http://developer.android.com/sdk/installing/studio.html下载,当前版本是V0.1。官方解释:Android Studio is anew Android developm…

JAVA面试题(2)
1 String 与 new 的不同 使用“”赋值不一定每次都创建一个新的字符串,而是从“字符串实例池”中查找字符串。使用“new”进行赋值,则每次都创建一个新的字符串。 2 String与StringBuffer String类是不可变类,字符串一旦初始化后,…

限制HTTP数据包发送Referer
一般点击一个A标签的时候都会发送 Referer 什么是 Referer? 就是你点击A标签 Referer的信息告诉服务端你从哪里点击出来的 可在HTML上加 <meta name"referrer" content"no-referrer">这样就不发送Referer头了
TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议
把这三个协议放到一起学习是因为这三个协议处于同一层,ARP协议用来找到目标主机的Ethernet网卡Mac地址,IP则承载要发送的消息。数据链路层可以从ARP得到数据的传送信息,而从IP得到要传输的数据信息。 1.IP协议 IP协议是TCP/IP协议的核心&…

数据结构与算法分析(C++版)(第二版)
查看书籍详细信息: 数据结构与算法分析(C版)(第二版) 内容简介 本书采用程序员最爱用的面向对象C语言来描述数据结构和算法,并把数据结构原理和算法分析技术有机地结合在一起,系统介绍了各种…

nginx反向代理原理讲解
一 、概述 反向代理(Reverse Proxy)方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务…