जब SwiftUI में कीबोर्ड दिखाई दे तो TextField को ऊपर ले जाएं


100

TextFieldमेरे मुख्य के अंदर सात हैं ContentView। जब उपयोगकर्ता कीबोर्ड खोलते हैं तो कुछ TextFieldकीबोर्ड के फ्रेम के नीचे छिपे होते हैं। इसलिए मैं सभी TextFieldको क्रमशः स्थानांतरित करना चाहता हूं जब कीबोर्ड दिखाई देता है।

मैंने TextFieldस्क्रीन पर जोड़ने के लिए नीचे दिए गए कोड का उपयोग किया है ।

struct ContentView : View {
    @State var textfieldText: String = ""

    var body: some View {
            VStack {
                TextField($textfieldText, placeholder: Text("TextField1"))
                TextField($textfieldText, placeholder: Text("TextField2"))
                TextField($textfieldText, placeholder: Text("TextField3"))
                TextField($textfieldText, placeholder: Text("TextField4"))
                TextField($textfieldText, placeholder: Text("TextField5"))
                TextField($textfieldText, placeholder: Text("TextField6"))
                TextField($textfieldText, placeholder: Text("TextField6"))
                TextField($textfieldText, placeholder: Text("TextField7"))
            }
    }
}

आउटपुट:

उत्पादन


आप स्क्रॉलव्यू का उपयोग कर सकते हैं। developer.apple.com/documentation/swiftui/scrollview
प्रशांत तुकड़िया

1
@PrashantTukadiya त्वरित प्रतिक्रिया के लिए धन्यवाद। मैंने स्क्रॉलव्यू के अंदर TextField को जोड़ा है लेकिन अभी भी उसी मुद्दे का सामना कर रहा हूं।
हितेश सुरानी

1
@DimaPaliychuk यह काम नहीं करेगा। यह स्विफ्टयूआई है
प्रशांत तुकड़िया

28
कीबोर्ड का प्रदर्शन और यह स्क्रीन पर सामग्री को अस्पष्ट करता है, पहले ऑब्जेक्टिव सी iPhone ऐप के बाद से चारों ओर क्या है? यह ऐसी समस्या है जिसे लगातार हल किया जा रहा है। मैं एक के लिए निराश हूं कि Apple ने SwiftUi के साथ इसे संबोधित नहीं किया है। मुझे पता है कि यह टिप्पणी किसी के लिए भी उपयोगी नहीं है, लेकिन मैं इस मुद्दे को उठाना चाहता था कि हमें वास्तव में Apple पर एक समाधान प्रदान करने के लिए दबाव डालना चाहिए और इस समुदाय पर भरोसा नहीं करना चाहिए कि यह सबसे आम समस्याओं की आपूर्ति करता है।
पी। एनट

जवाबों:


64

कोड Xcode, बीटा 7 के लिए अपडेट किया गया।

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

यदि कोई उनमें से किसी के लिए कीबोर्ड प्रकट होता है, तो पहले वाला सभी टेक्स्ट को हटा देता है। लेकिन जरूरत पड़ने पर ही। यदि कीबोर्ड टेक्स्ट फ़ील्ड को नहीं छिपाता है, तो वे स्थानांतरित नहीं होंगे।

दूसरे उदाहरण में, दृश्य केवल सक्रिय पाठ्यक्षेत्र को छिपाने से बचने के लिए पर्याप्त चलता है।

दोनों उदाहरण अंत में पाए जाने वाले समान कॉमन कोड का उपयोग करते हैं: जियोमेट्रीगेटर और कीबोर्डगार्डियन

पहला उदाहरण (सभी पाठ्य-सामग्री दिखाएं)

जब कीबोर्ड खोला जाता है, तो 3 टेक्स्टफिल्ड को ऊपर ले जाया जाता है ताकि सभी दिखाई दे सकें

struct ContentView: View {
    @ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 1)
    @State private var name = Array<String>.init(repeating: "", count: 3)

    var body: some View {

        VStack {
            Group {
                Text("Some filler text").font(.largeTitle)
                Text("Some filler text").font(.largeTitle)
            }

            TextField("enter text #1", text: $name[0])
                .textFieldStyle(RoundedBorderTextFieldStyle())

            TextField("enter text #2", text: $name[1])
                .textFieldStyle(RoundedBorderTextFieldStyle())

            TextField("enter text #3", text: $name[2])
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(GeometryGetter(rect: $kGuardian.rects[0]))

        }.offset(y: kGuardian.slide).animation(.easeInOut(duration: 1.0))
    }

}

दूसरा उदाहरण (केवल सक्रिय क्षेत्र दिखाएं)

जब प्रत्येक टेक्स्ट फ़ील्ड पर क्लिक किया जाता है, तो क्लिक किए गए टेक्स्ट फ़ील्ड को दृश्यमान बनाने के लिए दृश्य को केवल ऊपर ले जाया जाता है।

struct ContentView: View {
    @ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: 3)
    @State private var name = Array<String>.init(repeating: "", count: 3)

    var body: some View {

        VStack {
            Group {
                Text("Some filler text").font(.largeTitle)
                Text("Some filler text").font(.largeTitle)
            }

            TextField("text #1", text: $name[0], onEditingChanged: { if $0 { self.kGuardian.showField = 0 } })
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(GeometryGetter(rect: $kGuardian.rects[0]))

            TextField("text #2", text: $name[1], onEditingChanged: { if $0 { self.kGuardian.showField = 1 } })
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(GeometryGetter(rect: $kGuardian.rects[1]))

            TextField("text #3", text: $name[2], onEditingChanged: { if $0 { self.kGuardian.showField = 2 } })
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .background(GeometryGetter(rect: $kGuardian.rects[2]))

            }.offset(y: kGuardian.slide).animation(.easeInOut(duration: 1.0))
    }.onAppear { self.kGuardian.addObserver() } 
.onDisappear { self.kGuardian.removeObserver() }

}

GeometryGetter

यह एक ऐसा दृश्य है जो अपने मूल दृश्य के आकार और स्थिति को अवशोषित करता है। इसे प्राप्त करने के लिए, इसे .background संशोधक के अंदर कहा जाता है। यह एक बहुत शक्तिशाली संशोधक है, न कि किसी दृश्य की पृष्ठभूमि को सजाने का एक तरीका। .Background (MyView ()) के दृश्य को पास करते समय, MyView को माता-पिता के रूप में संशोधित दृश्य मिल रहा है। ज्योमेट्रीरीडर का उपयोग करना माता-पिता की ज्यामिति को जानने के लिए दृश्य को संभव बनाता है।

उदाहरण के लिए: Text("hello").background(GeometryGetter(rect: $bounds))पाठ दृश्य के आकार और स्थिति के साथ, और वैश्विक समन्वय स्थान का उपयोग करके, चर सीमाएं भरेंगे।

struct GeometryGetter: View {
    @Binding var rect: CGRect

    var body: some View {
        GeometryReader { geometry in
            Group { () -> AnyView in
                DispatchQueue.main.async {
                    self.rect = geometry.frame(in: .global)
                }

                return AnyView(Color.clear)
            }
        }
    }
}

अद्यतन मैंने DispatchQueue.main.async को जोड़ा, जबकि इसे प्रस्तुत किया जा रहा है, जबकि दृश्य की स्थिति को संशोधित करने की संभावना से बचने के लिए। ***

KeyboardGuardian

कीबोर्डगार्डियन का उद्देश्य, कीबोर्ड शो / छिपाने की घटनाओं पर नज़र रखना और गणना करना है कि दृश्य को स्थानांतरित करने के लिए कितना स्थान चाहिए।

अपडेट: मैंने स्लाइड को रीफ्रेश करने के लिए कीबोर्डगार्डियन को संशोधित किया, जब उपयोगकर्ता एक क्षेत्र से दूसरे में टैब करता है

import SwiftUI
import Combine

final class KeyboardGuardian: ObservableObject {
    public var rects: Array<CGRect>
    public var keyboardRect: CGRect = CGRect()

    // keyboardWillShow notification may be posted repeatedly,
    // this flag makes sure we only act once per keyboard appearance
    public var keyboardIsHidden = true

    @Published var slide: CGFloat = 0

    var showField: Int = 0 {
        didSet {
            updateSlide()
        }
    }

    init(textFieldCount: Int) {
        self.rects = Array<CGRect>(repeating: CGRect(), count: textFieldCount)

    }

    func addObserver() {
NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyBoardDidHide(notification:)), name: UIResponder.keyboardDidHideNotification, object: nil)
}

func removeObserver() {
 NotificationCenter.default.removeObserver(self)
}

    deinit {
        NotificationCenter.default.removeObserver(self)
    }



    @objc func keyBoardWillShow(notification: Notification) {
        if keyboardIsHidden {
            keyboardIsHidden = false
            if let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {
                keyboardRect = rect
                updateSlide()
            }
        }
    }

    @objc func keyBoardDidHide(notification: Notification) {
        keyboardIsHidden = true
        updateSlide()
    }

    func updateSlide() {
        if keyboardIsHidden {
            slide = 0
        } else {
            let tfRect = self.rects[self.showField]
            let diff = keyboardRect.minY - tfRect.maxY

            if diff > 0 {
                slide += diff
            } else {
                slide += min(diff, 0)
            }

        }
    }
}

