UIView 크기 조정 이벤트가 있습니까?


102

이미지 뷰의 행과 열이있는 뷰가 있습니다.

이보기의 크기가 조정되면 이미지보기 위치를 다시 정렬해야합니다.

이보기는 크기가 조정되는 다른보기의 하위보기입니다.

이보기의 크기가 조정되는시기를 감지하는 방법이 있습니까?


뷰의 크기는 언제 조정됩니까? 장치가 회전 할 때 또는 사용자가 멀티 터치를 사용하여 회전 할 때?
Evan Mulawski

이보기는 사용자가 다른보기 (마스터보기)의 버튼을 탭하면 크기가 조정됩니다.
live-love

답변:


98

Uli가 아래에 언급했듯이 적절한 방법 layoutSubviews은 imageViews를 재정의 하고 레이아웃하는 것입니다.

어떤 이유로 하위 클래스를 만들고을 재정의 할 수없는 layoutSubviews경우 관찰 bounds은 더러워진 경우에도 작동합니다. 더 나쁜 것은 관찰하는 데 위험이 있습니다. Apple은 KVO가 UIKit 클래스에서 작동한다고 보장하지 않습니다. 여기에서 Apple 엔지니어와의 토론을 읽어보십시오. 관련 개체는 언제 릴리스됩니까?

원래 답변 :

키-값 관찰을 사용할 수 있습니다.

[yourView addObserver:self forKeyPath:@"bounds" options:0 context:nil];

구현 :

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (object == yourView && [keyPath isEqualToString:@"bounds"]) {
        // do your stuff, or better schedule to run later using performSelector:withObject:afterDuration:
    }
}

2
실제로, subview를 배치하는 것은 layoutSubviews의 목적이므로 기능적이지만 크기 변경을 관찰하는 것은 IMO 잘못된 설계입니다.
uliwitness 2011

@uliwitness 잘 그들은이 물건을 계속 변경합니다. 어쨌든, 지금 당신은 사용해야 viewWillTransition등 등
댄 Rosenstark는

UIView가 아닌 ​​UIViewControllers의 viewWillTransition입니다.
Armand

layoutSubviews뷰의 현재 크기에 따라 다른 하위 뷰를 추가 / 제거하고 다른 제약 조건을 추가 / 제거해야하는 경우 여전히 권장되는 방법을 사용 하고 있습니까?
Chris Prince

1
글쎄요, 제 사건에 대해 방금 대답 한 것 같아요. 크기에 따라 설정을 수행하면 경계 재정의에 필요합니다. layoutSubviews에서 할 때 그렇지 않습니다.
Chris Prince

93

A의 UIView서브 클래스, 부동산 전문가들은 사용할 수 있습니다 :

override var bounds: CGRect {
    didSet {
        // ...
    }
}

서브 클래 싱없이 스마트 키 경로를 사용한 키-값 관찰 은 다음을 수행합니다.

var boundsObservation: NSKeyValueObservation?

func beginObservingBounds() {
    boundsObservation = observe(\.bounds) { capturedSelf, _ in
        // ...
    }
}

2
@Ali 왜 그렇게 생각하세요?
루돌프 Adamkovič

로드 프레임 변경시 경계가 변경되지 않는 것 같습니다 (이상하다는 것을 알고 있고 어쩌면 내가 뭔가 잘못했다고 생각합니다)
Ali

3
@Ali : 여기서 몇 번 언급했듯이 frame파생 및 런타임 계산 속성입니다. 당신이 그렇게 할 아주 똑똑하고 아는 이유가 없다면 이것을 무시하지 마십시오. 그렇지 않으면 : bounds또는 (더 나은)을 사용하십시오 layoutSubviews.
auco

3
원을 만드는 아주 좋은 방법입니다. 감사! override var bounds: CGRect { didSet { layer.cornerRadius = bounds.size.width / 2 }}
SimplGy

4
보기 계층 구조에서보기를 배치 한 위치에 따라 감지 bounds또는 frame변경이 작동한다고 보장 할 수 없습니다. layoutSubviews대신 재정의하겠습니다 . 참조 답변을.
HuaTham

31

UIView의 하위 클래스를 만들고 layoutSubview를 재정의합니다.


11
문제는 하위 뷰가 크기를 변경할 수있을뿐만 아니라 해당 크기 변경을 애니메이션 할 수 있다는 것입니다. UIView는 애니메이션을 실행할 때 매번 layoutSubviews를 호출하지 않습니다.
David Jeske 2013

1
@DavidJeske UIViewAnimationOptions에는 UIViewAnimationOptionLayoutSubviews라는 옵션이 있습니다. 도움이 될 것 같습니다. :)
Neal.Marlin

8

Swift 4 keypath KVO-이것이 iPad 측면 패널로의 자동 회전 및 이동을 감지하는 방법입니다. 어떤 관점에서 작동해야합니다. UIView의 레이어를 관찰해야했습니다.

private var observer: NSKeyValueObservation?

