Mac विंडो का आकार बदलने के दौरान स्क्रीन से बाहर खिसकने वाली SwiftUI सामग्री को ठीक करने के लिए, पहले पहचानें कि क्या ड्रॉइंग अपने लेआउट की सीमाओं से बाहर जा रही है, सामग्री सिकुड़ने से इनकार कर रही है, या एम्बेड किया गया AppKit दृश्य अपने कंटेनर को ट्रैक करना बंद कर रहा है। फिर उसी विशिष्ट सीमा को ठीक करें।

यह मार्गदर्शिका उन डेवलपरों के लिए है जो अपने Mac ऐप के आकार बदल सकने वाले इंटरफ़ेस को ठीक कर रहे हैं: लेबल पढ़ने योग्य रखना, नियंत्रणों तक पहुँचना आसान रखना और लंबी सामग्री को स्क्रॉल करने योग्य बनाना। नीचे दिए गए निदान क्रम में कृत्रिम लेबल का उपयोग किया गया है और SwiftUI लेआउट, विंडो आकार निर्धारण तथा AppKit टेक्स्ट रैपिंग के बीच अंतर किया गया है।

पहचानें कि आकार बदलने पर कौन-सी सीमा विफल होती है

SwiftUI लेआउट की शुरुआत पैरेंट से मिलने वाले आकार प्रस्ताव से होती है। चाइल्ड उसके जवाब में अपना आकार चुनता है; प्रस्ताव यह निर्देश नहीं है कि हर चीज़ को उसी आयत में क्लिप कर दिया जाए। Apple ProposedViewSize में न्यूनतम, अधिकतम और आदर्श आकार के प्रस्तावों का दस्तावेज़ देता है। इससे स्पष्ट होता है कि विंडो को संकरा करने से हर वंशज दृश्य का संकरा होना ज़रूरी नहीं है।

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

संदिग्ध चाइल्ड में अस्थायी रूप से .border(Color.orange) और उसके आस-पास के फ़्रेम या कंटेनर में .border(Color.blue) जोड़ें। उनके आयतों की तुलना करने के लिए मॉडिफ़ायर अलग-अलग स्तरों पर रखें। Apple का offset दस्तावेज़ मूल लेआउट स्थिति और खिसकी हुई ड्रॉइंग में अंतर करने के लिए इसी बॉर्डर तकनीक का उदाहरण देता है।

आपको क्या दिखता है पहले यह देखें अगला उपयोगी कदम
ड्रॉइंग स्थिर आयत से बाहर जा रही है offset, position, निर्देशांक की गणनाएँ प्लेसमेंट मॉडिफ़ायर एक-एक करके हटाएँ
कंटेनर संकरा होने पर भी लेबल चौड़ा बना रहता है क्षैतिज fixedSize, स्पष्ट चौड़ाइयाँ लेबल को सीमित चौड़ाई स्वीकार करने दें
नियंत्रण क्षैतिज पंक्ति में फिट नहीं हो पाते नियंत्रणों की कुल चौड़ाई और उनके बीच की दूरी लंबवत विकल्प दें
ऊँचाई घटने पर नीचे की सामग्री गायब हो जाती है ओवरफ़्लो व्यवहार का अभाव सामग्री वाले क्षेत्र को स्क्रॉल करने योग्य बनाएँ
AppKit में होस्ट किया गया SwiftUI पैनल खिसकता है होस्टिंग दृश्य की सीमाएँ और आकार संबंधी कन्स्ट्रेंट होस्ट के आकार की तुलना सामग्री की आवश्यकताओं से करें
AppKit टेक्स्ट दृश्य संकरा होता है, लेकिन पंक्तियाँ चौड़ी बनी रहती हैं टेक्स्ट कंटेनर की चौड़ाई ट्रैकिंग टेक्स्ट दृश्य और टेक्स्ट कंटेनर का कॉन्फ़िगरेशन जाँचें

ये दस्तावेज़ित व्यवहारों से निकली निदान संबंधी परिकल्पनाएँ हैं; ये इस बात की गारंटी नहीं देतीं कि किसी लक्षण का केवल एक ही कारण होगा। एक बार में एक संदिग्ध चीज़ बदलें और आकार बदलने का वही तरीका दोहराएँ। अगर किसी जटिल चाइल्ड को Text("Sample panel") से बदलने पर समस्या दूर हो जाती है, तो उस चाइल्ड की परतें धीरे-धीरे वापस जोड़ें।

ऐसे प्लेसमेंट और आकार निर्धारण नियम हटाएँ जो विंडो के साथ बदलने में बाधा डालते हैं

ऑफ़सेट और केंद्र-आधारित प्लेसमेंट जाँचें

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

position(x:y:) दृश्य के केंद्र को उसके पैरेंट के निर्देशांक स्थान में दिए गए निर्देशांकों पर रखता है। उन निर्देशांकों को ऊपरी-बाएँ कोना मानने से चाइल्ड के आकार से जुड़ी त्रुटि पैदा होती है। एक बार गणना की गई स्थिति पैरेंट का आकार बदलने पर अनुपयुक्त भी हो सकती है। साधारण लेबल और नियंत्रण वाले पैनल के लिए ऐसा अलाइनमेंट चुनें जो कंटेनर के सापेक्ष इच्छित संबंध व्यक्त करता हो। Apple केंद्र-आधारित व्यवहार को position(x:y:) में परिभाषित करता है।

उदाहरण के लिए, .frame(maxWidth: .infinity, alignment: .leading) एक लचीले फ़्रेम के भीतर अग्र-अलाइनमेंट व्यक्त करता है। यह किसी बड़े वंशज दृश्य की अपनी आकार संबंधी आवश्यकताओं को समाप्त नहीं करता। Apple का लचीले फ़्रेम का दस्तावेज़ बताता है कि फ़्रेम प्रस्तावों को कैसे सीमित करता है और अपने चाइल्ड को कैसे रखता है।

निश्चित चौड़ाइयाँ और आदर्श-आकार वाला टेक्स्ट जाँचें

समस्या वाली शाखा में स्पष्ट चौड़ाई सेटिंग और fixedSize के क्षैतिज उपयोग देखें। Apple स्पष्ट रूप से बताता है कि .fixedSize(horizontal: true, vertical: false) टेक्स्ट को पूरी स्ट्रिंग के लिए आवश्यक आदर्श चौड़ाई बनाए रखने देता है, जिससे वह अपने पैरेंट की सीमाओं से बाहर जा सकता है। रैप होने वाले मुख्य टेक्स्ट के लिए यह क्षैतिज आवश्यकता हटाएँ। जहाँ रैप किए गए टेक्स्ट की पूरी ऊँचाई बनाए रखना उचित हो, वहाँ .fixedSize(horizontal: false, vertical: true) पर विचार करें। fixedSize(horizontal:vertical:) देखें।

लंबवत आकार बनाए रखने के लिए उस ऊँचाई को समाने की जगह भी चाहिए। किसी छोटे, स्क्रॉल न होने वाले कंटेनर में लंबवत बढ़ता पैराग्राफ फिर भी पहुँच से बाहर हो सकता है। अगर सभी टेक्स्ट तक पहुँचना ज़रूरी है, तो लंबवत स्क्रॉल क्षेत्र का उपयोग करें; Apple ScrollView में समर्थित स्क्रॉलिंग दिशाओं का दस्तावेज़ देता है।

ज्यामिति पर आधारित गणनाएँ फिर से जाँचें

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

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

स्पष्ट ओवरफ़्लो व्यवहार वाला सघन लेआउट बनाएँ

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

Xcode में macOS SwiftUI ऐप बनाएँ, उसका डिप्लॉयमेंट लक्ष्य macOS 13 या उसके बाद का रखें, और जनरेट किए गए ऐप तथा कंटेंट-व्यू डिक्लेरेशन को इस एक फ़ाइल से बदलें। केवल एक @main डिक्लेरेशन रखें। इस उदाहरण में ViewThatFits और विंडो के आकार बदलने वाले API उपयोग किए गए हैं, जो macOS 13 पर उपलब्ध हैं। Apple उनके व्यवहार का दस्तावेज़ ViewThatFits और windowResizability(_:) में देता है।

import SwiftUI

@main
struct ResizeExampleApp: App {
    var body: some Scene {
        WindowGroup {
            ResizeExampleView()
                .frame(minWidth: 280, minHeight: 220)
        }
        .windowResizability(.contentMinSize)
    }
}

struct ResizeExampleView: View {
    @State private var selection = "Sample A"

    private let details = Array(
        repeating: "Sample notes wrap as the panel becomes narrower.",
        count: 12
    ).joined(separator: " ")

    var body: some View {
        ScrollView(.vertical) {
            VStack(alignment: .leading, spacing: 16) {
                Text("Sample panel")
                    .font(.title2)

                Text(details)
                    .fixedSize(horizontal: false, vertical: true)
                    .frame(maxWidth: .infinity, alignment: .leading)

                ViewThatFits(in: .horizontal) {
                    HStack(spacing: 12) {
                        Button("Choose Sample A") {
                            selection = "Sample A"
                        }
                        Button("Choose Sample B") {
                            selection = "Sample B"
                        }
                    }
                    .fixedSize(horizontal: true, vertical: false)

                    VStack(alignment: .leading, spacing: 12) {
                        Button("Choose Sample A") {
                            selection = "Sample A"
                        }
                        Button("Choose Sample B") {
                            selection = "Sample B"
                        }
                    }
                }

                Text("Selected: \(selection)")
            }
            .padding(20)
            .frame(
                minWidth: 0,
                maxWidth: .infinity,
                alignment: .leading
            )
        }
    }
}

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

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

इस उदाहरण की घोषणाओं और API उपलब्धता की संगति जाँची गई; यहाँ इसे कंपाइल नहीं किया गया क्योंकि Swift कंपाइलर उपलब्ध नहीं था। विंडो और टेक्स्ट के वास्तविक व्यवहार की पुष्टि के लिए इसे macOS पर चलाएँ।

