program tip

CALayer IOS의 자동 레이아웃 제약

radiobox 2020. 10. 24. 09:58
반응형

CALayer IOS의 자동 레이아웃 제약


안녕하세요 저는 edittext에 대해 한쪽 테두리를 설정하려고 시도한 iPhone 응용 프로그램을 개발 중입니다. 나는 다음과 같은 방식으로 이것을했다.

 int borderWidth = 1;
CALayer *leftBorder = [CALayer layer];

leftBorder.borderColor = [UIColor whiteColor].CGColor;
leftBorder.borderWidth = borderWidth;

leftBorder.frame = CGRectMake(0, textField.frame.size.height - borderWidth, textField
                              .frame.size.width, borderWidth);
[textField.layer addSublayer:leftBorder];

IB의 edittext에 몇 가지 제약을 두어 장치를 회전 할 때 그에 따라 텍스트 필드의 너비를 조정합니다. 내 문제는 편집 텍스트에 대해 설정 한 CALayer의 너비를 조정하지 않고 edittext의 너비를 조정한다는 것입니다. 따라서 CALayer 항목에도 몇 가지 제약을 두어야한다고 생각합니다. 그러나 나는 그것을하는 방법을 모른다. 이것에 대해 알고 있습니까? 도움이 필요하다. 감사합니다.


전체 자동 크기 조정 비즈니스는보기에 따라 다릅니다. 레이어는 자동 크기 조정되지 않습니다.

코드에서해야 할 일은 레이어의 크기를 직접 조정하는 것입니다.

예 :

viewController에서 당신은 할 것입니다

- (void) viewDidLayoutSubviews {
  [super viewDidLayoutSubviews]; //if you want superclass's behaviour... 
  // resize your layers based on the view's new frame
  self.editViewBorderLayer.frame = self.editView.bounds;
}

또는 사용자 정의 UIView에서 사용할 수 있습니다.

- (void)layoutSubviews {
  [super layoutSubviews]; //if you want superclass's behaviour...  (and lay outing of children)
  // resize your layers based on the view's new frame
  layer.frame = self.bounds;
}

이 솔루션을 확인하십시오. 아래와 같이 "YourView.bounds"경로에 KVO를 사용하십시오.

self.addObserver(self, forKeyPath: "YourView.bounds", options: .New, context: nil)

그런 다음 아래와 같이 처리하십시오.

override func observeValueForKeyPath(keyPath: String, ofObject object: AnyObject, change: [NSObject : AnyObject], context: UnsafeMutablePointer<Void>) {
        if (keyPath == "YourView.bounds") {
            YourLayer.frame = YourView.bounds
            return
        }
        super.observeValueForKeyPath(keyPath, ofObject: object, change: change, context: context)
    }

자세한 내용은 다음 링크를 참조하십시오.

https://theswiftdev.com/2015/03/28/auto-layout-with-layers/


내 사용자 정의보기의 layoutSubviews 메소드를 구현했습니다. 이 방법 내에서 내 하위 뷰 레이어의 현재 경계와 일치하도록 각 하위 레이어의 프레임을 업데이트합니다.

-(void)layoutSubviews{
      sublayer1.frame = self.layer.bounds;
}

답변 에 따르면 layoutSubviews필요한 모든 경우에 전화를받지 않습니다. 이 대리자 방법이 더 효과적이라는 것을 알았습니다.

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if(self != nil) {
        [self.layer addSublayer:self.mySublayer];
    }
    return self;
}

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

점선 테두리로 만들 때 내 솔루션

class DashedBorderView: UIView {

   let dashedBorder = CAShapeLayer()

   override init(frame: CGRect) {
       super.init(frame: frame)
       commonInit()
   }

   required init?(coder aDecoder: NSCoder) {
       super.init(coder: aDecoder)
       commonInit()
   }

   private func commonInit() {
       //custom initialization
       dashedBorder.strokeColor = UIColor.red.cgColor
       dashedBorder.lineDashPattern = [2, 2]
       dashedBorder.frame = self.bounds
       dashedBorder.fillColor = nil
       dashedBorder.cornerRadius = 2
       dashedBorder.path = UIBezierPath(rect: self.bounds).cgPath
       self.layer.addSublayer(dashedBorder)
   }

   override func layoutSublayers(of layer: CALayer) {
       super.layoutSublayers(of: layer)
       dashedBorder.path = UIBezierPath(rect: self.bounds).cgPath
       dashedBorder.frame = self.bounds
   }
}

Swift 3.x KVO 솔루션 (@ arango_86의 답변 업데이트)

관찰자 추가

self.addObserver(
    self, 
    forKeyPath: "<YOUR_VIEW>.bounds", 
    options: .new, 
    context: nil
)

값 관찰

override open func observeValue(
    forKeyPath keyPath: String?, 
    of object: Any?, 
    change: [NSKeyValueChangeKey : Any]?, 
    context: UnsafeMutableRawPointer?
) {
    if (keyPath == "<YOUR_VIEW.bounds") {
      updateDashedShapeLayerFrame()
      return
    }

    super.observeValue(
        forKeyPath: keyPath, 
        of: object, 
        change: change, 
        context: context
    )
}

비슷한 문제가있었습니다. 뷰와 함께 자동 레이아웃을 사용할 때 'CALayer'프레임을 설정해야합니다 ( IB가 아닌 코드에서 ).

In my case, I had a slightly convoluted hierarchy, having a view controller within a view controller. I ended up at this SO question and looked into the approach of using viewDidLayoutSubviews. That didn't work. Just in case your situation is similar to my own, here's what I found...

Overview

I wanted to set the frame for the CAGradientLayer of a UIView that I was positioning as a subview within a UIViewController using auto layout constraints.

Call the subview gradientView and the view controller child_viewController.

child_viewController was a view controller I'd set up as a kind of re-usable component. So, the view of child_viewController was being composed into a parent view controller - call that parent_viewController.

When viewDidLayoutSubviews of child_viewController was called, the frame of gradientView was not yet set.

(At this point, I'd recommend sprinkling some NSLog statements around to get a feel for the sequence of creation of views in your hierarchy, etc.)

So I moved on to try using viewDidAppear. However, due to the nested nature of child_viewController I found viewDidAppear was not being called.

(See this SO question: viewWillAppear, viewDidAppear not being called, not firing).

My current solution

I've added viewDidAppear in parent_viewController and from there I'm calling viewDidAppear in child_viewController.

For the initial load I need viewDidAppear as it's not until this is called in child_viewController that all of the subviews have their frames set. I can then set the frame for the CAGradientLayer...

I've said that this is my current solution because I'm not particularly happy with it.

After initially setting the frame of the CAGradientLayer - that frame can become invalid if the layout changes - e.g. rotating the device.

To handle this I'm using viewDidLayoutSubviews in child_viewController - to keep the frame of the CAGradientLayer within gradientView, correct.

It works but doesn't feel good. (Is there a better way?)

참고URL : https://stackoverflow.com/questions/24303279/auto-layout-constraint-on-calayer-ios

반응형