যখন কীবোর্ডটি SwiftUI এ প্রদর্শিত হবে তখন টেক্সটফিল্ডটি উপরে সরান


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"))
            }
    }
}

আউটপুট:

আউটপুট


আপনি স্ক্রোলভিউ ব্যবহার করতে পারেন। বিকাশকারী.এপল.
com/ ডকুমেন্টেশন / সুইফটুই / স্ক্রোলভিউ

4
@ প্রশান্তটুকাদিয়া দ্রুত প্রতিক্রিয়ার জন্য ধন্যবাদ। আমি স্ক্রোলভিউয়ের ভিতরে টেক্সটফিল্ড যুক্ত করেছি তবে এখনও একই সমস্যার মুখোমুখি।
हितেশ সুরানী

4
@ DimaPaliychuk এই কাজ করবে না। এটি সুইফটুআই
প্রশান্ত টুকাদিয়া

20
কীবোর্ডটি প্রদর্শন করা এবং এটি স্ক্রিনের বিষয়বস্তুকে অস্পষ্ট করে চলেছে, প্রথম উদ্দেশ্য সি আইফোন অ্যাপটি কি থেকে শুরু হয়েছে? এই সমস্যাটি যা প্রতিনিয়ত সমাধান করা হচ্ছে। আমি হতাশ হয়েছি যে অ্যাপল সুইফটউইয়ের সাথে এটিকে সম্বোধন করে নি। আমি জানি এই মন্তব্যটি কারও পক্ষে সহায়ক নয়, তবে আমি এই বিষয়টি উত্থাপন করতে চেয়েছিলাম যে সমাধানের জন্য আমাদের আপেলকে সত্যই চাপ দেওয়া উচিত এবং সর্বদাই সাধারণ সমস্যার সমাধান করার জন্য সম্প্রদায়ের উপর নির্ভর করা উচিত নয়।
পি এনট

উত্তর:


64

কোডটি এক্সকোড, বিটা 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() }

}

জ্যামিতিগেটর

এটি এমন একটি দৃশ্য যা এর প্যারেন্ট ভিউয়ের আকার এবং অবস্থান শোষণ করে। এটি অর্জন করার জন্য, এটিটিকে। ব্যাকগ্রাউন্ড মডিফায়ারের অভ্যন্তরে ডাকা হয়। এটি কোনও দৃশ্যের পটভূমি সাজানোর উপায় নয়, এটি একটি খুব শক্তিশালী সংশোধক। । ব্যাকগ্রাউন্ডে (মাইভিউ ()) এ কোনও দৃশ্য পাস করার সময়, মাইভিউ প্যারেন্ট হিসাবে পরিবর্তিত ভিউ পাচ্ছে। জ্যামিতিরিডার ব্যবহার করে পিতামাতার জ্যামিতিটি দেখা সম্ভব হয়েছে।

উদাহরণস্বরূপ: 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)
            }
        }
    }
}

আপডেটটি আমি ডিসপ্যাচকিউ.ইমেন.সিএনসিএনকে যুক্ত করেছিলাম, যখন দৃশ্যধারণের সময় এটি রেন্ডার হওয়ার সাথে সাথে তার অবস্থার পরিবর্তন করার সম্ভাবনা এড়ায় * ***

কীবোর্ডগার্ডিয়ান

কীবোর্ডগুয়ার্ডিয়ান এর উদ্দেশ্য হ'ল কীবোর্ড শো / লুকানো ইভেন্টগুলি ট্র্যাক রাখা এবং ভিউটি স্থানান্তরিত করার জন্য কতটা স্থান প্রয়োজন তা গণনা করা।

আপডেট: স্লাইডটি রিফ্রেশ করার জন্য আমি কীবোর্ডগার্ডিয়ানটি সংশোধন করেছি, যখন ব্যবহারকারী এক ক্ষেত্র থেকে অন্য ক্ষেত্রটিতে ট্যাব করে

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)
            }

        }
    }
}

4
প্রোটোকলের GeometryGetterসাথে সামঞ্জস্য রেখে পটভূমির চেয়ে ভিউ সংশোধক হিসাবে সংযুক্ত করা কি সম্ভব ViewModifier?
সুদারা

4
এটা সম্ভব, তবে লাভ কী? আপনি এটি এর সাথে সংযুক্ত হবেন: .modifier(GeometryGetter(rect: $kGuardian.rects[1]))পরিবর্তে .background(GeometryGetter(rect: $kGuardian.rects[1]))। পার্থক্যের খুব বেশি নয় (কেবলমাত্র 2 টি অক্ষর কম)।
কনটিকি

4
কিছু পরিস্থিতিতে আপনি যদি এই স্ক্রিনটি থেকে দূরে সরে যাচ্ছেন তবে নতুন আয়তক্ষেত্রটি বরাদ্দ করার সময় আপনি জ্যামিতিগেটরের অভ্যন্তরীণ প্রোগ্রাম থেকে একটি সংকেত অ্যাবোর্ট পেতে পারেন। যদি আপনার সাথে এটি ঘটে থাকে তবে স্ব
জুলিও

