Merata ruang banyak tampilan dalam tampilan wadah

279

Tata Letak Otomatis membuat hidup saya sulit. Secara teori, itu akan sangat berguna ketika saya berganti, tapi sepertinya saya terus berjuang sepanjang waktu.

Saya telah membuat proyek demo untuk mencoba mencari bantuan. Adakah yang tahu cara membuat ruang di antara tampilan bertambah atau berkurang secara merata setiap kali tampilan diubah ukurannya?

Berikut adalah tiga label (spasi manual secara vertikal):

image1

Yang saya inginkan adalah mereka mengubah ukuran spasi mereka (bukan ukuran tampilan) secara merata ketika saya memutar. Secara default, tampilan atas dan bawah melengkung ke tengah:

image2

nothappybob
sumber
mungkin menetapkan batasan dari satu label ke label lain, dan mengatur mereka hubungan "lebih besar atau sama dengan" akan membantu
BergP
terprogram misalnya dengan menggunakan metode NSLayoutConstraint: + (id) constraintWithItem: (id) view1 atribut: (NSLayoutAttribute) attr1 relatedBy: (NSLayoutRelation) kaitannya denganItem: (id) view2 atribut: (NSLayoutAttribute) di multiplier multipel konstan: (CGFloat) c
BergP
Saya membuka sumber pengganti UITabBar generik yang menggeneralisasikan pendekatan ini menggunakan Tata Letak Otomatis. Anda dapat memeriksa tes untuk melihat bagaimana saya menghasilkan kendala Tata Letak Otomatis saya. GGTabBar
Goles

Jawaban:

211

Jadi pendekatan saya memungkinkan Anda untuk melakukan ini dalam pembangun antarmuka. Apa yang Anda lakukan adalah membuat 'tampilan spacer' yang telah Anda atur agar sesuai dengan ketinggian. Kemudian tambahkan batasan atas dan bawah ke label (lihat tangkapan layar).

masukkan deskripsi gambar di sini

Lebih khusus lagi, saya memiliki batasan teratas pada 'Tampilan Spacer 1' untuk melakukan superview dengan batasan ketinggian prioritas lebih rendah dari 1000 dan dengan Ketinggian yang Sama dengan semua 'tampilan spacer' lainnya. 'Spacer View 4' memiliki batasan ruang bawah untuk superview. Setiap label memiliki batasan atas dan bawah masing-masing untuk 'tampilan spacer' terdekat.

Catatan: Pastikan Anda TIDAK memiliki batasan ruang atas / bawah ekstra pada label Anda untuk ditinjau; hanya yang ke 'tampilan ruang'. Ini akan memuaskan karena kendala atas dan bawah ada di 'Space View 1' dan 'Spacer View 4'.

Duh 1: Saya menggandakan pandangan saya dan hanya meletakkannya dalam mode lansekap sehingga Anda bisa melihatnya bekerja

Duh 2: 'Tampilan spacer' bisa transparan.

Duh 3: Pendekatan ini bisa diterapkan secara horizontal.

Spencer Hall
sumber
10
Ini bekerja. Bahkan tampilan spacer dapat disembunyikan dan mereka masih akan menghasilkan tata letak yang benar.
paulmelnikow
Ini sangat membantu. Seperti komentar tentang menandai tampilan spacer sebagai tersembunyi. Maka Anda masih bisa melihatnya di storyboard / xib Anda, tetapi mereka tidak muncul di aplikasi Anda. Sangat bagus.
shulmey
Saya berhasil hampir bekerja setelah beberapa jam upaya berulang. Sayangnya Xcode terus menghapus batasan ruang atas-ke-tombol dan ruang-bawah saya, memutus rantai antara tombol dan spacer, dan menggantinya dengan batasan ruang-ke-superview sewenang-wenang yang tidak berguna.
Desty
Pendekatan yang sama bekerja untuk saya dalam tata letak horizontal - Saya memiliki tampilan lebar tetap yang dipisahkan oleh tampilan lebar spacer yang sama. Sangat bagus bahwa saya tidak perlu mencampurnya dengan kode apa pun. Terima kasih!
Kamil Nomtek.com
2
Tidak perlu menggunakan spacer. Lihat jawaban saya di bawah ini.
smileBot
316

LIHAT, TANPA SPACER!

Berdasarkan saran di bagian komentar pada jawaban asli saya, terutama saran bermanfaat @ Rivera, saya telah menyederhanakan jawaban asli saya.

Saya menggunakan gif untuk menggambarkan betapa sederhananya ini. Saya harap Anda menemukan gif bermanfaat. Kalau-kalau Anda memiliki masalah dengan gif, saya sudah menyertakan jawaban lama di bawah ini dengan tangkapan layar biasa.

Instruksi:

1) Tambahkan tombol atau label Anda. Saya menggunakan 3 tombol.

2) Tambahkan batasan x pusat dari setiap tombol ke superview:

masukkan deskripsi gambar di sini

3) Tambahkan batasan dari setiap tombol ke batasan tata letak bawah:

masukkan deskripsi gambar di sini

4) Sesuaikan kendala yang ditambahkan pada # 3 di atas sebagai berikut:

a) pilih batasannya, b) hapus konstanta (atur ke 0), c) ubah pengali sebagai berikut: ambil jumlah tombol + 1, dan mulai dari atas, atur pengali sebagai tombolCountPlus1: 1 , lalu tombolCountPlus1 : 2 , dan akhirnya buttonCountPlus1: 3 . (Saya jelaskan dari mana saya mendapat formula ini dari jawaban lama di bawah, jika Anda tertarik).

masukkan deskripsi gambar di sini

5) Ini demo berjalan!

masukkan deskripsi gambar di sini

Catatan: Jika tombol Anda memiliki ketinggian yang lebih besar maka Anda perlu mengkompensasi hal ini dalam nilai konstan karena batasannya adalah dari bagian bawah tombol.


Jawaban Lama


Terlepas dari apa yang dikatakan oleh dokumen Apple dan buku hebat Erica Sadun ( Auto Layout Demystified ), adalah mungkin untuk menyamakan tampilan ruang tanpa spacer. Ini sangat mudah dilakukan di IB dan dalam kode untuk sejumlah elemen yang ingin Anda tempatkan secara merata. Yang Anda butuhkan hanyalah rumus matematika yang disebut "rumus bagian". Lebih mudah dilakukan daripada menjelaskan. Saya akan melakukan yang terbaik dengan mendemonstrasikannya dalam IB, tetapi itu mudah dilakukan dalam kode.

Dalam contoh yang dimaksud, Anda akan melakukannya

1) mulai dengan mengatur setiap label untuk memiliki batasan tengah. Ini sangat mudah dilakukan. Cukup kendalikan drag dari setiap label ke bawah.

2) Tahan shift, karena Anda mungkin juga menambahkan kendala lain yang akan kita gunakan, yaitu, "ruang bawah ke panduan tata letak bawah".

