如何创建可调整大小的圆形UIView? [英] How do I create a smoothly resizable circular UIView?

查看:82
本文介绍了如何创建可调整大小的圆形UIView?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个UIView,该视图显示一个半透明的圆,其边界内具有不透明的边框。我希望能够以两种方式更改界限-在-[UIView animateWithDuration:animations:] 块中,以及在捏手势识别器动作中每秒触发几次。我已经尝试过基于SO上其他答案的三种方法,但都不合适。

I'm trying to create a UIView which shows a semitransparent circle with an opaque border inside its bounds. I want to be able to change the bounds in two ways - inside a -[UIView animateWithDuration:animations:] block and in a pinch gesture recogniser action which fires several times a second. I've tried three approaches based on answers elsewhere on SO, and none are suitable.


  1. 设置视图的角半径 layoutSubviews 中的图层可提供平滑的平移,但是在动画过程中视图不会保持圆形;

  1. Setting the corner radius of the view's layer in layoutSubviews gives smooth translations, but the view doesn't stay circular during animations; it seems that cornerRadius isn't animatable.

drawRect中绘制圆:给出了一个一致的圆视图,但是如果圆圈太大,则由于设备花费太多时间重画圆圈,因此捏手势的大小会变得不稳定。

Drawing the circle in drawRect: gives a consistently circular view, but if the circle gets too big then resizing in the pinch gesture gets choppy because the device is spending too much time redrawing the circle.

添加CAShapeLayer并在 layoutSublayersOfLayer 中设置其path属性,该属性不会在UIView动画中进行动画处理,因为path不能隐式动画。

Adding a CAShapeLayer and setting its path property in layoutSublayersOfLayer, which doesn't animate inside UIView animations since path isn't implicitly animatable.

我是否可以创建一个始终为圆形且可平滑调整大小的视图?我还可以使用其他类型的层来利用硬件加速吗?

Is there a way for me to create a view which is consistently circular and smoothly resizable? Is there some other type of layer I could use to take advantage of the hardware acceleration?

UPDATE

A评论者要求我进一步说明我想更改-[UIView animateWithDuration:animations:] 块内的边界的意思。在我的代码中,我有一个包含圈子视图的视图。圆视图(使用cornerRadius的版本)会覆盖-[setBounds:] 以设置拐角半径:

A commenter has asked me to expand on what I mean when I say that I want to change the bounds inside a -[UIView animateWithDuration:animations:] block. In my code, I have a view which contains my circle view. The circle view (the version that uses cornerRadius) overrides -[setBounds:] in order to set the corner radius:

-(void)setBounds:(CGRect)bounds
{
    self.layer.cornerRadius = fminf(bounds.size.width, bounds.size.height) / 2.0;
    [super setBounds:bounds];
}

圆形视图的边界在中设置- [layoutSubviews]

-(void)layoutSubviews
{
    // some other layout is performed and circleRadius and circleCenter are
    // calculated based on the properties and current size of the view.

    self.circleView.bounds = CGRectMake(0, 0, circleRadius*2, circleRadius*2);
    self.circleView.center = circleCenter;
}

有时会在动画中调整视图的大小,例如:

The view is sometimes resized in animations, like so:

[UIView animateWithDuration:0.33 animations:^(void) {
    myView.frame = CGRectMake(x, y, w, h);
    [myView setNeedsLayout];
    [myView layoutIfNeeded];
}];

但是在这些动画中,如果我使用带有cornerRadius的图层绘制圆形视图,它会变得很有趣形状。我无法将动画持续时间传递到layoutSubviews中,因此需要在-[setBounds] 中添加正确的动画。

but during these animations, if I draw the circle view using a layer with a cornerRadius, it goes funny shapes. I can't pass the animation duration in to layoutSubviews so I need to add the right animation within -[setBounds].

推荐答案

非常感谢David,这是我找到的解决方案。最后,关键是使用视图的-[actionForLayer:forKey:] 方法,因为该方法在UIView块内使用,而不是图层的-[actionForKey] 返回。

With many thanks to David, this is the solution I found. In the end what turned out to be the key to it was using the view's -[actionForLayer:forKey:] method, since that's used inside UIView blocks instead of whatever the layer's -[actionForKey] returns.

@implementation SGBRoundView

-(CGFloat)radiusForBounds:(CGRect)bounds
{
    return fminf(bounds.size.width, bounds.size.height) / 2;
}

- (id)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor clearColor];
        self.opaque = NO;
        self.layer.backgroundColor = [[UIColor purpleColor] CGColor];
        self.layer.borderColor = [[UIColor greenColor] CGColor];
        self.layer.borderWidth = 3;
        self.layer.cornerRadius = [self radiusForBounds:self.bounds];
    }
    return self;
}

-(void)setBounds:(CGRect)bounds
{
    self.layer.cornerRadius = [self radiusForBounds:bounds];
    [super setBounds:bounds];
}

-(id<CAAction>)actionForLayer:(CALayer *)layer forKey:(NSString *)event
{
    id<CAAction> action = [super actionForLayer:layer forKey:event];

    if ([event isEqualToString:@"cornerRadius"])
    {
        CABasicAnimation *boundsAction = (CABasicAnimation *)[self actionForLayer:layer forKey:@"bounds"];
            if ([boundsAction isKindOfClass:[CABasicAnimation class]] && [boundsAction.fromValue isKindOfClass:[NSValue class]])
        {            
            CABasicAnimation *cornerRadiusAction = [CABasicAnimation animationWithKeyPath:@"cornerRadius"];
            cornerRadiusAction.delegate = boundsAction.delegate;
            cornerRadiusAction.duration = boundsAction.duration;
            cornerRadiusAction.fillMode = boundsAction.fillMode;
            cornerRadiusAction.timingFunction = boundsAction.timingFunction;

            CGRect fromBounds = [(NSValue *)boundsAction.fromValue CGRectValue];
            CGFloat fromRadius = [self radiusForBounds:fromBounds];
            cornerRadiusAction.fromValue = [NSNumber numberWithFloat:fromRadius];

            return cornerRadiusAction;
        }
    }

    return action;
}

@end

通过以下操作视图提供了边界,我能够获得正确的持续时间,填充模式和计时功能,最重要的是委托-没有这些,UIView动画的完成块就不会运行。

By using the action that the view provides for the bounds, I was able to get the right duration, fill mode and timing function, and most importantly delegate - without that, the completion block of UIView animations didn't run.

在几乎所有情况下,半径动画都遵循边界的动画-我尝试解决一些边缘情况,但基本上已经解决了。还值得一提的是,捏手势有时仍会变得生涩-我想即使是加速绘图也仍然很昂贵。

The radius animation follows that of the bounds in almost all circumstances - there are a few edge cases that I'm trying to iron out, but it's basically there. It's also worth mentioning that the pinch gestures are still sometimes jerky - I guess even the accelerated drawing is still costly.

这篇关于如何创建可调整大小的圆形UIView?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