4
@ জুলিওবাইলন আমি জানি না তবে সিগন্যাল অ্যাবার্টের সাহায্যে geometry.frameবাইরে চলে যাওয়া DispatchQueue.main.asyncএখন আপনার সমাধানটি পরীক্ষা করবে। আপডেট: সহায়তা if geometry.size.width > 0 && geometry.size.height > 0দেওয়ার আগে self.rect
রোমান ভাসিলিভ

4
এটি আমার জন্য নিজেও বিরতি দেয় সেলফ্রেট = জ্যামিতি.ফ্রেমে (ইন: .গ্লোবাল) সিগন্যাল অ্যাবোর্ট পেয়ে এবং এই ত্রুটিটি সমাধানের জন্য প্রস্তাবিত সমস্ত সমাধান চেষ্টা করে
মারওয়ান রুশদি ২r

55

@ র্রাফেলের সমাধানটি তৈরি করতে, আমি এটিকে আজকের xcode11 swiftUI সমর্থন দ্বারা ব্যবহারযোগ্য হিসাবে রূপান্তর করেছি।

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একটি ইউআই-র পুনঃ-রেন্ডারকে ট্রিগার করবে এবং কীবোর্ড দেখানোর সময় আপনার পাঠ্যফিল্ডটিকে উপরে সরিয়ে দেবে এবং বরখাস্ত করার সময় পিছনে ফিরে আসবে। তবে আমি কোনও স্ক্রোলভিউ ব্যবহার করি নি।


6
সরলতার জন্য আমি এই উত্তরটি পছন্দ করি। আমি .animation(.easeOut(duration: 0.16))কীবোর্ড স্লাইডিংয়ের গতির সাথে মেলে চেষ্টা করার জন্য যুক্ত করেছি ।
মার্ক মোয়েকেন্স

আপনি কিবোর্ডের জন্য সর্বোচ্চ উচ্চতা 340 কেন নির্ধারণ করেছেন?
ড্যানিয়েল রায়ান

4
@ ড্যানিয়েলরিয়ান কখনও কখনও কীবোর্ডের উচ্চতা সিমুলেটারে ভুল মানগুলি ফিরিয়ে দেয়। আমি বর্তমানে সমস্যাটি নিখুঁত করার কোনও উপায় বের করে আনতে পারি না
মাইকেল নিস

4
আমি নিজেই এই সমস্যাটি দেখিনি। সম্ভবত এটি সর্বশেষতম সংস্করণগুলিতে স্থির হয়েছে। বৃহত্তর কীবোর্ডগুলি (বা হবে) সেক্ষেত্রে আমি আকারটি লক করতে চাইনি।
ড্যানিয়েল রায়ান

4
আপনি চেষ্টা করতে পারে keyboardFrameEndUserInfoKey। এটি কীবোর্ডের জন্য চূড়ান্ত ফ্রেম রাখা উচিত।
ম্যাথিয়াস ক্লাসেন

50

আমি প্রস্তাবিত অনেকগুলি সমাধানের চেষ্টা করেছি, এবং যদিও বেশিরভাগ ক্ষেত্রে তারা কাজ করে, আমার কিছু সমস্যা ছিল - প্রধানত নিরাপদ অঞ্চল নিয়ে (আমার ট্যাবভিউয়ের ট্যাবটির ভিতরে একটি ফর্ম রয়েছে)।

আমি কয়েকটি ভিন্ন সমাধানের সংমিশ্রণটি শেষ করেছি এবং নির্দিষ্ট দৃশ্যের নিরাপদ অঞ্চল নীচে ইনসেট পেতে এবং প্যাডিংয়ের গণনায় এটি ব্যবহার করার জন্য জ্যামিতিরিডার ব্যবহার করেছি:

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
বাহ, জ্যামিতি রিডার এবং ভিউমোডিফায়ার সহ এটি এইগুলির মধ্যে সর্বাধিক সুইফটুআই সংস্করণ। ভাল লাগবে।
মাতেউজ

4
এটি এত দরকারী এবং মার্জিত। এটি লেখার জন্য আপনাকে অনেক ধন্যবাদ।
ড্যানিলো ক্যাম্পোস

4
আমি আমার কীবোর্ডের উপরে একটি ছোট ফাঁকা সাদা দেখছি। এই ভিউটি জ্যামিতি রিডার ভিউ, আমি ব্যাকগ্রাউন্ডের রঙ পরিবর্তন করে নিশ্চিত করেছি। জ্যামিতি রিডার কেন আমার আসল ভিউ এবং কীবোর্ডের মধ্যে প্রদর্শিত হচ্ছে তার কোনও ধারণা।
ব্যবহারকারী 832