3) Pilih "panduan tata ruang bawah ke bawah", dan "tengah secara horizontal dalam wadah". Lakukan ini untuk ketiga label.

Tahan shift untuk menambahkan dua batasan ini untuk setiap label

Pada dasarnya, jika kita mengambil label yang koordinatnya ingin kita tentukan dan membaginya dengan jumlah total label ditambah 1, maka kita memiliki nomor yang dapat kita tambahkan ke IB untuk mendapatkan lokasi yang dinamis. Saya menyederhanakan formula, tetapi Anda bisa menggunakannya untuk mengatur jarak horizontal atau vertikal dan horizontal secara bersamaan. Ini sangat kuat!

Inilah pengganda kami.

Label1 = 1/4 = .25,

Label2 = 2/4 = .5,

Label3 = 3/4 = .75

(Sunting: @Rivera berkomentar bahwa Anda dapat menggunakan rasio langsung di bidang pengali, dan xCode dengan melakukan matematika!)

4) Jadi, mari kita pilih Label1 dan pilih batasan bawah. Seperti ini: masukkan deskripsi gambar di sini

5) Pilih "Item Kedua" di Inspektur Atribut.

6) Dari drop down pilih "Reverse item pertama dan kedua".

7) Nol keluar dari nilai konstanta dan wC hAny. (Anda dapat menambahkan offset di sini jika Anda membutuhkannya).

8) Ini adalah bagian penting: Di bidang pengali tambahkan pengali pertama kami 0,25.

9) Ketika Anda mengaturnya, atur "Item pertama" ke "Tengah" karena kami ingin menempatkannya di tengah label y. Begini caranya semua itu harus terlihat.

masukkan deskripsi gambar di sini

10) Ulangi proses ini untuk setiap label dan pasang pengganda yang relevan: 0,5 untuk Label2, dan 0,75 untuk Label3. Inilah produk akhir dalam semua orientasi dengan semua perangkat ringkas! Sangat sederhana. Saya telah melihat banyak solusi yang melibatkan rim kode, dan spacer. Ini adalah solusi terbaik yang pernah saya lihat dalam masalah ini.

Pembaruan: @kraftydevil menambahkan bahwa panduan tata letak bawah hanya muncul di storyboard, bukan di xibs. Gunakan 'Bottom Space to Container' di xibs. Tangkapan yang bagus!

masukkan deskripsi gambar di sini

smileBot
sumber
2
Saya masih berjuang dengan itu. Saya pikir Anda harus menggunakan Xcode 6 karena tidak ada opsi 'wC hAny' di kendala Xcode 5. Ketika saya mengikuti instruksi Anda, semua subview macet ke tengah atas.
kraftydevil
4
@kraftydevil AFAIK Panduan tata letak bawah hanya muncul di storyboard, bukan di xibs. Gunakan 'Bottom Space to Container' di xibs.
Timur Kuchkarov
6
Oh - juga patut dicatat bahwa IB di Xcode 6 mendukung pengganda rasio, sehingga Anda dapat memasukkan hal-hal seperti "1: 4", "2: 5", "3: 4", dll.
Benjohn
3
Mencoba mencari tahu bagaimana melakukan ini secara horizontal - seperti TextView 1/3 pertama dari kiri, dan TextView 2/3 kedua (sisa jalan) ... ... (EDIT) mendapatkannya - lakukan 1/3 (kiri) Trailing-Space ke Right Margin, terbalik, nol, tetapkan seperti sebelumnya ...
kfmfe04
3
Untuk penspasian horizontal, cukup atur kendala trailing ke superview untuk setiap subview, lalu tetapkan misalnya pengali rasio. 5: 1, 5: 2, 5: 3, dll. Bergerak dari kiri ke kanan.
user3344977
98

Solusi Interface Builder yang sangat cepat:

Agar sejumlah tampilan ditempatkan secara merata dalam superview, cukup berikan masing-masing batasan "Align Center X to superview" untuk tata letak horizontal, atau "Align Center Y superview" untuk tata letak vertikal, dan atur Pengali menjadi N:p( CATATAN: beberapa lebih beruntung dengan p:N- lihat di bawah )

dimana

N = total number of views, dan

p = position of the view including spaces

Posisi pertama adalah 1, lalu spasi, membuat posisi berikutnya 3, jadi p menjadi seri [1,3,5,7,9, ...]. Berfungsi untuk sejumlah tampilan.

Jadi, jika Anda memiliki 3 tampilan ke luar, sepertinya ini:

Ilustrasi cara menyebarkan pandangan secara merata di IB

EDIT Note: Pilihan N:patau p:Ntergantung pada urutan relasi dari kendala alignment Anda. Jika "Item Pertama" adalah Superview.Center, Anda dapat menggunakan p:N, sedangkan jika Superview.Center adalah "Item Kedua", Anda dapat menggunakan N:p. Jika ragu, coba saja keduanya ... :-)

Memberikan
sumber
Solusi ini tidak akan mencerminkan desain jika Anda beralih ke bahasa lain
WOD
@wod Apa maksudmu? Beralih apa ke bahasa lain? Dan apa tepatnya yang rusak?
Mete
4
bagaimana jika elemen tidak memiliki ukuran yang sama? pola ini tidak akan berfungsi dengan benar bukan?
ucangetit
2
Saya tidak mengerti bagaimana solusi ini benar? Kesenjangan antara tepi layar dan elemen luar berbeda dengan kesenjangan antara elemen luar dan elemen tengah?
myles
6
Ini bukan untuk saya "sebagaimana adanya" Saya harus membalikkan pengganda (mis. 3: 1 dari item pertama dikonversi menjadi 1: 3). Hanya melempar ini ke luar jika itu membantu siapa pun.
Ces
70

Pada iOS 9, Apple telah membuat ini sangat mudah dengan (lama ditunggu) UIStackView. Cukup pilih tampilan yang ingin Anda isi di Interface Builder dan pilih Editor -> Embed In -> Stack view. Tetapkan batasan lebar / tinggi / margin yang sesuai untuk tampilan tumpukan, dan pastikan untuk mengatur properti Distribusi ke 'Penempatan yang sama':

Tentu saja, jika Anda perlu mendukung iOS 8 atau lebih rendah, Anda harus memilih salah satu opsi lain.

Glorfindel
sumber
Yap, ini menyedihkan bahwa ini tidak memiliki kompatibilitas retro, jadi sampai aplikasi Anda membutuhkan dukungan untuk IOS8 @Mete tanggapan adalah yang terbaik untuk saat ini.
ZiggyST
51

Saya telah naik rollercoaster cinta autolayout dan membencinya. Kunci untuk mencintai tampaknya menerima hal-hal berikut:

  1. Pengeditan antarmuka pembuat dan "membantu" penciptaan kendala hampir tidak berguna untuk semua kecuali kasus yang paling sepele
  2. Membuat kategori untuk menyederhanakan operasi umum adalah penyelamat karena kode ini sangat berulang dan bertele-tele.

