CALayers的UIView边界更改没有调整大小。为什么?


101

我有一个UIView其中大约CALayer添加了8个不同子层的图层。如果我修改视图的边界(动画),则视图本身会缩小(我用对其进行了检查backgroundColor),但是子层的大小保持不变

如何解决呢?

Answers:


149

我使用了与Solin相同的方法,但是该代码中有一个错字。该方法应为:

- (void)layoutSubviews {
  [super layoutSubviews];
  // resize your layers based on the view's new bounds
  mylayer.frame = self.bounds;
}

出于我的目的,我一直希望子图层为父视图的完整大小。将该方法放在您的视图类中。


8
您确定@fishinear吗?听起来您正在描述框架。理论上,边界应始终以0,0作为原点。
griotspeak

3
@griotspeak-事实并非如此。请参阅此处的bounds属性描述:developer.apple.com/library/ios/#documentation/uikit/reference/…- “默认情况下,bounds矩形的原点设置为(0,0),但您可以更改此值以显示视图的不同部分。”
jdc

非常感谢,自那以后,我了解到了一些情况(滚动视图,其中一个),虽然那是不正确的,但我忘记了此评论。
griotspeak

31
不要忘记调用[super layoutSubviews],因为这会导致各种UIKit类出现意外行为。
Kpmurphy91 2014年

2
自调整大小UITextView(scrollEnabled = NO)和自动布局对我来说效果不佳。我将一个文本视图固定到其超级视图,该视图又CALayer在其自身的底部(边框),并且我希望它在文本视图的高度更改时更新边框位置。由于某种原因layoutSubiews被称为为时已晚(图层位置已设置动画)。
iosdude

26

由于iPhone上的CALayer不支持布局管理器,因此我认为您必须将视图的主层设置为自定义CALayer子类,在其中可以覆盖layoutSublayers所有子层的框架。您还必须重写视图的+layerClass方法以返回新CALayer子类的类。


是否像OpenGL图层一样覆盖+ layerClass?也这样觉得。设置子层的框架?设置为什么?我必须根据超层的帧大小分别计算所有子层的帧/位置吗?是否没有任何类似“约束”或“链接到上层”的解决方案?哦,天哪,又是超出时间范围的一天。CGLayers调整了大小,但又太笨拙,CALayers足够快,但没有调整大小。好多惊喜 无论如何,谢谢您的答复。
GeriBorbás10年

3
Mac上的CALayer对此具有布局管理器,但iPhone上不提供。因此,是的,您必须自己计算框架尺寸。另一种选择是使用子视图而不是子层。然后,您可以相应地设置子视图的自动调整大小蒙版。
Ole Begemann,2010年

2
是的,UIViews的性能太昂贵了,这就是为什么我使用CALayers的原因。
GeriBorbás10年

我尝试了您建议的方式。它有效,但事实并非如此。我调整了动画视图的大小,但是子层在不同的动画中调整了大小。血腥的地狱,现在该怎么办?在CALayer子类中重写在视图动画的每个(!)帧上调用的方法是什么?有没有?
GeriBorbás10年

刚刚碰到这一点。似乎最好的选择是像Ole所说的那样对CALayer进行子类化,但这似乎不必要。
Dimitri

15

我在UIView中使用了它。

-(void)layoutSublayersOfLayer:(CALayer *)layer
{
    if (layer == self.layer)
    {
        _anySubLayer.frame = layer.bounds;
    }

super.layoutSublayersOfLayer(layer)
}

为我工作。


是的,这在iOS 8中对我有效。大概可以在早期版本中使用。我有一个渐变背景层,并且在旋转设备时需要调整该层的大小。
EPage_Ed 2015年

为我工作,但确实需要致电给超级

这是最好的答案!是的,我尝试过layoutSubviews,但是它只会破坏UITextField的布局,例如leftView和rightView消失,UITextField中的更多Text消失。也许我使用扩展而不是UIView的继承,但这是非常麻烦的。这项工作很棒!THX
米哈尔Ziobro

对于具有自定义工程图的图层(CALayerDelegatedraw(_:in:)),我只好也呼吁_anySubLayer.setNeedsDisplay()。然后这对我有用。
jedwidz

9

我有同样的问题。在自定义视图的层中,我添加了另外两个子层。为了调整子层的大小(每次更改自定义视图的边界时),我实现了layoutSubviews自定义视图的方法。在此方法中,我只是更新每个子图层的框架以匹配子视图图层的当前边界。

像这样:

-(void)layoutSubviews{
   //keep the same origin, just update the width and height
   if(sublayer1!=nil){
      sublayer1.frame = self.layer.bounds;
   }
}

16
仅供参考,您不需要,如果(sublayer1 =零!),因为ObjC定义了消息为零(在这种情况下,-setFrame :)作为无操作返回0
安德鲁包利华

7

2017年

这个问题的字面答案:

“ CALayers的UIView边界更改没有调整大小。为什么?”

是好是坏

needsDisplayOnBoundsChange

默认为false CALayer

解,

class CircularGradientViewLayer: CALayer {
    
    override init() {
        
        super.init()
        needsDisplayOnBoundsChange = true
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override open func draw(in ctx: CGContext) {
        go crazy drawing in .bounds
    }
}

确实,我指导您进行此质量检查

https://stackoverflow.com/a/47760444/294884

这说明了关键contentsScale设置到底是做什么的;您通常需要在设置needsDisplayOnBoundsChange时同样地进行设置。



0

正如[Ole]所写,CALayer不支持在iOS上自动调整大小。因此,您应该手动调整布局。我的选择是在(iOS 7和更早版本)内调整图层的框架

- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration 

或(从iOS 8开始)

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id <UIViewControllerTransitionCoordinator>)coordinato

0

在您的自定义视图中,您需要为自定义图层声明变量,而不是在范围初始化中声明变量。并且只需将其初始化一次,就不要尝试设置null值并重新初始化

    类CustomView:UIView {
        var customLayer:CALayer = CALayer()

        覆盖func layoutSubviews(){
            super.layoutSubviews()
    //保护let _fillColor = self._fillColor else {return}
            initializeLayout()
        }
        私人函式initializeLayout(){ 
            customLayer.removeFromSuperView()
            customLayer.frame = layer.bounds
                   
            layer.insertSubview(at:0)
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.