UIView çerçeve, sınırlar ve merkez


320

Bu özelliklerin doğru şekilde nasıl kullanılacağını bilmek istiyorum.

Anladığım kadarıyla, frameoluşturduğum görünümün kabından kullanılabilir. Görüntüleme konumunu kap görünümüne göre ayarlar. Ayrıca bu görünümün boyutunu da ayarlar.

Ayrıca centeroluşturduğum görünümün kapsayıcısından da kullanılabilir. Bu özellik, görünümün kabına göre konumunu değiştirir.

Son olarak, boundsgörünümün kendisine görecelidir. Görünüm için çekilebilir alanı değiştirir.

frameVe arasındaki ilişki hakkında daha fazla bilgi verebilir misiniz bounds? clipsToBoundsVe masksToBoundsözellikleri ne olacak ?


1
Bu Tartışma burada zaten çözüldü. bu yüzden lütfen buraya bakın veya burada verilen geliştirici belgelerini görebilirsiniz developer.apple.com/library/ios/#documentation/uikit/reference/… stackoverflow.com/questions/1210047/… slideshare.net/onoaonoa/cs193p-lecture-5 -görüntü-animasyon
Splendid

Yanıtlar:


577

Sorduğum soru birçok kez görüldüğü için ayrıntılı bir cevap vereceğim. Daha doğru içerik eklemek istiyorsanız bunu değiştirmekten çekinmeyin.

İlk olarak soru üzerine bir özet: çerçeve, sınırlar ve merkez ve ilişkileri.

Çerçeve Bir görünümün frame( CGRect), dikdörtgenin superviewkoordinat sistemindeki konumudur . Varsayılan olarak sol üst kısımdan başlar.

Sınırlar Bir görünümün bounds( CGRect) öğesi, kendi koordinat sisteminde bir görünüm dikdörtgenini ifade eder.

Merkez A center, 'koordinat sistemi' olarak CGPointifade edilir superviewve görünümün tam merkez noktasının konumunu belirler.

UIView + konumundan alındığında bunlar önceki özellikler arasındaki ilişkilerdir (gayri resmi denklemler oldukları için kodda çalışmazlar):

  • frame.origin = center - (bounds.size / 2.0)

  • center = frame.origin + (bounds.size / 2.0)

  • frame.size = bounds.size

NOT: Görünümler döndürüldüğünde bu ilişkiler geçerli değildir. Daha fazla bilgi için, Stanford CS193p kursuna dayanan The Kitchen Drawer'dan alınan aşağıdaki resme bir göz atmanızı öneririm . Krediler @Rhubarb'a gider .

Çerçeve, sınırlar ve merkez

Kullanmak, frameiçindeki bir görünümü yeniden konumlandırmanıza ve / veya yeniden boyutlandırmanıza olanak tanır superview. Genellikle a superview, örneğin belirli bir alt görünüm oluşturduğunuzda kullanılabilir. Örneğin:

// view1 will be positioned at x = 30, y = 20 starting the top left corner of [self view]
// [self view] could be the view managed by a UIViewController
UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

İçinde çizim yapmak için koordinatlara ihtiyaç duyduğunuzda viewgenellikle bakın bounds. Tipik bir örnek, viewbir alt görünümde birincinin iç kısmı olarak çizmek olabilir . Alt görünümü çizmek için denetimin bilinmesi gerekir bounds. Örneğin:

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(50.0f, 50.0f, 400.0f, 400.0f)];    
view1.backgroundColor = [UIColor redColor];

UIView* view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];    
view2.backgroundColor = [UIColor yellowColor];

[view1 addSubview:view2];

boundsBir görünümü değiştirdiğinizde farklı davranışlar oluşur . Örneğin, değiştirirseniz bounds size, framedeğişiklikler (ve tersi). Değişiklik centergörünümün etrafında gerçekleşir . Aşağıdaki kodu kullanın ve ne olduğunu görün:

