Untuk baris kecil label dalam app Mac, gunakan ViewThatFits untuk memilih awalan lengkap terpanjang yang muat, termasuk kiraan item tersembunyinya. Tutorial ini membina baris itu tanpa memotong label atau mengemas kini keadaan semasa reka letak.

Tugas khususnya ialah tetingkap macOS boleh ubah saiz yang mengandungi enam label sintetik. Kekalkan susunannya, paparkan hanya label lengkap dan tunjukkan lencana seperti 3 lagi untuk akhiran yang digugurkan. Penyelesaian ini mengandaikan ruang mendatar yang mencukupi untuk lencana kiraan sahaja dan ruang menegak yang mencukupi untuk satu baris.

Pilih alternatif baris lengkap

Apple mendokumenkan ViewThatFits sebagai pemilih anak pertama yang saiz idealnya muat dengan saiz yang dicadangkan pada paksi yang dikekang. Ia tersedia pada macOS 13 dan versi lebih baharu. Gunakan .horizontal di sini kerana tugas ini berkaitan dengan lebar baris; antara muka sekeliling mesti menyediakan ketinggian baris. ViewThatFits

Untuk enam label, sediakan tujuh alternatif mengikut urutan ini: keenam-enam label tanpa lencana, lima label bersama 1 lagi, empat bersama 2 lagi, dan seterusnya, hingga hanya 6 lagi. Setiap alternatif ialah satu baris lengkap. Lencananya turut diambil kira dalam keputusan muat, jadi penambahan kiraan tidak akan menolak label terakhir yang kelihatan secara tidak dijangka.

Ini melaksanakan dasar awalan: label pertama yang panjang boleh menyebabkan semua label digugurkan, walaupun label pendek selepasnya mungkin muat. Itu disengajakan. Jika tugas anda membenarkan label tertentu dilangkau, tetapkan dasar pemilihan yang berbeza itu sebelum melaksanakannya.

Gunakan fixedSize() pada setiap baris calon supaya label dan lencananya mengekalkan dimensi ideal. Apple menjelaskan bahawa pengubah suai ini boleh menyebabkan paparan melebihi sempadan induknya; ia tidak menjamin paparan itu muat dengan sendirinya. Di sini, bekas pemilihan yang mengelilinginya menentukan sama ada paparan itu muat. fixedSize()

Bina contoh macOS yang lengkap

Cipta app SwiftUI macOS dalam Xcode dan tetapkan sasaran penggunaan kepada macOS 13 atau versi lebih baharu. Gantikan deklarasi app dan paparan kandungan yang dijana dengan program satu fail berikut. Kekalkan tepat satu deklarasi app bertanda @main dalam sasaran.

Contoh ini menggunakan pengecam eksplisit dan bukannya teks label sebagai identiti. Dokumentasi ForEach Apple memerlukan elemen yang dikenal pasti atau laluan kunci pengecam yang eksplisit; pengecam yang berbeza juga membolehkan dua item berkongsi tajuk paparan yang sama. ForEach

import SwiftUI

struct DemoItem: Identifiable {
    let id: Int
    let title: String
}

struct ItemChip: View {
    let title: String

    var body: some View {
        Text(title)
            .lineLimit(1)
            .padding(.horizontal, 10)
            .padding(.vertical, 6)
            .background(
                RoundedRectangle(cornerRadius: 8)
                    .fill(Color.blue.opacity(0.12))
            )
    }
}

struct PrefixCandidate: View {
    let items: [DemoItem]
    let visibleCount: Int

    var body: some View {
        HStack(spacing: 8) {
            ForEach(items.prefix(visibleCount)) { item in
                ItemChip(title: item.title)
            }

            if visibleCount < items.count {
                Text("\(items.count - visibleCount) more")
                    .lineLimit(1)
                    .padding(.horizontal, 10)
                    .padding(.vertical, 6)
                    .background(
                        RoundedRectangle(cornerRadius: 8)
                            .fill(Color.gray.opacity(0.15))
                    )
            }
        }
        .fixedSize()
    }
}

struct WholeItemRow: View {
    let items: [DemoItem]

    var body: some View {
        if items.isEmpty {
            Text("No items")
                .fixedSize()
        } else {
            ViewThatFits(in: .horizontal) {
                ForEach(
                    Array((0...items.count).reversed()),
                    id: \.self
                ) { visibleCount in
                    PrefixCandidate(
                        items: items,
                        visibleCount: visibleCount
                    )
                }
            }
        }
    }
}