1
क्या यह प्रोटोकॉल के GeometryGetterअनुरूप बनाकर पृष्ठभूमि की तुलना में दृश्य संशोधक के रूप में संलग्न करना संभव है ViewModifier?
सुदरा

2
यह संभव है, लेकिन लाभ क्या है? आप इसे इस तरह संलग्न करेंगे: के .modifier(GeometryGetter(rect: $kGuardian.rects[1]))बजाय .background(GeometryGetter(rect: $kGuardian.rects[1]))। ज्यादा अंतर नहीं (केवल 2 अक्षर कम)।
कोंटिकी

3
यदि आप इस स्क्रीन से दूर नेविगेट कर रहे हैं तो कुछ स्थितियों में आप नए आयत को असाइन करते समय ज्योमेट्रीगेटर के अंदर प्रोग्राम से एक SIGNAL ABORT प्राप्त कर सकते हैं। कि आप के लिए होता है, तो बस सत्यापित करने के लिए है कि ज्यामिति के आकार कुछ कोड जोड़ने के शून्य से अधिक (geometry.size.width> 0 && geometry.size.height> 0) self.rect के लिए एक मूल्य असाइन करने से पहले
जूलियो Bailon

1
@JulioBailon मुझे पता नहीं है, लेकिन SIGNAL ABORT के साथ मदद geometry.frameकरने के कारण DispatchQueue.main.async, अब आपके समाधान का परीक्षण करेंगे। अपडेट: मदद if geometry.size.width > 0 && geometry.size.height > 0करने से पहले self.rect
रोमन वासिलीव

2
self.rect = geometry.frame (में: .global) पर मेरे लिए यह टूट जाता है और साथ ही सिग्नल गर्भपात हो रही है और इस त्रुटि को संबोधित करने के सभी प्रस्तावित समाधान की कोशिश की
मरवन Roushdy

55

@ क्रैपल के समाधान के निर्माण के लिए, मैंने इसे आज के xcode11 स्विफ्टयूआई समर्थन द्वारा प्रयोग करने योग्य बनाया।

import SwiftUI

final class KeyboardResponder: ObservableObject {
    private var notificationCenter: NotificationCenter
    @Published private(set) var currentHeight: CGFloat = 0

    init(center: NotificationCenter = .default) {
        notificationCenter = center
        notificationCenter.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    deinit {
        notificationCenter.removeObserver(self)
    }

    @objc func keyBoardWillShow(notification: Notification) {
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
            currentHeight = keyboardSize.height
        }
    }

    @objc func keyBoardWillHide(notification: Notification) {
        currentHeight = 0
    }
}

उपयोग:

struct ContentView: View {
    @ObservedObject private var keyboard = KeyboardResponder()
    @State private var textFieldInput: String = ""

    var body: some View {
        VStack {
            HStack {
                TextField("uMessage", text: $textFieldInput)
            }
        }.padding()
        .padding(.bottom, keyboard.currentHeight)
        .edgesIgnoringSafeArea(.bottom)
        .animation(.easeOut(duration: 0.16))
    }
}

प्रकाशित currentHeightएक UI फिर से प्रस्तुत करेगा और कीबोर्ड दिखाने पर अपने TextField को स्थानांतरित करेगा और खारिज किए जाने पर वापस नीचे आएगा। हालाँकि मैंने एक स्क्रॉल दृश्य का उपयोग नहीं किया था।


6
मुझे इसकी सरलता के लिए यह उत्तर पसंद है। मैंने .animation(.easeOut(duration: 0.16))कीबोर्ड के फिसलने की गति से मेल खाने की कोशिश की।
बजे मार्क मयकेन्स

आपने कीबोर्ड के लिए अधिकतम ऊंचाई 340 क्यों रखी है?
डैनियल रयान

1
@DanielRyan कभी-कभी कीबोर्ड ऊंचाई सिम्युलेटर में गलत मान लौटा रही थी। मैं वर्तमान में समस्या को हल करने के लिए एक तरीका नहीं जान सकता
माइकल नेस

1
मैंने खुद उस मुद्दे को नहीं देखा है। शायद यह नवीनतम संस्करणों में तय हो गया है। मैं उस स्थिति में आकार को लॉक नहीं करना चाहता था जब (या होगा) बड़े कीबोर्ड।
डैनियल रयान

1
आप के साथ कोशिश कर सकते हैं keyboardFrameEndUserInfoKey। कि कीबोर्ड के लिए अंतिम फ्रेम रखना चाहिए।
मैथियास क्लासेन

51

मैंने कई प्रस्तावित समाधानों की कोशिश की, और भले ही वे ज्यादातर मामलों में काम करते हैं, मेरे पास कुछ मुद्दे थे - मुख्य रूप से सुरक्षित क्षेत्र के साथ (मेरे पास टैब के अंदर एक फॉर्म है)।

मैंने कुछ अलग-अलग समाधानों के संयोजन को समाप्त किया, और विशिष्ट दृश्य के सुरक्षित क्षेत्र के नीचे इनसेट प्राप्त करने और पैडिंग की गणना में इसका उपयोग करने के लिए ज्यामिति-राइडर का उपयोग किया:

import SwiftUI
import Combine

struct AdaptsToKeyboard: ViewModifier {
    @State var currentHeight: CGFloat = 0

    func body(content: Content) -> some View {
        GeometryReader { geometry in
            content
                .padding(.bottom, self.currentHeight)
                .animation(.easeOut(duration: 0.16))
                .onAppear(perform: {
                    NotificationCenter.Publisher(center: NotificationCenter.default, name: UIResponder.keyboardWillShowNotification)
                        .merge(with: NotificationCenter.Publisher(center: NotificationCenter.default, name: UIResponder.keyboardWillChangeFrameNotification))
                        .compactMap { notification in
                            notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect
                    }
                    .map { rect in
                        rect.height - geometry.safeAreaInsets.bottom
                    }
                    .subscribe(Subscribers.Assign(object: self, keyPath: \.currentHeight))

                    NotificationCenter.Publisher(center: NotificationCenter.default, name: UIResponder.keyboardWillHideNotification)
                        .compactMap { notification in
                            CGFloat.zero
                    }
                    .subscribe(Subscribers.Assign(object: self, keyPath: \.currentHeight))
                })
        }
    }
}

उपयोग:

struct MyView: View {
    var body: some View {
        Form {...}
        .modifier(AdaptsToKeyboard())
    }
}

7
वाह, यह उन सभी का सबसे स्विफ्टयूआई संस्करण है, जिसमें ज्यामिति राइडर और ViewModifier है। इसे प्यार करना।
मत्युज

3
यह इतना उपयोगी और सुरुचिपूर्ण है। इसे लिखने के लिए बहुत-बहुत धन्यवाद।
डैनिलो कैंपोस

2
मैं अपने कीबोर्ड पर एक छोटा खाली सफेद दृश्य देख रहा हूं। यह दृश्य ज्योमेट्री राइडर व्यू है, जिसकी पुष्टि मैंने बैकग्राउंड कलर बदलने से की। किसी भी विचार क्यों GeometryReader मेरे वास्तविक दृश्य और कीबोर्ड के बीच दिखा रहा है।
user832

6
जब मैं कीबोर्ड के साथ दूसरी बार दृश्य पर जाता हूं, तो मुझे Thread 1: signal SIGABRTलाइन में त्रुटि हो रही है rect.height - geometry.safeAreaInsets.bottomऔर क्लिक करें TextField। इससे कोई फर्क नहीं पड़ता कि मैं TextFieldपहली बार क्लिक करता हूं या नहीं। ऐप अभी भी क्रैश हो जाता है।
JLively

2
अंत में कुछ है कि काम करता है! क्यों Apple हमारे लिए यह खिचड़ी भाषा नहीं है !!
डेव कोज़िकोव्स्की

35

मैंने एक ऐसा व्यू बनाया जो कीबोर्ड के दिखाई देने पर उसे सिकोड़ने के लिए किसी अन्य दृश्य को लपेट सकता है।

यह बहुत आसान है। हम कीबोर्ड शो / ईवेंट छिपाने के लिए प्रकाशक बनाते हैं और फिर उनका उपयोग करके सदस्यता लेते हैं onReceive। हम उस परिणाम का उपयोग कीबोर्ड के पीछे एक कीबोर्ड के आकार का आयत बनाने के लिए करते हैं।

struct KeyboardHost<Content: View>: View {
    let view: Content

    @State private var keyboardHeight: CGFloat = 0

    private let showPublisher = NotificationCenter.Publisher.init(
        center: .default,
        name: UIResponder.keyboardWillShowNotification
    ).map { (notification) -> CGFloat in
        if let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {
            return rect.size.height
        } else {
            return 0
        }
    }

    private let hidePublisher = NotificationCenter.Publisher.init(
        center: .default,
        name: UIResponder.keyboardWillHideNotification
    ).map {_ -> CGFloat in 0}

    // Like HStack or VStack, the only parameter is the view that this view should layout.
    // (It takes one view rather than the multiple views that Stacks can take)
    init(@ViewBuilder content: () -> Content) {
        view = content()
    }