6
আমি যখন দ্বিতীয়বার কীবোর্ডটি দিয়ে ভিউতে যাই এবং Thread 1: signal SIGABRTলাইনে ক্লিক করি rect.height - geometry.safeAreaInsets.bottomতখন আমি লাইনে ত্রুটি পাচ্ছি TextField। আমি TextFieldপ্রথমবার ক্লিক করব কিনা তা কিছু যায় আসে না। অ্যাপ্লিকেশনটি এখনও ক্র্যাশ করেছে।
লাইভলি

4
অবশেষে কিছু কাজ করে! আমাদের কাছে অ্যাপল কেন এটা বাদাম নয় !!
ডেভ কোজিকোভস্কি

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ভিউটির সামগ্রীটি সঙ্কুচিত হওয়ার পরিবর্তে উপরের দিকে সরানোর জন্য প্যাডিং বা অফসেটটি একটি আয়তক্ষেত্রযুক্ত ভিস্ট্যাকের মধ্যে রাখার পরিবর্তে যোগ করা যেতে পারে ।


6
আমি মনে করি এটিই সঠিক উত্তর। আমি একটি ছোটখাটো ঝাঁকুনি করেছি: একটি আয়তক্ষেত্রের পরিবর্তে আমি কেবল প্যাডিংয়ের পরিবর্তন করছি self.viewএবং এটি দুর্দান্ত কাজ করে। অ্যানিমেশন নিয়ে কোনও সমস্যা নেই
তায়ে

4
ধন্যবাদ! পুরোপুরি কাজ করে। @ টেয়েড যেমন বলেছে, প্যাডিং পদ্ধতির ব্যবহার করা আরও ভাল। চূড়ান্ত ফলাফলটি হবেvar body: some View { VStack { view .padding(.bottom, keyboardHeight) .animation(.default) } .onReceive(showPublisher.merge(with: hidePublisher)) { (height) in self.keyboardHeight = height } }
fdelafuente

4
কম ভোট সত্ত্বেও এটি সবচেয়ে দ্রুত উত্তর sw এবং যেকোনো ভিউ ব্যবহার করে পূর্ববর্তী পদ্ধতিটি ধাতব ত্বরণ সহায়তাটি ভেঙে দেয়।
নেলসন কার্ডাচি

4
এটি দুর্দান্ত সমাধান, তবে এখানে মূল সমস্যাটি হ'ল যদি আপনি সম্পাদনা করছেন এমন পাঠ্যক্ষেত্রটি কীবোর্ডটি গোপন করে থাকে তবেই আপনি দৃশ্যটি সরিয়ে নেওয়ার দক্ষতাটি ছেড়ে দেন। আমি বলতে চাইছি: বেশ কয়েকটি পাঠ্যক্ষেত্রের সাথে যদি আপনার একটি ফর্ম থাকে এবং আপনি প্রথমটির সম্পাদনা শুরু করেন তবে আপনি সম্ভবত এটিটিকে সরাতে চান না কারণ এটি পর্দার বাইরে চলে যাবে।
সুপারপুসিও

আমি উত্তরটি সত্যিই পছন্দ করি তবে অন্য সমস্ত উত্তরগুলির মতো এটি যদি আপনার ট্যাববারের ভিতরে থাকে বা ভিউ স্ক্রিনের নীচে ফ্লাশ না হয় তবে এটি কাজ করে না।
বেন প্যাচ

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())
  }
}


ভাল লাগল ভাগ করে নেওয়ার জন্য ধন্যবাদ.
দশক

4
শীতল হবে, যদি এটি কেবল অফসেট হয়, প্রয়োজনে (যেমন স্ক্রোল করবেন না, যদি কীবোর্ডটি ইনপুট উপাদানটি আবরণ না করে)। ভাল
দশক

এটি দুর্দান্ত কাজ করে, আপনাকে ধন্যবাদ। খুব পরিষ্কার বাস্তবায়ন এছাড়াও, এবং আমার জন্য, শুধুমাত্র প্রয়োজন হলে স্ক্রল।
জোশুয়া

অসাধারণ! আপনি এটি গিথুব বা অন্য কোথাও সরবরাহ করবেন না কেন? :) বা আপনি এটি github.com/hackiftekhar/IQKeyboardManager এর জন্য পরামর্শ দিতে পারেন কারণ তাদের কাছে এখনও পুরো সুইফটইউ সমর্থন নেই
স্কনড্ডারবলকেন

ওরিয়েন্টেশন পরিবর্তনের সাথে দুর্দান্ত খেলবে না এবং প্রয়োজন পড়ুক না কেন তা অফসেট করে দেবে।
গ্র্যান্ডস্টেফ

16

অথবা আপনি কেবল আইকিউকিবোর্ডম্যানেজারসুইফ্ট ব্যবহার করতে পারেন