Yang mengatakan, apa yang Anda coba tidak mudah dan akan sulit untuk dicapai dalam pembangun antarmuka. Sangat mudah dilakukan dalam kode. Kode ini, dalam viewDidLoad, menciptakan dan menempatkan tiga label bagaimana Anda memintanya:

// Create three labels, turning off the default constraints applied to views created in code
UILabel *label1 = [UILabel new];
label1.translatesAutoresizingMaskIntoConstraints = NO;
label1.text = @"Label 1";

UILabel *label2 = [UILabel new];
label2.translatesAutoresizingMaskIntoConstraints = NO;
label2.text = @"Label 2";

UILabel *label3 = [UILabel new];
label3.translatesAutoresizingMaskIntoConstraints = NO;
label3.text = @"Label 3";

// Add them all to the view
[self.view addSubview:label1];
[self.view addSubview:label2];
[self.view addSubview:label3];

// Center them all horizontally
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1.0 constant:0]];

// Center the middle one vertically
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label2 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterY multiplier:1.0 constant:0]];

// Position the top one half way up
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label1 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:0.5 constant:0]];

// Position the bottom one half way down
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:label3 attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:label2 attribute:NSLayoutAttributeCenterY multiplier:1.5 constant:0]];

Seperti yang saya katakan, kode ini jauh disederhanakan dengan beberapa metode kategori UIView, tetapi untuk kejelasan saya sudah melakukannya jauh di sini.

Kategori ini ada di sini untuk mereka yang tertarik, dan memiliki metode untuk secara merata mengatur jarak tampilan di sepanjang sumbu tertentu.

jrturton
sumber
Anda Tuan, adalah penyelamat. Saya tidak mengerti # 1 sampai sekarang. Pembuat antarmuka membuat saya gila, tapi saya pikir itu bisa melakukan semua hal yang sama. Saya lebih suka menggunakan kode, jadi ini sempurna, dan saya akan langsung menggunakan metode kategorinya.
nothappybob
Meskipun pasti cukup dekat, ini tidak cukup memecahkan masalah yang ditanyakan (menjaga ukuran tampilan tetap sama dengan jarak antar subview). Solusi ini adalah jawaban kasus umum yang disempurnakan.
smileyborg
21

Sebagian besar solusi ini bergantung pada jumlah item ganjil sehingga Anda dapat mengambil item tengah dan menempatkannya di tengah. Bagaimana jika Anda memiliki jumlah barang merata yang masih ingin Anda bagikan secara merata? Inilah solusi yang lebih umum. Kategori ini secara merata akan mendistribusikan sejumlah item di sepanjang sumbu vertikal atau horizontal.

Contoh penggunaan untuk mendistribusikan 4 label secara vertikal dalam superview mereka:

[self.view addConstraints:
     [NSLayoutConstraint constraintsForEvenDistributionOfItems:@[label1, label2, label3, label4]
                                        relativeToCenterOfItem:self.view
                                                    vertically:YES]];

NSLayoutConstraint + EvenDistribution.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of views to be evenly distributed horizontally
 * or vertically relative to the center of another item. This is used to maintain an even
 * distribution of subviews even when the superview is resized.
 */
+ (NSArray *) constraintsForEvenDistributionOfItems:(NSArray *)views
                             relativeToCenterOfItem:(id)toView
                                         vertically:(BOOL)vertically;

@end

NSLayoutConstraint + EvenDistribution.m

@implementation NSLayoutConstraint (EvenDistribution)

+(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                           relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
{
    NSMutableArray *constraints = [NSMutableArray new];
    NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;

    for (NSUInteger i = 0; i < [views count]; i++) {
        id view = views[i];
        CGFloat multiplier = (2*i + 2) / (CGFloat)([views count] + 1);
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                      attribute:attr
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:toView
                                                                      attribute:attr
                                                                     multiplier:multiplier
                                                                       constant:0];
        [constraints addObject:constraint];
    }

    return constraints;
}

@end
Ben Dolman
sumber
1
Ini bekerja dengan menghapus semua kendala dan segera setelah itu, menambahkan batasan Lebar dan Tinggi ke objek-objek itu, kemudian memanggil metode constraintForEvenDistributionOfItems: relativeToCenterOfItem: vertikal:
carlos_ms
@carlos_ms Saya ingin sekali melihat kode Anda, karena ketika saya mencoba dengan jumlah item genap, kode ini berfungsi dengan sempurna ketika mengganti orientasi perangkat. Apakah Anda yakin tidak secara tidak sengaja memiliki beberapa kendala lain (seperti kendala autoresizing) yang menyebabkan konflik?
Ben Dolman
Berikut adalah contoh membuat 4 label dan menempatkannya secara merata di sepanjang sumbu vertikal: gist.github.com/bdolman/5379465
Ben Dolman
20

Cara yang benar dan termudah adalah dengan menggunakan Stack Views.

  1. Tambahkan label / tampilan Anda ke Stack View :

masukkan deskripsi gambar di sini

  1. Pilih Stack View dan atur Distribusi menjadi Equal Spacing :

masukkan deskripsi gambar di sini

  1. Tambahkan Spacing ke batasan tetangga terdekat ke Stack View dan perbarui frame:

masukkan deskripsi gambar di sini

  1. Tambahkan batasan Ketinggian untuk semua label (opsional). Diperlukan hanya untuk tampilan yang tidak memiliki Ukuran Intrinsik). Label misalnya tidak perlu di sini batasan ketinggian dan hanya perlu mengatur numberOfLines = 3 atau 0 misalnya.

masukkan deskripsi gambar di sini

  1. Nikmati Pratinjau:

masukkan deskripsi gambar di sini

Oleh Kudinov
sumber
2
Ini> = iOS 9.0 saja jadi periksa target penyebaran Anda sebelum Anda mulai menerapkan :) Senang melihat ini telah ditambahkan sekalipun!
DivideByZer0
1
2018 sekarang, gunakan tampilan tumpukan
Jingshao Chen
17

Lihat pustaka sumber terbuka PureLayout . Ini menawarkan beberapa metode API untuk mendistribusikan tampilan, termasuk varian di mana jarak antara setiap tampilan ditetapkan (ukuran tampilan bervariasi sesuai kebutuhan), dan di mana ukuran setiap tampilan ditetapkan (jarak antar tampilan bervariasi sesuai kebutuhan). Perhatikan bahwa semua ini dilakukan tanpa menggunakan "tampilan spacer".

Dari NSArray + PureLayout.h :

// NSArray+PureLayout.h

// ...

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (variable) in the dimension along the axis and will have spacing (fixed) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                         withFixedSpacing:(CGFloat)spacing;