    var body: some View {
        VStack {
            view
            Rectangle()
                .frame(height: keyboardHeight)
                .animation(.default)
                .foregroundColor(.clear)
        }.onReceive(showPublisher.merge(with: hidePublisher)) { (height) in
            self.keyboardHeight = height
        }
    }
}

आप इस तरह से दृश्य का उपयोग कर सकते हैं:

var body: some View {
    KeyboardHost {
        viewIncludingKeyboard()
    }
}

इसे सिकोड़ने के बजाय व्यू की सामग्री को ऊपर ले जाने के लिए, पैडिंग या ऑफसेट को viewआयत के साथ VStack में डालने के बजाय जोड़ा जा सकता है ।


6
मुझे लगता है कि यह सही उत्तर है। बस एक मामूली ट्विक मैंने किया: एक आयत के बजाय मैं बस के पैडिंग को संशोधित कर रहा हूं self.viewऔर यह बहुत अच्छा काम करता है। एनीमेशन के साथ कोई समस्या नहीं है
Tae

5
धन्यवाद! अच्छी तरह से काम। जैसा कि @Taed ने कहा, यह एक पेडिंग दृष्टिकोण का उपयोग करना बेहतर है। अंतिम परिणाम होगाvar body: some View { VStack { view .padding(.bottom, keyboardHeight) .animation(.default) } .onReceive(showPublisher.merge(with: hidePublisher)) { (height) in self.keyboardHeight = height } }
fdelafuente

1
कम वोटों के बावजूद यह सबसे तेजी से जवाब देने वाला है। और AnyView का उपयोग करके पिछले दृष्टिकोण, धातु त्वरण मदद को तोड़ता है।
नेल्सन कार्डासी

4
यह एक महान समाधान है, लेकिन यहां मुख्य मुद्दा यह है कि आप केवल दृश्य को स्थानांतरित करने की क्षमता ढीली करते हैं यदि कीबोर्ड उस टेक्स्टफ़ील्ड को छिपा रहा है जिसे आप संपादित कर रहे हैं। मेरा मतलब है: यदि आपके पास कई टेक्स्टफील्ड्स के साथ एक फॉर्म है और आप शीर्ष पर पहले एक को संपादित करना शुरू करते हैं तो आप शायद यह नहीं चाहते हैं कि यह ऊपर चले जाए क्योंकि यह स्क्रीन से बाहर निकल जाएगा।
१०:१५

मुझे वास्तव में उत्तर पसंद है, लेकिन अन्य सभी उत्तरों की तरह यह तब भी काम नहीं करता है जब आपका दृश्य एक TabBar के अंदर है या दृश्य स्क्रीन के नीचे फ्लश नहीं है।
बेन पैच

25

मैंने दृश्य संशोधक का उपयोग करने के लिए वास्तव में सरल बनाया है।

नीचे दिए गए कोड के साथ एक स्विफ्ट फ़ाइल जोड़ें और इस संशोधक को अपने विचारों में जोड़ें:

.keyboardResponsive()
import SwiftUI

struct KeyboardResponsiveModifier: ViewModifier {
  @State private var offset: CGFloat = 0

  func body(content: Content) -> some View {
    content
      .padding(.bottom, offset)
      .onAppear {
        NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { notif in
          let value = notif.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
          let height = value.height
          let bottomInset = UIApplication.shared.windows.first?.safeAreaInsets.bottom
          self.offset = height - (bottomInset ?? 0)
        }

        NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { notif in
          self.offset = 0
        }
    }
  }
}

extension View {
  func keyboardResponsive() -> ModifiedContent<Self, KeyboardResponsiveModifier> {
    return modifier(KeyboardResponsiveModifier())
  }
}


2
अच्छा होगा, अगर यह केवल ऑफसेट होगा, यदि आवश्यक हो (यानी स्क्रॉल न करें, यदि कीबोर्ड इनपुट तत्व को कवर नहीं करता है)। अच्छा है करने के लिए ...
दशकों

यह बहुत अच्छा काम करता है, धन्यवाद। बहुत ही साफ-सुथरा कार्यान्वयन, और मेरे लिए, यदि आवश्यक हो तो केवल स्क्रॉल करता है।
जोशुआ

बहुत बढ़िया! आप इसे Github या अन्य जगहों पर क्यों नहीं प्रदान करते हैं? :) या आप इसे github.com/hackiftekhar/IQKeyboardManager को सुझा सकते हैं क्योंकि उनके पास अभी तक पूर्ण स्विफ्टयूआई समर्थन नहीं है
श्चोड्डर्बल्केन

अभिविन्यास परिवर्तन के साथ अच्छा नहीं खेलेंगे और इसकी आवश्यकता है या नहीं, इसकी परवाह किए बिना ऑफसेट करेंगे।
ग्रैंडस्टेप

यहाँ एक मुद्दा यह है कि यह बिल्कुल भी एनिमेट नहीं कर रहा है ... एक बहुत ही चिड़चिड़ा मोशन बनाता है is
Zorayr

22

Xcode 12 - एक पंक्ति कोड

इस संशोधक को इसमें जोड़ें TextField

.ignoresSafeArea(.keyboard, edges: .bottom)

डेमो

एप्पल ताकि आप स्थानांतरित करने के लिए उपयोग कर सकते हैं, सुरक्षित क्षेत्र के लिए एक क्षेत्र के रूप में कुंजीपटल जोड़ा किसी भीView अन्य क्षेत्रों की तरह कीबोर्ड के साथ।


यह किसी भी पर काम करता है View, सहित TextEditor
मोजतबा होसैनी

@MojtabaHosseini अगर मैं इस व्यवहार को रोकना चाहती हूं तो क्या होगा? मेरी एक छवि है जो अब कीबोर्ड को खोलते समय ऊपर ले जाया जा रहा है, जिसे मैं स्थानांतरित नहीं करना चाहता।
कियर्स

1
आप एक प्रश्न पूछ सकते हैं और इसे यहां लिंक कर सकते हैं। तो मैं आपके प्रतिलिपि योग्य कोड पर एक नज़र डाल सकता हूं और देख सकता हूं कि क्या मैं मदद कर सकता हूं :) @kyrers
Mojtaba Hosseini

2
मैंने खुद ही इसका पता लगा लिया। .ignoresSafeArea(.keyboard)अपने दृश्य में जोड़ें ।
leonboe1

3
दुर्भाग्य से यह केवल iOS 14 है ...
Xaxxus

16

या आप बस IQKeyBoardManagerSwift का उपयोग कर सकते हैं

और वैकल्पिक रूप से टूलबार को छुपाने के लिए इसे अपने ऐप डेलीगेट में जोड़ सकते हैं और कीबोर्ड को छुपाने के लिए किसी भी अन्य कीबोर्ड पर क्लिक करने पर सक्षम कर सकते हैं।

        IQKeyboardManager.shared.enableAutoToolbar = false
        IQKeyboardManager.shared.shouldShowToolbarPlaceholder = false
        IQKeyboardManager.shared.shouldResignOnTouchOutside = true
        IQKeyboardManager.shared.previousNextDisplayMode = .alwaysHide

यह मेरे लिए वास्तव में (अप्रत्याशित) तरीका है। ठोस।
हैलोटीमो

इस ढांचे ने उम्मीद से भी बेहतर काम किया। साझा करने के लिए धन्यवाद!
रिचर्ड पॉटियर

1
SwiftUI पर मेरे लिए काम करना ठीक है - धन्यवाद @DominatorVbN - iPad परिदृश्य मोड पर मैं IQKeyboardManager.shared.keyboardDistanceFromTextFieldआरामदायक अंतराल प्राप्त करने के लिए 40 तक बढ़ने की आवश्यकता थी ।
रिचर्ड ग्रोव्स

IQKeyboardManager.shared.enable = trueमेरे टेक्स्ट फ़ील्ड को छिपाने से कीबोर्ड रखने के लिए भी सेट करना पड़ा । किसी भी मामले में यह सबसे अच्छा समाधान है। मेरे पास 4 फ़ील्ड हैं जो लंबवत रूप से व्यवस्थित हैं और अन्य समाधान मेरे निचले-सबसे फ़ील्ड के लिए काम करेंगे, लेकिन शीर्ष-सबसे अधिक दृश्य को बाहर कर देंगे।
मिस्टरएड

12

आपको ScrollViewकीबोर्ड के आकार का एक निचला पैडिंग जोड़ने और सेट करने की आवश्यकता है ताकि सामग्री कीबोर्ड दिखाई देने पर स्क्रॉल करने में सक्षम हो।

कीबोर्ड का आकार पाने के लिए, आपको NotificationCenterकीबोर्ड ईवेंट के लिए रजिस्टर करने के लिए उपयोग करना होगा । आप ऐसा करने के लिए एक कस्टम वर्ग का उपयोग कर सकते हैं:

import SwiftUI
import Combine

final class KeyboardResponder: BindableObject {
    let didChange = PassthroughSubject<CGFloat, Never>()

    private var _center: NotificationCenter
    private(set) var currentHeight: CGFloat = 0 {
        didSet {
            didChange.send(currentHeight)
        }
    }