এবং সরঞ্জামদণ্ডটি আড়াল করতে এবং কীবোর্ডের অন্য কোনও ভিউতে ক্লিক করার পরে কীবোর্ডের আড়াল সক্ষম করতে এটি আপনার অ্যাপের প্রতিনিধিতে optionচ্ছিকভাবে যুক্ত করতে পারেন।

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

এটি আসলে আমার জন্যও (অপ্রত্যাশিত) উপায়। সলিড।
হ্যালো টিমো

এই কাঠামোটি প্রত্যাশার চেয়ে আরও ভাল কাজ করেছে। ভাগ করার জন্য আপনাকে ধন্যবাদ!
রিচার্ড পাউটিয়ার

4
SwiftUI- এ আমার জন্য ঠিক আছে - ধন্যবাদ @ ডমিনেটরভিবিএন - আইপ্যাডের ল্যান্ডস্কেপ মোডে আমি 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: সুইফটইউআই টিউটোরিয়াল

আপনি 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স্ক্রোল ভিউয়ের আকার সামঞ্জস্য করার চেয়ে অন্য কিছু ব্যবহার করার কথা বিবেচনা করা উচিত ।


আরে মনে হচ্ছে আপনার কাছে বাইন্ডেবলবজেক্টের অভিজ্ঞতা আছে। আমি এটি যেমন চাই তেমন কাজ করতে পারি না। এটা তোলে চমৎকার হবে যদি তোমাদের উপর চেহারা পারে: stackoverflow.com/questions/56500147/...
SwiftiSwift

আপনি কেন @ অবজেক্টবাইন্ডিং ব্যবহার করছেন না
সুইফটিউইফট

4
BindableObjectঅবচয় সহ , দুর্ভাগ্যক্রমে, এটি আর কাজ করছে না।
লিনাসগেফার্থ

4
@LinusGeffarth জন্য কি এটা এর মূল্য, BindableObjectশুধু নাম দেওয়া হয় ObservableObject, এবং didChangeকরতে objectWillChange। অবজেক্টটি ঠিকঠাক দর্শন আপডেট করে (যদিও আমি এর @ObservedObjectপরিবর্তে ব্যবহার করে পরীক্ষা করেছি @State)
SeizeTheDay

হাই, এই সমাধান সামগ্রীটি স্ক্রোল করছে, তবে এটি কীবোর্ডের উপরে কিছু সাদা অঞ্চল দেখায় যা পাঠ্যক্ষেত্রের অর্ধেকটি লুকায়। দয়া করে আমাকে জানান যে আমরা কীভাবে সাদা অঞ্চলটি সরিয়ে ফেলতে পারি।
শাহবাজ সাজ্জাদ

12

এক্সকোড 12 - একটি লাইন কোড

এই সংশোধকটি যুক্ত করুন TextField

.ignoresSafeArea(.keyboard, edges: .bottom)

ডেমো

অ্যাপল তাই আপনি স্থানান্তর করতে এটি ব্যবহার করতে পারেন, নিরাপদ এলাকার জন্য একটি অঞ্চল হিসাবে কীবোর্ড যোগ কোনোView অন্য অঞ্চলের মত কীবোর্ড আছে।


এটি টেক্সটফিল্ডের জন্য কাজ করে তবে টেক্সটএডিটরের কী হবে?
Первушин

এটা তোলে উপর কাজ করে কোন View সহ TextEditor
মোজতাবা হোসেইনি

4
সবেমাত্র পরীক্ষিত, এক্সকোড বিটা 6,
টেক্সটএডিটর

4
আপনি একটি প্রশ্ন জিজ্ঞাসা করতে এবং এটি এখানে লিঙ্ক করতে পারেন। সুতরাং আমি আপনার পুনরায় উত্পাদনযোগ্য কোডটি একবার দেখে নিতে পারি এবং আমি কী সাহায্য করতে পারি তা দেখুন :) @ কায়ার্স
মোজতাবা হোসেইনি

4
আমি নিজেই এটি আবিষ্কার। .ignoresSafeArea(.keyboard)আপনার দর্শন যোগ করুন ।
leonboe1

6

আমি একটি কার্যকর এসপিএম প্যাকেজ যা বিদ্যমান একটি .keyboardAware()সংশোধক সরবরাহ করে বিদ্যমান বিদ্যমান সমাধানগুলি পর্যালোচনা এবং পুনরায় সংশোধন করেছি:

কীবোর্ডঅওয়ারসুইফ্টইউআই