/** Distributes the views in this array equally along the selected axis in their superview. Views will be the same size (fixed) in the dimension along the axis and will have spacing (variable) between them. */
- (NSArray *)autoDistributeViewsAlongAxis:(ALAxis)axis
                                alignedTo:(ALAttribute)alignment
                            withFixedSize:(CGFloat)size;

// ...

Karena itu semua open source, jika Anda tertarik untuk melihat bagaimana ini dicapai tanpa spacer tampilan lihat saja implementasinya. (Itu tergantung pada pengungkit baik untuk constant maupun multiplier untuk kendala.)

smileyborg
sumber
Kerja bagus! Meskipun Anda mungkin harus mengganti nama repo sehingga Anda dapat membuatnya tersedia melalui cocoapods.
jrturton
9

Saya mengalami masalah yang sama dan menemukan posting ini. Namun, tidak ada jawaban yang tersedia saat ini memecahkan masalah dengan cara yang Anda inginkan. Mereka tidak membuat spasi sama, melainkan mendistribusikan pusat label secara merata. Penting untuk dipahami bahwa ini tidak sama. Saya telah membuat diagram kecil untuk menggambarkan hal ini.

Lihat Spacing Illustration

Ada 3 tampilan, semuanya 20pt tinggi. Menggunakan salah satu metode yang disarankan mendistribusikan pusat pandangan secara merata dan memberi Anda tata letak bergambar. Perhatikan bahwa pusat-y dari tampilan diberi jarak yang sama. Namun, jarak antara tampilan superview dan tampilan atas adalah 15pt, sedangkan jarak antara tampilan tampilan hanya 5pt. Agar tampilan spasi sama, keduanya harus 10pt, yaitu semua panah biru harus 10pt.

Meskipun demikian, saya belum menemukan solusi generik yang bagus. Saat ini ide terbaik saya adalah memasukkan "spacing views" antara subview dan mengatur ketinggian tampilan spacing agar sama.

Florian
sumber
1
Saya telah menggunakan solusi pandangan spacer tersembunyi, yang berfungsi dengan baik.
paulmelnikow
8

Saya bisa menyelesaikan ini sepenuhnya di IB:

  1. Buat batasan untuk menyelaraskan pusat Y dari masing-masing subview Anda ke tepi bawah superview.
  2. Atur pengali dari masing-masing kendala ini menjadi 1 / 2n, 3 / 2n, 5 / 2n,…, n-1 / 2n di mana n adalah jumlah subview yang Anda distribusikan.

Jadi jika Anda memiliki tiga label, atur pengganda ke masing-masing kendala tersebut ke 0,1666667, 0,5, 0,833333.

hayesk
sumber
1
Saya benar-benar harus melakukan 1 / n 3 / n 5 / n 7 / n hingga (2n-1) / n
Hamzah Malik
5

Saya menemukan metode yang sempurna dan sederhana. Tata letak otomatis tidak memungkinkan Anda untuk mengubah ukuran spasi secara merata, tetapi memungkinkan Anda untuk mengubah ukuran tampilan secara merata. Cukup taruh beberapa tampilan tak terlihat di antara bidang Anda dan beri tahu tata letak otomatis agar ukurannya tetap sama. Itu bekerja dengan sempurna!

XIB awal

Membentang XIB

Satu hal yang perlu diperhatikan; ketika saya mengurangi ukuran di perancang antarmuka, kadang-kadang menjadi bingung dan meninggalkan label di tempat itu, dan itu memiliki konflik jika ukuran diubah oleh jumlah yang ganjil. Kalau tidak, itu bekerja dengan sempurna.

sunting: Saya menemukan bahwa konflik menjadi masalah. Karena itu, saya mengambil salah satu batasan spasi, menghapusnya dan menggantinya dengan dua kendala, yang lebih besar dari atau sama dan kurang sama atau sama. Keduanya berukuran sama dan memiliki prioritas yang jauh lebih rendah daripada kendala lainnya. Hasilnya tidak ada konflik lebih lanjut.

Owen Godfrey
sumber
4

Membangun jawaban Ben Dolman, ini mendistribusikan pandangan lebih merata (dengan padding, dll):

+(NSArray *)constraintsForEvenDistributionOfItems:(NSArray *)views
                           relativeToCenterOfItem:(id)toView vertically:(BOOL)vertically
{
    NSMutableArray *constraints = [NSMutableArray new];
    NSLayoutAttribute attr = vertically ? NSLayoutAttributeCenterY : NSLayoutAttributeCenterX;

    CGFloat min = 0.25;
    CGFloat max = 1.75;
    CGFloat d = (max-min) / ([views count] - 1);
    for (NSUInteger i = 0; i < [views count]; i++) {
        id view = views[i];
        CGFloat multiplier = i * d + min;
        NSLayoutConstraint *constraint = [NSLayoutConstraint constraintWithItem:view
                                                                      attribute:attr
                                                                      relatedBy:NSLayoutRelationEqual
                                                                         toItem:toView
                                                                      attribute:attr
                                                                     multiplier:multiplier
                                                                       constant:0];
        [constraints addObject:constraint];
    }

    return constraints;
}
Ray W
sumber
3

Dengan label, setidaknya ini berfungsi dengan baik:

@"H:|-15-[first(==second)]-[second(==third)]-[third(==first)]-15-|

Jika yang pertama memiliki lebar yang sama dengan yang kedua, dan yang kedua yang ketiga, dan yang ketiga yang pertama, maka mereka semua akan mendapatkan lebar yang sama ... Anda bisa melakukannya secara horizontal (H) dan vertikal (V).

Johannes
sumber
3

versi 3 cepat

let _redView = UIView()
        _redView.backgroundColor = UIColor.red
        _redView.translatesAutoresizingMaskIntoConstraints = false

        let _yellowView = UIView()
        _yellowView.backgroundColor = UIColor.yellow
        _yellowView.translatesAutoresizingMaskIntoConstraints = false

        let _blueView = UIView()
        _blueView.backgroundColor = UIColor.blue
        _blueView.translatesAutoresizingMaskIntoConstraints = false

        self.view.addSubview(_redView)
        self.view.addSubview(_yellowView)
        self.view.addSubview(_blueView)

        var views = ["_redView": _redView, "_yellowView": _yellowView, "_blueView":_blueView]

        var nslayoutConstraint_H = NSLayoutConstraint.constraints(withVisualFormat: "|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|", options: [.alignAllTop, .alignAllBottom], metrics: nil, views: views)
        self.view.addConstraints(nslayoutConstraint_H)

        var nslayoutConstraint_V = NSLayoutConstraint.constraints(withVisualFormat: "V:[_redView(60)]", options: NSLayoutFormatOptions.init(rawValue: 0), metrics: nil, views: views)
        self.view.addConstraints(nslayoutConstraint_V)


        let constraint_red = NSLayoutConstraint.init(item: self.view, attribute: .centerY, relatedBy: .equal, toItem: _redView, attribute: .centerY, multiplier: 1, constant: 0)
        self.view.addConstraint(constraint_red)

        let constraint_yellow = NSLayoutConstraint.init(item: self.view, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .centerX, multiplier: 1, constant: 0)
        self.view.addConstraint(constraint_yellow)

        let constraint_yellow1 = NSLayoutConstraint.init(item: _redView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 0.5, constant: 0)
        self.view.addConstraint(constraint_yellow1)

        let constraint_yellow2 = NSLayoutConstraint.init(item: _blueView, attribute: .centerX, relatedBy: .equal, toItem: _yellowView, attribute: .leading, multiplier: 1.5, constant: 40)
        self.view.addConstraint(constraint_yellow2)