    init(center: NotificationCenter = .default) {
        _center = center
        _center.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        _center.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    deinit {
        _center.removeObserver(self)
    }

    @objc func keyBoardWillShow(notification: Notification) {
        print("keyboard will show")
        if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
            currentHeight = keyboardSize.height
        }
    }

    @objc func keyBoardWillHide(notification: Notification) {
        print("keyboard will hide")
        currentHeight = 0
    }
}

BindableObjectअनुरूपता आप एक के रूप में इस वर्ग का उपयोग करने की अनुमति देगा Stateऔर देखने अपडेट लागू करने। यदि आवश्यक हो तो इसके लिए ट्यूटोरियल देखें BindableObject: SwiftUI ट्यूटोरियल

जब आपको वह मिल जाता है, तो आपको ScrollViewकीबोर्ड दिखाई देने पर उसके आकार को कम करने के लिए कॉन्फ़िगर करने की आवश्यकता होती है। सुविधा के लिए मैंने इसे ScrollViewकिसी तरह के घटक में लपेटा :

struct KeyboardScrollView<Content: View>: View {
    @State var keyboard = KeyboardResponder()
    private var content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    var body: some View {
        ScrollView {
            VStack {
                content
            }
        }
        .padding(.bottom, keyboard.currentHeight)
    }
}

अब आपको बस इतना करना है कि आप अपनी सामग्री को कस्टम के अंदर एम्बेड करें ScrollView

struct ContentView : View {
    @State var textfieldText: String = ""

    var body: some View {
        KeyboardScrollView {
            ForEach(0...10) { index in
                TextField(self.$textfieldText, placeholder: Text("TextField\(index)")) {
                    // Hide keyboard when uses tap return button on keyboard.
                    self.endEditing(true)
                }
            }
        }
    }

    private func endEditing(_ force: Bool) {
        UIApplication.shared.keyWindow?.endEditing(true)
    }
}

संपादित करें: कीबोर्ड के छिपने पर स्क्रॉल व्यवहार वास्तव में अजीब है। शायद पैडिंग को अपडेट करने के लिए एक एनीमेशन का उपयोग करके इसे ठीक किया जाएगा, या आपको paddingस्क्रॉल दृश्य आकार को समायोजित करने के अलावा किसी और चीज़ का उपयोग करने पर विचार करना चाहिए ।


ऐसा लगता है कि आप bindableobject में अनुभव है। मैं इसे काम नहीं कर सकता जैसा मैं चाहता हूं। यह अच्छा होगा यदि आप अधिक देख सकते हैं: stackoverflow.com/questions/56500147/…
SwiftiSwift

आप @ObjectBinding
SwiftiSwift

3
BindableObjectपदावनत के साथ , यह अब और काम नहीं कर रहा है, दुर्भाग्य से।
LinusGeffarth

2
@LinusGeffarth जो इसके लायक है, BindableObjectउसके लिए बस इसका नाम बदलकर ObservableObject, और किया didChangeगया था objectWillChange। ऑब्जेक्ट दृश्य को ठीक-ठीक अपडेट करता है (हालाँकि मैंने @ObservedObjectइसके बजाय इसका उपयोग करके परीक्षण किया है @State)
SeizeTheDay

नमस्ते, यह समाधान सामग्री को स्क्रॉल कर रहा है, लेकिन यह कीबोर्ड के ऊपर कुछ सफेद क्षेत्र दिखाता है जो टेक्स्टफील्ड के आधे हिस्से को छुपाता है। कृपया मुझे बताएं कि हम सफेद क्षेत्र को कैसे हटा सकते हैं।
शाहबाज़ सज्जाद

6

मैंने एक संशोधित एसपीएम पैकेज में मौजूदा समाधानों की समीक्षा की और उन्हें संशोधित किया जो एक .keyboardAware()संशोधक प्रदान करता है :

KeyboardAwareSwiftUI

उदाहरण:

struct KeyboardAwareView: View {
    @State var text = "example"

    var body: some View {
        NavigationView {
            ScrollView {
                VStack(alignment: .leading) {
                    ForEach(0 ..< 20) { i in
                        Text("Text \(i):")
                        TextField("Text", text: self.$text)
                            .textFieldStyle(RoundedBorderTextFieldStyle())
                            .padding(.bottom, 10)
                    }
                }
                .padding()
            }
            .keyboardAware()  // <--- the view modifier
            .navigationBarTitle("Keyboard Example")
        }

    }
}

स्रोत:

import UIKit
import SwiftUI

public class KeyboardInfo: ObservableObject {

    public static var shared = KeyboardInfo()

    @Published public var height: CGFloat = 0

    private init() {
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged), name: UIApplication.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged), name: UIResponder.keyboardWillHideNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardChanged), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
    }

    @objc func keyboardChanged(notification: Notification) {
        if notification.name == UIApplication.keyboardWillHideNotification {
            self.height = 0
        } else {
            self.height = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.height ?? 0
        }
    }

}

struct KeyboardAware: ViewModifier {
    @ObservedObject private var keyboard = KeyboardInfo.shared

    func body(content: Content) -> some View {
        content
            .padding(.bottom, self.keyboard.height)
            .edgesIgnoringSafeArea(self.keyboard.height > 0 ? .bottom : [])
            .animation(.easeOut)
    }
}

extension View {
    public func keyboardAware() -> some View {
        ModifiedContent(content: self, modifier: KeyboardAware())
    }
}

मैं सिर्फ टेक्स्टव्यू की आधी ऊंचाई देखता हूं। क्या आप जानते हैं कि इसे कैसे हल किया जाए?
मटरू अलेक्जेंडर

अच्छा। इसने मेरा समय बचाया। इसका उपयोग करने से पहले, हम जानते हैं कि यह संशोधक दृश्य के तल गद्दी को संभालता है।
ब्राउन्सो हान

5

मैंने शुरुआती बिंदु के रूप में बेंजामिन किंडल के जवाब का इस्तेमाल किया, लेकिन मेरे पास कुछ मुद्दे थे जिन्हें मैं संबोधित करना चाहता था।

  1. यहां अधिकांश उत्तर कीबोर्ड के फ्रेम को बदलने से संबंधित नहीं हैं, इसलिए यदि उपयोगकर्ता कीबोर्ड ऑनस्क्रीन के साथ डिवाइस को घुमाता है तो वे टूट जाते हैं। keyboardWillChangeFrameNotificationइसे संसाधित किए गए सूचनाओं की सूची में जोड़ना ।
  2. मैं समान-लेकिन-अलग-अलग मानचित्र बंद होने के साथ कई प्रकाशक नहीं चाहता था, इसलिए मैंने सभी तीन कीबोर्ड सूचनाओं को एक ही प्रकाशक में जंजीर में बांध दिया। यह वास्तव में एक लंबी श्रृंखला है, लेकिन प्रत्येक चरण बहुत सीधा है।
  3. मैंने वह initफ़ंक्शन प्रदान किया है, @ViewBuilderजिससे आप KeyboardHostकिसी अन्य दृश्य की तरह दृश्य का उपयोग कर सकते हैं और अपनी सामग्री को अनुगामी क्लोजर में पास कर सकते हैं, क्योंकि सामग्री दृश्य को पैरामीटर के रूप में पास करने के विपरीत है init
  4. जैसा कि Tae और fdelafuente ने टिप्पणी में सुझाव दिया था कि मैंने Rectangleनीचे की पैडिंग को समायोजित करने के लिए स्वैप किया था ।
  5. हार्ड-कोडेड "UIKeyboardFrameEndUserInfoKey" स्ट्रिंग उपयोग करने के बजाय मैं में प्रदान की तार उपयोग करना चाहता था UIWindowके रूप में UIWindow.keyboardFrameEndUserInfoKey

खींच रहा है कि मेरे पास एक साथ:

struct KeyboardHost<Content>: View  where Content: View {
    var content: Content

    /// The current height of the keyboard rect.
    @State private var keyboardHeight = CGFloat(0)

    /// A publisher that combines all of the relevant keyboard changing notifications and maps them into a `CGFloat` representing the new height of the
    /// keyboard rect.
    private let keyboardChangePublisher = NotificationCenter.Publisher(center: .default,
                                                                       name: UIResponder.keyboardWillShowNotification)
        .merge(with: NotificationCenter.Publisher(center: .default,
                                                  name: UIResponder.keyboardWillChangeFrameNotification))
        .merge(with: NotificationCenter.Publisher(center: .default,
                                                  name: UIResponder.keyboardWillHideNotification)
            // But we don't want to pass the keyboard rect from keyboardWillHide, so strip the userInfo out before
            // passing the notification on.
            .map { Notification(name: $0.name, object: $0.object, userInfo: nil) })
        // Now map the merged notification stream into a height value.
        .map { ($0.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect ?? .zero).size.height }
        // If you want to debug the notifications, swap this in for the final map call above.
//        .map { (note) -> CGFloat in
//            let height = (note.userInfo?[UIWindow.keyboardFrameEndUserInfoKey] as? CGRect ?? .zero).size.height
//
//            print("Received \(note.name.rawValue) with height \(height)")
//            return height
//    }

    var body: some View {
        content
            .onReceive(keyboardChangePublisher) { self.keyboardHeight = $0 }
            .padding(.bottom, keyboardHeight)
            .animation(.default)
    }