উদাহরণ:

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. এখানে বেশিরভাগ উত্তর কীবোর্ডটির ফ্রেম পরিবর্তন করে এমনটি মোকাবেলা করে না, তাই ব্যবহারকারী কীবোর্ড অনস্ক্রিনের সাহায্যে ডিভাইসটি ঘোরান they keyboardWillChangeFrameNotificationপ্রক্রিয়াজাত ঠিকানাগুলি বিজ্ঞপ্তিগুলির তালিকায় যুক্ত করা।
  2. আমি অনুরূপ-ভিন্ন-ভিন্ন মানচিত্রের সমাপ্তি সহ একাধিক প্রকাশক চাইনি, তাই আমি তিনটি কীবোর্ড বিজ্ঞপ্তি একক প্রকাশককে বেঁধে রেখেছি। এটি স্বীকৃতভাবে একটি দীর্ঘ চেইন তবে প্রতিটি পদক্ষেপ বেশ সোজা।
  3. আমি এমন initফাংশন সরবরাহ করেছি যা এমন কোনও গ্রহণ করে @ViewBuilderযাতে আপনি KeyboardHostঅন্যান্য ভিউয়ের মতো দর্শনটি ব্যবহার করতে পারেন এবং আপনার বিষয়বস্তুটিকে প্যারামিটার হিসাবে দেখানোর বিপরীতে, কেবল একটি পেছনের বন্ধে আপনার সামগ্রীটি পাস করতে পারেন init
  4. যেমন টা এবং 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

আপনি জিএসর্জো যে সমস্যাগুলি দেখছেন তা কি বিশদভাবে বলতে পারেন? আমি এই অ্যাপ্লিকেশনটিতে এই কোডটি ব্যবহার করছি এবং এটি আমার পক্ষে ভাল কাজ করছে।
টিমোথি স্যান্ডার্স

আপনি কি দয়া করে চালু গেল PridictiveiOS এ keyboardSettings-> General-> Keyboard-> Pridictive। এক্ষেত্রে এটি ক্যালক্লেটটি ঠিক করে না এবং কীবোর্ডে প্যাডিং যুক্ত করে
GSerjo

@ জিসারজো: আইওএস 13.1 বিটা চালানো একটি আইপ্যাড টাচে (7 তম জেন) আমার কাছে ভবিষ্যদ্বাণীপূর্ণ পাঠ্য সক্ষম রয়েছে। এটি সঠিকভাবে পূর্বাভাস সারিটির উচ্চতার জন্য প্যাডিং যুক্ত করে। (লক্ষণীয় গুরুত্বপূর্ণ, আমি এখানে কীবোর্ডের উচ্চতা সামঞ্জস্য করছি না , আমি নিজেই ভিউয়ের প্যাডিংয়ে যোগ করছি )) ডিবাগিং মানচিত্রে অদলবদল করার চেষ্টা করুন যা মন্তব্য করা হয়েছে এবং ভবিষ্যদ্বাণীটির জন্য যে মানগুলি পেয়েছে তার সাথে খেলুন কীবোর্ড আমি অন্য মন্তব্য একটি লগ পোস্ট করব।
তীমথিয় স্যান্ডার্স

"ডিবাগিং" মানচিত্রটি নিরবিচ্ছিন্ন করে আপনি দেখতে পাচ্ছেন যে মানটি নির্ধারিত হচ্ছে keyboardHeight। আমার আইপড টাচে (প্রতিকৃতিতে) ভবিষ্যদ্বাণীপূর্ণ একটি কীবোর্ড 254 পয়েন্ট। এটি ছাড়া 216 পয়েন্ট। এমনকি অনস্ক্রিন এবং প্যাডিং আপডেটগুলি সঠিকভাবে কীবোর্ড দিয়ে ভবিষ্যদ্বাণীপূর্ণ বন্ধ করতে পারি। ভবিষ্যদ্বাণীপূর্ণ সহ একটি কীবোর্ড যুক্ত করা: Received UIKeyboardWillChangeFrameNotification with height 254.0 Received UIKeyboardWillShowNotification with height 254.0 যখন আমি ভবিষ্যদ্বাণীপূর্ণ পাঠ্যটি বন্ধ করি:Received UIKeyboardWillChangeFrameNotification with height 216.0
টিমোথি স্যান্ডার্স

4

এটি @ কনটিকি যা তৈরি করেছে তা থেকে অভিযোজিত। আমার এটি বিটা 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প্রয়োজনীয় অ্যারে ক্ষমতা; কাঁচাভ্যালু হিসাবে অন্যরা যথাযথ সূচক দেয় যা আপনি .বেস্টগ্রাউন্ড (জ্যামিতিজেটার) কলগুলির জন্য ব্যবহার করবেন।

সেট আপ করার সাথে সাথে, ভিউগুলি কীবোর্ডগার্ডিয়ান এ এটি সহ পায়:

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

আসল আন্দোলনটি এরকম:

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

দৃশ্যের সাথে সংযুক্ত আমার ক্ষেত্রে এটি সম্পূর্ণ নেভিগেশনভিউয়ের সাথে সংযুক্ত, তাই কীবোর্ড প্রদর্শিত হওয়ার সাথে সাথে পুরো সমাবেশটি স্লাইড হয়ে যায়।