struct ContentView: View {
    let items: [DemoItem] = [
        DemoItem(id: 1, title: "Sketch"),
        DemoItem(id: 2, title: "Color samples"),
        DemoItem(id: 3, title: "Shapes"),
        DemoItem(id: 4, title: "Paper textures"),
        DemoItem(id: 5, title: "Layout notes"),
        DemoItem(id: 6, title: "Preview")
    ]

    var body: some View {
        VStack(alignment: .leading, spacing: 16) {
            Text("Sample labels")
                .font(.headline)

            WholeItemRow(items: items)
                .frame(maxWidth: .infinity, alignment: .leading)

            Text("Resize the window to change how many labels fit.")
                .foregroundStyle(.secondary)
        }
        .font(.system(size: 14))
        .padding(24)
        .frame(minWidth: 320, idealWidth: 680, minHeight: 160)
    }
}

@main
struct WholeItemsDemoApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

Pengecam calon ialah bilangan item yang mungkin kelihatan, disusun menurun daripada jumlah item hingga sifar. Dalam setiap calon, pengecam item mengenal pasti label. Setiap lelaran menghasilkan satu PrefixCandidate, yang mengandungi satu baris mendatar.

Bingkai fleksibel di bahagian luar membolehkan baris menerima ruang mendatar yang tersedia sambil mengekalkan kandungan terpilih sejajar ke tepi kiri. Kekalkan fixedSize() pada calon di dalam ViewThatFits. Menggunakannya pada keseluruhan bekas pemilihan akan mengubah cara bekas itu bertindak balas terhadap cadangan lebar daripada induknya.

Ini ialah contoh kod sumber lengkap, tetapi ia tidak dikompil atau dijalankan di sini kerana toolchain Swift tidak tersedia. Pengiraan ilustrasi dalam bahagian seterusnya telah disemak secara berasingan; lebar teks sebenar perlu disahkan dalam app Mac.

Sertakan lencana semasa mengira ruang yang muat

Peraturan keputusannya mudah: pilih bilangan item kelihatan paling tinggi yang calonnya muat sepenuhnya. Kiraan tersembunyi sentiasa jumlah item ditolak bilangan item yang kelihatan dalam calon itu. Tiada anggaran berasingan yang perlu disegerakkan.

Pertimbangkan baris ilustrasi empat item dengan lebar 72, 96, 64 dan 88 mata, termasuk ruang dalam setiap item. Anggap jarak 8 mata dan lencana 60 mata bagi setiap kiraan item tersembunyi yang bukan sifar. Ini ialah nilai input rekaan untuk pengiraan, bukannya ukuran daripada app contoh.

Apabila keempat-empat item kelihatan, lebar yang diperlukan ialah 72 + 96 + 64 + 88 + 3 × 8 = 344 mata. Dengan tiga item kelihatan, lencana menggantikan akhiran yang digugurkan, jadi lebarnya menjadi 72 + 96 + 64 + 3 × 8 + 60 = 316 mata. Tiga jarak diperlukan kerana calon itu mengandungi tiga item dan satu lencana.

Lebar tersedia Item kelihatan Item tersembunyi Lebar calon terpilih
344 mata 4 0 344 mata
343 mata 3 1 316 mata
300 mata 2 2 244 mata
220 mata 1 3 140 mata
60 mata 0 4 60 mata

Dalam program ini, setiap calon mengandungi teks lencana sebenar. Oleh itu, ia mengambil kira perbezaan antara rentetan lencana tanpa bergantung pada andaian lebar tetap dalam ilustrasi. Lebar calon tidak semestinya berubah dalam jumlah yang seragam; bilangan item kelihatan yang disusun menurun menyatakan keutamaan pemilihan.

Calon kiraan sahaja menetapkan lebar minimum yang boleh digunakan. Jika lencana itu pun tidak muat, mustahil untuk memaparkan jumlah penuh dalam lebar tersedia berdasarkan peraturan ini. Sediakan lebar minimum yang mencukupi, benarkan susun atur lain atau pindahkan kiraan ke tempat lain. Jangan anggap pemotongan sebagai hasil item lengkap yang berjaya.

Contoh ini menyediakan lebar kandungan minimum dan fon eksplisit yang agak kecil untuk lencana sintetiknya yang pendek. Jika anda menukar perkataan, fon, ruang dalam atau susun atur sekeliling, semak semula kes kiraan sahaja. Lebar minimum yang dipilih untuk contoh ini bukan ukuran lencana yang sesuai untuk semua keadaan.

Asingkan pemilihan reka letak daripada kitar hayat paparan

Kiraan tersembunyi ialah input tidak berubah bagi setiap calon. Program ini tidak menulis kepada binding daripada kaedah pengukuran, menjadualkan kemas kini kiraan secara tak segerak atau membuat kesimpulan tentang keterlihatan daripada panggil balik penampilan. Pemilihan baris turut memilih lencana yang sepadan.