    init(@ViewBuilder _ content: @escaping () -> Content) {
        self.content = content()
    }
}

struct KeyboardHost_Previews: PreviewProvider {
    static var previews: some View {
        KeyboardHost {
            TextField("TextField", text: .constant("Preview text field"))
        }
    }
}


यह समाधान काम नहीं करता है, यह Keyboardऊंचाई बढ़ाता है
GSerjo

क्या आप @GSerjo को देखने वाली समस्याओं के बारे में विस्तार से बता सकते हैं? मैं अपने ऐप में इस कोड का उपयोग कर रहा हूं और यह मेरे लिए ठीक काम कर रहा है।
तीमुथियुस सैंडर्स

क्या आप कृपया PridictiveiOS में चालू कर सकते हैं keyboardSettings-> General-> Keyboard-> Pridictive। इस स्थिति में यह
कैलक्लेट

@GSerjo: IOS 13.1 बीटा पर चलने वाले iPad टच (7 वें जीन) पर प्रिडिक्टिव टेक्स्ट सक्षम है। यह भविष्यवाणी पंक्ति की ऊंचाई के लिए सही ढंग से पैडिंग जोड़ता है। (ध्यान दें, मैं यहां कीबोर्ड की ऊंचाई को समायोजित नहीं कर रहा हूं, मैं स्वयं दृश्य के पैडिंग में शामिल कर रहा हूं ।) डिबगिंग मानचित्र में स्वैप करने का प्रयास करें जो कि टिप्पणी की गई है और आपके द्वारा पूर्वानुमान के लिए प्राप्त मानों के साथ खेलते हैं। कुंजीपटल। मैं एक और टिप्पणी में एक लॉग पोस्ट करूँगा।
टिमोथी सैंडर्स

"डिबगिंग" नक्शे के अनियोजित होने के कारण आप मान को असाइन किया जा सकता है keyboardHeight। मेरे iPod टच पर (चित्र में) 254 अंक पर भविष्य कहनेवाला कीबोर्ड है। इसके बिना 216 अंक है। मैं एक कीबोर्ड ऑनस्क्रीन और पेडिंग अपडेट को सही तरीके से अनुमान लगा सकता हूं। भविष्य कहनेवाला के साथ एक कीबोर्ड जोड़ना: Received UIKeyboardWillChangeFrameNotification with height 254.0 Received UIKeyboardWillShowNotification with height 254.0 जब मैं भविष्य कहनेवाला पाठ बंद कर देता हूं:Received UIKeyboardWillChangeFrameNotification with height 216.0
टिमोथी सैंडर्स

5

इन जवाबों का एक बहुत वास्तव में ईमानदार होने के लिए फूला हुआ लगता है। यदि आप SwiftUI का उपयोग कर रहे हैं तो आप कम्बाइन का भी उपयोग कर सकते हैं।

KeyboardResponderनीचे दिखाए गए अनुसार बनाएँ , फिर आप पहले प्रदर्शित के रूप में उपयोग कर सकते हैं।

IOS 14 के लिए अपडेट किया गया।

import Combine
import UIKit

final class KeyboardResponder: ObservableObject {

    @Published var keyboardHeight: CGFloat = 0

    init() {
        NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)
            .compactMap { notification in
                (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.height
            }
            .receive(on: DispatchQueue.main)
            .assign(to: \.keyboardHeight)
    }
}


struct ExampleView: View {
    @ObservedObject private var keyboardResponder = KeyboardResponder()
    @State private var text: String = ""

    var body: some View {
        VStack {
            Text(text)
            Spacer()
            TextField("Example", text: $text)
        }
        .padding(.bottom, keyboardResponder.keyboardHeight)
    }
}

मैंने एनीमेशन से मेल खाने के लिए एक .animation (.easeIn) जोड़ा जिसके साथ कीबोर्ड दिखाई देता है
Michiel Pelt

(आईओएस 13 के लिए इस उत्तर के इतिहास पर जाएं)
लोरिस फो

1
नमस्ते, .assign (to: \ .keyboardHeight) यह त्रुटि दे रहा है "संदर्भ से महत्वपूर्ण पथ प्रकार नहीं समझा जा सकता है; स्पष्ट रूप से मूल प्रकार निर्दिष्ट करने पर विचार करें"। कृपया मुझे ios 13 और ios 14 दोनों के लिए उचित और स्वच्छ समाधान बताएं
शाहबाज सज्जाद

मुझे UIResponder.keyboardWillHideNotification के लिए एक और श्रोता जोड़ना था। इसके अलावा - यह एकमात्र उपाय है जो मेरे लिए काम करता है। धन्यवाद!
एंटोनिन कारसेक

4

यह @kontiki द्वारा निर्मित से अनुकूलित है। मेरे पास यह बीटा 8 / जीएम बीज के तहत एक ऐप में चल रहा है, जहां स्क्रॉल किए जाने वाले फ़ील्ड की जरूरत है एक नेविगेशन व्यू के अंदर एक फॉर्म का हिस्सा है। यहाँ कीबोर्डगार्डियन है:

//
//  KeyboardGuardian.swift
//
//  /programming/56491881/move-textfield-up-when-thekeyboard-has-appeared-by-using-swiftui-ios
//

import SwiftUI
import Combine

/// The purpose of KeyboardGuardian, is to keep track of keyboard show/hide events and
/// calculate how much space the view needs to be shifted.
final class KeyboardGuardian: ObservableObject {
    let objectWillChange = ObservableObjectPublisher() // PassthroughSubject<Void, Never>()

    public var rects: Array<CGRect>
    public var keyboardRect: CGRect = CGRect()

    // keyboardWillShow notification may be posted repeatedly,
    // this flag makes sure we only act once per keyboard appearance
    private var keyboardIsHidden = true

    var slide: CGFloat = 0 {
        didSet {
            objectWillChange.send()
        }
    }

    public var showField: Int = 0 {
        didSet {
            updateSlide()
        }
    }

    init(textFieldCount: Int) {
        self.rects = Array<CGRect>(repeating: CGRect(), count: textFieldCount)

        NotificationCenter.default.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        NotificationCenter.default.addObserver(self, selector: #selector(keyBoardDidHide(notification:)), name: UIResponder.keyboardDidHideNotification, object: nil)

    }

    @objc func keyBoardWillShow(notification: Notification) {
        if keyboardIsHidden {
            keyboardIsHidden = false
            if let rect = notification.userInfo?["UIKeyboardFrameEndUserInfoKey"] as? CGRect {
                keyboardRect = rect
                updateSlide()
            }
        }
    }

    @objc func keyBoardDidHide(notification: Notification) {
        keyboardIsHidden = true
        updateSlide()
    }

    func updateSlide() {
        if keyboardIsHidden {
            slide = 0
        } else {
            slide = -keyboardRect.size.height
        }
    }
}

उसके बाद, मैंने रेस्म्स एरे में स्लॉट्स और कुल संख्या को ट्रैक करने के लिए एक एनुम का उपयोग किया:

enum KeyboardSlots: Int {
    case kLogPath
    case kLogThreshold
    case kDisplayClip
    case kPingInterval
    case count
}

KeyboardSlots.count.rawValueआवश्यक सरणी क्षमता है; रॉवैल्यू के रूप में अन्य लोग आपके द्वारा .background (GeometryGetter) कॉल्स के लिए उपयुक्त इंडेक्स देंगे।

उस सेट के साथ, इस के साथ कीबोर्डगार्डियन पर विचार मिलते हैं:

@ObservedObject private var kGuardian = KeyboardGuardian(textFieldCount: SettingsFormBody.KeyboardSlots.count.rawValue)

वास्तविक आंदोलन इस तरह है:

.offset(y: kGuardian.slide).animation(.easeInOut(duration: 1))

दृश्य से जुड़ा हुआ। मेरे मामले में, यह संपूर्ण नेविगेशन दृश्य से जुड़ा हुआ है, इसलिए कीबोर्ड के प्रकट होते ही पूरा असेंबली स्लाइड हो जाता है।

मैंने SwiftUI वाले दशमलव कीबोर्ड पर Done टूलबार या रिटर्न कुंजी प्राप्त करने की समस्या को हल नहीं किया है, इसलिए इसके बजाय मैं इसे एक टैप पर कहीं और छिपाने के लिए उपयोग कर रहा हूं:

struct DismissingKeyboard: ViewModifier {
    func body(content: Content) -> some View {
        content
            .onTapGesture {
                let keyWindow = UIApplication.shared.connectedScenes
                        .filter({$0.activationState == .foregroundActive})
                        .map({$0 as? UIWindowScene})
                        .compactMap({$0})
                        .first?.windows
                        .filter({$0.isKeyWindow}).first
                keyWindow?.endEditing(true)                    
        }
    }
}

आप इसे एक दृश्य के रूप में संलग्न करते हैं

.modifier(DismissingKeyboard())

कुछ विचार (जैसे, बीनने वाले) उस संलग्न को पसंद नहीं करते हैं, इसलिए आपको कुछ हद तक बारीक होने की आवश्यकता हो सकती है कि आप केवल बाहरी दृश्य पर थप्पड़ मारने के बजाय संशोधक को कैसे संलग्न करते हैं।

कड़ी मेहनत के लिए @kontiki को बहुत धन्यवाद। आपको अभी भी उसके ज्यामिति-चित्रक की आवश्यकता होगी ऊपर (नहीं, मैंने इसे प्राथमिकता में उपयोग करने के लिए इसे बदलने के लिए काम नहीं किया) क्योंकि वह अपने उदाहरणों में दिखाता है।


1
अलग-अलग करने वालों के लिए: क्यों? मैंने कुछ उपयोगी जोड़ने का प्रयास किया, इसलिए मैं जानना चाहूंगा कि कैसे आपके विचार में मैं गलत हो गया
फेल्डर

4

ऊपर दिए गए समाधानों में से कुछ में कुछ समस्याएँ थीं और जरूरी नहीं कि "सबसे साफ" दृष्टिकोण हो। इस वजह से, मैंने नीचे कार्यान्वयन के लिए कुछ चीजों को संशोधित किया है।

extension View {
    func onKeyboard(_ keyboardYOffset: Binding<CGFloat>) -> some View {
        return ModifiedContent(content: self, modifier: KeyboardModifier(keyboardYOffset))
    }
}

struct KeyboardModifier: ViewModifier {
    @Binding var keyboardYOffset: CGFloat
    let keyboardWillAppearPublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardWillShowNotification)
    let keyboardWillHidePublisher = NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)

    init(_ offset: Binding<CGFloat>) {
        _keyboardYOffset = offset
    }

    func body(content: Content) -> some View {
        return content.offset(x: 0, y: -$keyboardYOffset.wrappedValue)
            .animation(.easeInOut(duration: 0.33))
            .onReceive(keyboardWillAppearPublisher) { notification in
                let keyWindow = UIApplication.shared.connectedScenes
                    .filter { $0.activationState == .foregroundActive }
                    .map { $0 as? UIWindowScene }
                    .compactMap { $0 }
                    .first?.windows
                    .filter { $0.isKeyWindow }
                    .first

                let yOffset = keyWindow?.safeAreaInsets.bottom ?? 0

                let keyboardFrame = (notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue ?? .zero

                self.$keyboardYOffset.wrappedValue = keyboardFrame.height - yOffset
        }.onReceive(keyboardWillHidePublisher) { _ in
            self.$keyboardYOffset.wrappedValue = 0
        }
    }
}
struct RegisterView: View {
    @State var name = ""
    @State var keyboardYOffset: CGFloat = 0