আমি সুইফটইউআই দিয়ে দশমিক কীবোর্ডে ডোন টুলবার বা রিটার্ন কী পাওয়ার সমস্যাটি সমাধান করি নি, পরিবর্তে আমি অন্য কোথাও একটি ট্যাপে এটি আড়াল করার জন্য এটি ব্যবহার করছি:

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())

কিছু দর্শন (যেমন, পিকচার) এর সাথে সংযুক্ত হওয়া পছন্দ করে না, সুতরাং আপনাকে বাহ্যিকতম দৃশ্যে কেবল চড় মারার পরিবর্তে আপনি কীভাবে সংশোধকটি সংযুক্ত করেন তাতে কিছুটা দানাদার হতে পারে।

কঠোর পরিশ্রমের জন্য @ কনটিকিকে অনেক ধন্যবাদ। আপনার তার উপরে এখনও তাঁর জ্যামিতি গিটটার প্রয়োজন হবে (না, আমি এটি পছন্দগুলিতে ব্যবহার করে রূপান্তর করার কাজটি করিনি) তিনি তার উদাহরণগুলিতে বর্ণনা করেছেন।


4
স্বতন্ত্র যারা পৃথক: কেন? আমি দরকারী কিছু যুক্ত করার চেষ্টা করেছি, তাই আপনার দৃষ্টিতে আমি কীভাবে ভুল হয়ে গেল তা জানতে চাই
ফিল্ডুর

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বর্তমানে এই অজানা ব্যতিক্রম ক্রাশগুলির কারণ হিসাবে ব্যবহার করা হয়েছিল (যদিও এটি ইন্টারফেসের প্রয়োজনীয়তাগুলি পূরণ করে) এবং অফসেট কোড প্রয়োগ করার সময় একটি স্ক্রোলভিউ সামগ্রিকভাবে সেরা পন্থা।


খুব সুন্দর সমাধান, অত্যন্ত সুপারিশ! কীবোর্ডটি বর্তমানে সক্রিয় ছিল কিনা তা নির্দেশ করতে আমি একটি বুল যুক্ত করেছি।
চিনাবাদামশায়ার

4

এই উত্তরগুলির অনেকগুলি সত্যই সত্য বলে মনে হয় যে এটি সৎ হতে পারে। আপনি যদি SwiftUI ব্যবহার করে থাকেন তবে আপনি পাশাপাশি কম্বাইনেরও ব্যবহার করতে পারেন।

KeyboardResponderনীচে প্রদর্শিত হিসাবে একটি তৈরি করুন , তারপরে আপনি আগের প্রদর্শিত হিসাবে ব্যবহার করতে পারেন।

আইওএস 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 ছোড়া

(আইওএসের জন্য 13 এই উত্তরটির ইতিহাসে যান)
লরিস ফয়ে

উচ্চ,। দয়া করে আমাকে উভয় iOS 13 এবং iOS 14. সঠিক এবং পরিষ্কার সমাধান জানাতে
শাহবাজ সাজ্জাদ

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())

আমি এই উত্তরটি পছন্দ করি তবে আমি 'স্ক্রিনসাইজ.পোর্ট্রেট' কোথা থেকে আসছে তা আমি নিশ্চিত নই।
মিশা প্রস্তর

হাই @ মিশা স্টোন ধন্যবাদ আমার পদ্ধতির চয়ন করুন। স্ক্রিনসাইজ.পোর্ট্রেট হ'ল একটি শ্রেণি যা আমি ওরিয়েন্টেশন এবং শতাংশের উপর স্ক্রিন বেসের পরিমাপগুলি অর্জন করার জন্য তৈরি করেছিলাম .... তবে আপনি আপনার অনুবাদটির জন্য প্রয়োজনীয় কোনও মান দিয়ে এটি প্রতিস্থাপন করতে পারেন
ব্ল্যাকটিয়াগো

3

এক্সকোড 12 বিটা 4 একটি নতুন দর্শন সংশোধক যুক্ত করেছে ignoresSafeAreaযা আপনি এখন কীবোর্ড এড়ানোর জন্য ব্যবহার করতে পারেন।

.ignoresSafeArea([], edges: [])

এটি কীবোর্ড এবং সমস্ত নিরাপদ অঞ্চল প্রান্ত এড়িয়ে চলে। আপনি .keyboardযদি এড়াতে না চান তবে আপনি প্রথম প্যারামিটার সেট করতে পারেন। এটির জন্য কিছু প্রশ্ন রয়েছে, কমপক্ষে আমার দৃষ্টিভঙ্গি হায়ারার্কি সেটআপে, তবে মনে হচ্ছে যে অ্যাপল আমাদের কী-বোর্ডটি এড়াতে চান।


2

উত্তর এখান থেকে অনুলিপি করা হয়েছে: সুইফটইউআই সহ টেক্সটফিল্ড সর্বদা কীবোর্ড শীর্ষে থাকে

