How to get the keyboard height on multiple screens with SwiftUI and move the button

后端 未结 3 574
不知归路
不知归路 2021-02-09 02:22

The following code gets the keyboard height when the keyboard is displayed and moves the button by the keyboard height.

This movement is performed in the same way at the

相关标签:
3条回答
  • 2021-02-09 02:55

    Your code has a couple of things missing. There's no NavigationView, and no TextFields to make the keyboard appear. Consider updating your code.

    Anyway, the problem can be solved easily by replacing: keyboardFrameBeginUserInfoKey with keyboardFrameEndUserInfoKey.

    Update:

    You also need to use the same KeyboardResponder, otherwise you will creating multiple instances. Alternatively, you can put it into your Evironment.

    And you forgot to include TextFields to your code, so the keyboard will show up to test it.

    The following code works:

    import SwiftUI
    
    struct ContentView: View {
        @ObservedObject private var keyboard = KeyboardResponder()
    
        var body: some View {
            NavigationView {
                VStack {
                    Text("ContentView")
                    TextField("enter text", text: .constant(""))
                    Spacer()
    
                    NavigationLink(destination: SecondContentView(keyboard: keyboard)) {
                        Text("Next")
                    }
                    .offset(x: 0, y: -keyboard.currentHeight)
                }
            }
        }
    }
    
    import SwiftUI
    
    struct SecondContentView: View {
        @ObservedObject var keyboard: KeyboardResponder
    
        var body: some View {
            VStack {
                Text("SubContentView")
                TextField("enter text", text: .constant(""))
                Spacer()
    
                NavigationLink(destination: Text("ThirdContentView()")) {
                    Text("Next")
                }
                .offset(x: 0, y: -keyboard.currentHeight)
            }
        }
    }
    
    class KeyboardResponder: ObservableObject {
        private var _center: NotificationCenter
        @Published var currentHeight: CGFloat = 0
    
        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) {
            if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
                currentHeight = keyboardSize.height
            }
        }
    
        @objc func keyBoardWillHide(notification: Notification) {
            currentHeight = 0
        }
    }
    
    0 讨论(0)
  • 2021-02-09 02:57

    SwiftUI + Combine

    @Published var keyboardHeight: CGFloat = 0 // if one is in ViewModel: ObservableObject
    
    private var cancellableSet: Set<AnyCancellable> = []
        
    init() {
            
         NotificationCenter.default.publisher(for: UIWindow.keyboardWillShowNotification)
           .map {
                 guard
                     let info = $0.userInfo,
                     let keyboardFrame = info[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect
                     else { return 0 }
    
                 return keyboardFrame.height
             }
             .assign(to: \.keyboardHeight, on: self)
             .store(in: &cancellableSet)
            
         NotificationCenter.default.publisher(for: UIWindow.keyboardDidHideNotification)
             .map { _ in 0 }
             .assign(to: \.keyboardHeight, on: self)
             .store(in: &cancellableSet)
        }
        
    
    0 讨论(0)
  • 2021-02-09 03:07

    Using ViewModifier

    You can use ViewModifier of swiftui is much simpler

    import SwiftUI
    import Combine
    
    struct KeyboardAwareModifier: ViewModifier {
        @State private var keyboardHeight: CGFloat = 0
    
        private var keyboardHeightPublisher: AnyPublisher<CGFloat, Never> {
            Publishers.Merge(
                NotificationCenter.default
                    .publisher(for: UIResponder.keyboardWillShowNotification)
                    .compactMap { $0.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue }
                    .map { $0.cgRectValue.height },
                NotificationCenter.default
                    .publisher(for: UIResponder.keyboardWillHideNotification)
                    .map { _ in CGFloat(0) }
           ).eraseToAnyPublisher()
        }
    
        func body(content: Content) -> some View {
            content
                .padding(.bottom, keyboardHeight)
                .onReceive(keyboardHeightPublisher) { self.keyboardHeight = $0 }
        }
    }
    
    extension View {
        func KeyboardAwarePadding() -> some View {
            ModifiedContent(content: self, modifier: KeyboardAwareModifier())
        }
    }
    

    And in your view

    struct SomeView: View {
        @State private var someText: String = ""
    
        var body: some View {
            VStack {
                Spacer()
                TextField("some text", text: $someText)
            }.KeyboardAwarePadding()
        }
    }
    

    KeyboardAwarePadding() will automatically add a padding in your view, It's more elegant.

    0 讨论(0)
提交回复
热议问题