Mac ऐप में लेबलों की छोटी पंक्ति के लिए, ViewThatFits का उपयोग करके फ़िट होने वाला सबसे लंबा पूरा शुरुआती क्रम चुनें और उसमें छिपे आइटमों की गिनती शामिल करें। यह ट्यूटोरियल लेबलों को काटे बिना या लेआउट के दौरान स्थिति अपडेट किए बिना वह पंक्ति बनाता है।

ठोस काम है ऐसा आकार बदल सकने वाला macOS विंडो बनाना जिसमें छह कृत्रिम लेबल हों। उनका क्रम बनाए रखें, केवल पूरे लेबल दिखाएँ और छोड़े गए अंतिम आइटमों के लिए 3 more जैसा बैज दिखाएँ। यह समाधान मानता है कि केवल गिनती वाला बैज दिखाने के लिए पर्याप्त क्षैतिज जगह और एक पंक्ति के लिए पर्याप्त ऊर्ध्वाधर जगह है।

पंक्ति के पूरे विकल्प चुनें

Apple के दस्तावेज़ के अनुसार, ViewThatFits सीमित अक्षों पर प्रस्तावित आकार में फ़िट होने वाले पहले चाइल्ड को चुनता है। यह macOS 13 और उसके बाद के संस्करणों में उपलब्ध है। यहाँ .horizontal का उपयोग करें, क्योंकि काम पंक्ति की चौड़ाई से जुड़ा है; आसपास के इंटरफ़ेस को पंक्ति की ऊँचाई उपलब्ध करानी होगी। ViewThatFits

छह लेबलों के लिए इस क्रम में सात विकल्प दें: बिना बैज के सभी छह लेबल, 1 more के साथ पाँच लेबल, 2 more के साथ चार लेबल, और इसी तरह अंत में केवल 6 more। हर विकल्प एक पूरी पंक्ति है। उसका बैज भी फ़िट होने के निर्णय में शामिल होता है, इसलिए गिनती जोड़ने से आख़िरी दिखने वाला लेबल अनपेक्षित रूप से बाहर नहीं होगा।

यह शुरुआती क्रम की नीति लागू करता है: पहला लेबल लंबा होने पर सभी लेबल छोड़े जा सकते हैं, भले ही बाद का कोई छोटा लेबल फ़िट हो जाए। यह जानबूझकर ऐसा है। अगर आपके काम में अलग-अलग लेबल छोड़ने की अनुमति है, तो लागू करने से पहले वह अलग चयन नीति तय करें।

हर संभावित पंक्ति पर fixedSize() लागू करें, ताकि उसके लेबल और बैज अपने आदर्श आयाम बनाए रखें। Apple बताता है कि यह मॉडिफ़ायर किसी व्यू को उसके पैरेंट की सीमाओं से बाहर जाने दे सकता है; यह अपने आप फ़िट होने की गारंटी नहीं देता। यहाँ, उसे घेरने वाला चयन कंटेनर फ़िट होने का निर्णय करता है। fixedSize()

macOS का पूरा उदाहरण बनाएँ

Xcode में macOS SwiftUI ऐप बनाएँ और उसका डिप्लॉयमेंट टार्गेट macOS 13 या उसके बाद का संस्करण रखें। जनरेट की गई ऐप घोषणा और कंटेंट व्यू को नीचे दिए गए एकल-फ़ाइल प्रोग्राम से बदलें। टार्गेट में @main से चिह्नित ऐप घोषणा ठीक एक ही रखें।

यह उदाहरण लेबल के टेक्स्ट को पहचान के रूप में इस्तेमाल करने के बजाय स्पष्ट आइडेंटिफ़ायर का उपयोग करता है। Apple के ForEach दस्तावेज़ के अनुसार, पहचाने जा सकने वाले एलिमेंट या स्पष्ट आइडेंटिफ़ायर की की-पाथ आवश्यक है; अलग-अलग आइडेंटिफ़ायर होने से दो आइटमों का दिखाया गया शीर्षक एक जैसा भी हो सकता है। 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()
        }
    }
}