আমি বিভিন্ন পদ্ধতির চেষ্টা করেছি এবং তাদের মধ্যে কেউই আমার পক্ষে কাজ করেনি। নীচে এই একমাত্র বিভিন্ন ডিভাইসের জন্য কাজ করেছে।

একটি ফাইলে এই এক্সটেনশনটি যুক্ত করুন:

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)
  }
}

4
কল করার সময় কেবলমাত্র একটি এফওয়াইআই, আপনি অবজেক্টগুলির মালিক হন NotificationCenter.default.addObserver... আপনার যথাযথ সময়ে
এগুলি সংরক্ষণ

হাই @ দ্য কোডিংআর্ট, ঠিক আছে আমি এটির মতো চেষ্টা করার চেষ্টা করেছি ( oleb.net/blog/2018/01/noticationcenter-removeobserver ) তবে এটি আমার পক্ষে কার্যকর বলে মনে হচ্ছে না, কোনও ধারণা?
রায়

2

যেমনটি মার্ক ক্রেনেক এবং হাইকো উল্লেখ করেছেন, অ্যাপল মনে হয়েছে Xcode 12 বিটা 4-এ শেষ অবধি এই সমস্যাটির সমাধান করছেন Th এক্সকোড 12 বিটা 5 এর রিলিজ নোট অনুসারে 18 আগস্ট 2020 প্রকাশিত হয়েছে "ফর্ম, তালিকা, এবং পাঠ্যপরিচয়কারী আর কীবোর্ডের পিছনে সামগ্রী লুকায় না ((66172025)"। আমি এটি ডাউনলোড করেছি এবং কিছু দিন আগে এএ শুরু করেছি এমন একটি অ্যাপ্লিকেশনে একটি ফর্ম ধারক সহ এটি বিটা 5 সিমুলেটারে (আইফোন এসই 2) একটি দ্রুত পরীক্ষা দিয়েছি।

এটি এখন একটি টেক্সটফিল্ডের জন্য "কেবলমাত্র কাজ করে" । কীবোর্ডের জন্য জায়গা তৈরি করার জন্য সুইফটইআই স্বয়ংক্রিয়ভাবে এনক্যাপসুলেটিং ফর্মটিতে উপযুক্ত নীচের প্যাডিং সরবরাহ করবে। এবং এটি কীবোর্ডের ঠিক উপরে টেক্সটফিল্ডটি প্রদর্শন করতে স্বয়ংক্রিয়ভাবে ফর্মটি স্ক্রোল করবে। কীবোর্ডটি যখন সামনে আসে তখন স্ক্রোলভিউ ধারকটি এখন দুর্দান্ত আচরণ করে।

যাইহোক, comment a একটি মন্তব্যে নির্দেশিত হিসাবে, টেক্সটএডিটারে সমস্যা আছে । বিটা 5 এবং 6 স্বয়ংক্রিয়ভাবে কীবোর্ডের জন্য জায়গা তৈরি করার জন্য এনক্যাপসুলেটিং ফর্মটিতে উপযুক্ত নীচের প্যাডিং সরবরাহ করবে। তবে এটি ফর্মটি স্বয়ংক্রিয়ভাবে স্ক্রোল করবে না। কীবোর্ডটি টেক্সটএডিটরটি কভার করবে। সুতরাং টেক্সটফিল্ডের বিপরীতে, ব্যবহারকারীকে টেক্সটএডিটরটি দৃশ্যমান করতে ফর্মটি স্ক্রোল করতে হবে। আমি একটি বাগ রিপোর্ট ফাইল করব। সম্ভবত বিটা 7 এটি ঠিক করবে। খুব কাছে …

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


আমি আপেল রিলিজ নোট দেখতে পাচ্ছি, বিটা 5 এবং বিটা 6-তে পরীক্ষা করা হয়েছে, টেক্সটফিল্ড কাজ করে, টেক্সটএডিটর নোট, আমি কী মিস করছি? @ স্টেট ভেরি টেক্সট = "" ভৌত শরীর: কিছু দেখুন {ফর্ম {বিভাগ {পাঠ্য (পাঠ্য) ra ফ্রেম (উচ্চতা: 500)} বিভাগ {পাঠ্যফিল্ড ("5555", পাঠ্য: $ পাঠ্য) f ফ্রেম (উচ্চতা: 50)} বিভাগ {টেক্সটএডিটর (পাঠ্য: $ পাঠ্য)। ফ্রেম (উচ্চতা: 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
    }
}

আপনার সমাধানটি চেষ্টা করে ... দেখুন পাঠ্যক্ষেত্রের অর্ধেক পর্যন্ত স্ক্রোল করা আছে। উপরোক্ত সমাধানটি চেষ্টা করে দেখুন। একই ইস্যু পেয়েছি। সাহায্য করুন!!!
সোনা

@ জিওনা, একটি সাধারণ অ্যাপে চেষ্টা করুন, আপনি হয়ত কিছু আলাদা করছেন different এছাড়াও, আপনি যদি নিরাপদ অঞ্চল ব্যবহার করে থাকেন তবে '- (UIWindow.keyWindow? .SafeAreaInsets.bottom ?? 0)' সরানোর চেষ্টা করুন।
সুসাহা

সরানো হয়েছে (UIWindow.keyWindow? .safeAreaInsets.bottom ?? 0) তবে আমি কীবোর্ডের উপরে একটি সাদা স্থান পাচ্ছি
Sona

1

হ্যান্ডলিং TabViewএর

আমি বেঞ্জামিন কিন্ডলের উত্তর পছন্দ করি তবে এটি ট্যাবভিউ সমর্থন করে না। ট্যাবভিউগুলি পরিচালনা করার জন্য তার কোডটিতে আমার সামঞ্জস্যটি এখানে:

  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তার MyHostingControllerপরিবর্তে ব্যবহারে পরিবর্তন করুন UIHostingController

এটি হয়ে গেলে, আমার সুইফটআইআই কোডের ভিতরে কীবোর্ড নিয়ে চিন্তা করার দরকার নেই।

(দ্রষ্টব্য: আমি এটি করার কোনও কার্যকরতা এখনও পুরোপুরি বুঝতে, এটি যথেষ্ট ব্যবহার করি নি!)


1

এইভাবেই আমি সুইফটুইতে কীবোর্ডটি হ্যান্ডেল করি। মনে রাখার বিষয়টি হ'ল এটি ভিটিস্ট্যাকের সাথে গণনা তৈরি করছে যা এটি সংযুক্ত।

আপনি এটি একটি সংশোধক হিসাবে একটি ভিউতে ব্যবহার করেন। এই পথে:

struct LogInView: View {

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

সুতরাং এই সংশোধকটিতে আসতে, প্রথমে, ভিস্ট্যাকটিতে নির্বাচিত টেক্সটফিল্ডের অবস্থান পেতে ইউআইআরআইএসপেন্ডারের একটি বর্ধন তৈরি করুন:

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)
  }
}

আপনি এখন কোনও পাঠ্যফিল্ড গোপন করে কীবোর্ড এড়াতে কম্বাইন ব্যবহার করে কিবোর্ডমডিফায়ার তৈরি করতে পারেন:

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

আইওএস 14 (বিটা 4) হিসাবে এটি বেশ সহজ কাজ করে:

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

এবং ভিউয়ের আকারটি কীবোর্ডের শীর্ষের সাথে সামঞ্জস্য করে। ফ্রেম (.ম্যাক্সহাইট: ...) ইত্যাদির সাথে অবশ্যই আরও পরিমার্জনগুলি সম্ভব। আপনি এটি বের করতে পারবেন।

দুর্ভাগ্যক্রমে আইপ্যাডে ভাসমান কীবোর্ড সরানোর সময় এখনও সমস্যা তৈরি করে। তবে উপরে উল্লিখিত সমাধানগুলিও হবে এবং এটি এখনও বিটা, আমি আশা করি তারা এটি নির্ধারণ করতে পারে।

থেক্স এক্সেল, শেষ পর্যন্ত!


এটি কিছুতেই কাজ করে না (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)
        }
        
    }
}

আমার ভিএম:

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

আমি এটি পরিচালনা করেছি সবচেয়ে মার্জিত উত্তরটি রাফেলের সমাধানের মতো। কীবোর্ড ইভেন্টগুলি শোনার জন্য একটি ক্লাস তৈরি করুন। প্যাডিং সংশোধন করতে কীবোর্ড আকারটি ব্যবহার না করে, কীবোর্ড আকারের একটি নেতিবাচক মানটি ফিরুন এবং বাইরের সর্বাধিক দর্শনের কনটেইনারগুলির অফসেট সামঞ্জস্য করতে। অফসেট (y :) সংশোধক ব্যবহার করুন। এটি যথেষ্ট পরিমাণে অ্যানিমেট করে এবং যে কোনও দৃষ্টিতে কাজ করে।


আপনি কীভাবে এনিমেট করতে পেলেন? আমার কাছে আছে .offset(y: withAnimation { -keyboard.currentHeight }), তবে সামগ্রীটি অ্যানিমেটগুলির পরিবর্তে লাফ দেয়।
jjatie

কয়েকটা বিটা আগে হয়েছিল যে আমি এই কোডটি দিয়েছি, তবে আমার আগের মন্তব্যের সময় রানটাইমের সময় একটি ভিস্ট্যাকের অফসেটটি পরিবর্তন করা দরকার ছিল, সুইফটইউআই আপনার জন্য পরিবর্তনটি সঞ্চারিত করবে।
pcallycat
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.