CALayers는 UIView의 경계 변경에 따라 크기가 조정되지 않았습니다. 왜?


101

나는이 UIView팔에 대해 다른이있는 CALayer그 레이어에 추가 하위 레이어. 경우 내가보기의 경계 수정 (애니메이션)을, 다음 뷰 자체는 (내가 그것을 확인 축소 backgroundColor), 그러나 서브 레이어 '의 크기는 변경되지 않습니다 .

이것을 해결하는 방법?

답변:


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/…- "기본적으로 경계 사각형의 원점은 (0, 0)으로 설정되어 있지만 보기의 다른 부분을 표시하려면이 값을 변경하십시오. "
— jdc 2013 년

많은 감사합니다. 사실이 아닌 몇 가지 사례 (스크롤보기)를 배웠지 만이 설명을 잊어 버렸습니다.
— griotspeak의 2013 년

31
[super layoutSubviews]를 호출하는 것을 잊지 마십시오. 다양한 UIKit 클래스에서 예기치 않은 동작이 발생할 수 있습니다.
— Kpmurphy91 2014 년

2
이것은 자동 크기 조정 UITextView(scrollEnabled = NO) 및 자동 레이아웃으로 저에게 잘 맞지 않았습니다 . 수퍼 뷰에 고정 된 텍스트 뷰가 있었는데,이 뷰 CALayer는 맨 아래에 (테두리)가 있었고, 텍스트 뷰의 높이가 변경되면 테두리 위치를 업데이트하고 싶었습니다. 어떤 이유로 layoutSubiews너무 늦게 호출되었습니다 (그리고 레이어 위치가 애니메이션되었습니다).
— iosdude

26

iPhone의 CALayer는 레이아웃 관리자를 지원하지 않기 때문에 뷰의 메인 레이어 layoutSublayers를 모든 하위 레이어의 프레임을 설정하기 위해 재정의하는 사용자 정의 CALayer 하위 클래스로 만들어야한다고 생각합니다 . 또한 +layerClass새 CALayer 하위 클래스의 클래스를 반환하려면 뷰의 메서드를 재정의해야합니다 .


OpenGL 레이어 재정의의 경우처럼 + layerClass를 재정의 하시겠습니까? 그렇게 생각하십시오. 하위 레이어의 프레임을 설정 하시겠습니까? 무엇으로 설정 하시겠습니까? 수퍼 레이어 프레임 크기에 따라 모든 서브 레이어의 프레임 / 위치를 개별적으로 계산해야합니까? "제약과 유사한"또는 "슈퍼 레이어에 링크"와 같은 솔루션이 없습니까? 오, 세상에, 다른 날이 틀렸어. CGLayers의 크기가 조정되었지만 너무 느려 CALayers는 충분히 빠르지 만 크기가 조정되지 않았습니다. 너무 많은 놀라움. 어쨌든 답장을 보내 주셔서 감사합니다.
— Geri Borbás

3
Mac의 CALayer에는이를위한 레이아웃 관리자가 있지만 iPhone에서는 사용할 수 없습니다. 그렇습니다. 프레임 크기를 직접 계산해야합니다. 또 다른 옵션은 하위 레이어 대신 하위 뷰를 사용하는 것입니다. 그런 다음 그에 따라 하위 뷰의 자동 크기 조정 마스크를 설정할 수 있습니다.
— Ole Begemann

2
Ya, UIViews는 성능이 너무 비싼 클래스이므로 CALayers를 사용합니다.
— Geri Borbás

나는 당신이 제안한 방식을 시도했습니다. 작동하지만 그렇지 않습니다. 애니메이션 된 뷰의 크기를 조정하지만 다른 애니메이션에서 하위 레이어의 크기가 조정됩니다. 젠장, 이제 어떡해? 뷰 애니메이션의 모든 (!) 프레임에서 호출되는 CALayer 하위 클래스에서 재정의하는 방법은 무엇입니까? 있어요?
— Geri Borbás

이것도 만났습니다. Ole이 말한 것처럼 CALayer를 하위 클래스로 만드는 것이 가장 좋은 옵션 인 것 같지만 불필요하게 번거로운 것 같습니다.
— Dimitri

15

나는 이것을 UIView에서 사용했습니다.

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

super.layoutSublayersOfLayer(layer)
}

나를 위해 작동합니다.


예, 이것은 iOS 8에서 저에게 효과적이었습니다. 아마도 이전 버전에서 작동했을 것입니다. 그라데이션 배경 레이어가 있었고 장치를 회전 할 때 레이어 크기를 조정해야했습니다.
— EPage_Ed

나를 위해 일했다,하지만 슈퍼에 이르기까지 호출이 필요 않았다
— 엔트로피

이것이 최고의 답변입니다! 네, layoutSubviews를 시도했지만 leftView 및 rightView와 같은 UITextField의 레이아웃이 사라지고 UITextField의 더 많은 텍스트가 사라집니다. 아마도 UIView 상속 대신 확장을 사용했지만 매우 버그가 많았습니다. 이것은 훌륭하게 작동합니다! THX
— Michał Ziobro

사용자 정의 도면 ( CALayerDelegate's draw(_: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
참고로, ObjC는 0을 반환하는 no-op으로 메시지를 nil (이 경우 -setFrame :)로 정의하므로 if (sublayer1! = nil)이 필요하지 않습니다.
— Andrew Pouliot

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

이 QA로 안내합니다.

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

도대체 중요한 contentsScale설정이 하는 일을 설명합니다 . 일반적으로 needsDisplayOnBoundsChange를 설정할 때 동일하게 설정해야합니다.


5

Swift 3 버전

사용자 지정 셀에서 다음 줄 추가

먼저 선언

let gradientLayer: CAGradientLayer = CAGradientLayer()

그런 다음 다음 줄을 추가하십시오.

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

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 값을 설정하고 다시 초기화하지 마십시오.

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

        func layoutSubviews () {
            super.layoutSubviews ()
    // 가드 let _fillColor = self._fillColor else {return}
            initializeLayout ()
        }
        private func initializeLayout () { 
            customLayer.removeFromSuperView ()
            customLayer.frame = layer.bounds
                   
            layer.insertSubview (at : 0)
        }
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.