UITextField 的键盘是否必须占据整个屏幕?

Does the keyboard for a UITextField have to take up the whole screen?

看来键盘不必占据整个屏幕,请查看我post的问题部分中的更新。谢谢

描述

Use UITextField to place a full-screen keyboard on the screen.

reference

我已经设置了 UISplitViewController,我希望 RootViewController(又名 MasterViewController)显示 UITextField 和键盘。然后我想要右边的搜索结果(在 "ResultViewController" (UIViewController).

想法是当用户输入时,建议结果。

我尝试过的:

我首先通过 storyboard 向我的 RootViewController 添加了一个 UITextField,但是当我通过 textField.becomeFirstResponder().[=25 激活键盘时它占据了整个屏幕=]

我想如果我使用 UIAlertController 我会解决这个问题,但键盘仍然占据了整个屏幕。

class RootViewController: UIViewController {

 override func viewDidLoad() {

    let alertController = UIAlertController(title: "Search", message: "Search for something!.", preferredStyle: UIAlertControllerStyle.Alert)

    alertController.addTextFieldWithConfigurationHandler({(textField: UITextField!) in
        textField.placeholder = "Search"
    })
    self.addChildViewController(alertController)
    alertController.view.frame = self.view.frame
    self.view.addSubview(alertController.view)
 }
}

问题:

使用 UISplitViewController 时,如何让键盘只停留在 RootViewController 中而不占据整个屏幕?

更新: 看来这已经在新苹果电视上的 Netflix 应用程序中实现了。键盘在顶部,占据了整个宽度。底部分为两部分。左边是建议的单词结果,右边是可能视频的视频封面集合视图。一切都随着用户输入而更新。

如果这被认为是 Apple TV 的糟糕设计,请随时指出原因。

屏幕截图:

这是我目前得到的。文本框打开一个占满整个屏幕的键盘。

使用 built-in SDK 方法无法仅在屏幕的一部分显示键盘。

A UIKeyboard 显示在应用程序的 window 上,而不显示在其任何子视图上。要完成您想要的行为,请使用反射在应用程序的 UIWindow 上获取对 UIKeyboard object 的引用(通过遍历 window 的子视图),并更改其框架以匹配 RootViewController.

的宽度

入门可以看私有UIKeyboard.h tvOS header here。我应该注意到 Apple 可能有适当的代码来禁用调整键盘大小(例如 willMoveToWindow:didMoveToWindow)。这是未定义的行为,你的里程数会有所不同,如果它能起作用的话。

你已经删除了对我关于 Netflix 应用程序的回答的评论,但正如 shirefriendship 在他们的回答中所说,Netflix 可能使用了 TVML 模板。您可以走那条路并构建一个混合 tvOS/TVML 应用程序。此外,您还可以在 RootViewController.

中使用 UICollectionView 手动构建键盘

Netflix 正在使用 TVML 模板而不是 UIKit 来实现他们的搜索。您可以使用 searchTemplate. You can learn to mix TVML and UIKit 实现与 Netflix 相同的美学效果。不幸的是,searchTemplate 的可定制性不足以符合您想要的布局。目前无法为 Apple TV 实施您的特定布局。

简介:

我终于能够在不使用 TVML templates 的情况下实现它。最终解决方案如下所示:

总体思路是创建一个 UICollectionViewController 和一个 UICollectionViewCell。然后以编程方式添加键盘并通过 AppDelegate 将其添加到 TabViewController


如何使用结果实现此搜索视图:

第 1 步:故事板和控制器创建

打开您的故事板并创建一个 UICollectionViewController(带有自定义 class“SearchResultViewController”),没有附加到您的TabViewController.

在其中创建一个 UICollectionViewCell,其中包含您想要的任何 labelsimagesUICollectionViewCell 应该有一个名为“VideoSearchCell”的自定义 class。

你的 SearchViewController 里面应该没有其他东西。

第 2 步:将 SearchViewController 添加到 TabViewController 并通过 AppDelegate 以编程方式实现键盘

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    override init() {

    }
    func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        // Override point for customization after application launch.
        if let tabController = window?.rootViewController as? UITabBarController {
            tabController.viewControllers?.append(configueSearchController())
        }

        return true
    }

    //... standard code in-between

    func configueSearchController() -> UIViewController {

        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        guard let searchResultController = storyboard.instantiateViewControllerWithIdentifier(SearchResultViewController.storyboardIdentifier) as? SearchResultViewController else {
            fatalError("Unable to instatiate a SearchResultViewController from the storyboard.")
        }

        /*
         Create a UISearchController, passing the `searchResultsController` to
         use to display search results.
         */
        let searchController = UISearchController(searchResultsController: searchResultsController)
        searchController.searchResultsUpdater = searchResultsController
        searchController.searchBar.placeholder = NSLocalizedString("Enter keyword (e.g. Gastric Bypass)", comment: "")

        // Contain the `UISearchController` in a `UISearchContainerViewController`.
        let searchContainer = UISearchContainerViewController(searchController: searchController)
        searchContainer.title = NSLocalizedString("Search", comment: "")

        // Finally contain the `UISearchContainerViewController` in a `UINavigationController`.
        let searchNavigationController = UINavigationController(rootViewController: searchContainer)
        return searchNavigationController

    }

}

