如何使用 SwiftUI 在多个屏幕上获取键盘高度并移动按钮

     2023-02-23     311

关键词:

【中文标题】如何使用 SwiftUI 在多个屏幕上获取键盘高度并移动按钮【英文标题】:How to get the keyboard height on multiple screens with SwiftUI and move the button 【发布时间】:2019-09-01 12:28:57 【问题描述】:

以下代码获取键盘显示时的键盘高度,并将按钮移动键盘高度。

在转换源(ContentView)和转换目标(SecibdContentView)以相同的方式执行此移动,但按钮不会在转换目标处移动。

如何使按钮在多个屏幕上移动相同?

import SwiftUI

struct ContentView: View 
    @ObservedObject private var keyboard = KeyboardResponder()

    var body: some View 
        NavigationView 
            VStack 
                Text("ContentView")

                Spacer()

                NavigationLink(destination: SecondContentView()) 
                    Text("Next")
                
                .offset(x: 0, y: -keyboard.currentHeight)
            
        
    


import SwiftUI

struct SecondContentView: View 
    @ObservedObject private var keyboard = KeyboardResponder()

    var body: some View 
        VStack 
            Text("SubContentView")

            Spacer()

            NavigationLink(destination: 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.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue 
            currentHeight = keyboardSize.height
        
    

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

【问题讨论】:

在模拟器上试过了,真是个解决办法。很遗憾看到 SwiftUI 不能原生处理这个问题。还是我错过了什么? 【参考方案1】:

使用 ViewModifier

你可以使用swiftui的ViewModifier就简单多了

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

在你看来

struct SomeView: View 
    @State private var someText: String = ""

    var body: some View 
        VStack 
            Spacer()
            TextField("some text", text: $someText)
        .KeyboardAwarePadding()
    

KeyboardAwarePadding() 会自动在你的视图中添加一个 padding,这样更优雅。

【讨论】:

确实非常优雅的解决方案。处理 safeAreaInsets.bottom ``` func body(content: Content) -> some View content .padding(.bottom, keyboardHeight) .edgesIgnoringSafeArea(keyboardHeight==0 ? [] :.bottom) .onReceive(keyboardHeightPublisher) 的微小改动) self.keyboardHeight = $0 ``` 不错的解决方案,但是如何使它也适用于放置在滚动视图中的 VStack? 由于某种原因,我的键盘高度在69.0(隐藏时)和336.0(显示时)之间切换,从来没有 0.0 这很奇怪。有什么想法吗? @MatrosovAlexander,还添加一个 .edgesIgnoringSafeArea(.bottom)【参考方案2】:

SwiftUI + 组合

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

【讨论】:

我猜这应该是在一个类而不是结构中吧?【参考方案3】:

您的代码缺少一些内容。没有 NavigationView,也没有让键盘出现的 TextField。考虑更新您的代码。

无论如何,通过将keyboardFrameBeginUserInfoKey 替换为keyboardFrameEndUserInfoKey 即可轻松解决问题。

更新:

您还需要使用相同的 KeyboardResponder,否则您将创建多个实例。或者,您可以将其放入您的环境中。

而且你忘记在代码中包含 TextFields,所以键盘会显示出来进行测试。

以下代码有效:

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
    

【讨论】:

对不起。添加了导航视图。我将keyboardFrameBeginUserInfoKey更改为keyboardFrameEndUserInfoKey,但无法确认SubContentView中按钮的移动。 您忘记包含文本字段。我更新了我的答案以包含一个可行的解决方案。 一旦有人开始在键盘上打字,这就会停止工作

如何在 macOS 上检测 SwiftUI 中的键盘事件?

】如何在macOS上检测SwiftUI中的键盘事件?【英文标题】:HowtodetectkeyboardeventsinSwiftUIonmacOS?【发布时间】:2020-04-1107:44:08【问题描述】:如何在macOS上的SwiftUI视图中检测键盘事件?我希望能够使用击键来控制特定屏幕上的项目,但... 查看详情

如何在 macOS 上检测 SwiftUI 中的键盘事件?

】如何在macOS上检测SwiftUI中的键盘事件?【英文标题】:HowtodetectkeyboardeventsinSwiftUIonmacOS?【发布时间】:2020-04-1107:44:08【问题描述】:如何在macOS上的SwiftUI视图中检测键盘事件?我希望能够使用击键来控制特定屏幕上的项目,但... 查看详情

如何在 React-Native 中获得键盘的高度?

】如何在React-Native中获得键盘的高度?【英文标题】:HowtogetaheightofaKeyboardinReact-Native?【发布时间】:2018-03-1703:42:18【问题描述】:我在我的应用程序中使用React-Navigation,该应用程序由具有多个屏幕的StackNavigator组成,其中一些... 查看详情

如何计算 SwiftUI 中的标签栏高度?

】如何计算SwiftUI中的标签栏高度?【英文标题】:HowtocalculateTabBarheightinSwiftUI?【发布时间】:2020-01-3119:24:24【问题描述】:我有一个播放器高度为屏幕高度1/3的页面。在频道下,滚动视图中有多个频道。我正在尝试将滚动视图... 查看详情

如何在 Web 应用程序上获取键盘高度

】如何在Web应用程序上获取键盘高度【英文标题】:Howtogetkeyboardheightonawebapp【发布时间】:2017-05-3118:55:08【问题描述】:这是一个网络应用程序,针对任何移动浏览器,但主要是适用于iOS10的Chrome和Safari。当用户单击任何输入时... 查看详情

如何使用 SwiftUI 获取 ScrollView 的动态文本高度

】如何使用SwiftUI获取ScrollView的动态文本高度【英文标题】:HowtogetdynamicTextheightforaScrollViewwithSwiftUI【发布时间】:2019-06-3015:28:43【问题描述】:这给了我正确的动态文本高度importSwiftUIstructContentView:Viewvarbody:someViewListText("Thisissome... 查看详情

SwiftUI - 如何防止工作表中的键盘向上推我的主 UI

】SwiftUI-如何防止工作表中的键盘向上推我的主UI【英文标题】:SwiftUI-HowtopreventkeyboardinasheettopushupmymainUI【发布时间】:2021-12-2603:04:01【问题描述】:我在引导过程中使用工作表(SwiftUI)让人们输入文本,但是每当关闭工作表时,... 查看详情

在 SwiftUI 中,如何增加按钮的高度?

】在SwiftUI中,如何增加按钮的高度?【英文标题】:InSwiftUI,HowdoIincreasetheheightofabutton?【发布时间】:2020-04-0423:45:03【问题描述】:正如您在屏幕截图中看到的,按钮高度没有调整到适合文本大小,使它看起来很丑。我怎样才能... 查看详情

如何在 tvOS 上使用 SwiftUI 在多个水平列表之间导航

】如何在tvOS上使用SwiftUI在多个水平列表之间导航【英文标题】:HowtonavigatebetweenmultiplehorizontallistwithSwiftUIontvOS【发布时间】:2020-09-1011:17:30【问题描述】:我在全局垂直列表中有多个可滚动的水平列表,我很难管理焦点更改。... 查看详情

SwiftUI DatePicker:有没有办法让他们不能使用键盘来编辑字段?

】SwiftUIDatePicker:有没有办法让他们不能使用键盘来编辑字段?【英文标题】:SwiftUIDatePicker:Isthereawaytomakeitsotheycan\'tusethekeyboardtoeditthefields?【发布时间】:2021-06-0700:19:30【问题描述】:我有一个应用程序,我正在使用多个日期选... 查看详情

android点击输入框弹出键盘,布局随键盘往上移动

...度,之前根据经验值,在有些手机上有点不大准,现改成屏幕整体高度的1/3*   1、大于屏幕整体高度的1/3:键盘显示 获取Scroll的窗体坐标*             算出main需要滚... 查看详情

如何在 SwiftUI 中获取不同视图的帧(大小和坐标)?

】如何在SwiftUI中获取不同视图的帧(大小和坐标)?【英文标题】:Howtogetframes(sizeandcoordinates)fordifferentviewsinSwiftUI?【发布时间】:2020-04-2018:13:53【问题描述】:我需要为VStack中的多个视图获取框架。我认为使用GeometryReader但它... 查看详情

SwiftUI如何在关闭时将数据传递到上一个屏幕

】SwiftUI如何在关闭时将数据传递到上一个屏幕【英文标题】:SwiftUIhowtopassdatatopreviousscreenondismiss【发布时间】:2021-07-1611:59:11【问题描述】:我想将关闭presentViewController的数据传递到上一个屏幕。在这里,我想使用块将数据作... 查看详情

如何使用javascript检测iphone/ipad中屏幕键盘的高度

】如何使用javascript检测iphone/ipad中屏幕键盘的高度【英文标题】:Howtodetecttheheightofonscreenkeyboardiniphone/ipadusingjavascript【发布时间】:2018-04-2814:38:43【问题描述】:我想知道iphone/ipad中屏幕键盘的高度,用于聊天应用程序。我可以... 查看详情

SwiftUI - 如何在运行时更改内部内容后获取 ScrollView 内容高度

】SwiftUI-如何在运行时更改内部内容后获取ScrollView内容高度【英文标题】:SwiftUI-HowtogetScrollViewContentHeightafteroncetheinsidecontentischangedinRuntime【发布时间】:2021-11-1210:25:10【问题描述】:当计数值为静态时,我可以根据以下代码打... 查看详情

如何使用 SwiftUI 在 iOS 上获取和显示联系人照片?

】如何使用SwiftUI在iOS上获取和显示联系人照片?【英文标题】:HowtogetanddisplaycontactphotosoniOSwithSwiftUI?【发布时间】:2020-11-2309:31:30【问题描述】:我有一个正在运行的脚本,可以使用SwiftUI在iOS上读取和显示所有联系人,但我也... 查看详情

SwiftUI - 如何获取 ScrollView 内容的大小(高度)

】SwiftUI-如何获取ScrollView内容的大小(高度)【英文标题】:SwiftUI-Howtogetsize(height)ofScrollViewcontent【发布时间】:2020-05-2810:46:35【问题描述】:我想确定我的(垂直)ScrollView中内容的高度。ScrollView//MyContent这可能吗?我尝试了一... 查看详情

SwiftUI - 如何从不同的视图中获取 GeometryReader 的大小/高度?

】SwiftUI-如何从不同的视图中获取GeometryReader的大小/高度?【英文标题】:SwiftUI-HowtogetGeometryReadersize/heightfromdifferentView?【发布时间】:2021-04-2519:34:58【问题描述】:如何从另一个视图访问一个视图的大小?为了获得“Helloworld!”... 查看详情