UIView yeniden boyutlandırma etkinliği var mı?


102

İçinde görüntü satırları ve sütunları olan bir görünümüm var.

Bu görünüm yeniden boyutlandırılırsa, görüntü izleme konumlarını yeniden düzenlemem gerekir.

Bu görünüm, yeniden boyutlandırılan başka bir görünümün alt görünümüdür.

Bu görünümün ne zaman yeniden boyutlandırıldığını algılamanın bir yolu var mı?


Görünüm ne zaman yeniden boyutlandırılır? Cihaz döndüğünde veya kullanıcı çoklu dokunma özelliğini kullanarak cihazı döndürdüğünde?
Evan Mulawski

Bu görünüm, kullanıcı başka bir görünümdeki (ana görünüm) bir düğmeye dokunduğunda yeniden boyutlandırılır.
live-love

Yanıtlar:


98

Uli'nin aşağıda yorumladığı gibi, bunu yapmanın doğru yolu layoutSubviewsoradaki imageView'ları geçersiz kılmak ve yerleştirmektir.

Herhangi bir nedenle, alt sınıflara girip geçersiz kılamıyorsanız layoutSubviews, gözlem yapmak, kirliyken boundsbile işe yaramalıdır. Daha da kötüsü, gözlemlemeyle ilgili bir risk var - Apple, KVO'nun UIKit sınıflarında çalışacağını garanti etmez. Apple mühendisi ile yapılan tartışmayı buradan okuyun: İlişkili bir nesne ne zaman piyasaya sürülür?

orijinal cevap:

Anahtar / değer gözlemlemeyi kullanabilirsiniz:

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

ve uygulayın:

- (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
Gerçekten, alt görünümlerin yerleştirilmesi tam olarak layoutSubviews'in amacıdır, bu nedenle işlevselken boyut değişikliklerini gözlemlemek IMO'nun kötü tasarımıdır.
uliwitness

@uliwitness iyi bu şeyleri değiştirmeye devam ediyorlar. Her neyse, şimdi viewWillTransitionvb.
Kullanmalısınız

viewWillTransition of UIViewControllers için, UIView için değil.
Armand

layoutSubviewsGörünümün mevcut boyutuna bağlı olarak, farklı alt görünümlerin eklenmesi / kaldırılması gerekiyorsa ve farklı kısıtlamaların eklenmesi / kaldırılması gerekiyorsa, hala önerilen bir yöntem mi kullanılıyor ?
Chris Prince

1
Sanırım bunu davam için cevapladım. Kurulumu yaptığımda (boyuta bağlı olarak) sınırların geçersiz kılınmasına ihtiyacım var, çalışıyor. Bunu layoutSubviews alt görünümlerinde yaptığımda olmuyor.
Chris Prince

93

Bir UIViewalt sınıfta, özellik gözlemcileri kullanılabilir:

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

Subclassing olmadan anahtar değeri gözlem ile akıllı anahtar yolları yapar:

var boundsObservation: NSKeyValueObservation?

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

2
@Ali Neden böyle düşünüyorsun?
Rudolf Adamkovič

yük çerçevesi değiştiğinde, ancak sınırlar değişmiyor gibi görünüyor (garip olduğunu biliyorum ve belki de yanlış bir şey söylüyorum)
Ali

3
@ Ali: Burada birkaç kez bahsedildiği gibi: frametüretilmiş ve çalışma zamanı hesaplamalı bir özelliktir. Bunu yapmak için çok akıllı ve bilerek bir nedeniniz yoksa bunu geçersiz kılmayın. aksi takdirde: boundsveya (daha da iyisi) kullanın layoutSubviews.
auco

3
Bir daire oluşturmanın harika bir yolu. Teşekkürler! override var bounds: CGRect { didSet { layer.cornerRadius = bounds.size.width / 2 }}
SimplGy

4
Görünümünüzü görünüm hiyerarşisinde nereye koyduğunuza bağlı olarak, algılama boundsveya framedeğişikliğin çalışacağı garanti edilmez. Onun layoutSubviewsyerine geçersiz kılardım. Bunu ve bu cevapları görün .
HuaTham

32

UIView alt sınıfını oluşturun ve düzeni geçersiz kılın


11
bununla ilgili sorun, alt görünümlerin yalnızca boyutlarını değiştirememeleri, aynı zamanda bu boyut değişikliğini canlandırabilmeleridir. UIView animasyonu çalıştırdığında, her seferinde layoutSubviews'i çağırmaz.
David Jeske

1
@DavidJeske UIViewAnimationOptions, UIViewAnimationOptionLayoutSubviews adında bir seçeneğe sahiptir. Sanırım bu yardımcı olabilir. :)
Neal.Marlin