添加 SearchResultViewController 的基本框架后,您应该能够在 运行 项目时看到搜索视图顶部的键盘。

第 3 步:处理文本输入和更新结果

您会注意到,在我的 filterString 中,我使用了一个名为 ScoreVideo 的 class 和一个 StringSearchService。这些只是我用来过滤视频列表的 classes(又名:self.vms.videos)。

所以最后,只需使用 filterString,创建一个新的 过滤列表 并重新加载您的集合视图。

import UIKit
import Foundation

class SearchResultViewController: UICollectionViewController, UISearchResultsUpdating {


    //private let cellComposer = DataItemCellComposer()
    private var vms: VideoManagerService!

    private var filteredVideos = [ScoreVideo]()
    static let storyboardIdentifier = "SearchResultViewController"

    var filterString = "" {
        didSet {
            // Return if the filter string hasn't changed.
            guard filterString != oldValue else { return }
                // Apply the filter or show all items if the filter string is empty.
                if self.filterString.isEmpty {
                    self.filteredVideos = StringSearchService.start(self.filterString, videos: self.vms.videos)
                }
                else {
                    self.filteredVideos = StringSearchService.start(self.filterString, videos: self.vms.videos)
                }
           self.collectionView?.reloadData()
        }
    }

    override func viewDidLoad() {
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        self.vms = appDelegate.getVideoManagerService()

    }

    // MARK: UICollectionViewDataSource

    override func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
        return 1
    }

    override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        print("count..\(filteredVideos.count)")
        return filteredVideos.count
    }

    override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        // Dequeue a cell from the collection view.
        return collectionView.dequeueReusableCellWithReuseIdentifier(VideoSearchCell.reuseIdentifier, forIndexPath: indexPath)
    }

    // MARK: UICollectionViewDelegate

    override func collectionView(collectionView: UICollectionView, willDisplayCell cell: UICollectionViewCell, forItemAtIndexPath indexPath: NSIndexPath) {
        guard let cell = cell as? VideoSearchCell else { fatalError("Expected to display a `VideoSearchCell`.") }
        let item = filteredVideos[indexPath.row]
        cell.configureCell(item.video)

    }

    override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
        dismissViewControllerAnimated(true, completion: nil)
    }

    // MARK: UISearchResultsUpdating

    func updateSearchResultsForSearchController(searchController: UISearchController) {
        print("updating... \(searchController.searchBar.text)")
        filterString = searchController.searchBar.text!.lowercaseString ?? ""
    }
}

如有不明之处,欢迎随时提问。我很可能忘记了什么。谢谢

答案灵感来自 apple sample code