【问题标题】:CALayers didn't get resized on its UIView's bounds change. Why?CALayers 没有在其 UIView 的边界更改时调整大小。为什么?
【发布时间】:2011-01-31 00:59:38
【问题描述】:

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

如何解决?

【问题讨论】:

  • layer.autoresizingMask 可能会有所帮助。

标签: iphone ios objective-c uiview calayer


【解决方案1】:

2017:

这个问题的字面答案:

“CALayers 没有根据 UIView 的边界变化调整大小。为什么?”

是好是坏:

needsDisplayOnBoundsChange

CALayer 中默认为 false (!!)。

解决方案,

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
    }
}

确实,我将您引导至此 QA

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

这就解释了,关键的contentsScale 到底是做什么的。当你设置needsDisplayOnBoundsChange时,你通常需要设置它。

【讨论】:

    【解决方案2】:

    在您的自定义视图中,您需要为您的自定义层声明变量,不要在作用域初始化中声明变量。并且只初始化一次,不要尝试设置空值并重新初始化

    类自定义视图:UIView { var customLayer:CALayer = CALayer() 覆盖 func layoutSubviews() { super.layoutSubviews() // 守卫 let _fillColor = self._fillColor else {return} 初始化布局() } 私人函数初始化布局(){ customLayer.removeFromSuperView() customLayer.frame = layer.bounds layer.insertSubview(at:0) } }

    【讨论】:

      【解决方案3】:

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

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

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

      【讨论】:

      • @fishinear 你确定吗?听起来你在描述框架。从理论上讲,bounds 应该始终以 0,0 作为其原点。
      • @griotspeak - 实际上并非如此。请参阅此处对 bounds 属性的描述:developer.apple.com/library/ios/#documentation/uikit/reference/… --“默认情况下,边界矩形的原点设置为 (0, 0),但您可以更改此值以显示视图的不同部分。”
      • 非常感谢,从那以后我了解到一些情况(滚动视图,其中之一)不是真的,但我忘记了这条评论。
      • 不要忘记调用 [super layoutSubviews],因为这可能会导致各种 UIKit 类出现意外行为。
      • 这对我来说效果不是很好,因为我使用了自动调整大小的UITextView (scrollEnabled = NO) 和自动布局。我有一个文本视图固定到它的超级视图,它的底部有一个CALayer(边框),我希望它在文本视图的高度发生变化时更新边框位置。出于某种原因,layoutSubiews 被调用得太晚了(图层位置被动画化了)。
      【解决方案4】:

      我在 UIView 中使用了这个。

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

      为我工作。

      【讨论】:

      • 是的,这在 iOS 8 中对我有用。大概可以在早期版本中使用。我有一个渐变背景图层,需要在设备旋转时调整图层大小。
      • 为我工作,但它确实需要打电话给 super
      • 这是最好的答案!是的,我已经尝试过 layoutSubviews,但它只会破坏我的 UITextField 的布局,例如 leftView 和 rightView 消失,UITextField 中的更多文本消失。也许我使用了扩展而不是 UIView 的继承,但它非常有问题。这很好用! THX
      • 对于带有自定义绘图的图层(CALayerDelegate's draw(_:in:)),我还必须调用_anySubLayer.setNeedsDisplay()。然后这对我有用。
      【解决方案5】:

      Swift 3 版本

      在自定义单元格中,添加以下行

      先声明

      let gradientLayer: CAGradientLayer = CAGradientLayer()
      

      然后添加以下行

      override func layoutSubviews() {
          gradientLayer.frame = self.YourCustomView.bounds
      }
      

      【讨论】:

      • 别忘了致电super.layoutSubviews()。省略此调用可能会导致某些视图出现意外行为。
      【解决方案6】:

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

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

      或(从 iOS 8 开始)

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

      【讨论】:

        【解决方案7】:

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

        类似这样的:

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

        【讨论】:

        • 仅供参考,您不需要 if(sublayer1!=nil),因为 ObjC 将消息定义为 nil(在本例中为 -setFrame:) 作为返回 0 的无操作。
        • 别忘了致电[super layoutSubviews]。省略此调用可能会导致意外行为。
        【解决方案8】:

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

        【讨论】:

        • 在 OpenGL 层覆盖的情况下覆盖 +layerClass 吗?也这样觉得。设置子图层的框架?设置成什么?我必须根据超级层的帧大小单独计算所有子层的帧/位置吗?没有任何“类似约束”或“链接到超级层”的解决方案吗?哦,上帝,又过了一天。 CGLayers 已调整大小,但太慢,CALayers 足够快,但没有调整大小。这么多惊喜。无论如何,谢谢您的回复。
        • Mac 上的 CALayer 有用于此的布局管理器,但它们在 iPhone 上不可用。所以是的,你必须自己计算框架尺寸。另一种选择可能是使用子视图而不是子层。然后你可以相应地设置子视图的自动调整掩码。
        • 是的,UIViews 是性能太昂贵的类,这就是我使用 CALayers 的原因。
        • 我尝试了你建议的方式。它有效,但不是。我调整了动画视图的大小,但子层在不同的动画中调整了大小。该死的,现在该怎么办?在视图动画的每个(!)帧上调用的 CALayer 子类中覆盖的方法是什么?有吗?
        • 刚刚也碰到了这个。似乎最好的选择是像 Ole 所说的那样子类化 CALayer,但这似乎不必要地麻烦。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-30
        • 1970-01-01
        • 2018-09-03
        • 1970-01-01
        • 2018-06-15
        相关资源
        最近更新 更多