当前位置: 首页 > 编程日记 > 正文

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 +拆点)

题目链接 我做的伤心了&#xff0c;不知是模版效率低&#xff0c;还是错了&#xff0c;交上就是TLE&#xff0c;找了份别人的代码&#xff0c;改了好几下终于过了。。 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},//请求中要传送的参数,会自动拼接成一个路径&#xff0c;在php中用get方式获取…

Python 数据库操作 psycopg2

文章目录安装基本使用安装 psycopg 是 Python 语言中 PostpreSQL数据库接口 安装环境&#xff1a; Python&#xff1a;v2.7, v3.4~3.8PostGreSQL&#xff1a;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中的一个命令行工具&#xff0c;可以用于得到程序的log信息 log类是一个日志类&#xff0c;可以在代码中使用logcat打印出消息 常见的日志纪录方法包括&#xff1a;方法 描述 v(String,String) (vervbose)显…

[iOS]如何重新架构 JPVideoPlayer ?

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

函数项目一个超感人的故事:关于swfupload在某些环境下面session丢失的完美解决方案(看完我哭了)...

查了好多资料&#xff0c;发现还是不全&#xff0c;干脆自己整理吧&#xff0c;至少保证在我的做法正确的&#xff0c;以免误导读者&#xff0c;也是给自己做个记录吧&#xff01; 标题吸引到你了吗&#xff1f; 先说一下这个题问成形的原因。大家都晓得 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 命令 对一个空文件&#xff0c;git 初始化。文件名称增加…

UIBezierPath和CAShapeLayer创建不规则View(Swift 3.0)

最近一个朋友在做图片处理的 App&#xff0c;想要实现类似 MOLDIV App 拼图的UI效果&#xff08;如何创建不规则的 view&#xff09;&#xff0c;就问我有什么想法。我首先想到的就是 UIBezierPathCAShapeLayer的方式&#xff0c;为了验证自己的想法&#xff0c;写了一个小 dem…

http响应状态

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

antlr.collections.AST.getLine()I问题的起因及解决

在我们的java web 项目中引入hibernate和struts&#xff0c;当我们使用HQL语句进行查询时会报 antlr.collections.AST.getLine()I的错误&#xff0c;导致程序无法继续运行&#xff0c;这并不是我们的程序写的有错误&#xff0c;出现这个异常的原因是因为我们使用的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 签到题 关注合天智汇公众号&#xff0c;回复hxb2018得到flag。0x…

Operation Queues并发编程

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

socket 服务器浏览器与服务器客户端实例

一、服务器与浏览器 // 取得本机的loopback网络地址&#xff0c;即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配置环境变量的两种方法

第一种&#xff1a; 1.打开终端,输入&#xff1a; cd ~ 会进入~文件夹 2.然后输入&#xff1a;touch .bash_profile 回车执行后&#xff0c; 3.再输入&#xff1a;open -e .bash_profile 会在TextEdit中打开这个文件&#xff08;如果以前没有配置过环境变量&#xff0c;那么这…

linux之x86裁剪移植---字符界面sdl开发入门

linux下有没有TurboC2.0那样的画点、线、圆的图形函数库&#xff0c;有没有grapihcs.h&#xff0c;或者与之相对应或相似的函数库是什么&#xff1f;有没有DirectX这样的游戏开发库&#xff1f;SDL就是其中之一。SDL&#xff08;Simple DirectMedia Layer&#xff09;是一个夸平…

iOS 视频捕获系列Swift之AVFoundation(一)

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

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:提供详细的操作系统信息&#xff0c;为提权做准备。 2.extension_dir:php扩展的路径 3.$_SERVER[‘HTTP_HOST’]:网站真实IP、CDN什么的都不存在的&#xff0c;找到真实ip&#xff0c;扫一扫旁站&#xff0c;没准就拿下几个站。 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之间的转换

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

【转】Word2007中不连续页码设置 多种页码设置

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

vim编辑器异常退出产生备份文件

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

从0到1思考与实现iOS-Widget

讲述之前首先看下demo效果图&#xff1a; 基本的展开收起、本App本体交互然后再展示几个效果不错的 Widget app 毒物 && KeepESPNPCalcMusixmatchFantastical 2Carrot Weatherdemo 地址在此&#xff01;欢迎star 比心一、Widget总览 Widget 是 iOS8 推出第一版&…

Android Studio 初体验

Google在I/O2013大会上发布了Android新的开发工具Android Studio&#xff0c;趁周末时间做了一下尝试。有需要的可以在http://developer.android.com/sdk/installing/studio.html下载&#xff0c;当前版本是V0.1。官方解释&#xff1a;Android Studio is anew Android developm…

JAVA面试题(2)

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

限制HTTP数据包发送Referer

一般点击一个A标签的时候都会发送 Referer 什么是 Referer&#xff1f; 就是你点击A标签 Referer的信息告诉服务端你从哪里点击出来的 可在HTML上加 <meta name"referrer" content"no-referrer">这样就不发送Referer头了

TCP/IP详解学习笔记(3)-IP协议,ARP协议,RARP协议

把这三个协议放到一起学习是因为这三个协议处于同一层&#xff0c;ARP协议用来找到目标主机的Ethernet网卡Mac地址&#xff0c;IP则承载要发送的消息。数据链路层可以从ARP得到数据的传送信息&#xff0c;而从IP得到要传输的数据信息。 1.IP协议 IP协议是TCP/IP协议的核心&…

数据结构与算法分析(C++版)(第二版)

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

nginx反向代理原理讲解

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