    var body: some View {

        VStack {
            WelcomeMessageView()
            TextField("Type your name...", text: $name).bordered()
        }.onKeyboard($keyboardYOffset)
            .background(WelcomeBackgroundImage())
            .padding()
    }
}

मुझे एक क्लीनर दृष्टिकोण पसंद आया होगा और सामग्री को ऑफसेट करने के लिए निर्मित दृश्य (संशोधक नहीं) में जिम्मेदारी को स्थानांतरित करना होगा, लेकिन ऐसा प्रतीत होता है कि मैं ऑफसेट कोड को दृश्य में स्थानांतरित करते समय प्रकाशकों को ठीक से ट्रिगर नहीं कर सका। ...

यह भी ध्यान दें कि प्रकाशकों को इस उदाहरण में उपयोग किया जाना था क्योंकि final classवर्तमान में अज्ञात अपवाद क्रैश (भले ही यह इंटरफ़ेस आवश्यकताओं को पूरा करता है) और ऑफसेट कोड को लागू करते समय एक स्क्रॉलव्यू समग्र दृष्टिकोण है।


बहुत अच्छा समाधान, अत्यधिक की सिफारिश! मैंने यह इंगित करने के लिए एक बूल जोड़ा कि क्या कीबोर्ड वर्तमान में सक्रिय था।
मूँगफली के दानेदार

3

मुझे यकीन नहीं है कि SwiftUI के लिए संक्रमण / एनीमेशन एपीआई पूरा हो गया है, लेकिन आप इसके CGAffineTransformसाथ उपयोग कर सकते हैं.transformEffect

इस तरह प्रकाशित संपत्ति के साथ एक अवलोकन कीबोर्ड वस्तु बनाएं:

    final class KeyboardResponder: ObservableObject {
    private var notificationCenter: NotificationCenter
    @Published var readyToAppear = false

    init(center: NotificationCenter = .default) {
        notificationCenter = center
        notificationCenter.addObserver(self, selector: #selector(keyBoardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
        notificationCenter.addObserver(self, selector: #selector(keyBoardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
    }

    deinit {
        notificationCenter.removeObserver(self)
    }

    @objc func keyBoardWillShow(notification: Notification) {
        readyToAppear = true
    }

    @objc func keyBoardWillHide(notification: Notification) {
        readyToAppear = false
    }

}

तब आप उस संपत्ति का उपयोग इस तरह से अपने विचार को पुनर्व्यवस्थित करने के लिए कर सकते हैं:

    struct ContentView : View {
    @State var textfieldText: String = ""
    @ObservedObject private var keyboard = KeyboardResponder()

    var body: some View {
        return self.buildContent()
    }

    func buildContent() -> some View {
        let mainStack = VStack {
            TextField("TextField1", text: self.$textfieldText)
            TextField("TextField2", text: self.$textfieldText)
            TextField("TextField3", text: self.$textfieldText)
            TextField("TextField4", text: self.$textfieldText)
            TextField("TextField5", text: self.$textfieldText)
            TextField("TextField6", text: self.$textfieldText)
            TextField("TextField7", text: self.$textfieldText)
        }
        return Group{
            if self.keyboard.readyToAppear {
                mainStack.transformEffect(CGAffineTransform(translationX: 0, y: -200))
                    .animation(.spring())
            } else {
                mainStack
            }
        }
    }
}

या सरल

VStack {
        TextField("TextField1", text: self.$textfieldText)
        TextField("TextField2", text: self.$textfieldText)
        TextField("TextField3", text: self.$textfieldText)
        TextField("TextField4", text: self.$textfieldText)
        TextField("TextField5", text: self.$textfieldText)
        TextField("TextField6", text: self.$textfieldText)
        TextField("TextField7", text: self.$textfieldText)
    }.transformEffect(keyboard.readyToAppear ? CGAffineTransform(translationX: 0, y: -50) : .identity)
            .animation(.spring())

मुझे यह उत्तर बहुत पसंद है, लेकिन मुझे यकीन नहीं है कि 'स्क्रीनसाइज.पोर्टरेट' कहां से आ रही है।
मीशा स्टोन

हाय @MishaStone धन्यवाद पोर मेरा दृष्टिकोण चुनें। ScreenSize.portrait एक वर्ग है जिसे मैंने ओरिएंटेशन और प्रतिशत के आधार पर स्क्रीन बेस का माप प्राप्त करने के लिए बनाया था .... लेकिन आप इसे अपने अनुवाद के लिए किसी भी मूल्य की आवश्यकता के साथ बदल सकते हैं
ब्लैकटिगो

3

Xcode 12 बीटा 4 एक नया दृश्य संशोधक जोड़ता है जिसका ignoresSafeAreaउपयोग आप अब कीबोर्ड से बचने के लिए कर सकते हैं।

.ignoresSafeArea([], edges: [])

यह कीबोर्ड और सभी सुरक्षित क्षेत्र किनारों से बचा जाता है। .keyboardयदि आप इसे टालना नहीं चाहते हैं तो आप पहला पैरामीटर सेट कर सकते हैं। कम से कम मेरे विचार में पदानुक्रम सेटअप में कुछ क्विर्क्स हैं, लेकिन ऐसा लगता है कि यह वही है जिस तरह से Apple हमें कीबोर्ड से बचना चाहता है।


2

यहां से कॉपी किया गया उत्तर: SwiftUI के साथ हमेशा कीबोर्ड टॉप पर TextField

मैंने विभिन्न तरीकों की कोशिश की है, और उनमें से किसी ने भी मेरे लिए काम नहीं किया है। यह नीचे एक ही है जो विभिन्न उपकरणों के लिए काम करता है।

इस एक्सटेंशन को एक फ़ाइल में जोड़ें:

import SwiftUI
import Combine

extension View {
    func keyboardSensible(_ offsetValue: Binding<CGFloat>) -> some View {
        
        return self
            .padding(.bottom, offsetValue.wrappedValue)
            .animation(.spring())
            .onAppear {
                NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillShowNotification, object: nil, queue: .main) { notification in
                    
                    let keyWindow = UIApplication.shared.connectedScenes
                        .filter({$0.activationState == .foregroundActive})
                        .map({$0 as? UIWindowScene})
                        .compactMap({$0})
                        .first?.windows
                        .filter({$0.isKeyWindow}).first
                    
                    let bottom = keyWindow?.safeAreaInsets.bottom ?? 0
                    
                    let value = notification.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect
                    let height = value.height
                    
                    offsetValue.wrappedValue = height - bottom
                }
                
                NotificationCenter.default.addObserver(forName: UIResponder.keyboardWillHideNotification, object: nil, queue: .main) { _ in
                    offsetValue.wrappedValue = 0
                }
        }
    }
}

आपके विचार में, आपको ऑफसेटवैल्यू को बांधने के लिए एक चर की आवश्यकता है:

struct IncomeView: View {

  @State private var offsetValue: CGFloat = 0.0

  var body: some View { 
    
    VStack {
     //...       
    }
    .keyboardSensible($offsetValue)
  }
}

2
बस एक FYI करें, आप कॉल करते समय ऑब्जेक्ट्स के मालिक हैं NotificationCenter.default.addObserver... आपको उन स्टोर करने और पर्यवेक्षकों को उचित समय पर निकालने की आवश्यकता है ...
TheCodingArt

हाय @TheCodingArt, यह सही है कि मैंने ऐसा करने की कोशिश की है ( oleb.net/blog/2018/01/notificationcenter-removeobserver ) लेकिन यह मेरे लिए काम नहीं करता है, कोई विचार?
रे

2

जैसा कि मार्क Krenek और Heiko ने बताया है, Apple Xcode 12 बीटा में लंबे समय से इस मुद्दे को संबोधित करता प्रतीत हो रहा था। चीजें तेजी से बढ़ रही हैं। Xcode 12 बीटा 5 के लिए जारी किए गए नोट्स के अनुसार 18 अगस्त, 2020 को प्रकाशित किया गया था "प्रपत्र, सूची, और TextEditor अब कीबोर्ड के पीछे सामग्री छिपा नहीं सकते हैं। (66172025)"। मैं अभी इसे डाउनलोड करता हूं और बीटा 5 सिम्युलेटर (आईफोन एसई 2) में एक त्वरित कंटेनर के साथ एक ऐप में एक त्वरित परीक्षण दिया था जो मैंने कुछ दिनों पहले शुरू किया था।

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

हालाँकि, जैसा कि Андрей Первушин ने एक टिप्पणी में बताया, TextEditor के साथ एक समस्या है । बीटा 5 और 6 स्वचालित रूप से कीबोर्ड के लिए जगह बनाने के लिए एन्कैप्सुलेटिंग फॉर्म को उपयुक्त तल पेडिंग प्रदान करेगा। लेकिन यह स्वचालित रूप से फ़ॉर्म को स्क्रॉल नहीं करेगा। कीबोर्ड TextEditor को कवर करेगा। इसलिए TextField के विपरीत, उपयोगकर्ता को TextEditor को दिखाई देने के लिए फ़ॉर्म को स्क्रॉल करना होगा। मैं एक बग रिपोर्ट दर्ज करूंगा। शायद बीटा 7 इसे ठीक कर देगा। बहुत करीब …

https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-14-beta-release-notes/


मैं देख रहा हूँ Apple जारी नोट, Beta5 और Beta6 पर परीक्षण किया, TextField काम करता है, TextEditor नहीं, मुझे क्या याद आती है? @State var text = "" var body: some View {फॉर्म {सेक्शन {टेक्स्ट (टेक्स्ट) .frame (ऊंचाई: 500)} सेक्शन {TextField ("5555", टेक्स्ट: $ टेक्स्ट) .frame (ऊंचाई: 50)}। खंड {TextEditor (पाठ: $ पाठ) .frame (ऊंचाई: 120)}}}
Андрей Первушин

2

उपयोग:

import SwiftUI

var body: some View {
    ScrollView {
        VStack {
          /*
          TextField()
          */
        }
    }.keyboardSpace()
}

कोड:

import SwiftUI
import Combine

let keyboardSpaceD = KeyboardSpace()
extension View {
    func keyboardSpace() -> some View {
        modifier(KeyboardSpace.Space(data: keyboardSpaceD))
    }
}

class KeyboardSpace: ObservableObject {
    var sub: AnyCancellable?
    
    @Published var currentHeight: CGFloat = 0
    var heightIn: CGFloat = 0 {
        didSet {
            withAnimation {
                if UIWindow.keyWindow != nil {
                    //fix notification when switching from another app with keyboard
                    self.currentHeight = heightIn
                }
            }
        }
    }
    
    init() {
        subscribeToKeyboardEvents()
    }
    
    private let keyboardWillOpen = NotificationCenter.default
        .publisher(for: UIResponder.keyboardWillShowNotification)
        .map { $0.userInfo![UIResponder.keyboardFrameEndUserInfoKey] as! CGRect }
        .map { $0.height - (UIWindow.keyWindow?.safeAreaInsets.bottom ?? 0) }
    
    private let keyboardWillHide =  NotificationCenter.default
        .publisher(for: UIResponder.keyboardWillHideNotification)
        .map { _ in CGFloat.zero }
    
    private func subscribeToKeyboardEvents() {
        sub?.cancel()
        sub = Publishers.Merge(keyboardWillOpen, keyboardWillHide)
            .subscribe(on: RunLoop.main)
            .assign(to: \.self.heightIn, on: self)
    }
    
    deinit {
        sub?.cancel()
    }
    
    struct Space: ViewModifier {
        @ObservedObject var data: KeyboardSpace
        
        func body(content: Content) -> some View {
            VStack(spacing: 0) {
                content
                
                Rectangle()
                    .foregroundColor(Color(.clear))
                    .frame(height: data.currentHeight)
                    .frame(maxWidth: .greatestFiniteMagnitude)

            }
        }
    }
}

extension UIWindow {
    static var keyWindow: UIWindow? {
        let keyWindow = UIApplication.shared.connectedScenes
            .filter({$0.activationState == .foregroundActive})
            .map({$0 as? UIWindowScene})
            .compactMap({$0})
            .first?.windows
            .filter({$0.isKeyWindow}).first
        return keyWindow
    }
}

आपके समाधान की कोशिश की ... दृश्य केवल टेक्स्टफील्ड के आधे हिस्से तक स्क्रॉल किया गया है। उपरोक्त सभी समाधान की कोशिश की। एक ही मुद्दा मिला। कृपया सहायता कीजिए!!!
सोना

@Zeona, एक साधारण ऐप में प्रयास करें, आप कुछ अलग कर रहे होंगे। यदि आप सुरक्षित क्षेत्र का उपयोग कर रहे हैं, तो '- (UIWindow.keyWindow? .SafeAreaInsets.bottom ?? 0)' को हटाने का प्रयास करें।
8suhas

हटा दिया गया (UIWindow.keyWindow; .safeAreaInsets.bottom ?? 0) तब मुझे कीबोर्ड के ऊपर एक सफेद जगह मिल रही है
सोना

1

हैंडलिंग TabViewकी

मुझे बेंजामिन किंडल का जवाब पसंद है लेकिन यह TabViews का समर्थन नहीं करता है। यहाँ TabViews को संभालने के लिए उनके कोड के लिए मेरा समायोजन है:

  1. UITabViewफ़्रेम सेट होने पर टैब के आकार को संग्रहीत करने के लिए एक्सटेंशन जोड़ें । हम इसे स्टैटिक वेरिएबल में स्टोर कर सकते हैं क्योंकि प्रोजेक्ट में आमतौर पर केवल एक ही टैब व्यू होता है (यदि आपका एक से अधिक है, तो आपको समायोजित करने की आवश्यकता होगी)।
extension UITabBar {

    static var size: CGSize = .zero

    open override var frame: CGRect {
        get {
            super.frame
        } set {
            UITabBar.size = newValue.size
            super.frame = newValue
        }
    }
}
  1. टैब बार की ऊँचाई को ध्यान onReceiveमें KeyboardHostरखते हुए आपको उसे देखने के नीचे बदलना होगा :
.onReceive(showPublisher.merge(with: hidePublisher)) { (height) in
            self.keyboardHeight = max(height - UITabBar.size.height, 0)
        }
  1. और बस! सुपर सिंपल 🎉।

1

मैंने UIHostingControllerइसका विस्तार और समायोजन करके एक पूरी तरह से अलग दृष्टिकोण लिया additionalSafeAreaInsets:

class MyHostingController<Content: View>: UIHostingController<Content> {
    override init(rootView: Content) {
        super.init(rootView: rootView)
    }

    @objc required dynamic init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        NotificationCenter.default.addObserver(self, 
                                               selector: #selector(keyboardDidShow(_:)), 
                                               name: UIResponder.keyboardDidShowNotification,
                                               object: nil)
        NotificationCenter.default.addObserver(self, 
                                               selector: #selector(keyboardWillHide), 
                                               name: UIResponder.keyboardWillHideNotification, 
                                               object: nil)
    }       

    @objc func keyboardDidShow(_ notification: Notification) {
        guard let info:[AnyHashable: Any] = notification.userInfo,
            let frame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else {
                return
        }

        // set the additionalSafeAreaInsets
        let adjustHeight = frame.height - (self.view.safeAreaInsets.bottom - self.additionalSafeAreaInsets.bottom)
        self.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: adjustHeight, right: 0)

        // now try to find a UIResponder inside a ScrollView, and scroll
        // the firstResponder into view
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { 
            if let firstResponder = UIResponder.findFirstResponder() as? UIView,
                let scrollView = firstResponder.parentScrollView() {
                // translate the firstResponder's frame into the scrollView's coordinate system,
                // with a little vertical padding
                let rect = firstResponder.convert(firstResponder.frame, to: scrollView)
                    .insetBy(dx: 0, dy: -15)
                scrollView.scrollRectToVisible(rect, animated: true)
            }
        }
    }

    @objc func keyboardWillHide() {
        self.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
    }
}

/// IUResponder extension for finding the current first responder
extension UIResponder {
    private struct StaticFirstResponder {
        static weak var firstResponder: UIResponder?
    }

    /// find the current first responder, or nil
    static func findFirstResponder() -> UIResponder? {
        StaticFirstResponder.firstResponder = nil
        UIApplication.shared.sendAction(
            #selector(UIResponder.trap),
            to: nil, from: nil, for: nil)
        return StaticFirstResponder.firstResponder
    }

    @objc private func trap() {
        StaticFirstResponder.firstResponder = self
    }
}

/// UIView extension for finding the receiver's parent UIScrollView
extension UIView {
    func parentScrollView() -> UIScrollView? {
        if let scrollView = self.superview as? UIScrollView {
            return scrollView
        }

        return superview?.parentScrollView()
    }
}

फिर इसके बजाय SceneDelegateउपयोग के लिए बदलें ।MyHostingControllerUIHostingController

जब ऐसा हो गया, तो मुझे अपने SwiftUI कोड के अंदर कीबोर्ड के बारे में चिंता करने की आवश्यकता नहीं है।

(ध्यान दें: मैंने इसे करने के किसी भी निहितार्थ को पूरी तरह से समझने के लिए अभी तक इसका उपयोग नहीं किया है!)


1

यह वह तरीका है जो मैं स्विफ्टयूई में कीबोर्ड को संभालता हूं। याद रखने वाली बात यह है कि यह VStack पर गणना कर रहा है जिससे यह जुड़ा हुआ है।

आप इसे एक दृश्य पर एक संशोधक के रूप में उपयोग करते हैं। इस तरफ:

struct LogInView: View {

  var body: some View {
    VStack {
      // Your View
    }
    .modifier(KeyboardModifier())
  }
}

तो इस संशोधक में आने के लिए, सबसे पहले, UStesponder का एक एक्सटेंशन बनाएं ताकि VStuff में चयनित TextField स्थिति प्राप्त हो सके:

import UIKit

// MARK: Retrieve TextField first responder for keyboard
extension UIResponder {

  private static weak var currentResponder: UIResponder?

  static var currentFirstResponder: UIResponder? {
    currentResponder = nil
    UIApplication.shared.sendAction(#selector(UIResponder.findFirstResponder),
                                    to: nil, from: nil, for: nil)
    return currentResponder
  }

  @objc private func findFirstResponder(_ sender: Any) {
    UIResponder.currentResponder = self
  }

  // Frame of the superview
  var globalFrame: CGRect? {
    guard let view = self as? UIView else { return nil }
    return view.superview?.convert(view.frame, to: nil)
  }
}

अब आप TextField को छिपाने वाले कीबोर्ड से बचने के लिए Combine का उपयोग करके KeyboardModifier बना सकते हैं:

import SwiftUI
import Combine

// MARK: Keyboard show/hide VStack offset modifier
struct KeyboardModifier: ViewModifier {

  @State var offset: CGFloat = .zero
  @State var subscription = Set<AnyCancellable>()

  func body(content: Content) -> some View {
    GeometryReader { geometry in
      content
        .padding(.bottom, self.offset)
        .animation(.spring(response: 0.4, dampingFraction: 0.5, blendDuration: 1))
        .onAppear {

          NotificationCenter.default.publisher(for: UIResponder.keyboardWillHideNotification)
            .handleEvents(receiveOutput: { _ in self.offset = 0 })
            .sink { _ in }
            .store(in: &self.subscription)

          NotificationCenter.default.publisher(for: UIResponder.keyboardWillChangeFrameNotification)
            .map(\.userInfo)
            .compactMap { ($0?[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect)?.size.height }
            .sink(receiveValue: { keyboardHeight in
              let keyboardTop = geometry.frame(in: .global).height - keyboardHeight
              let textFieldBottom = UIResponder.currentFirstResponder?.globalFrame?.maxY ?? 0
              self.offset = max(0, textFieldBottom - keyboardTop * 2 - geometry.safeAreaInsets.bottom) })
        .store(in: &self.subscription) }
        .onDisappear {
          // Dismiss keyboard
          UIApplication.shared.windows
            .first { $0.isKeyWindow }?
            .endEditing(true)

          self.subscription.removeAll() }
    }
  }
}

1

IOS 14 (बीटा 4) के लिए यह काफी सरल है:

var body: some View {
    VStack {
        TextField(...)
    }
    .padding(.bottom, 0)
}

और दृश्य का आकार कीबोर्ड के शीर्ष पर समायोजित होता है। फ्रेम के साथ निश्चित रूप से अधिक परिशोधन संभव है (.maxHeight: ...) आदि। आप इसे समझेंगे।

दुर्भाग्य से iPad पर फ्लोटिंग कीबोर्ड अभी भी समस्या का कारण बनता है। लेकिन उपर्युक्त समाधान भी होगा, और यह अभी भी बीटा है, मुझे आशा है कि वे इसका पता लगाएंगे।

Thx Apple, आखिर!


यह बिल्कुल (14.1) काम नहीं करता है। क्या विचार है?
बर्गलर-देव

0

मेरे विचार:

struct AddContactView: View {
    
    @Environment(\.presentationMode) var presentationMode : Binding<PresentationMode>
    
    @ObservedObject var addContactVM = AddContactVM()
    
    @State private var offsetValue: CGFloat = 0.0
    
    @State var firstName : String
    @State var lastName : String
    @State var sipAddress : String
    @State var phoneNumber : String
    @State var emailID : String
    
  
    var body: some View {
        
        
        VStack{
            
            Header(title: StringConstants.ADD_CONTACT) {
                
                self.presentationMode.wrappedValue.dismiss()
            }
            
           ScrollView(Axis.Set.vertical, showsIndicators: false){
            
            Image("contactAvatar")
                .padding(.top, 80)
                .padding(.bottom, 100)
                //.padding(.vertical, 100)
                //.frame(width: 60,height : 60).aspectRatio(1, contentMode: .fit)
            
            VStack(alignment: .center, spacing: 0) {
                
                
                TextFieldBorder(placeHolder: StringConstants.FIRST_NAME, currentText: firstName, imageName: nil)
                
                TextFieldBorder(placeHolder: StringConstants.LAST_NAME, currentText: lastName, imageName: nil)
                
                TextFieldBorder(placeHolder: StringConstants.SIP_ADDRESS, currentText: sipAddress, imageName: "sipPhone")
                TextFieldBorder(placeHolder: StringConstants.PHONE_NUMBER, currentText: phoneNumber, imageName: "phoneIcon")
                TextFieldBorder(placeHolder: StringConstants.EMAILID, currentText: emailID, imageName: "email")
                

            }
            
           Spacer()
            
        }
        .padding(.horizontal, 20)
        
            
        }
        .padding(.bottom, self.addContactVM.bottomPadding)
        .onAppear {
            
            NotificationCenter.default.addObserver(self.addContactVM, selector: #selector(self.addContactVM.keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
            
             NotificationCenter.default.addObserver(self.addContactVM, selector: #selector(self.addContactVM.keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
        }
        
    }
}

मेरा VM:

class AddContactVM : ObservableObject{
    
    @Published var contact : Contact = Contact(id: "", firstName: "", lastName: "", phoneNumbers: [], isAvatarAvailable: false, avatar: nil, emailID: "")
    
    @Published var bottomPadding : CGFloat = 0.0
    
    @objc  func keyboardWillShow(_ notification : Notification){
        
        if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
            let keyboardRectangle = keyboardFrame.cgRectValue
            let keyboardHeight = keyboardRectangle.height
            self.bottomPadding = keyboardHeight
        }
        
    }
    
    @objc  func keyboardWillHide(_ notification : Notification){
        
        
        self.bottomPadding = 0.0
        
    }
    
}

मूल रूप से, कीबोर्ड ऊंचाई के आधार पर नीचे की गद्दी का प्रबंधन।


-3

मेरे द्वारा प्रबंधित किया गया सबसे सुरुचिपूर्ण उत्तर, रैपेल के समाधान के समान है। कीबोर्ड इवेंट्स सुनने के लिए एक क्लास बनाएं। हालांकि, पैडिंग को संशोधित करने के लिए कीबोर्ड आकार का उपयोग करने के बजाय, कीबोर्ड आकार का नकारात्मक मान लौटाएं, और बाहरी सबसे अधिक दृश्य कंटेनरों के ऑफसेट को समायोजित करने के लिए .offset (y :) संशोधक का उपयोग करें। यह काफी अच्छी तरह से एनिमेट करता है, और किसी भी दृश्य के साथ काम करता है।


आपको यह कैसे प्राप्त हुआ? मेरे पास है .offset(y: withAnimation { -keyboard.currentHeight }), लेकिन सामग्री एनिमेशन के बजाय कूदती है।
जजेटी

यह कुछ समय पहले की बात है कि मैंने इस कोड के साथ मेल किया था, लेकिन मेरी पूर्व टिप्पणी के समय, रनटाइम के दौरान एक vstack की भरपाई को संशोधित करने की आवश्यकता थी जो कि, SwiftUI आपके लिए परिवर्तन को चेतन करेगा।
पीसीएलकैट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.