欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

iOS动画案例(1) 类似于qq账号信息里的一个动画效果

程序员文章站 2023-12-21 09:04:22
受人所托,做一个类似于qq账号信息里的一个动画,感觉挺有意思,也没感觉有多难,就开始做了,结果才发现学的数学知识都还给体育老师了,研究了大半天才做出来。  先看...

受人所托,做一个类似于qq账号信息里的一个动画,感觉挺有意思,也没感觉有多难,就开始做了,结果才发现学的数学知识都还给体育老师了,研究了大半天才做出来。

 先看一下动画效果:

iOS动画案例(1) 类似于qq账号信息里的一个动画效果

用到的知识点:

(1)三角函数
(2)calayer
(3)catransaction
(4)uibezierpath
(5)cakeyframeanimation
(6)caanimationgroup

iOS动画案例(1) 类似于qq账号信息里的一个动画效果

 如图,这明显是一段圆弧,那么要确定这段一段圆弧的位置,就得确定这段圆弧的圆心和圆心角。我规定圆心在手机屏幕的左顶点,也就是(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;
}

 这个动画的难点其实是确定四个按钮的坐标以及圆弧的半径,主要是学的数学都忘的差不多了,还好重新捡起来还算不难。

以上所述是小编给大家介绍的ios动画案例(1) 类似于qq账号信息里的一个动画效果,希望对大家有所帮助

上一篇:

下一篇: