药丸形 UIButton 摆动动画的奇怪行为
Strange behaviour with a wiggle animation of a pill shaped UIButton
我的视图有一个 UIButton,它通过将角半径设置为视图高度的一半而呈丸状。一切都很好,但是当它处于动画状态时(通过旋转摆动),角半径似乎发生了变化,使药丸形状变形。当动画结束时全部returns转为正常:
正常外观:
动画外观(见角半径):
这里显示了一段录音:
动画代码 (Xamarin c#) 如下所示:
public static void Wiggle(UIView view, double duration = 0.1f, float repeatCount = 3.0f)
{
UIView.Animate(duration,
() => view.Transform = CGAffineTransform.MakeRotation((nfloat)(-5f * Math.PI / 180f)),
() =>
{
UIView.AnimateNotify(duration, 0.0f, UIViewAnimationOptions.Repeat | UIViewAnimationOptions.Autoreverse | UIViewAnimationOptions.AllowUserInteraction,
() =>
{
UIView.SetAnimationRepeatCount(repeatCount);
view.Transform = CGAffineTransform.MakeRotation((nfloat)(5f * Math.PI / 180f));
},
(animationFinished) =>
{
UIView.Animate(duration, 0, UIViewAnimationOptions.AllowUserInteraction,
() => { view.Transform = CGAffineTransform.MakeIdentity(); }, null);
});
});
}
正如视频中所见,并非总是如此。有时药丸的形状仍然存在。它发生在模拟器和真实设备上。有什么线索吗?谢谢
您没有显示“PillShape”代码,但我假设您在 “将角半径设置为视图高度的一半” 在 LayoutSubviews()
?
如果是这样,问题可能是当您旋转 按钮时 它的高度在变化,您不再有正确的半径。
您最好使用图层动画,而不是旋转视图本身。
我不使用 Xamarin/C#,所以这是基于 Objective-C 代码...希望它能帮助您。
这使用了慢速(0.5 秒)的动画,可以很容易地看出半径在旋转过程中没有变化。点击按钮 start/stop 动画:
using Foundation;
using System;
using UIKit;
using CoreAnimation;
using ObjCRuntime;
namespace QuickTestApp
{
public partial class ViewController : UIViewController
{
public WigglePillButton btn { get; private set; }
public bool isWiggling { get; private set; }
public ViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
btn = new WigglePillButton();
btn.TranslatesAutoresizingMaskIntoConstraints = false;
btn.SetTitle("Testing", UIControlState.Normal);
btn.BackgroundColor = UIColor.SystemBlueColor;
View.AddSubview(btn);
// Get the parent view's layout
var margins = View.SafeAreaLayoutGuide;
btn.CenterXAnchor.ConstraintEqualTo(margins.CenterXAnchor).Active = true;
btn.CenterYAnchor.ConstraintEqualTo(margins.CenterYAnchor).Active = true;
btn.WidthAnchor.ConstraintEqualTo(120).Active = true;
btn.AddTarget(this, new Selector("ButtonClickAction:"), UIControlEvent.TouchUpInside);
isWiggling = false;
}
[Export("ButtonClickAction:")]
public void ButtonClickAction(UIButton sender)
{
if (isWiggling)
{
btn.StopAnim();
} else {
btn.StartAnim();
}
isWiggling = !isWiggling;
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
public class WigglePillButton : UIButton
{
public override void LayoutSubviews()
{
base.LayoutSubviews();
var maskingShapeLayer = new CAShapeLayer()
{
Path = UIBezierPath.FromRoundedRect(Bounds, 12).CGPath
};
Layer.Mask = maskingShapeLayer;
}
public void StartAnim()
{
AddAnimations();
}
public void StopAnim()
{
Layer.RemoveAllAnimations();
}
private void AddAnimations()
{
CATransaction.Begin();
Layer.AddAnimation(RotAnim(), "rot");
CATransaction.Commit();
}
private CAKeyFrameAnimation RotAnim()
{
CAKeyFrameAnimation animation = CAKeyFrameAnimation.FromKeyPath("transform.rotation.z");
double angle = 5f * Math.PI / 180f;
animation.Values = new[] { NSNumber.FromDouble(angle), NSNumber.FromDouble(-angle) };
animation.AutoReverses = true;
animation.Duration = 0.5;
animation.RepeatCount = float.PositiveInfinity;
return animation;
}
}
}
我的视图有一个 UIButton,它通过将角半径设置为视图高度的一半而呈丸状。一切都很好,但是当它处于动画状态时(通过旋转摆动),角半径似乎发生了变化,使药丸形状变形。当动画结束时全部returns转为正常:
正常外观:
动画外观(见角半径):
这里显示了一段录音:
动画代码 (Xamarin c#) 如下所示:
public static void Wiggle(UIView view, double duration = 0.1f, float repeatCount = 3.0f)
{
UIView.Animate(duration,
() => view.Transform = CGAffineTransform.MakeRotation((nfloat)(-5f * Math.PI / 180f)),
() =>
{
UIView.AnimateNotify(duration, 0.0f, UIViewAnimationOptions.Repeat | UIViewAnimationOptions.Autoreverse | UIViewAnimationOptions.AllowUserInteraction,
() =>
{
UIView.SetAnimationRepeatCount(repeatCount);
view.Transform = CGAffineTransform.MakeRotation((nfloat)(5f * Math.PI / 180f));
},
(animationFinished) =>
{
UIView.Animate(duration, 0, UIViewAnimationOptions.AllowUserInteraction,
() => { view.Transform = CGAffineTransform.MakeIdentity(); }, null);
});
});
}
正如视频中所见,并非总是如此。有时药丸的形状仍然存在。它发生在模拟器和真实设备上。有什么线索吗?谢谢
您没有显示“PillShape”代码,但我假设您在 “将角半径设置为视图高度的一半” 在 LayoutSubviews()
?
如果是这样,问题可能是当您旋转 按钮时 它的高度在变化,您不再有正确的半径。
您最好使用图层动画,而不是旋转视图本身。
我不使用 Xamarin/C#,所以这是基于 Objective-C 代码...希望它能帮助您。
这使用了慢速(0.5 秒)的动画,可以很容易地看出半径在旋转过程中没有变化。点击按钮 start/stop 动画:
using Foundation;
using System;
using UIKit;
using CoreAnimation;
using ObjCRuntime;
namespace QuickTestApp
{
public partial class ViewController : UIViewController
{
public WigglePillButton btn { get; private set; }
public bool isWiggling { get; private set; }
public ViewController(IntPtr handle) : base(handle)
{
}
public override void ViewDidLoad()
{
base.ViewDidLoad();
// Perform any additional setup after loading the view, typically from a nib.
btn = new WigglePillButton();
btn.TranslatesAutoresizingMaskIntoConstraints = false;
btn.SetTitle("Testing", UIControlState.Normal);
btn.BackgroundColor = UIColor.SystemBlueColor;
View.AddSubview(btn);
// Get the parent view's layout
var margins = View.SafeAreaLayoutGuide;
btn.CenterXAnchor.ConstraintEqualTo(margins.CenterXAnchor).Active = true;
btn.CenterYAnchor.ConstraintEqualTo(margins.CenterYAnchor).Active = true;
btn.WidthAnchor.ConstraintEqualTo(120).Active = true;
btn.AddTarget(this, new Selector("ButtonClickAction:"), UIControlEvent.TouchUpInside);
isWiggling = false;
}
[Export("ButtonClickAction:")]
public void ButtonClickAction(UIButton sender)
{
if (isWiggling)
{
btn.StopAnim();
} else {
btn.StartAnim();
}
isWiggling = !isWiggling;
}
public override void DidReceiveMemoryWarning()
{
base.DidReceiveMemoryWarning();
// Release any cached data, images, etc that aren't in use.
}
}
public class WigglePillButton : UIButton
{
public override void LayoutSubviews()
{
base.LayoutSubviews();
var maskingShapeLayer = new CAShapeLayer()
{
Path = UIBezierPath.FromRoundedRect(Bounds, 12).CGPath
};
Layer.Mask = maskingShapeLayer;
}
public void StartAnim()
{
AddAnimations();
}
public void StopAnim()
{
Layer.RemoveAllAnimations();
}
private void AddAnimations()
{
CATransaction.Begin();
Layer.AddAnimation(RotAnim(), "rot");
CATransaction.Commit();
}
private CAKeyFrameAnimation RotAnim()
{
CAKeyFrameAnimation animation = CAKeyFrameAnimation.FromKeyPath("transform.rotation.z");
double angle = 5f * Math.PI / 180f;
animation.Values = new[] { NSNumber.FromDouble(angle), NSNumber.FromDouble(-angle) };
animation.AutoReverses = true;
animation.Duration = 0.5;
animation.RepeatCount = float.PositiveInfinity;
return animation;
}
}
}