8

Swift 4 tuş yolu KVO - Otomatik döndürmeyi ve iPad yan paneline geçmeyi böyle algıladım. Herhangi bir görünümde çalışmalıdır. UIView katmanını gözlemlemek gerekiyordu.

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()
    //...
}

Bu çözüm benim için çalıştı. Swift'de yeniyim ve burada kullandığınız \ .bounds sözdiziminden emin değilim. Bu tam olarak ne anlama geliyor?
WBuck


.layerhile yaptı! Kullanmanın neden view.observeişe yaramadığını biliyor musunuz ?
d4Rk

@ d4Rk - Bilmiyorum. Tahminim, katman sınırları UIView çerçevelerinden daha az belirsizdir. Örneğin, UITableView'ın contentOffset, alt görünümlerinin son koordinatlarını etkileyecektir. Emin değil.
Warren Stringer

BU BENİM İÇİN BÜYÜK BİR CEVAP. Benim durumum, görüşlerimi düzenlemek için Otomatik Yerleşim kullanmamdır. AMA UICollectionViewFlowLayout sizi açık bir itemSize vermeye zorlar. ancak collectionView boyutunuz değiştiğinde (benim durumumda AutoLayout ile bir araç çubuğu gösterdiğimde olduğu gibi) - itemSize aynı kalır ve = [gözlemci şu ana kadar elde ettiğim en temiz yaklaşımdır. ve en iyisi !!
Yitzchak

7

Bir UIView alt sınıfı oluşturabilir ve

setFrame: (CGRect) çerçeve

yöntem. Bu, görünümün çerçevesi (yani boyutu) değiştirildiğinde çağrılan yöntemdir. Bunun gibi bir şey yapın:

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

  // Do your custom code here.
}

Mantıklı ve işlevsel. İyi karar.
El Zorko

1
Bilginize Bu, UIImageView alt sınıfı için çalışmaz. Daha fazla bilgi burada: stackoverflow.com/questions/19216684/…
William Entriken

Ayrıca, otomatik döndürme nedeniyle yeniden boyutlandırma sırasında alt sınıfımda setFrame:çağrılmadı . Not: Otomatik düzen ve iOS 7.0 kullanıyorum. UITextViewlayoutSubviews:
ma11hew28

3
asla geçersiz kılma setFrame:. frametüretilmiş bir özelliktir. Cevabımı görün
Adlai Holler

7

Oldukça eski ama yine de iyi bir soru. Apple'ın örnek kodunda ve bazı özel UIView alt sınıflarında, setBounds'u kabaca şu şekilde geçersiz kılarlar:

-(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];
}

Geçersiz kılmak setFrame:iyi bir fikir DEĞİLDİR. frameelde edilir center, boundsve transformIOS mutlaka çağrı olmayacak şekilde setFrame:.


2
Bu doğrudur (teoride). Ancak, setBounds:çerçeve özelliği ayarlanırken de çağrılmaz (en azından iOS 7.1'de). Bu, ek mesajı önlemek için eklenen bir optimizasyon Apple olabilir.
nschum

1
… Ve Apple'ın kendi erişimcilerini aramamaları için kötü tasarım.
osxdirk

1
Aslında, her iki frame ve boundsgörünüşüdür altta yatan elde edilir CALayer; onlar sadece katmanın tutucusunu çağırırlar. Ve katman sınırlarını ayarlarken katman setFrame:çerçevesini setBounds:ayarlar. Yani birini veya diğerini geçersiz kılamazsınız. Ayrıca, layoutSubviewsaşırı derecede çağrılır (sadece geometri değişikliklerinde değil), bu nedenle her zaman iyi bir seçenek olmayabilir. Hala arıyorum ...
big_m

-3

Bir UIViewController örneğindeyseniz, geçersiz kılma viewDidLayoutSubviewshile yapar.

override func viewDidLayoutSubviews() {
    // update subviews
}

UIViewController için değil, UIView boyutu değişti.
Gastón Antonio Montes

@ GastónAntonioMontes bunun için teşekkürler! Arasında bir ilişki olduğunu fark etmiş olabilirsinizUIViewÖrnekler ve UIViewControllerörnekler . Dolayısıyla UIView, VC eklenmemiş bir örneğiniz varsa , diğer cevaplar harika, ancak bir VC'ye bağlı olursanız, bu sizin adamınızdır. Maalesef davanız için geçerli değil.
Dan Rosenstark
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.