iOS动画案例(1)
受人所托,模仿qq账号信息里的一个动画,感觉挺有意思,也没感觉有多难,就开始做了,结果才发现学的数学知识都还给体育老师了,研究了大半天才做出来。
先看一下动画效果:
用到的知识点:
(1)三角函数
(2)CALayer
(3)CATransaction
(4)UIBezierPath
(5)CAKeyframeAnimation
(6)CAAnimationGroup
如图,这明显是一段圆弧,那么要确定这段一段圆弧的位置,就得确定这段圆弧的圆心和圆心角。我规定圆心在手机屏幕的左顶点,也就是(0,0),圆心角为60°。别问我为什么这么确定,我也是一点点尝试的。我们先设手机屏幕的宽度为 ScreenWidth,圆弧半径为R;那么R = ScreenWidth/cos(60°);知道了这些开始画圆弧。
// 屏幕的宽度
CGFloat width = [UIScreen mainScreen].bounds.size.width;
// 圆半径
float r = 2 * width / sqrt(3);
// 画曲线
UIColor *color = [UIColor redColor];
[color set];
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, 0) radius:r startAngle:M_PI / 2 endAngle:M_PI / 6 clockwise:NO];
path.lineWidth = 1.0;
path.lineCapStyle = kCGLineCapRound;
path.lineJoinStyle = kCGLineJoinRound;
[path stroke];
确定了圆心角和半径就要确定ABCD四个点的坐标了,分别作为四张图片的圆心。圆弧SA和圆弧DE的圆心角一样,设定为7.5°,那么弧AB、弧BC、弧CD的圆心角设定为相等,分别为(60 - 7.5 * 2)/ 3 = 15°。那么A点的坐标就等于(R * sin7.5,R * cos7.5°);B,C,D点的坐标一样用三角函数求,分别为(R * sin22.5,R * cos22.5°),(R * sin37.5,R * cos37.5°),(R * sin52.5,R * cos52.5°)。ABCD其实都是一个按钮,下面开始放按钮。
// 放图片
for (int i = 0; i < 4; i++) {
// 一共四个按钮 从左到右index分别为0,1,2,3
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = [self getButtonFrame:i];
button.tag = i + 1;
[button addTarget:self action:@selector(buttonClick:) forControlEvents:UIControlEventTouchUpInside];
[button setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d",i + 1]] forState:UIControlStateNormal];
// 设置按钮为圆
button.layer.cornerRadius = 25;
button.layer.borderColor = [UIColor greenColor].CGColor;
button.layer.masksToBounds = YES;
button.layer.borderWidth = 2.0f;
[self addSubview:button];
}
// 根据Index确定按钮的坐标
- (CGRect)getButtonFrame: (int) index {
float radians = M_PI * (7.5 + 15 * index) / 180;
CGFloat width = [UIScreen mainScreen].bounds.size.width;
float r = 2 * width / sqrt(3);
CGRect frame = CGRectMake(sin(radians) * r, cos(radians) * r, 50, 50);
frame.origin.x = frame.origin.x - 25;
frame.origin.y = frame.origin.y - 25;
return frame;
}
头像默认放第一个。
self.head = [[UIImageView alloc] initWithFrame:[self getButtonFrame:0]];
self.head.image = [UIImage imageNamed:@"myHead"];
self.head.layer.borderColor = [UIColor greenColor].CGColor;
self.head.layer.masksToBounds = YES;
self.head.layer.cornerRadius = 25;
self.head.layer.borderWidth = 2.0f;
[self addSubview:self.head];
之后按钮点击之后,头像移动到按钮点击的地方。
// 按钮点击事件
- (void)buttonClick:(UIButton *)button {
// 原来图片所在按钮的index
int preIndex = [self getPreviousIndexByFrame:self.head.frame];
int buttonIndex = (int)button.tag - 1;
// 点击图片所在按钮 不做任何操作
if (preIndex == buttonIndex) {
return;
}
CGFloat width = [UIScreen mainScreen].bounds.size.width;
float r = 2 * width / sqrt(3);
//加入动画效果
CALayer *transitionLayer = [[CALayer alloc] init];
//显式事务默认开启动画效果,kCFBooleanTrue关闭 保证begin和commit 之间的属性修改同时进行
transitionLayer.contents = self.head.layer.contents;
transitionLayer.borderColor = [UIColor greenColor].CGColor;
transitionLayer.masksToBounds = YES;
transitionLayer.cornerRadius = 25;
transitionLayer.borderWidth = 2.0f;
transitionLayer.frame = self.head.frame;
transitionLayer.backgroundColor=[UIColor blueColor].CGColor;
[self.layer addSublayer:transitionLayer];
self.head.hidden = YES;
UIBezierPath *movePath;
//路径曲线 贝塞尔曲线
if (buttonIndex > preIndex) {
// 向上滑 逆时针
movePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, 0) radius:r startAngle:[self getAnticlockwiseByIndex:preIndex] endAngle:[self getAnticlockwiseByIndex:buttonIndex] clockwise:NO];
[movePath moveToPoint:transitionLayer.position];
}else {
// 向下滑 顺时针
movePath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(0, 0) radius:r startAngle:[self getClockwiseAngleByIndex:preIndex] endAngle:[self getClockwiseAngleByIndex:buttonIndex] clockwise:YES];
[movePath moveToPoint:transitionLayer.position];
}
//关键帧动画效果
CAKeyframeAnimation *positionAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
// 动画轨迹
positionAnimation.path = movePath.CGPath;
// 动画完成之后是否删除动画效果
positionAnimation.removedOnCompletion = NO;
// 设置开始的时间
positionAnimation.beginTime = CACurrentMediaTime();
CGFloat time = 0.7;
if (labs(buttonIndex - preIndex) > 1) {
time = 0.4 * labs(buttonIndex - preIndex);
}
//动画总时间
positionAnimation.duration = time;
// 动画的方式 淡入淡出
positionAnimation.timingFunction=[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
// 执行完之后保存最新的状态
positionAnimation.fillMode = kCAFillModeForwards;
// 动画完成之后,是否回到原来的地方
positionAnimation.autoreverses= NO;
[transitionLayer addAnimation:positionAnimation forKey:@"opacity"];
[CATransaction setCompletionBlock:^{
[NSThread sleepForTimeInterval:time];
self.head.hidden = NO;
self.head.frame = button.frame;
[transitionLayer removeFromSuperlayer];
}];
}
// 根据Index获得顺时针的弧度
- (float)getAnticlockwiseByIndex: (NSInteger)index {
return M_PI * (0.5 - (7.5 + 15 * index) / 180);
}
// 根据Index获得逆时针的弧度
- (float)getClockwiseAngleByIndex: (NSInteger)index {
index = 3 - index;
return M_PI * (30 + 7.5 + 15 * index) / 180;
}
这个动画的难点其实是确定四个按钮的坐标以及圆弧的半径,主要是学的数学都忘的差不多了,还好重新捡起来还算不难。GitHub下载地址,欢迎下载。
iOS动画案例(1)的更多相关文章
- iOS动画案例(2) 仿网易新闻标题动画
由于产品的需要,做了一个和网易新闻标题类似的动画效果,现在新闻类的APP都是采用这样的动画效果,来显示更多的内容.先看一下动画效果: 由于这个动画效果在很多场合都有应用,所以我专门封装了一个控 ...
- iOS动画案例(1) 仿qq账号信息里的一个动画
受人所托,模仿qq账号信息里的一个动画,感觉挺有意思,也没感觉有多难,就开始做了,结果才发现学的数学知识都还给体育老师了,研究了大半天才做出来. 先看一下动画效果: 用到的知识点: ( ...
- 《慕客网:IOS动画案例之会跳动的登入界面(下)》学习笔记 -Sketch的使用
导出选中的一个图片,比如这里我们选中background,然后点击软件的右下角,可以设置导出的尺寸: 然后添加1倍,2倍,3倍的尺寸,因为在ihpne6之后就需要这三个尺寸倍数的UI,以适应不同设备的 ...
- 《慕客网:IOS动画案例之会跳动的登入界面(上)》学习笔记 -Sketch的使用
选中需要放进文件夹里的文件,然后按command+G,就会自动生成文件夹并把需要放进的文件包含进去了.(组 Group) 选中需要锁住的图层,然后按command+shift+L就可以将图层锁住.(锁 ...
- IOS动画(Core Animation)总结 (参考多方文章)
一.简介 iOS 动画主要是指Core Animation框架.官方使用文档地址为:Core Animation Guide. Core Animation是IOS和OS X平台上负责图形渲染与动画的 ...
- (转)iOS动画Core Animation
文章转载:http://blog.sina.com.cn/s/blog_7b9d64af0101b8nh.html 在iOS中动画实现技术主要是:Core Animation. Core Animat ...
- 解析 iOS 动画原理与实现
这篇文章不会教大家如何实现一个具体的动画效果,我会从动画的本质出发,来说说 iOS 动画的原理与实现方式. 什么是动画 动画,顾名思义,就是能“动”的画.人的眼睛对图像有短暂的记忆效应,所以当眼睛看到 ...
- IOS动画隐式,显式,翻页
// ViewController.m // IOS动画0817 // // Created by 张艳锋 on 15/8/17. // Copyright (c) 2015年 张艳锋. Al ...
- iOS动画原理
1. iOS动画原理 本质:动画对象(这里是UIView)的状态,基于时间变化的反应 分类:可以分为显式动画(关键帧动画和逐帧动画)和隐式动画 关键帧和逐帧总结:关键帧动画的实现方式,只需要修改某个属 ...
随机推荐
- bootstrap中的居左和居右
1.pull-left和pull-right 2.text-left.text-center和text-right
- ARM架构解析
ARM架构解析 (2014-11-23 21:56:53) 转载▼ 标签: francis_hao arm架构 arm核 soc 分类: MCU 先来谈一下ARM的发展史:1978年12月5日,物理学 ...
- CodeForces 620E New Year Tree
线段树+位运算 首先对树进行DFS,写出DFS序列,记录下每一个节点控制的区间范围.然后就是区间更新和区间查询了. 某段区间的颜色种类可以用位运算来表示,方便计算. 如果仅有第i种颜色,那么就用十进制 ...
- logback配置
好吧,项目中一直使用的是logback做日志记录. 开始跑Demo的时候,一直会报Failed to load class org.slf4j.impl.StaticLogger的错误.后来googl ...
- 日志文件 统计 网站PV IP
1. 安装rrdtool yum install rrdtool 2. 创建 rrdtool 数据库 rrdtool create /opt/local/rrdtool/jicki.rrd -s 30 ...
- nginx 生成 缩略图 and 生成缩略图到硬盘
nginx 编译的时候增加 ./configure --with-http_image_filter_module 配置如下 server { listen 80; server_name ...
- jsoncpp第二篇------API
更多API参考jsoncpp头文件 1 jsoncpp的api简要说明 1,解析(json字符串转为对象) std::string strDataJson; Json::Reader JReader ...
- LWIP_STM32_ENC28J60_NETCONN_UDP(3)
前面移植了lwip之后只是简单地做了一个dhcp的程序,但是实际工作中经常要用来通讯,那今天就来讲一讲怎么用lwip来进行UDP通讯 要使用数据通信首先第一步得知道lwip是怎么样保存数据的,在使用n ...
- LPC1788的外部中断和GPIO中断
首先是gpio中断,这一点和1768不同,1768使用的中断时和eint3共用中断通道,到了1788,专门为gpio开辟了中断 #ifndef __JOYPAD_H_ #define __JOYPAD ...
- bzoj4010: [HNOI2015]菜肴制作【拓扑排序】
想到了一个分治方法,每一次尽量放小的那个,把它依赖的放在左边,不依赖的放在右边. TLE 80: #include <bits/stdc++.h> #define rep(i, a, b) ...