Bingkai, batas, dan tengah UIView

320

Saya ingin tahu cara menggunakan properti ini dengan cara yang benar.

Seperti yang saya mengerti, framedapat digunakan dari wadah tampilan yang saya buat. Ini mengatur posisi tampilan relatif terhadap tampilan wadah. Ini juga mengatur ukuran tampilan itu.

Juga centerdapat digunakan dari wadah tampilan yang saya buat. Properti ini mengubah posisi tampilan relatif terhadap wadahnya.

Akhirnya, boundsrelatif terhadap pandangan itu sendiri. Ini mengubah area yang dapat digambar untuk tampilan.

Bisakah Anda memberikan info lebih lanjut tentang hubungan antara framedan bounds? Bagaimana dengan clipsToBoundsdan masksToBoundspropertinya?

Lorenzo B
sumber
1
Diskusi ini sudah diselesaikan di sini. jadi tolong lihat di sini atau lihat Dokumentasi pengembang yang diberikan di sini developer.apple.com/library/ios/#documentation/uikit/reference/… stackoverflow.com/questions/1210047/… slideshare.net/onoaonoa/cs193p-lecture-5 -view-animation
Splendid

Jawaban:

577

Karena pertanyaan yang saya ajukan telah dilihat berulang kali, saya akan memberikan jawaban terperinci. Jangan ragu untuk memodifikasinya jika Anda ingin menambahkan lebih banyak konten yang benar.

Pertama rekap pada pertanyaan: bingkai, batas dan pusat dan hubungan mereka.

Frame A view's frame( CGRect) adalah posisi persegi panjangnya di superviewsistem koordinat. Secara default dimulai di kiri atas.

Bounds A view's bounds( CGRect) mengekspresikan persegi panjang view dalam sistem koordinatnya sendiri.

Pusat A centeradalah CGPointdinyatakan dalam superviewsistem koordinat dan menentukan posisi titik tengah tampilan yang tepat.

Diambil dari posisi UIView + ini adalah hubungan (mereka tidak bekerja dalam kode karena mereka adalah persamaan informal) di antara properti sebelumnya:

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

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

  • frame.size = bounds.size

CATATAN: Hubungan ini tidak berlaku jika tampilan diputar. Untuk info lebih lanjut, saya sarankan Anda melihat gambar berikut yang diambil dari The Kitchen Drawer berdasarkan kursus Stanford CS193p . Kredit diberikan ke @Rhubarb .

Bingkai, batas dan tengah

Dengan menggunakan, frameAnda dapat mengubah posisi dan / atau mengubah ukuran tampilan di dalamnya superview. Biasanya dapat digunakan dari superview, misalnya, saat Anda membuat subview tertentu. Sebagai contoh:

// 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];

Ketika Anda membutuhkan koordinat untuk menggambar di dalam, viewAnda biasanya merujuk bounds. Contoh tipikalnya adalah menggambar dalam viewsubview sebagai inset yang pertama. Menggambar subview perlu mengetahui boundssuperview. Sebagai contoh:

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

Perilaku yang berbeda terjadi ketika Anda mengubah boundstampilan. Misalnya, jika Anda mengubah bounds size, frameperubahan (dan sebaliknya). Perubahan terjadi di sekitar centertampilan. Gunakan kode di bawah ini dan lihat apa yang terjadi:

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));

Selanjutnya, jika Anda mengubah bounds originAnda mengubah originsistem koordinat internal. Secara default originberada di (0.0, 0.0)(sudut kiri atas). Misalnya, jika Anda mengubah originuntuk view1Anda dapat melihat (komentar kode sebelumnya jika Anda mau) yang sekarang sudut kiri atas untuk view2menyentuh yang view1. Motivasinya cukup sederhana. Anda mengatakan kepada view1bahwa sudut kiri atas kini berada pada posisi (20.0, 20.0)tapi karena view2's frame originmulai dari (20.0, 20.0), mereka akan bertepatan.

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

Ini originmewakili viewposisi dalam superviewtetapi menggambarkan posisi boundspusat.