Pastikan kandungan calon yang berulang ringkas. Mengulang label merentas alternatif tidak mewujudkan satu identiti bersama untuk label itu merentas semua alternatif. Apple menjelaskan bahawa storan keadaan dikaitkan dengan identiti paparan dan perubahan identiti boleh menggantikan keadaan. Demystify SwiftUI

Jika kemudian anda menggantikan label dengan kawalan boleh sunting, simpan nilai bersamanya dalam induk sepunya atau model, lalu hantarkan input atau binding yang sesuai kepada setiap persembahan. Apple mengesyorkan agar keadaan bersama diletakkan pada leluhur sepunya terdekat bagi paparan yang memerlukannya. Jangan bergantung pada keadaan setempat calon untuk kekal selepas persembahan berubah. Mengurus keadaan antara muka pengguna

Penyelesaian ini memaparkan kiraan tersembunyi dalam baris terpilih. Ia tidak mendedahkan kiraan terpilih kepada paparan sebelah atau model app. Pemula ViewThatFits yang didokumenkan Apple menerima paksi yang dikekang dan kandungan calon; ia tidak menyediakan binding kiraan terpilih. Anggap pengeksportan nilai itu sebagai keperluan reka bentuk tambahan. init(in:content:)

Ketahui bila reka letak tersuai memerlukan reka bentuk berbeza

Layout tersuai sesuai apabila anda memerlukan geometri khusus. Apple mentakrifkan tanggungjawab terasnya sebagai melaporkan saiz komposit dan menetapkan kedudukan subpaparan melalui proksi reka letak. Proksi itu menyediakan operasi pengukuran dan peletakan, bukannya akses terus kepada paparan asas. Layout

Jangan laksanakan pengguguran hanya dengan berhenti meletakkan item selepas item terakhir yang muat. Dokumentasi LayoutSubview Apple mengarahkan anda meletakkan setiap subpaparan sekali. Melangkau peletakan bukan mekanisme penyembunyian yang didokumenkan, dan proksi reka letak tidak menyediakan operasi umum untuk menulis semula kandungan bagi menukar subpaparan lain menjadi label kiraan baharu. LayoutSubview

Jika anda membina reka letak tersuai, pastikan pengukuran dan peletakan sepadan, termasuk jarak dan cadangan saiz yang digunakan. Apple secara jelas menghendaki pengiraan tersebut konsisten. Kontrak itu tetap terpakai apabila reka letak menguji beberapa susunan yang mungkin. placeSubviews(in:proposal:subviews:cache:)

Pendekatan calon ini sengaja dihadkan skopnya. Untuk enam item, ia menerangkan tujuh baris calon dan 21 kemunculan item merentas baris tersebut. Secara umum, bilangan kemunculan item meningkat sebagai n × (n + 1) / 2. Ini ialah kiraan struktur, bukannya penanda aras prestasi atau dakwaan bahawa setiap calon dirender pada setiap kemas kini. Gunakannya untuk koleksi label kecil; lakukan pemprofilan sebelum mengembangkannya kepada koleksi besar atau kandungan yang berat.

Sahkan baris pada sempadannya

Jalankan app dan ubah saiz tetingkapnya secara perlahan. Semak syarat berikut sebelum menyesuaikan komponen ini:

  • Pada lebar yang besar, semua label dipaparkan dan tiada lencana 0 lagi.
  • Apabila tetingkap dikecilkan, label hilang dari hujung tanpa label separa atau elipsis.
  • Bilangan item yang kelihatan ditambah kiraan tersembunyi pada lencana sentiasa sama dengan enam.
  • Dengan label pertama yang luar biasa panjang, calon kiraan sahaja kekal tersedia.
  • Dengan tatasusunan kosong, baris memaparkan Tiada item.
  • Dengan tajuk pendua dan pengecam yang berbeza, kedua-dua item kekal diwakili dalam kiraan.
  • Selepas menukar fon atau perkataan pada lencana, calon kiraan sahaja masih muat pada lebar minimum yang disokong.

Untuk baris kecil yang tersusun, alternatif lengkap menjadikan peraturan muat mudah diperiksa: setiap calon merangkumi label, jarak dan kiraan tersembunyi yang tepat. Kekalkan syarat lebar minimum dengan jelas dan kandungan berulang secara ringan, maka baris itu boleh menyesuaikan diri apabila saiz tetingkap berubah tanpa item separa atau kitaran kemas kini kiraan yang berasingan.

Sumber