उम्मीदवार आइडेंटिफ़ायर संभावित दिखने वाली गिनतियाँ हैं, जो आइटमों की कुल गिनती से शून्य तक घटते क्रम में हैं। हर उम्मीदवार के भीतर, आइटम आइडेंटिफ़ायर लेबलों की पहचान करते हैं। हर इटरेशन एक PrefixCandidate बनाता है, जिसमें एक क्षैतिज पंक्ति होती है।

बाहरी लचीला फ़्रेम पंक्ति को उपलब्ध क्षैतिज जगह देता है और चुने गए कंटेंट को बाएँ किनारे पर संरेखित रखता है। fixedSize() को ViewThatFits के भीतर उम्मीदवार पर ही रखें। इसे पूरे चयन कंटेनर पर लगाने से यह बदल जाएगा कि कंटेनर अपने पैरेंट की चौड़ाई के प्रस्ताव पर कैसे प्रतिक्रिया देता है।

यह स्रोत का पूरा उदाहरण है, लेकिन यहाँ इसे कंपाइल या चलाया नहीं गया, क्योंकि Swift टूलचेन उपलब्ध नहीं था। अगले सेक्शन में दिए गए उदाहरणात्मक हिसाब को अलग से जाँचा गया; टेक्स्ट की वास्तविक चौड़ाइयों की पुष्टि Mac ऐप में करनी होगी।

फ़िट की गणना में बैज शामिल करें

उपयोगी निर्णय नियम यह है: ऐसी सबसे बड़ी दिखने वाली गिनती चुनें जिसकी पूरी पंक्ति फ़िट हो। छिपे हुए आइटमों की गिनती हमेशा कुल आइटमों की गिनती में से उस उम्मीदवार की दिखने वाली गिनती घटाने पर मिलती है। इसे सिंक में रखने के लिए अलग से कोई अनुमान लगाने की ज़रूरत नहीं है।

चार आइटमों वाली एक उदाहरणात्मक पंक्ति पर विचार करें, जिसकी चौड़ाइयाँ 72, 96, 64 और 88 पॉइंट हैं; इनमें आइटम की पैडिंग शामिल है। मान लें कि स्पेसिंग 8 पॉइंट है और छिपे आइटमों की कोई भी गैर-शून्य गिनती दिखाने वाले बैज की चौड़ाई 60 पॉइंट है। ये हिसाब के लिए गढ़े गए इनपुट हैं, नमूना ऐप की माप नहीं।

जब सभी चार आइटम दिखते हैं, तो उनकी आवश्यक चौड़ाई 72 + 96 + 64 + 88 + 3 × 8 = 344 पॉइंट होती है। तीन आइटम दिखने पर बैज छोड़े गए अंतिम आइटमों की जगह लेता है, इसलिए चौड़ाई 72 + 96 + 64 + 3 × 8 + 60 = 316 पॉइंट हो जाती है। तीन गैप चाहिए, क्योंकि उम्मीदवार में तीन आइटम और एक बैज है।

उपलब्ध चौड़ाई दिखने वाले आइटम छिपे हुए आइटम चुने गए उम्मीदवार की चौड़ाई
344 पॉइंट 4 0 344 पॉइंट
343 पॉइंट 3 1 316 पॉइंट
300 पॉइंट 2 2 244 पॉइंट
220 पॉइंट 1 3 140 पॉइंट
60 पॉइंट 0 4 60 पॉइंट

प्रोग्राम में हर उम्मीदवार में उसका वास्तविक बैज टेक्स्ट शामिल होता है। इसलिए यह उदाहरण में मानी गई स्थिर चौड़ाई पर निर्भर किए बिना, बैज टेक्स्टों के बीच के अंतर को संभालता है। उम्मीदवारों की चौड़ाइयों में एकसमान अंतर होना ज़रूरी नहीं; घटती हुई दिखने वाली गिनती चयन की प्राथमिकता बताती है।