Akhirnya, boundsdan origintidak terkait konsep. Keduanya memungkinkan untuk memperoleh frametampilan (Lihat persamaan sebelumnya).

Studi kasus View1

Inilah yang terjadi ketika menggunakan cuplikan berikut.

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]));

Gambar relatif.

masukkan deskripsi gambar di sini

Ini yang terjadi jika saya mengubah [self view]batasan seperti berikut.

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

Gambar relatif.

masukkan deskripsi gambar di sini

Di sini Anda mengatakan [self view]bahwa sudut kiri atas sekarang berada di posisi (30.0, 20.0) tetapi karena view1asal bingkai dimulai dari (30.0, 20.0), mereka akan bertepatan.

Referensi tambahan (untuk memperbarui dengan referensi lain jika Anda mau)

Tentang clipsToBounds(sumber Apple doc)

Menetapkan nilai ini ke YA menyebabkan subview terpotong pada batas-batas penerima. Jika diatur ke TIDAK, subview yang bingkainya melampaui batas yang terlihat dari receiver tidak terpotong. Nilai standarnya adalah TIDAK.

Dengan kata lain, jika tampilan frameadalah (0, 0, 100, 100)dan subview-nya (90, 90, 30, 30), Anda hanya akan melihat sebagian dari subview itu. Yang terakhir tidak akan melebihi batas tampilan induk.

masksToBoundssetara dengan clipsToBounds. Alih-alih ke UIView, properti ini diterapkan ke CALayer. Di bawah tenda, clipsToBoundspanggilan masksToBounds. Untuk referensi lebih lanjut, lihat Bagaimana hubungan antara clipsToBounds UIView dan maskALToBounds CALayer? .

Lorenzo Boaro
sumber
@Rhubarb Anda benar sekali. Saya akan menunjukkannya dalam jawaban saya. Terima kasih.
Lorenzo B
Saya tidak tahu apakah saya akan mendapatkan jawaban tetapi mengapa subview bergerak ke arah negatif ketika batas asal diubah. Sepertinya tidak bisa mendapatkan kepalaku sekitar itu. Terima kasih!!
nimgrg
@nimgrg Tampaknya pandangan bergerak ke arah negatif tetapi tidak. Koordinat internal superview diubah.
Lorenzo B
maafkan kemampuan geometrik saya, jika koordinat internal superview diubah ke asal (30.0, 20.0), apakah titik (0,0) terletak di dalam kotak biru atau di luarnya. Saya hanya mencoba melacak perubahan dan membuatnya masuk akal. Terima kasih telah meluangkan waktu untuk menjawab.
nimgrg
@flexaddicted: Hai, slide yang Anda tambahkan mengatakan: "Lihat tengah B di ruang koordinatnya sendiri adalah: bounds.size.width / 2 + origin.x" - mengapa demikian? Karena judulnya mengatakan dalam ruang koordinatnya sendiri , saya akan mengatakan itu adalah: bounds.size.width / 2 + bounds.origin.x ?? Bukan ??
134

Pertanyaan ini sudah memiliki jawaban yang bagus, tetapi saya ingin menambahkannya dengan beberapa gambar. Jawaban lengkap saya ada di sini.

Untuk membantu saya mengingat bingkai , saya memikirkan bingkai foto di dinding . Seperti halnya gambar dapat dipindahkan ke mana saja di dinding, sistem koordinat bingkai tampilan adalah superview. (dinding = superview, bingkai = tampilan)

Untuk membantuku mengingat batasan , aku memikirkan batasan lapangan basket . Bola basket berada di suatu tempat di dalam pengadilan seperti halnya sistem koordinat batas tampilan dalam pandangan itu sendiri. (pengadilan = tampilan, bola basket / pemain = konten di dalam tampilan)

Seperti halnya bingkai, view.center juga berada dalam koordinat superview.

Frame vs Bounds - Contoh 1

Kotak kuning mewakili bingkai tampilan. Kotak hijau mewakili batas tampilan. Titik merah di kedua gambar mewakili asal bingkai atau batas dalam sistem koordinat mereka.

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

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