NSLog(@"Old Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"Old Center %@", NSStringFromCGPoint(view2.center));    

CGRect frame = view2.bounds;
frame.size.height += 20.0f;
frame.size.width += 20.0f;
view2.bounds = frame;

NSLog(@"New Frame %@", NSStringFromCGRect(view2.frame));
NSLog(@"New Center %@", NSStringFromCGPoint(view2.center));

Değiştirmek Dahası, bounds origindeğiştirmek originiç koordinat sisteminin. Varsayılan originolarak (0.0, 0.0)(en üst köşedir). Örneğin, originiçin öğesini değiştirirseniz, view1artık sol üst köşenin bu view2tuşa dokunduğunu görebilirsiniz (isterseniz önceki kodu yorumlayın) view1. Motivasyon oldukça basit. Sen söylemek view1üst sol köşesi artık pozisyonda olduğunu (20.0, 20.0)ancak o zamandan beri view2bireyin frame origindan başlar (20.0, 20.0), bunlar denk gelecek.

CGRect frame = view1.bounds;
frame.origin.x += 20.0f;
frame.origin.y += 20.0f;
view1.bounds = frame; 

originTemsil eder viewonun içinde pozisyonunu superviewancak konumunu tarif boundsmerkezi.

Son olarak, boundsve originilgili kavramlar değildir. Her ikisi framede bir görünümün türetilmesine izin verir (Önceki denklemlere bakınız).

View1'in örnek olay incelemesi

Aşağıdaki kod parçasını kullanırken neler olduğu aşağıda açıklanmıştır.

UIView* view1 = [[UIView alloc] initWithFrame:CGRectMake(30.0f, 20.0f, 400.0f, 400.0f)];
view1.backgroundColor = [UIColor redColor];

[[self view] addSubview:view1];

NSLog(@"view1's frame is: %@", NSStringFromCGRect([view1 frame]));
NSLog(@"view1's bounds is: %@", NSStringFromCGRect([view1 bounds]));
NSLog(@"view1's center is: %@", NSStringFromCGPoint([view1 center]));

Göreli görüntü.

resim açıklamasını buraya girin

Bunun yerine [self view], aşağıdaki gibi sınırları değiştirirsem ne olur ?

// previous code here...
CGRect rect = [[self view] bounds];
rect.origin.x += 30.0f;
rect.origin.y += 20.0f;
[[self view] setBounds:rect];

Göreli görüntü.

resim açıklamasını buraya girin

Burada [self view]sol üst köşesinin şimdi pozisyonda (30.0, 20.0) olduğunu söylüyorsunuz , ancak view1çerçeve kökeni (30.0, 20.0) 'dan başladığı için çakışıyorlar.

Ek referanslar (isterseniz diğer referanslarla güncellemek için)

Hakkında clipsToBounds(kaynak Apple doc)

Bu değerin EVET olarak ayarlanması, alt görüntülerin alıcının sınırlarına kırpılmasına neden olur. HAYIR olarak ayarlanırsa, çerçeveleri alıcının görünür sınırlarının ötesine uzanan alt görünümler kırpılmaz. Varsayılan değer hayır.

Bile görünüyor eğer başka deyişle, frameolup (0, 0, 100, 100)ve bunun Subview olduğunu (90, 90, 30, 30), bu subview sadece bir kısmını göreceksiniz. İkincisi, üst görünümün sınırlarını aşmayacaktır.

masksToBoundseşittir clipsToBounds. A yerine UIViewbu özellik a öğesine uygulanır CALayer. Kaputun altında clipsToBoundsaramalar masksToBounds. Daha fazla referans için UIView'un clipsToBounds ve CALayer'ın masksToBounds arasındaki ilişki nasıl? .


@Rhubarb Çok haklısın. Cevabımda işaret edeceğim. Teşekkürler.
Lorenzo B

Bir cevap alıp alamayacağımı bilmiyorum ama sınırların kökenleri değiştiğinde alt görünüm neden negatif yönde hareket ediyor. Sadece kafamı o parçanın etrafına doyamıyorum. Teşekkürler!!
nimgrg

@nimgrg Görünüşe göre görünüm olumsuz yönde hareket ediyor ama değil. Denetimin iç koordinatları değiştirilir.
Lorenzo B

geometrik yeteneklerimi affet, eğer denetimin iç koordinatları başlangıç ​​noktasına (30.0, 20.0) değiştirilirse, (0,0) noktası mavi karenin içinde mi yoksa dışında mıdır. Sadece değişiklikleri takip etmeye ve anlamlandırmaya çalışıyorum. Cevaplamak için zaman ayırdığınız için teşekkür ederiz.
nimgrg

@flexaddicted: Merhaba, eklediğiniz slayt şöyle diyor: "B'nin kendi koordinat alanında ortası: bounds.size.width / 2 + origin.x" - neden böyle? Başlık kendi koordinat alanında söylediği için şunu söyleyebilirim: bounds.size.width / 2 + bounds.origin.x ?? Öyle değil mi ??

134

Bu sorunun zaten iyi bir cevabı var, ama daha fazla fotoğrafla tamamlamak istiyorum. Tam cevabım burada.

Çerçeveyi hatırlamama yardımcı olmak için, duvardaki bir resim çerçevesini düşünüyorum . Tıpkı bir resmin duvarın herhangi bir yerine taşınabilmesi gibi, bir görünümün çerçevesinin koordinat sistemi de denetimdir. (duvar = denetim, çerçeve = görünüm)

Sınırları hatırlamama yardımcı olmak için, bir basketbol sahasının sınırlarını düşünüyorum . Basketbol mahkemede bir yerlerde, tıpkı manzaranın sınırlarının koordinat sisteminin manzaranın içinde olduğu gibi. (mahkeme = manzara, basketbol / oyuncular = manzara içindeki içerik)

Çerçeve gibi, view.center da denetimin koordinatlarındadır.

Çerçeve ve Sınırlar - Örnek 1

Sarı dikdörtgen görünümün çerçevesini temsil eder. Yeşil dikdörtgen görünümün sınırlarını temsil eder. Her iki görüntüdeki kırmızı nokta, çerçevenin kaynağını veya koordinat sistemlerindeki sınırları temsil eder.

Frame
    origin = (0, 0)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

resim açıklamasını buraya girin


ÖRNEK 2

Frame
    origin = (40, 60)  // That is, x=40 and y=60
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

resim açıklamasını buraya girin


ÖRNEK 3

Frame
    origin = (20, 52)  // These are just rough estimates.
    width = 118
    height = 187

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

resim açıklamasını buraya girin


Örnek 4

Bu, örnek 2 ile aynıdır, ancak bu sefer görünümün tüm içeriği, görünümün sınırlarına kırpılmamış gibi görünecek şekilde gösterilir.

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (0, 0)
    width = 80
    height = 130

resim açıklamasını buraya girin


Örnek 5

Frame
    origin = (40, 60)
    width = 80
    height = 130

Bounds 
    origin = (280, 70)
    width = 80
    height = 130

resim açıklamasını buraya girin

Yine, daha fazla ayrıntı ile cevabım için buraya bakın.


2
Teşekkürler Suragch. Çerçeve ve sınır farkının gerçekten çok net bir resmi. Çabalarınızı gerçekten takdir ediyorum.
Mohd Haider

Kısa ve öz bir cevapta görmek istediğim tüm şeyler. Teşekkürler!
Matt Chuang

Müthiş! Örnek 3: Anlamıyorum. çerçevenizin başlangıç ​​noktasını biraz hareket ettirdiniz, bu görüntünüzün dönüşünü nasıl değiştirir?
Bal

@ asma22, Örnek 3 Bir görüntüyü döndürdüğünüzde çerçevenin değiştiğini ancak sınırların değişmediğini göstermeye çalışıyordum. Tam yanıtımı görün .
Suragch

89

Bu görüntüyü çerçeve, sınırlar vb. Anlamak için en yararlı buldum.

resim açıklamasını buraya girin

Ayrıca frame.size != bounds.sizegörüntü döndürüldüğünde lütfen unutmayın .


14
Bin kelimeye bedel bir resim.
Narendra Kamma

3
Mümkün olan en iyi açıklama
Ratikanta Patra

@Erben Mo: Merhaba, eklediğiniz slayt şöyle diyor: "B'nin kendi koordinat alanında ortası: bounds.size.width / 2 + origin.x" - neden böyle? Başlık kendi koordinat alanında söylediği için şunu söyleyebilirim: bounds.size.width / 2 + bounds.origin.x ?? Öyle değil mi ??

1
Bu görüntünün kaynağı nedir? Bağlantı?
David

1
@David iTunesU'daki Stanford'un CS193p kursundan: burada bulundu: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fall
preynolds 21:15

3

Bence bunu düşünürseniz CALayer, her şey daha açık.

Çerçeve gerçekten görünümün veya katmanın ayrı bir özelliği değildir, sınırlardan, konumdan (UIView merkez) ve dönüştürmeden .

Temel olarak, katman / görünüm mizanpajlarının bu üç özellik (ve anchorPoint) tarafından nasıl gerçekten karar verildiği ve bu üç özellikten herhangi biri, dönüşümü değiştirmek gibi başka bir özelliği değiştirmeyecektir.


2

Bu gönderinin ayrıntılı açıklaması ile çok iyi cevaplar var. Sadece, Sınırlar, Merkezi, Sınır Kökeni WWDC 2011 video Transform Frame anlamı için görsel gösterimi ile başka bir açıklaması olduğunu ifade etmek istiyorum UIKit Rendering anlama 22 20:10 kadar: @ 4 başlayarak


0

Yukarıdaki cevapları okuduktan sonra, yorumlarımı ekliyorum.

Online gezen, varsayalım web tarayıcısı senin olduğu framekarar verir hangi nerede ve ne büyüklükte web sayfasını göstermek için. Tarayıcı kaydırarakbounds.origin web sayfasının hangi bölümünün gösterileceğine siz karar verirsiniz. bounds.originanlamak zor. Öğrenmenin en iyi yolu, Tek Parametreli Uygulama oluşturmak, bu parametreleri değiştirmeye çalışmak ve alt görüntülerin nasıl değiştiğini görmektir.

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.

UIView *view1 = [[UIView alloc] initWithFrame:CGRectMake(100.0f, 200.0f, 200.0f, 400.0f)];
[view1 setBackgroundColor:[UIColor redColor]];

UIView *view2 = [[UIView alloc] initWithFrame:CGRectInset(view1.bounds, 20.0f, 20.0f)];
[view2 setBackgroundColor:[UIColor yellowColor]];
[view1 addSubview:view2];

[[self view] addSubview:view1];

NSLog(@"Old view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"Old view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));

// Modify this part.
CGRect bounds = view1.bounds;
bounds.origin.x += 10.0f;
bounds.origin.y += 10.0f;

// incase you need width, height
//bounds.size.height += 20.0f;
//bounds.size.width += 20.0f;

view1.bounds = bounds;

NSLog(@"New view1 frame %@, bounds %@, center %@", NSStringFromCGRect(view1.frame), NSStringFromCGRect(view1.bounds), NSStringFromCGPoint(view1.center));
NSLog(@"New view2 frame %@, bounds %@, center %@", NSStringFromCGRect(view2.frame), NSStringFromCGRect(view2.bounds), NSStringFromCGPoint(view2.center));
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.