केवल गिनती वाला उम्मीदवार न्यूनतम उपयोगी चौड़ाई तय करता है। अगर वह बैज भी फ़िट न हो, तो इन नियमों के तहत उपलब्ध चौड़ाई में पूरी गिनती दिखाना असंभव है। पर्याप्त न्यूनतम चौड़ाई दें, कोई अलग व्यवस्था अपनाएँ या गिनती कहीं और दिखाएँ। कटे हुए कंटेंट को पूरे आइटम दिखाने का सफल परिणाम न मानें।

यह नमूना कंटेंट की न्यूनतम चौड़ाई और उसके छोटे कृत्रिम बैज के लिए थोड़ा बड़ा स्पष्ट फ़ॉन्ट देता है। अगर आप शब्दावली, फ़ॉन्ट, पैडिंग या आसपास का लेआउट बदलते हैं, तो केवल गिनती वाले मामले की फिर से जाँच करें। इस उदाहरण के लिए चुनी गई न्यूनतम चौड़ाई हर बैज के लिए सार्वभौमिक माप नहीं है।

लेआउट चयन को व्यू के जीवनचक्र से अलग रखें

छिपी हुई गिनती हर उम्मीदवार के अपरिवर्तनीय इनपुट का हिस्सा है। प्रोग्राम मापने की विधि से बाइंडिंग में मान नहीं लिखता, गिनती अपडेट को एसिंक्रोनस रूप से शेड्यूल नहीं करता और दिखने का अनुमान लगाने के लिए अपीयरेंस कॉलबैक का उपयोग नहीं करता। पंक्ति चुनने के साथ उसका मेल खाता बैज भी चुना जाता है।

दोहराए जाने वाले उम्मीदवार कंटेंट को सरल रखें। अलग-अलग विकल्पों में किसी लेबल को दोहराने से उस लेबल की सभी विकल्पों में एक साझा पहचान स्थापित नहीं होती। Apple बताता है कि स्टेट स्टोरेज व्यू की पहचान से जुड़ी होती है और पहचान बदलने पर स्टेट बदल सकती है। Demystify SwiftUI

अगर बाद में आप लेबलों को संपादन योग्य कंट्रोल से बदलते हैं, तो उनकी साझा वैल्यू किसी सामान्य पूर्वज या मॉडल में रखें और हर प्रस्तुति में उचित इनपुट या बाइंडिंग पास करें। Apple साझा स्टेट को उन व्यू के सबसे निकटतम साझा पूर्वज में रखने की सलाह देता है जिन्हें उसकी ज़रूरत है। प्रस्तुति बदलने पर उम्मीदवार-स्थानीय स्टेट बने रहने पर निर्भर न रहें। Managing user interface state

यह समाधान चुनी गई पंक्ति के भीतर छिपी हुई गिनती दिखाता है। यह चुनी गई गिनती को किसी सिब्लिंग व्यू या ऐप्लिकेशन मॉडल के लिए उपलब्ध नहीं कराता। Apple का दस्तावेज़ित ViewThatFits इनिशियलाइज़र सीमित अक्षों और उम्मीदवार कंटेंट को स्वीकार करता है; यह चुनी गई गिनती की बाइंडिंग नहीं देता। उस मान को बाहर उपलब्ध कराना एक अतिरिक्त डिज़ाइन आवश्यकता मानें। init(in:content:)

जानें कि कस्टम लेआउट के लिए अलग डिज़ाइन कब चाहिए

विशेष ज्यामिति की ज़रूरत होने पर कस्टम Layout उपयुक्त है। Apple इसकी मुख्य ज़िम्मेदारियाँ संयुक्त आकार बताना और लेआउट प्रॉक्सी के ज़रिए सबव्यू की स्थिति निर्धारित करना बताता है। प्रॉक्सी मापने और रखने की कार्रवाइयाँ देते हैं, अंतर्निहित व्यू तक सीधी पहुँच नहीं। Layout

