如何在iOS中添加一个UIView在键盘上方

4

我一直在尝试在iOS上显示一个toast消息。我的做法是当有任何通知时,我取得了导航控制器视图并添加了一个子视图来显示我的toast消息。

    UIView *top_view = self.navigationController.view;
    [top_view showToast:string];

一切都正常。然而,如果键盘在最前面,我的 toast 视图不会添加到其上方。有什么问题吗?小帮助可能会节省我的时间。谢谢。

7个回答

9
你可以通过将子视图添加到主窗口来显示toast。
UIWindow *toastDisplaywindow = [[[UIApplication sharedApplication] delegate] window];;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) 
{
   if (![[testWindow class] isEqual:[UIWindow class]]) 
    {
       self.toastDisplaywindow = testWindow;
       break;
    }
}
[toastDisplaywindow showToast:string];

如果正在显示键盘,则会将其显示为一个单独的窗口,位于您通常的主窗口上方。因此需要检查键盘是否正在显示。如果是,则在该窗口上添加 toast 消息,否则在主窗口上添加。

我在此链接中找到了另一种方法,可以直接获取键盘的 UIView(如果需要的话)。


仍然存在同样的问题... Toast 显示在键盘后面而不是上方。 - Newbee
已更新答案。请尝试这个。 - Adithya
谢谢,我会尝试并告诉您结果.. :) - Newbee

8

你需要将你的子视图添加到:

UIWindow *window = [UIApplication sharedApplication].windows.lastObject;

这是位于键盘顶部的地方。


3

一般来说,键盘视图不是您主窗口的一部分。当您聚焦于任何文本框时,它会随着新窗口出现。

尝试使用以下代码访问您的键盘视图。

[[[UIApplication sharedApplication] windows] objectAtIndex:1]

请记住,只有在您的屏幕上有键盘时才能使用此功能。


我也尝试了你的代码,它也能正常工作。谢谢你的答案 ;) - Newbee

2
另一种方法是添加自定义UIWindow,然后将其WindowLevel设置为最后一个窗口的+1。
类似这样的东西。
NSArray *windows = [[UIApplication sharedApplication] windows];  
UIWindow *lastWindow = (UIWindow *)[windows lastObject];  
myWindow.windowLevel = lastWindow.windowLevel + 1;

请查看这个主题https://forums.developer.apple.com/thread/16375


1

更新至Swift3

UIApplication.shared.windows.last


0
尝试将视图作为以下类的子视图添加。此代码片段适用于iOS 14及以上版本。不确定旧版本是否可行。参考:Toaster Github repo 使用方法: ToastWindow.shared.addSubView(/your_view/)
public final class ToastWindow: UIWindow {
public static let shared = ToastWindow(frame: UIScreen.main.bounds, mainWindow: UIApplication.shared.connectedScenes.flatMap { ($0 as? UIWindowScene)?.windows ?? [] }.first { $0.isKeyWindow } )

override public var rootViewController: UIViewController? {
    get {
        guard !self.isShowing else {
            isShowing = false
            return nil
        }
        guard let firstWindow = UIApplication.shared.delegate?.window else { return nil }
        return firstWindow is ToastWindow ? nil : firstWindow?.rootViewController
    }
    set { /* Do nothing */ }
}

override public var isHidden: Bool {
    willSet { isShowing = true }
    didSet { isShowing = false }
}

/// Will not return `rootViewController` while this value is `true`. Needed for iOS 13.
private var isShowing = false

/// Returns original subviews. `ToastWindow` overrides `addSubview()` to add a subview to the
/// top window instead itself.
private var originalSubviews = NSPointerArray.weakObjects()
private weak var mainWindow: UIWindow?

// MARK: - Init
public init(frame: CGRect, mainWindow: UIWindow?) {
    super.init(frame: frame)
    self.mainWindow = mainWindow
    self.isUserInteractionEnabled = false
    self.gestureRecognizers = nil
    self.windowLevel = .init(rawValue: .greatestFiniteMagnitude)
    let keyboardWillShowName = UIWindow.keyboardWillShowNotification
    let keyboardDidHideName = UIWindow.keyboardDidHideNotification
    self.backgroundColor = .clear
    self.isHidden = false

    NotificationCenter.default.addObserver( self, selector: #selector(self.keyboardWillShow),
                                            name: keyboardWillShowName,
                                            object: nil )
    NotificationCenter.default.addObserver( self, selector: #selector(self.keyboardDidHide),
                                            name: keyboardDidHideName,
                                            object: nil )
}

required public init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented: please use ToastWindow.shared")
}

override public func addSubview(_ view: UIView) {
    super.addSubview(view)
    self.originalSubviews.addPointer(Unmanaged.passUnretained(view).toOpaque())
    self.topWindow()?.addSubview(view)
}

public override func becomeKey() {
    super.becomeKey()
    mainWindow?.makeKey()
}


// MARK: - Keyboard methods
@objc private func keyboardWillShow() {
    guard let topWindow = self.topWindow(),
          let subviews = self.originalSubviews.allObjects as? [UIView] else { return }
    for subview in subviews {
        topWindow.addSubview(subview)
    }
}

@objc private func keyboardDidHide() {
    guard let subviews = self.originalSubviews.allObjects as? [UIView] else { return }
    for subview in subviews {
        super.addSubview(subview)
    }
}

/// Returns top window that isn't self
private func topWindow() -> UIWindow? {
    if let window = UIApplication.shared.windows.last(where: {
        ToastWindowKeyboardObserver.shared.didKeyboardShow || $0.isOpaque
    }), window !== self {
        return window
    }
    return nil
}
}

final fileprivate class ToastWindowKeyboardObserver {
static let shared = ToastWindowKeyboardObserver()
private(set) var didKeyboardShow: Bool = false
private(set) var keyboardHeight = 0.0

private init() {
    let keyboardWillShowName = UIWindow.keyboardWillShowNotification
    let keyboardDidHideName = UIWindow.keyboardDidHideNotification

    NotificationCenter.default.addObserver( self, selector: #selector(keyboardWillShow),
                                            name: keyboardWillShowName,
                                            object: nil )
    NotificationCenter.default.addObserver( self, selector: #selector(keyboardDidHide),
                                            name: keyboardDidHideName,
                                            object: nil )
}

@objc func keyboardWillShow(_ notification: Notification) {
    if let keyboardFrame: NSValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue {
        let keyboardRectangle = keyboardFrame.cgRectValue
        keyboardHeight = keyboardRectangle.height
    }
    didKeyboardShow = true
}

@objc private func keyboardDidHide() {
    didKeyboardShow = false
}
}

如果它不起作用,请检查键盘观察器是否返回正确的值。 - abhimuralidharan

0

iOS9中,Adithya的答案不起作用,

UIWindow *window = [UIApplication sharedApplication].windows.lastObject;

这段代码可以正常运行。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接