सामग्री का लेआउट ठीक करने के बाद विंडो की सीमाएँ तय करें

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

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

अगर विंडो का नियंत्रण AppKit के पास है और वह SwiftUI को होस्ट करती है, तो होस्टिंग सीमा को अलग से जाँचें। macOS 13 और उसके बाद, NSHostingView.sizingOptions SwiftUI सामग्री से निकले कन्स्ट्रेंट को नियंत्रित करता है। जब होस्ट विंडो का contentView हो, तो यह विंडो की सामग्री के न्यूनतम और अधिकतम आकार भी अपडेट करता है। Apple यह भी बताता है कि जब होस्ट का फ़्रेम, उसकी SwiftUI सामग्री के लिए आवश्यक आकार से अलग होता है, तो सामग्री केंद्र में रखी जाती है। भरपाई के लिए ऑफ़सेट जोड़ने से पहले इन संबंधों की जाँच करें। NSHostingView sizingOptions देखें।

AppKit और TextKit तभी जाँचें जब समस्या वाले दृश्य में उनका उपयोग हो

SwiftUI को प्रतिनिधित्व किए गए मूल दृश्य का आकार तय करने दें

NSViewRepresentable के लिए SwiftUI प्रतिनिधित्व किए गए AppKit दृश्य के frame और bounds को नियंत्रित करता है। Apple स्पष्ट रूप से चेतावनी देता है कि इन गुणों को स्वयं सेट करना SwiftUI से टकराता है और अनिर्धारित व्यवहार पैदा करता है। अगर आपका आकार बदलने वाला हैंडलर बार-बार प्रतिनिधित्व किए गए मूल दृश्य का फ़्रेम असाइन करता है, तो स्वामित्व का यह टकराव हटाएँ और आकार निर्धारण को SwiftUI सीमा के माध्यम से व्यक्त करें। NSViewRepresentable देखें।

जब कस्टम मापन आवश्यक हो, तो macOS 13 और उसके बाद sizeThatFits(_:nsView:context:) उपलब्ध है। एक लेआउट पास के दौरान इसे कई प्रस्ताव मिल सकते हैं; nil लौटाने से डिफ़ॉल्ट आकार निर्धारण का अनुरोध होता है। परिणाम को पिछली विंडो चौड़ाई के बजाय मौजूदा प्रस्ताव और सामग्री पर निर्भर बनाएँ। प्रस्तावित आयाम अनिर्दिष्ट हो तो उसे अपने आप शून्य मानने के बजाय मापन की स्पष्ट नीति तय करें। प्रतिनिधित्व दृश्य का आकार निर्धारण देखें।

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

टेक्स्ट रैपिंग की चौड़ाई को टेक्स्ट दृश्य की चौड़ाई से अलग रखें

अगर समस्या वाला चाइल्ड NSTextView है, तो उसकी मौजूदा चौड़ाई की तुलना उसके टेक्स्ट कंटेनर की चौड़ाई से करें। Apple बताता है कि NSTextContainer.widthTracksTextView का डिफ़ॉल्ट मान false है; इसे true पर सेट करने से टेक्स्ट दृश्य की चौड़ाई बदलने पर कंटेनर अपनी चौड़ाई समायोजित करता है। जब पंक्तियों को टेक्स्ट दृश्य की चौड़ाई के अनुसार फिर से प्रवाहित होना चाहिए, तब यही संबंधित नियंत्रण है। widthTracksTextView देखें।

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

आपके कार्यान्वयन में जिस टेक्स्ट इंजन का उपयोग हो रहा है, उसे बनाए रखें। Apple बताता है कि NSTextView या उसके टेक्स्ट कंटेनर पर layoutManager ऐक्सेस करने से वह NSLayoutManager का उपयोग करने वाले संगतता मोड में जा सकता है। TextKit 2 दृश्य का निदान करते समय इसे यूँ ही न जोड़ें। मौजूदा इंजन और डिप्लॉयमेंट लक्ष्य के लिए उपयुक्त API उपयोग करें। NSTextView देखें।

चौड़ाई और ऊँचाई में बदलाव के दौरान सुधार की पुष्टि करें

अपने ऐप में यह अंतिम क्रम अपनाएँ:

  1. विंडो को धीरे-धीरे उस बिंदु से आगे संकरा करें जहाँ मूल समस्या हुई थी, फिर उसे फिर से चौड़ा करें।
  2. ऊँचाई अलग से घटाएँ और पुष्टि करें कि आवश्यक सारी सामग्री तक पहुँचा जा सकता है।
  3. लंबे कृत्रिम लेबल और कई पंक्तियों वाले टेक्स्ट के साथ दोहराएँ।
  4. चौड़ी और सघन, दोनों व्यवस्थाओं में हर नियंत्रण सक्रिय करके देखें।
  5. AppKit टेक्स्ट दृश्य के लिए पुष्टि करें कि आकार बदलने की दोनों दिशाओं में रैपिंग मौजूदा चौड़ाई के अनुसार होती है।

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

स्रोत