菜鸟教程小白 发表于 2022-12-13 13:08:44

ios - iOS中非常自定义的UIButton动画


                                            <p><p>我有一个自定义按钮,它是我自己的 <code>UIButton</code> 子类。它看起来像一个带圆圈的箭头,从某个角度 <code>startAngle</code> 开始,到某个 <code>endAngle=startAngle+1.5*M_PI</code> 结束。
<code>startAngle</code> 是按钮的属性,然后在其 <code>drawRect:</code> 方法中使用。
当按下这个按钮时,我想让这个箭头围绕它的中心连续旋转 2Pi。所以我认为我可以轻松使用 <code></code> 但显然它不能使用,因为它不允许为自定义属性设置动画。 CoreAnimation 也不适合,因为它只为 <code>CALayer</code> 属性设置动画。 </p>

<p>那么在iOS中实现<code>UIView</code>子类的自定义属性动画最简单的方法是什么?
或者也许我错过了一些东西,而使用已经提到的技术是可能的?</p>

<p>谢谢。</p></p>
                                    <br><hr><h1><strong>Best Answer-推荐答案</ strong></h1><br>
                                            <p><p>感谢 <a href="https://stackoverflow.com/users/796103/jenox" rel="noreferrer noopener nofollow">Jenox</a>我已经使用 CADisplayLink 更新了动画代码,这似乎是比 NSTimer 更正确的解决方案。所以我现在用 CADisplayLink 展示正确的实现。和上一个很接近,但更简单一点。</p>

<p>我们将 QuartzCore 框架添加到我们的项目中。
然后我们在我们类的头文件中放入以下几行:</p>

<pre><code>CADisplayLink* timer;
Float32 animationDuration;// Duration of one animation loop
Float32 initAngle;// Represents the initial angle
Float32 angle;// Angle used for drawing
CFTimeInterval startFrame;// Timestamp of the animation start

-(void)startAnimation;// Method to start the animation
-(void)animate;// Method for updating the property or stopping the animation
</code></pre>

<p>现在在实现文件中,我们设置动画持续时间的值和其他初始值:</p>

<pre><code>initAngle=0.75*M_PI;
angle=initAngle;
animationDuration=1.5f;// Arrow makes full 360° in 1.5 seconds
startFrame=0;// The animation hasn&#39;t been played yet
</code></pre>

<p>要开始动画,我们需要创建 CADisplayLink 实例,该实例将调用方法 <code>animate</code> 并将其添加到我们应用程序的主 RunLoop:</p>

<pre><code>-(void)startAnimation
{
   timer = ;
    forMode:NSDefaultRunLoopMode];
}
</code></pre>

<p>此计时器将在应用程序的每个 runLoop 中调用 <code>animate</code> 方法。</p>

<p>现在来实现我们在每次循环后更新属性的方法:</p>

<pre><code>-(void)animate
{
   if(startFrame==0) {
      startFrame=timer.timestamp;// Setting timestamp of start of animation to current moment
      return;// Exiting till the next run loop
   }
   CFTimeInterval elapsedTime = timer.timestamp-startFrame;// Time that has elapsed from start of animation
   Float32 timeProgress = elapsedTime/animationDuration;// Determine the fraction of full animation which should be shown
   Float32 animProgress = timingFunction(timeProgress); // The current progress of animation
   angle=initAngle+animProgress*2.f*M_PI;// Setting angle to new value with added rotation corresponding to current animation progress
   if (timeProgress&gt;=1.f)
   {// Stopping animation
      angle=initAngle; // Setting angle to initial value to exclude rounding effects
      ;// Stopping the timer
      startFrame=0;// Resetting time of start of animation
   }
   ;// Redrawing with updated angle value
}
</code></pre>

<p>因此,与 NSTimer 不同,我们现在不需要计算更新角度属性和重绘按钮的时间间隔。我们现在只需要计算从动画开始已经过去了多少时间,并将属性设置为与此进度相对应的值。 </p>

<p>我必须承认,动画比 NSTimer 更流畅。
默认情况下,CADisplayLink 在每个运行循环中调用 <code>animate</code> 方法。当我计算帧速率时,它是 120 fps。我认为它不是很有效,所以我通过在将 CADisplayLink 的 frameInterval 属性添加到 mainRunLoop 之前将其降低到仅 22 fps:</p>

<pre><code>timer.frameInterval=3;
</code></pre>

<p>这意味着它将在第一次运行循环时调用 <code>animate</code> 方法,然后在接下来的 3 次循环中什么也不做,并在第 4 次调用,以此类推。这就是为什么 frameInterval 只能是整数。</p></p>
                                   
                                                <p style="font-size: 20px;">关于ios - iOS中非常自定义的UIButton动画,我们在Stack Overflow上找到一个类似的问题:
                                                        <a href="https://stackoverflow.com/questions/10132420/" rel="noreferrer noopener nofollow" style="color: red;">
                                                                https://stackoverflow.com/questions/10132420/
                                                        </a>
                                                </p>
                                       
页: [1]
查看完整版本: ios - iOS中非常自定义的UIButton动画