override func viewDidLoad() {
    super.viewDidLoad()
    observer = view.layer.observe(\.bounds) { object, _ in
        print(object.bounds)
    }
    // ...
}
override func viewWillDisappear(_ animated: Bool) {
    observer?.invalidate()
    //...
}

이 솔루션은 저에게 효과적이었습니다. 저는 Swift를 처음 사용했으며 여기에서 사용한 \ .bounds 구문에 대해 잘 모르겠습니다. 그게 정확히 무엇을 의미합니까?
WBuck

여기에 더 많은 토론이 있습니다 : github.com/ole/whats-new-in-swift-4/blob/master/…
Warren Stringer

.layer트릭을했다! 왜 사용 view.observe이 작동하지 않는지 아십니까?
d4Rk

@ d4Rk-모르겠어요. 내 생각 엔 레이어 경계가 UIView 프레임보다 덜 모호하다는 것입니다. 예를 들어 UITableView의 contentOffset은 하위보기의 최종 좌표에 영향을줍니다. 확실하지 않다.
Warren Stringer

이것은 저에게 큰 대답입니다. 제 경우는 뷰 레이아웃을 위해 AutoLayout을 사용하고 있다는 것입니다. 그러나 UICollectionViewFlowLayout은 명시적인 itemSize를 제공하도록 강제합니다. 하지만 collectionView 크기가 변경되면 (예 : AutoLayout을 사용하여 도구 모음을 표시 할 때와 같이) itemSize는 동일하게 유지되고 = [관찰자가 지금까지 얻은 가장 깨끗한 접근 방식입니다. 그리고 최고!
Yitzchak

7

UIView의 하위 클래스를 만들고 재정의 할 수 있습니다.

setFrame : (CGRect) 프레임

방법. 뷰의 프레임 (즉, 크기)이 변경 될 때 호출되는 메서드입니다. 다음과 같이하십시오.

- (void) setFrame:(CGRect)frame
{
  // Call the parent class to move the view
  [super setFrame:frame];

  // Do your custom code here.
}

감각적이고 기능적. 좋은 전화.
El Zorko 2012 년

1
참고로 이것은 UIImageView 하위 클래스에서 작동하지 않습니다. 여기에 더 많은 정보 : stackoverflow.com/questions/19216684/...
윌리엄 Entriken

또한 자동 회전으로 인해 크기를 조정하는 동안 하위 클래스에서 setFrame:호출되지 않았습니다 . 참고 : 자동 레이아웃 및 iOS 7.0을 사용하고 있습니다. UITextViewlayoutSubviews:
ma11hew28

3
재정의하지 마십시오 setFrame:. frame파생 속성입니다. 내 대답을 참조하십시오
애들 소리 쳐

7

꽤 오래되었지만 여전히 좋은 질문입니다. Apple의 샘플 코드와 일부 개인 UIView 하위 클래스에서는 다음과 같이 setBounds를 재정의합니다.

-(void)setBounds:(CGRect)newBounds {
    BOOL const isResize = !CGSizeEqualToSize(newBounds.size, self.bounds.size);
    if (isResize) [self prepareToResizeTo:newBounds.size]; // probably saves 
    [super setBounds:newBounds];
    if (isResize) [self recoverFromResizing];
}

재정의 setFrame:는 좋은 생각이 아닙니다. frame에서 파생 center, bounds그리고 transform아이폰 OS가 반드시 호출하지 않도록, setFrame:.


2
이것은 사실입니다 (이론상). 그러나 setBounds:프레임 속성을 설정할 때도 호출되지 않습니다 (적어도 iOS 7.1에서는). 이것은 추가 메시지를 피하기 위해 Apple이 추가 한 최적화 일 수 있습니다.
nschum

1
… 그리고 애플 측의 나쁜 디자인은 그들 자신의 접근자를 부르지 않는 것입니다.
osxdirk 2014 년

1
사실, 모두 frame 와는 bounds뷰의 기본에서 파생 된 CALayer; 그냥 레이어의 게터를 호출합니다. 그리고 setFrame:반면, 레이어의 프레임을 설정 setBounds:세트 레이어 경계입니다. 따라서 둘 중 하나만 무시할 수 없습니다. 또한 layoutSubviews과도하게 호출되기 때문에 (지오메트리 변경뿐만 아니라) 항상 좋은 옵션이 아닐 수도 있습니다. 아직 찾고 있습니다 ...
big_m dec.

-3

UIViewController 인스턴스에있는 경우 재정의 viewDidLayoutSubviews가 트릭을 수행합니다.

override func viewDidLayoutSubviews() {
    // update subviews
}

UIViewController가 아닌 UIView 크기가 필요합니다.
Gastón Antonio Montes 2017 년

@ GastónAntonioMontes 감사합니다! UIView인스턴스와 UIViewController인스턴스 간의 관계를 발견했을 수 있습니다 . 따라서 UIViewVC가 연결되지 않은 인스턴스 가있는 경우 다른 답변은 훌륭하지만 VC에 연결되면이 사람이 바로 그 사람입니다. 귀하의 경우에는 해당되지 않습니다.
Dan Rosenstark 2017-10-05
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.