Sarath Raveendran
sumber
1
Menguraikan bagaimana kode ini menjawab pertanyaan akan membantu pengunjung masa depan.
JAL
2

Saya tahu sudah lama sejak jawaban pertama, tapi saya baru saja menemukan masalah yang sama dan saya ingin berbagi solusi. Untuk generasi yang akan datang ...

Saya menetapkan pandangan saya pada viewDidLoad:

- (void)viewDidLoad {

    [super viewDidLoad];

    cancelButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    cancelButton.translatesAutoresizingMaskIntoConstraints = NO;
    [cancelButton setTitle:@"Cancel" forState:UIControlStateNormal];
    [self.view addSubview:cancelButton];

    middleButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    middleButton.translatesAutoresizingMaskIntoConstraints = NO;
    [middleButton setTitle:@"Middle" forState:UIControlStateNormal];
    [self.view addSubview:middleButton];

    nextButton = [UIButton buttonWithType: UIButtonTypeRoundedRect];
    nextButton.translatesAutoresizingMaskIntoConstraints = NO;
    [nextButton setTitle:@"Next" forState:UIControlStateNormal];
    [self.view addSubview:nextButton];


    [self.view setNeedsUpdateConstraints];

}

Dan kemudian, pada updateViewConstrains, pertama-tama saya menghapus semua batasan, kemudian saya membuat kamus tampilan dan kemudian saya menghitung ruang yang akan digunakan di antara tampilan. Setelah itu, saya hanya menggunakan Format Bahasa Visual untuk mengatur batasan:

- (void)updateViewConstraints {


    [super updateViewConstraints];

    [self.view removeConstraints:self.view.constraints];

    NSDictionary *viewsDictionary = NSDictionaryOfVariableBindings(cancelButton, nextButton, middleButton);

    float distance=(self.view.bounds.size.width-cancelButton.intrinsicContentSize.width-nextButton.intrinsicContentSize.width-middleButton.intrinsicContentSize.width-20-20)/  ([viewsDictionary count]-1);  // 2 times 20 counts for the left & rigth margins
    NSNumber *distancies=[NSNumber numberWithFloat:distance];

//    NSLog(@"Distancies: %@", distancies);
//    
//    NSLog(@"View Width: %f", self.view.bounds.size.width);
//    NSLog(@"Cancel Width: %f", cancelButton.intrinsicContentSize.width);
//    NSLog(@"Middle Width: %f", middleButton.intrinsicContentSize.width);
//    NSLog(@"Next Width: %f", nextButton.intrinsicContentSize.width);



    NSArray *constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-[cancelButton]-dis-[middleButton]-dis-[nextButton]-|"
                                                                   options:NSLayoutFormatAlignAllBaseline
                                                                   metrics:@{@"dis":distancies}
                                                                     views:viewsDictionary];


    [self.view addConstraints:constraints];



    constraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:[nextButton]-|"
                                                          options:0
                                                          metrics:nil
                                                            views:viewsDictionary];
    [self.view addConstraints:constraints];



}

Hal yang baik tentang metode ini adalah Anda harus melakukan sedikit matematika. Saya tidak mengatakan ini adalah solusi yang sempurna, tetapi saya bekerja untuk tata letak yang saya coba capai.

Saya harap ini membantu.

Marcal
sumber
2

Berikut adalah solusi yang akan memusatkan secara vertikal sejumlah subview, meskipun ukurannya unik. Yang ingin Anda lakukan adalah membuat wadah tingkat menengah, tempatkan di superview, lalu taruh semua subview dalam wadah dan atur sesuai dengan satu sama lain. Namun yang terpenting, Anda juga harus membatasi mereka di bagian atas dan bawah wadah, sehingga wadah tersebut dapat berukuran dan dipusatkan di superview dengan benar. Dengan mencari ketinggian yang tepat dari subview-nya, wadah dapat secara vertikal terpusat.

Dalam contoh ini, selfadalah superview di mana Anda memusatkan semua subview.

NSArray *subviews = @[ (your subviews in top-to-bottom order) ];

UIView *container = [[UIView alloc] initWithFrame:CGRectZero];
container.translatesAutoresizingMaskIntoConstraints = NO;
for (UIView *subview in subviews) {
    subview.translatesAutoresizingMaskIntoConstraints = NO;
    [container addSubview:subview];
}
[self addSubview:container];

[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeLeft multiplier:1.0f constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeRight multiplier:1.0f constant:0.0f]];
[self addConstraint:[NSLayoutConstraint constraintWithItem:container attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual
                                                    toItem:self attribute:NSLayoutAttributeCenterY multiplier:1.0f constant:0.0f]];

if (0 < subviews.count) {
    UIView *firstSubview = subviews[0];
    [container addConstraint:[NSLayoutConstraint constraintWithItem:firstSubview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                             toItem:container attribute:NSLayoutAttributeTop multiplier:1.0f constant:0.0f]];
    UIView *lastSubview = subviews.lastObject;
    [container addConstraint:[NSLayoutConstraint constraintWithItem:lastSubview attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual
                                                             toItem:container attribute:NSLayoutAttributeBottom multiplier:1.0f constant:0.0f]];

    UIView *subviewAbove = nil;
    for (UIView *subview in subviews) {
        [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual
                                                                 toItem:container attribute:NSLayoutAttributeCenterX multiplier:1.0f constant:0.0f]];
        if (subviewAbove) {
            [container addConstraint:[NSLayoutConstraint constraintWithItem:subview attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual
                                                                     toItem:subviewAbove attribute:NSLayoutAttributeBottom multiplier:1.0f constant:10.0f]];
        }
        subviewAbove = subview;
    }
}
Kevin Conner
sumber
Ini adalah solusi terbaik saat menggunakan tampilan dengan ukuran berbeda yang harus dipusatkan.
noobsmcgoobs
2

Saya baru saja menyelesaikan masalah saya menggunakan fitur pengali. Saya tidak yakin itu bekerja untuk semua kasus, tetapi bagi saya itu bekerja dengan sempurna. Saya menggunakan Xcode 6.3 FYI.

Apa yang akhirnya saya lakukan adalah:

1) Pertama-tama menempatkan tombol saya pada layar lebar 320px seperti yang saya inginkan pada perangkat 320px.

langkah 1: mendapatkan tombol diposisikan

2) Lalu saya menambahkan kendala Space terkemuka untuk melakukan superview pada semua tombol saya.

langkah 2: tambahkan batasan ruang terkemuka

3) Kemudian saya memodifikasi properti dari ruang terdepan sehingga konstanta adalah 0 dan pengali adalah offset x dibagi dengan lebar layar (mis. Tombol pertama saya adalah 8px dari tepi kiri jadi saya mengatur pengali ke 8/320)

4) Maka langkah penting di sini adalah mengubah Item kedua dalam relasi kendala menjadi superview. Mengolah alih-alih superview.leading. Ini adalah kunci karena superview. Memimpin adalah 0 dan mengikuti dalam kasus saya adalah 320, jadi 8/320 adalah 8 px pada perangkat 320px, maka ketika lebar superview berubah menjadi 640 atau apa pun, tampilan semua bergerak pada rasio relatif terhadap lebar dari ukuran layar 320px. Matematika di sini jauh lebih sederhana untuk dipahami.

langkah 3 & 4: ubah pengali ke xPos / screenWidth dan atur item kedua ke .Trailing

ucangetit
sumber
2

Banyak jawaban yang tidak benar, tetapi dapatkan banyak penghitungan. Di sini saya hanya menulis solusi secara pemrograman, tiga tampilan adalah perataan horizontal, tanpa menggunakan tampilan spacer , tetapi hanya berfungsi ketika lebar label diketahui saat digunakan dalam storyboard .

NSDictionary *views = NSDictionaryOfVariableBindings(_redView, _yellowView, _blueView);

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|->=0-[_redView(40)]->=0-[_yellowView(40)]->=0-[_blueView(40)]->=0-|" options:NSLayoutFormatAlignAllTop | NSLayoutFormatAlignAllBottom metrics:nil views:views]];

[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[_redView(60)]" options:0 metrics:nil views:views]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:_redView attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];

[self.view addConstraint:[NSLayoutConstraint constraintWithItem:self.view attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeCenterX multiplier:1 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_redView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:0.5 constant:0]];
[self.view addConstraint:[NSLayoutConstraint constraintWithItem:_blueView attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:_yellowView attribute:NSLayoutAttributeLeading multiplier:1.5 constant:40]];
zgjie
sumber
2

Ini jawaban lain. Saya menjawab pertanyaan serupa dan melihat tautan yang dirujuk ke pertanyaan ini. Saya tidak melihat jawaban yang mirip dengan jawaban saya. Jadi, saya berpikir untuk menulisnya di sini.

  class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.whiteColor()
        setupViews()
    }

    var constraints: [NSLayoutConstraint] = []

    func setupViews() {

        let container1 = createButtonContainer(withButtonTitle: "Button 1")
        let container2 = createButtonContainer(withButtonTitle: "Button 2")
        let container3 = createButtonContainer(withButtonTitle: "Button 3")
        let container4 = createButtonContainer(withButtonTitle: "Button 4")

        view.addSubview(container1)
        view.addSubview(container2)
        view.addSubview(container3)
        view.addSubview(container4)

        [

            // left right alignment
            container1.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
            container1.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20),
            container2.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container2.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
            container3.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container3.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),
            container4.leftAnchor.constraintEqualToAnchor(container1.leftAnchor),
            container4.rightAnchor.constraintEqualToAnchor(container1.rightAnchor),


            // place containers one after another vertically
            container1.topAnchor.constraintEqualToAnchor(view.topAnchor),
            container2.topAnchor.constraintEqualToAnchor(container1.bottomAnchor),
            container3.topAnchor.constraintEqualToAnchor(container2.bottomAnchor),
            container4.topAnchor.constraintEqualToAnchor(container3.bottomAnchor),
            container4.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),


            // container height constraints
            container2.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
            container3.heightAnchor.constraintEqualToAnchor(container1.heightAnchor),
            container4.heightAnchor.constraintEqualToAnchor(container1.heightAnchor)
            ]
            .forEach { $0.active = true }
    }


    func createButtonContainer(withButtonTitle title: String) -> UIView {
        let view = UIView(frame: .zero)
        view.translatesAutoresizingMaskIntoConstraints = false

        let button = UIButton(type: .System)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setTitle(title, forState: .Normal)
        view.addSubview(button)

        [button.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor),
            button.leftAnchor.constraintEqualToAnchor(view.leftAnchor),
            button.rightAnchor.constraintEqualToAnchor(view.rightAnchor)].forEach { $0.active = true }

        return view
    }
}

masukkan deskripsi gambar di sini

Dan lagi, ini dapat dilakukan dengan cukup mudah dengan iOS9 UIStackViews juga.

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.greenColor()
        setupViews()
    }

    var constraints: [NSLayoutConstraint] = []

    func setupViews() {

        let container1 = createButtonContainer(withButtonTitle: "Button 1")
        let container2 = createButtonContainer(withButtonTitle: "Button 2")
        let container3 = createButtonContainer(withButtonTitle: "Button 3")
        let container4 = createButtonContainer(withButtonTitle: "Button 4")

        let stackView = UIStackView(arrangedSubviews: [container1, container2, container3, container4])
        stackView.translatesAutoresizingMaskIntoConstraints = false
        stackView.axis = .Vertical
        stackView.distribution = .FillEqually
        view.addSubview(stackView)

        [stackView.topAnchor.constraintEqualToAnchor(view.topAnchor),
            stackView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor),
            stackView.leftAnchor.constraintEqualToAnchor(view.leftAnchor, constant: 20),
            stackView.rightAnchor.constraintEqualToAnchor(view.rightAnchor, constant: -20)].forEach { $0.active = true }
    }


    func createButtonContainer(withButtonTitle title: String) -> UIView {
        let button = UIButton(type: .Custom)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.backgroundColor = UIColor.redColor()
        button.setTitleColor(UIColor.whiteColor(), forState: .Normal)
        button.setTitle(title, forState: .Normal)
        let buttonContainer = UIStackView(arrangedSubviews: [button])
        buttonContainer.distribution = .EqualCentering
        buttonContainer.alignment = .Center
        buttonContainer.translatesAutoresizingMaskIntoConstraints = false
        return buttonContainer
    }
}

Perhatikan bahwa pendekatannya sama persis seperti di atas. Ini menambahkan empat tampilan wadah yang diisi sama dan tampilan ditambahkan ke setiap tampilan tumpukan yang disejajarkan di tengah. Tapi, versi UIStackView ini mengurangi beberapa kode dan terlihat bagus.

Sandeep
sumber
1

Pendekatan lain mungkin memiliki label atas dan bawah memiliki kendala relatif terhadap tampilan atas dan bawah, masing-masing, dan memiliki tampilan tengah memiliki kendala atas dan bawah relatif masing-masing dengan tampilan pertama dan ketiga.