masukkan deskripsi gambar di sini


Contoh 2

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

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

masukkan deskripsi gambar di sini


Contoh 3

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

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

masukkan deskripsi gambar di sini


Contoh 4

Ini sama dengan contoh 2, kecuali kali ini seluruh konten tampilan ditampilkan karena akan terlihat seperti jika tidak terpotong pada batas tampilan.

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

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

masukkan deskripsi gambar di sini


Contoh 5

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

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

masukkan deskripsi gambar di sini

Sekali lagi, lihat di sini untuk jawaban saya dengan lebih detail.

Suragch
sumber
2
Terima kasih Suragch. Ini benar-benar gambaran yang sangat jelas tentang bingkai dan perbedaan terikat. Saya sangat menghargai upaya Anda.
Mohd Haider
Semua hal yang ingin saya lihat dalam satu jawaban singkat dan ringkas. Terima kasih!
Matt Chuang
Luar biasa! Sebagai Contoh 3: Saya tidak mengerti. Anda hanya sedikit memindahkan asal bingkai, bagaimana hal itu mengubah rotasi gambar Anda?
Sayang
@ asma22, Pada contoh 3 saya hanya mencoba untuk menunjukkan bahwa ketika Anda memutar gambar bingkai berubah tetapi batas tidak. Lihat jawaban saya yang lebih lengkap .
Suragch
89

Saya menemukan gambar ini paling membantu untuk memahami bingkai, batas, dll.

masukkan deskripsi gambar di sini

Harap perhatikan juga bahwa frame.size != bounds.sizeketika gambar diputar.

Erben Mo
sumber
14
Sebuah gambar yang bernilai ribuan kata.
Narendra Kamma
3
Penjelasan terbaik yang mungkin
Ratikanta Patra
@ Erben Mo: Hai, slide yang Anda tambahkan mengatakan: "Lihat tengah B di ruang koordinatnya sendiri adalah: bounds.size.width / 2 + origin.x" - mengapa demikian? Karena judulnya mengatakan dalam ruang koordinatnya sendiri , saya akan mengatakan itu adalah: bounds.size.width / 2 + bounds.origin.x ?? Bukan ??
1
Apa sumber gambar ini? Tautan?
David
1
@David Ini dari kursus CS193p Stanford di iTunesU ditemukan di sini: www.stanford.edu/class/cs193p/cgi-bin/drupal/downloads-2013-fall
preynolds
3

Saya pikir jika Anda berpikir dari sudut pandang CALayer, semuanya lebih jelas.

Frame sebenarnya bukan properti yang berbeda dari tampilan atau layer sama sekali, itu adalah properti virtual, dihitung dari batas, posisi ( UIViewpusat), dan transformasi.

Jadi pada dasarnya bagaimana tata letak lapisan / tampilan benar-benar ditentukan oleh ketiga properti ini (dan anchorPoint), dan salah satu dari ketiga properti ini tidak akan mengubah properti lainnya, seperti mengubah transformasi tidak mengubah batas.

coolbeet
sumber
2

Ada jawaban yang sangat bagus dengan penjelasan terperinci untuk posting ini. Saya hanya ingin merujuk bahwa ada penjelasan lain dengan representasi visual untuk makna Frame, Batas, Pusat, Transform, Batas Asal dalam video WWDC 2011 Memahami Rendering UIKit mulai dari @ 4: 22 hingga 20:10

Wael Showair
sumber
0

Setelah membaca jawaban di atas, di sini menambahkan interpretasi saya.

Misalkan browsing online, browser web adalah Anda frameyang menentukan di mana dan seberapa besar untuk menampilkan halaman web. Scroller browser adalah milik Anda bounds.originyang menentukan bagian halaman web mana yang akan ditampilkan. bounds.originsulit dimengerti. Cara terbaik untuk belajar adalah membuat Aplikasi Tampilan Tunggal, mencoba memodifikasi parameter ini dan melihat bagaimana perubahan tampilan.

- (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));
NSTNF
sumber