केवल आख़िरी फ़िट होने वाले आइटम के बाद प्लेसमेंट रोककर आइटम हटाने की कोशिश न करें। Apple के LayoutSubview दस्तावेज़ के अनुसार, हर सबव्यू को एक बार रखना चाहिए। प्लेसमेंट छोड़ना छिपाने का दस्तावेज़ित तरीका नहीं है, और लेआउट प्रॉक्सी कोई सामान्य कंटेंट-रीराइटिंग ऑपरेशन नहीं देता जिससे किसी दूसरे सबव्यू को नया गिनती लेबल बनाया जा सके। LayoutSubview

अगर आप कस्टम लेआउट बनाते हैं, तो माप और प्लेसमेंट के बीच तालमेल बनाए रखें; इसमें स्पेसिंग और इस्तेमाल किया गया आकार प्रस्ताव भी शामिल हैं। Apple स्पष्ट रूप से इन गणनाओं में संगति की माँग करता है। कई संभावित व्यवस्थाओं को आज़माने पर भी यह नियम लागू होता है। placeSubviews(in:proposal:subviews:cache:)

उम्मीदवारों वाला तरीका जानबूझकर सीमित रखा गया है। छह आइटमों के लिए यह सात संभावित पंक्तियाँ और उन पंक्तियों में आइटमों के 21 रूप बताता है। सामान्य रूप में, आइटमों के रूपों की संख्या n × (n + 1) / 2 के अनुसार बढ़ती है। यह संरचनात्मक गिनती है, प्रदर्शन बेंचमार्क नहीं और न ही यह दावा कि हर अपडेट पर हर उम्मीदवार रेंडर होता है। छोटे लेबल संग्रह के लिए इसका उपयोग करें; इसे बड़े संग्रह या महँगे कंटेंट तक बढ़ाने से पहले प्रदर्शन मापें।

पंक्ति की सीमाओं पर जाँच करें

ऐप चलाएँ और उसकी विंडो को धीरे-धीरे आकार बदलें। कंपोनेंट को अनुकूलित करने से पहले इन स्थितियों की जाँच करें:

  • अधिक चौड़ाई पर सभी लेबल दिखते हैं और 0 more बैज नहीं होता।
  • विंडो संकरी होने पर लेबलों के अंत से आइटम गायब होते हैं; कोई लेबल आंशिक रूप से या एलिप्सिस के साथ नहीं दिखता।
  • दिखने वाले आइटमों की गिनती और बैज की छिपे आइटमों की गिनती का योग हमेशा छह होता है।
  • पहले लेबल की लंबाई असाधारण रूप से अधिक होने पर भी केवल गिनती वाला उम्मीदवार उपलब्ध रहता है।
  • खाली ऐरे होने पर पंक्ति No items दिखाती है।
  • अलग आइडेंटिफ़ायर और एक जैसे शीर्षक होने पर भी दोनों आइटम गिनती में शामिल रहते हैं।
  • फ़ॉन्ट या बैज की शब्दावली बदलने के बाद भी केवल गिनती वाला उम्मीदवार न्यूनतम समर्थित चौड़ाई में फ़िट होता है।

छोटी और क्रमबद्ध पंक्ति के लिए, पूरे विकल्प फ़िट होने के नियम को जाँचना आसान बनाते हैं: हर उम्मीदवार में उसके लेबल, स्पेसिंग और छिपे आइटमों की सटीक गिनती शामिल होती है। न्यूनतम चौड़ाई की शर्त स्पष्ट और दोहराए जाने वाले कंटेंट को हल्का रखें; इस तरह पंक्ति आंशिक आइटमों या गिनती अपडेट के अलग चक्र के बिना विंडो के आकार के अनुसार ढल सकती है।

स्रोत