Perhatikan bahwa Anda memiliki kontrol lebih besar atas kendala daripada yang mungkin terlihat dengan menyeret tampilan dekat satu sama lain hingga muncul garis putus-putus memandu - ini menunjukkan kendala antara dua objek yang akan dibentuk alih-alih antara objek dan superview.

Dalam hal ini Anda kemudian ingin mengubah batasan menjadi "Lebih besar dari atau sama dengan" nilai yang diinginkan, alih-alih "sama dengan" untuk memungkinkan mereka mengubah ukuran. Tidak yakin apakah ini akan melakukan apa yang Anda inginkan.

Colin
sumber
1

Cara yang sangat mudah untuk menyelesaikan ini di InterfaceBuilder:

Atur label tengah (label2) ke "Pusat Horisontal dalam Wadah" dan "Pusat Vertikal dalam Wadah"

Pilih label tengah dan label atas (label1 + label2) dan tambahkan DUA kendala untuk Penempatan Vertikal. Satu dengan Greater Than atau Equal jarak min. Satu dengan Less Than atau Equal the max spacing.

Hal yang sama untuk label tengah dan label bawah (label2 + label3).

Selain itu Anda juga dapat menambahkan dua batasan pada label1 - Top Space To SuperView dan dua kendala untuk label2 - Bottom Space To SuperView.

Hasilnya adalah bahwa semua 4 spacing akan mengubah ukurannya secara merata.

berkelanjutan86
sumber
2
Saya menemukan bahwa ini hanya berfungsi ketika Anda mengubah ukuran superview sehingga spasi mengambil nilai min atau max persis. Saat Anda mengubah ukurannya menjadi suatu nilai di antara keduanya, subview tidak didistribusikan secara merata.
Dorian Roy
1

Saya telah membuat fungsi yang mungkin membantu. Contoh penggunaan ini:

 [self.view addConstraints: [NSLayoutConstraint fluidConstraintWithItems:NSDictionaryOfVariableBindings(button1, button2, button3)
                                                                asString:@[@"button1", @"button2", @"button3"]
                                                               alignAxis:@"V"
                                                          verticalMargin:100
                                                        horizontalMargin:50
                                                             innerMargin:25]];

akan menyebabkan distribusi vertikal (maaf tidak memiliki 10 reputasi untuk menanamkan gambar). Dan jika Anda mengubah sumbu dan beberapa nilai margin:

alignAxis:@"H"
verticalMargin:120
horizontalMargin:20
innerMargin:10

Anda akan mendapatkan distribusi horizontal itu .

Saya pemula di iOS tetapi voaà!

EvenDistribution.h

@interface NSLayoutConstraint (EvenDistribution)

/**
 * Returns constraints that will cause a set of subviews
 * to be evenly distributed along an axis.
 */
+ (NSArray *)  fluidConstraintWithItems:(NSDictionary *) views
                               asString:(NSArray *) stringViews
                              alignAxis:(NSString *) axis
                         verticalMargin:(NSUInteger) vMargin
                       horizontalMargin:(NSUInteger) hMargin
                            innerMargin:(NSUInteger) inner;
@end

EvenDistribution.m

#import "EvenDistribution.h"

@implementation NSLayoutConstraint (EvenDistribution)

+ (NSArray *) fluidConstraintWithItems:(NSDictionary *) dictViews
                              asString:(NSArray *) stringViews
                             alignAxis:(NSString *) axis
                        verticalMargin:(NSUInteger) vMargin
                      horizontalMargin:(NSUInteger) hMargin
                           innerMargin:(NSUInteger) iMargin

{
    NSMutableArray *constraints = [NSMutableArray arrayWithCapacity: dictViews.count];
    NSMutableString *globalFormat = [NSMutableString stringWithFormat:@"%@:|-%d-",
                                     axis,
                                     [axis isEqualToString:@"V"] ? vMargin : hMargin
                                     ];



        for (NSUInteger i = 0; i < dictViews.count; i++) {

            if (i == 0)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@]-%d-", stringViews[i], iMargin]];
            else if(i == dictViews.count - 1)
                [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-", stringViews[i], stringViews[i-1]]];
            else
               [globalFormat appendString:[NSString stringWithFormat: @"[%@(==%@)]-%d-", stringViews[i], stringViews[i-1], iMargin]];

            NSString *localFormat = [NSString stringWithFormat: @"%@:|-%d-[%@]-%d-|",
                                     [axis isEqualToString:@"V"] ? @"H" : @"V",
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin,
                                     stringViews[i],
                                     [axis isEqualToString:@"V"] ? hMargin : vMargin];

            [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:localFormat
                                                                                     options:0
                                                                                     metrics:nil
                                                                                       views:dictViews]];


    }
    [globalFormat appendString:[NSString stringWithFormat:@"%d-|",
                                [axis isEqualToString:@"V"] ? vMargin : hMargin
                                ]];

    [constraints addObjectsFromArray:[NSLayoutConstraint constraintsWithVisualFormat:globalFormat
                                                                             options:0
                                                                             metrics:nil
                                                                               views:dictViews]];

    return constraints;

}

@end
penumbra
sumber
1

Ya, Anda bisa melakukan ini hanya dalam pembangun antarmuka dan tanpa menulis kode - satu peringatan adalah bahwa Anda mengubah ukuran label daripada mendistribusikan spasi. Dalam hal ini, sejajarkan Label 2's X dan Y ke superview sehingga diperbaiki di tengah. Kemudian atur ruang vertikal label 1 ke superview dan label 2 ke standar, ulangi untuk label 3. Setelah mengatur label 2, cara termudah untuk mengatur label 1 dan 3 adalah mengubah ukurannya sampai label tersebut patah.

Berikut adalah tampilan horizontal, perhatikan bahwa ruang vertikal antara label 1 dan 2 diatur ke standar:tampilan horisontal

Dan inilah versi potretnya:masukkan deskripsi gambar di sini

Saya menyadari mereka tidak benar-benar berjarak 100% sama antara garis dasar karena perbedaan antara ruang standar antara label dan ruang standar untuk superview. Jika itu mengganggu Anda, atur ukuran ke 0 dan bukan standar

James
sumber
1

Saya menetapkan nilai lebar hanya untuk item pertama (> = lebar) dan jarak minimum antara setiap item (> = jarak). Lalu saya menggunakan Ctrl untuk menyeret item kedua, ketiga ... pada yang pertama untuk menghubungkan dependensi antar item.

masukkan deskripsi gambar di sini

Vladimír Slavík
sumber
1

Terlambat ke pesta tapi aku punya solusi untuk membuat menu secara horizontal dengan spasi. Ini dapat dengan mudah dilakukan menggunakan ==NSLayoutConstraint

const float MENU_HEIGHT = 40;

- (UIView*) createMenuWithLabels: (NSArray *) labels
    // labels is NSArray of NSString
    UIView * backgroundView = [[UIView alloc]init];
    backgroundView.translatesAutoresizingMaskIntoConstraints = false;

    NSMutableDictionary * views = [[NSMutableDictionary alloc] init];
    NSMutableString * format = [[NSMutableString alloc] initWithString: @"H:|"];
    NSString * firstLabelKey;

    for(NSString * str in labels)
    {
        UILabel * label = [[UILabel alloc] init];
        label.translatesAutoresizingMaskIntoConstraints = false;
        label.text = str;
        label.textAlignment = NSTextAlignmentCenter;
        label.textColor = [UIColor whiteColor];
        [backgroundView addSubview: label];
        [label fixHeightToTopBounds: MENU_HEIGHT-2];
        [backgroundView addConstraints: [label fixHeightToTopBounds: MENU_HEIGHT]];
        NSString * key = [self camelCaseFromString: str];
        [views setObject: label forKey: key];
        if(firstLabelKey == nil)
        {
            [format appendString: [NSString stringWithFormat: @"[%@]", key]];
            firstLabelKey = key;
        }
        else
        {
            [format appendString: [NSString stringWithFormat: @"[%@(==%@)]", key, firstLabelKey]];
        }
    }

    [format appendString: @"|"];

    NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat: (NSString *) format
                                                                               options: 0
                                                                               metrics: nil
                                                                                 views: (NSDictionary *) views];
    [backgroundView addConstraints: constraints];
    return backgroundView;
}
tsuz
sumber
0

Android memiliki metode chaining views bersama dalam sistem tata letak berbasis kendala yang ingin saya tiru. Pencarian membawa saya ke sini tetapi tidak ada jawaban yang cukup berhasil. Saya tidak ingin menggunakan StackViews karena mereka cenderung membuat saya lebih sedih daripada menghemat waktu. Saya akhirnya menciptakan solusi yang menggunakan UILayoutGuides ditempatkan di antara tampilan. Mengontrol lebarnya memungkinkan berbagai jenis distribusi, gaya berantai dalam bahasa Android. Fungsi menerima anchor yang memimpin dan mengikuti bukannya tampilan induk. Ini memungkinkan rantai ditempatkan di antara dua tampilan sewenang-wenang daripada didistribusikan di dalam tampilan induk. Itu memang menggunakan UILayoutGuideyang hanya tersedia di iOS 9+ tapi itu seharusnya tidak menjadi masalah lagi.

public enum LayoutConstraintChainStyle {
    case spread //Evenly distribute between the anchors
    case spreadInside //Pin the first & last views to the sides and then evenly distribute
    case packed //The views have a set space but are centered between the anchors.
}

public extension NSLayoutConstraint {

    static func chainHorizontally(views: [UIView],
                                  leadingAnchor: NSLayoutXAxisAnchor,
                                  trailingAnchor: NSLayoutXAxisAnchor,
                                  spacing: CGFloat = 0.0,
                                  style: LayoutConstraintChainStyle = .spread) -> [NSLayoutConstraint] {
    var constraints = [NSLayoutConstraint]()
    guard views.count > 1 else { return constraints }
    guard let first = views.first, let last = views.last, let superview = first.superview else { return constraints }

    //Setup the chain of views
    var distributionGuides = [UILayoutGuide]()
    var previous = first
    let firstGuide = UILayoutGuide()
    superview.addLayoutGuide(firstGuide)
    distributionGuides.append(firstGuide)
    firstGuide.identifier = "ChainDistribution\(distributionGuides.count)"
    constraints.append(firstGuide.leadingAnchor.constraint(equalTo: leadingAnchor))
    constraints.append(first.leadingAnchor.constraint(equalTo: firstGuide.trailingAnchor, constant: spacing))
    views.dropFirst().forEach { view in
        let g = UILayoutGuide()
        superview.addLayoutGuide(g)
        distributionGuides.append(g)
        g.identifier = "ChainDistribution\(distributionGuides.count)"
        constraints.append(contentsOf: [
            g.leadingAnchor.constraint(equalTo: previous.trailingAnchor),
            view.leadingAnchor.constraint(equalTo: g.trailingAnchor)
        ])
        previous = view
    }
    let lastGuide = UILayoutGuide()
    superview.addLayoutGuide(lastGuide)
    constraints.append(contentsOf: [lastGuide.leadingAnchor.constraint(equalTo: last.trailingAnchor),
                                    lastGuide.trailingAnchor.constraint(equalTo: trailingAnchor)])
    distributionGuides.append(lastGuide)

    //Space the according to the style.
    switch style {
    case .packed:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(greaterThanOrEqualToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalTo: first.widthAnchor))
            constraints.append(contentsOf:
                distributionGuides.dropFirst().dropLast()
                    .map { $0.widthAnchor.constraint(equalToConstant: spacing) }
                )
        }
    case .spread:
        if let first = distributionGuides.first {
            constraints.append(contentsOf:
                distributionGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: first.widthAnchor) })
        }
    case .spreadInside:
        if let first = distributionGuides.first, let last = distributionGuides.last {
            constraints.append(first.widthAnchor.constraint(equalToConstant: spacing))
            constraints.append(last.widthAnchor.constraint(equalToConstant: spacing))
            let innerGuides = distributionGuides.dropFirst().dropLast()
            if let key = innerGuides.first {
                constraints.append(contentsOf:
                    innerGuides.dropFirst().map { $0.widthAnchor.constraint(equalTo: key.widthAnchor) }
                )
            }
        }
    }

    return constraints
}
Sam Corder
sumber
0

Saya ingin menyelaraskan 5 gambar secara horizontal, jadi saya akhirnya mengikuti respons Mete dengan sedikit perbedaan.

Gambar pertama akan dipusatkan secara horizontal dalam wadah yang sama dengan 0 dan pengganda 1: 5:

gambar pertama

Gambar kedua akan dipusatkan secara horizontal dalam wadah yang sama dengan 0 dan pengganda 3: 5: gambar kedua

Dan seperti itu untuk sisa gambar. Misalnya, gambar kelima (dan yang terakhir) akan dipusatkan secara horizontal dalam wadah yang sama dengan 0 dan pengganda 9: 5: gambar terakhir

Seperti yang dijelaskan Mete, urutannya adalah 1, 3, 5, 7, 9, dll. Posisi mengikuti logika yang sama: posisi pertama adalah 1, lalu spasi, kemudian posisi berikutnya 3, dan seterusnya.

Adriana Pineda
sumber
-1

Mengapa Anda tidak membuat tableView dan membuatnya isScrollEnabled = false

Josh O'Connor
sumber
Tidak mengerti downvote, solusi saya adalah berpikir di luar kotak. Mengapa harus pusing membuat daftar dengan autolayout ketika kakao memberi Anda daftar di UITableView?
Josh O'Connor