首页 iOS.& Swift Books uikit学徒

42
iPad. 由Matthijs Hollemans撰写& Fahim Farook

即使您在iPad上写得很好的应用程序,但iPad也不会优化TheE。 iPhone和iPad之间存在很大差异:它们都运行类似的操作系统并访问完全相同的框架。 Pocket iPad有一个更大的屏幕,这使得所有的区别。

鉴于可用的更大屏幕房地产,在iPad上,您可以有不同的和i,其中哪些元素可以更好地实现额外的屏幕空间。这就是差异是iPad优化应用程序和IPAD上也运行的iPhone应用程序之间的差异。

在本章中,您将介绍以下内容:

  • 部署平台: 蜂巢将加固模式融为套,仅用于Suntioring特定电视机。

  • 拆分视图控制器: 使用拆分视图 - 查看友好控制器更好地利用可靠的屏幕到iPad。

  • 改善次要窗格: 从iPhone版本(具有一些调整)重新使用详细信息屏幕,以显示有关iPad的详细信息。

  • 故事板中的大小类: 使用大小类来定制特定屏幕的iPad。

  • 你自己的popover: 创建酥料饼要在iPad上显示的菜单。

  • 发送来自应用程序的电子邮件: 使用内置电子邮件功能在应用程序上发送支持。

  • 在更大的iphone景观: 正确处理横向模式,为更大的iPhone设备正确地处理,因为它们在横向模式下类似于迷你iPad。

部署平台

使用Xcode创建的所有新的IOS项目默认支持iPhone和iPad平台。但是,如果您更喜欢,您仍然可以将应用程序更改为仅适用于iPhone - 或iPad,或者在创建项目后。你会 不是 做那个 Storesearch.,但如果您想知道如何使更改仅支持特定的平台,这就是你的方式。

➤去 项目设置 屏幕并选择StoreSearch目标。

在里面 一般的 标签下面 部署信息 每个平台都有一个复选框。您可以查看所启用的那些,或者取消选中所禁用的那些。

如何更改设备支持
如何更改设备支持

笔记: 虽然您还可以启用MAC支持(通过MAC Catalyst),以便您的iOS应用程序的代码也为您的MacOS应用程序提供支持,这是否适用于您的特定应用程序,也可以取决于您使用的库和功能。

➤你会的 不是 对上面的设置进行任何更改,如果您之前没有尝试过此操作,则现在尝试在iPad模拟器上运行是个好主意。请注意iPad模拟器是巨大的,所以您可能需要使用 窗户▸适合屏幕 从模拟器菜单选项,使其适合在您的屏幕。

在iPad模拟器中存储
在iPad模拟器中存储

打印精细的作品,口袋正如我之前所说的,只需炸毁界面到iPad大小就不会利用更大的屏幕优惠的所有额外空间。因此,您将使用Uikit必须在iPad上提供的一些特殊功能,例如拆分视图控制器和填充港。

拆分视图控制器

在iPhone上,也有一些例外,例如,当你里面嵌入另一个视图控制器,视图控制器通常管理整个屏幕。

在横向和纵向拆分视图控制器
DFI mrhiv TEAB qokznorraw背包methkmiyu EJP zaqjnaof ahoacyiwoezl

检查iPad方向

因为iPad具有比iPhone不同的尺寸,所以它也将以不同的方式使用。景观与肖像变得更重要的是更多的重要人物是使用​​iPad侧身以及二倍的愚蠢。因此,您的iPad应用程序实际上必须同样支持所有方向。

Info.Plist中支持的设备方向
hre hohzogwil ruxoje aqeabcaquikl ay icru.xhuzj

添加拆分视图控制器

添加拆分视图控制器很容易 - 您只需将拆分视图控制器对象添加到故事板。拆分视图仅在iPad上可见;在iPhone上,它保持隐藏。

故事板与新的拆分视图控制器
ZJA QVEJYKAULZ YUQD NBE COD JFYOQ REAW REMFRASYOC

初级和次级窗格连接到拆分视图
QNA hposoxn otj lotephitq zonow UTI pegxitsup PU JKI cbney NOIS

拆分视图控制器中的应用程序
XSU AYJ在E ZVGEN CAIP Lechhoywis

修复主窗格

主要窗格在横向上工作正常,但在纵向模式下,它不可见。您可以通过以下方式显示:

title= NSLocalizedString("搜索", comment: "split view primary button")

改善次级窗格

次级窗格需要更多的工作 - 它尚未非常好。此外,在搜索结果中挖掘一行应该填写拆分视图的辅助窗格,而不是提出新的弹出窗口。

弹出或不弹出

➤将以下实例变量添加到 DetailViewController.swift.swift.:

var isPopUp = false
override func viewDidLoad() {
  super.viewDidLoad()
  if isPopUp {
    popupView.layer.cornerRadius = 10
    let gestureRecognizer = UITapGestureRecognizer(
      target: self, 
      action: #selector(close))
    gestureRecognizer.cancelsTouchesInView = false
    gestureRecognizer.delegate = self
    view.addGestureRecognizer(gestureRecognizer)
    // Gradient view
    view.backgroundColor = UIColor.clear
    let dimmingView = GradientView(frame: CGRect.zero)
    dimmingView.frame = view.bounds
    view.insertSubview(dimmingView, at: 0)
  } else {
    view.backgroundColor = UIColor(patternImage: UIImage(
      named: "风景Background")!)
    popupView.isHidden = true
  }
  if searchResult != nil {
    updateUI()
  }
}
使次要窗格看起来更好
Zepomy sci totehmikx mutu puat wovmey

// MARK: - Properties
var splitVC: UISplitViewController {
  return window!.rootViewController as! UISplitViewController
}

var searchVC: SearchViewController {
  let nav = splitVC.viewControllers.first as! UINavigationController
  return nav.viewControllers.first as! SearchViewController
}

var detailVC: DetailViewController {
  let nav = splitVC.viewControllers.last as! UINavigationController
  return nav.viewControllers.first as! DetailViewController
}
weak var splitViewDetail: DetailViewController?
searchVC.splitViewDetail = detailVC
func tableView(
  _ tableView: UITableView,
  didSelectRowAt indexPath: IndexPath
) {
  searchBar.resignFirstResponder()

  if view.window!.rootViewController!.traitCollection
    .horizontalSizeClass == .compact {
    tableView.deselectRow(at: indexPath, animated: true)
    performSegue(withIdentifier: "ShowDetail", 
                 sender: indexPath)
  } else {
    if case .results(let list) = search.state {
      splitViewDetail?.searchResult = list[indexPath.row]
    }
  }
}
var searchResult: SearchResult! {
  didSet {
    if isViewLoaded {
      updateUI()
    }
  }
}
popupView.isHidden = false
二次窗格显示关于所选择的项目有关的附加信息
Zwu bovedheby qavu ltesr isnaliexay ahgi oqaew CBU sejavloz ETAS

在辅助窗格中显示应用程序名称

如果应用程序在辅助窗格上方的导航栏中显示其名称,则会很好。目前所有的空间似乎都浪费了。理想情况下,这将使用应用程序的本地名称。

if let displayName = 
Bundle.main.localizedInfoDictionary?["CFBundleDisplayName"] as? String {
  title= displayName
}
CFBundleDisplayName = "Storesearch.";
这是一个好看的头衔
劳斯是一个taig-beumisc yozci

删除IPad上的输入焦点

在iPhone上,为搜索栏提供输入焦点,所以键盘在启动应用程序后立即出现。在iPad上,这看起来并不好,所以让我们让这个功能有条件。

if UIDevice.current.userInterfaceIdiom != .pad {
  searchBar.becomeFirstResponder()
}

隐藏纵向模式下的主窗格

在纵向模式下,点击搜索结果后,主窗格保持可见并模糊次要窗格的一半。当用户选择选择时,最好隐藏主窗格。

private func hidePrimaryPane() {
  UIView.animate(
    withDuration: 0.25,
    animations: {
      self.splitViewController!.preferredDisplayMode = .secondaryOnly
    }, completion: { _ in
      self.splitViewController!.preferredDisplayMode = .automatic
    }
  )
}
if splitViewController!.displayMode != .oneBesideSecondary {
  hidePrimaryPane()
}

修复iPhone的细节弹出窗口

详细信息视图现在在iPad上的拆分视图控制器中运行良好。但是,您是否回复并在iPhone上测试过,看看您的更改是否影响了该平台上的任何现有功能?

在开始时显示主要窗格

当您在iPhone上使用拆分控制器时,iOS会自动折叠主窗格并在启动时显示辅助窗格。您可以通过成为拆分视图控制器的委托并指定在iPhone上时使用的行为来更改此行为。

extension SceneDelegate: UISplitViewControllerDelegate {
  func splitViewController(
    _ svc: UISplitViewController,
    topColumnForCollapsingToProposedTopColumn proposedTopColumn: UISplitViewController.Column
  ) -> UISplitViewController.Column {
    if UIDevice.current.userInterfaceIdiom == .phone {
      return .primary
    }
    return proposedTopColumn
  }
}
splitVC.delegate = self

删除iPhone上的导航栏

我们不希望导航栏显示在iPhone上运行的应用程序。

override func viewWillAppear(_ animated: Bool) {
  super.viewWillAppear(animated)
  if UIDevice.current.userInterfaceIdiom == .phone {
    navigationController?.navigationBar.isHidden = true
  }
}

修复细节弹出窗口

➤ In prepare(for:sender:) in searchViewController.swift.,添加行:

detailViewController.isPopUp = true

修复景观屏幕

iPhone屏幕上的景观目前看起来是这样的:

iPhone景观视图有一些问题
TTA Etyilu Hulpmkuta Diep Bud Qela Emjuov

let viewWidth = scrollView.bounds.size.width
let viewHeight = scrollView.bounds.size.height
let viewWidth = UIScreen.main.bounds.size.width
let viewHeight = UIScreen.main.bounds.size.height

故事板的大小课程

Even though you’ve placed the existing DetailViewController in the secondary pane, the app is not using all that extra space on an iPad effectively. It would be good if you could keep using the same logic from the DetailViewController class but change the layout of its user interface to suit the iPad better.

视图中的大小类为:窗格
SEDO HNUHXOP紫外线CVO Zuuv IV:PIBO

水平和垂直尺寸类
Fiyukijduy Ink Falmetoh Mewa Freulpif

卸载特定大小类的项目

详细信息窗格不需要设备上的关闭按钮。这不是一个弹出所以我们有理由予以驳回。让我们移除从故事板按钮。

安装复选框
mdu omggidbij dpuklnib

添加一个变化的定期,定时班级规模
Ujwoph一个leruuwiog维姆YWE wanilij,kamegur乔迪wnums

该选项可以在每个大小的阶级基础被改变
TYA igtoit兽医十一xferniq未Ë工程量清单,cehu fbiyh xevux

关闭按钮仍然存在但灰色
GSO vjato sixhur iy kcirc ydurall mov gtebic uen

左上角没有更接近的按钮
Ra nixi dyode dettig iq gvo wud-lols yobpot

更改故事板布局对于给定尺寸级别

当然,细节弹出窗口在iPad上也太宽了:]使用先前使用大小类的变体来解决此iPhone设备。您可以执行同样的事情来更改细节屏幕的布局,以在iPad上更大。

特定于iPad的更改后的弹出式视图
FDI WES-UC JEAL AJHON AKEW-HZELEDOD VMINDIY

添加了标签的字体类尺寸变化
Ekhakf我paxa vhuhq mezuonoec PUW PRU ropay'b fatj

在iPad现在使用不同的限制对二次窗格
HBI UFID WIP iney daqroyimj werxxjauhkz咄DLI hokekzeqs PENO

你自己的popover

任何曾经使用过iPad的人毫无疑问熟悉港口,当您在导航栏或工具栏中点击按钮时出现的浮动面板。它们是一个非常方便的UI元素。

添加菜单项

➤在故事板中,首先切换回来 iPhone SE 因为在iPad模式中,视图控制器的巨大和占用陶氏空间。

新表视图控制器的设计
lsu sopovb mow xwo fut zukji beuy hewdkojrog

显示为popover.

要在POLPOVER中显示视图控制器,需要一个触发POPOVER的按钮。但是,您没有故事板上的导航控制器 - 导航控制器在运行时由拆分视图控制器自动添加。

// Popover action button
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .action, target: self, action: #selector(showPopover(_:)))
@objc func showPopover(_ sender: UIBarButtonItem) {
  guard let popover = storyboard?.instantiateViewController(
    withIdentifier: "PopoverView") else { return }
  popover.modalPresentationStyle = .popover
  if let ppc = popover.popoverPresentationController {
    ppc.barButtonItem = sender
  }
  present(popover, animated: true, completion: nil)
}
菜单有点太高了
e HED BIA REDC的CQUB SEXU

设置popover大小

Popover并不真正知道其内容视图控制器的大大,所以它只是选择尺寸,这只是丑陋。你可以告诉它的观点控制器应该是多大的 优选的内容大小 property.

改变酥料饼的优选宽度和高度
Thushipq yju wciqoccig buckl IPZ pauprb AR MVA vaxakel

菜单弹出型,尺寸适合
Dwu Rusu Xaqubay Qajy O Qoqi Mkay Behc

从应用程序发送电子邮件

现在,让我们制作“发送支持电子邮件”菜单选项工作。让用户从您的应用程序中发送电子邮件非常简单。

menuviewcontroller类

To make things work, you’ll create a new class named MenuViewController for the popover, give it a delegate protocol, and have DetailViewController implement those delegate methods.

protocol MenuViewControllerDelegate: class {
  func menuViewControllerSendEmail(_ controller: MenuViewController)
}
weak var delegate: MenuViewControllerDelegate?
// MARK: - Table View Delegates
override func tableView(
  _ tableView: UITableView, 
  didSelectRowAt indexPath: IndexPath
) {
  tableView.deselectRow(at: indexPath, animated: true)
  if indexPath.row == 0 {
    delegate?.menuViewControllerSendEmail(self)
  }
}

设置MenuViewController委托

Now you have to make DetailViewController the delegate for this menu popover.

extension DetailViewController: MenuViewControllerDelegate {
  func menuViewControllerSendEmail(_: MenuViewController) {
  }
}
@objc func showPopover(_ sender: UIBarButtonItem) {
  guard let popover = storyboard?.instantiateViewController(
    withIdentifier: "PopoverView") as? MenuViewController    // Change this
  else { return }
  popover.modalPresentationStyle = .popover
  if let ppc = popover.popoverPresentationController {
    ppc.barButtonItem = sender
  }
  popover.delegate = self                                    // Add this
  present(popover, animated: true, completion: nil)
}

显示邮件撰写视图

➤ The MFMailComposeViewController lives in the MessageUI framework — import that in DetailViewController.swift.swift.:

import MessageUI
dismiss(animated: true) {
  if MFMailComposeViewController.canSendMail() {
    let controller = MFMailComposeViewController()
    controller.setSubject(
      NSLocalizedString("Support Request", comment: "Email subject"))
    controller.setToRecipients(["[email protected]"])
    self.present(controller, animated: true, completion: nil)
  }
}
电子邮件界面
jne i-noip ejfodsoku

邮件撰写查看代理

请注意,发送和取消按钮实际上不出现做任何事情。那是因为你还需要公然从事委托的邮件撰写看法。

extension DetailViewController: MFMailComposeViewControllerDelegate {
  func mailComposeController(
    _ controller: MFMailComposeViewController, 
    didFinishWith result: MFMailComposeResult, 
    error: Error?
  ) {
    dismiss(animated: true, completion: nil)
  }
}
controller.mailComposeDelegate = self

在更大的iphone景观

具有更大屏幕的iPhone,如加号,XR,11,11,11 Pro Max是奇怪的野兽。它们主要像其他任何iPhone一样工作,但有时他们会得到想法,假装成为iPad。

更大的iPhone手机横向视图被搞砸
Hju dojljkoxo viog忘记zijten xezcuh乌伊的oWxabud

正确显示拆分视图,为更大的iPhone正确

To stop the 风景ViewController from showing up, you have to make the rotation logic smarter.

override func willTransition(
  to newCollection: UITraitCollection,
  with coordinator: UIViewControllerTransitionCoordinator
) {
  super.willTransition(to: newCollection, with: coordinator)
  switch newCollection.verticalSizeClass {
  case .compact:
    if newCollection.horizontalSizeClass == .compact {  // Add this
      showLandscape(with: coordinator)
    }                                                   // Add this
  case .regular, .unspecified:
    hideLandscape(with: coordinator)
  @unknown default:
    break
  }
}
iPhone 8 Plus上的应用程序具有分割视图
YFE OJV IR KRI Adrixi 9 NHUR CEQD O JZBOS-Soun

更改iPhone的拆分视图显示模式

但是......有一个问题 - 当应用程序启动时,您仍然只看到辅助窗格。您必须点击“搜索”按钮以查看主窗格。那不是一个非常好的设计,即使这只会影响一些iPhone ......

if UIDevice.current.userInterfaceIdiom == .phone {
  splitVC.preferredDisplayMode = .oneBesideSecondary
}
主窗格在iPhone 8 Plus上叠加辅助程序
RPA QZZZawn WIPO Zoxg JKO Dihuqnn JKO Dihuqnn ID Urfuxo 6 XP ROPW A CFHEL-POIK

添加更大的iPhone每班基于用户界面的变化

当然,细节窗格现在使用iPhone-Soze设计,而不是iPad设计。

添加于正常大小的类宽度的变化,高度紧凑
UpnibrØhumuafaiq SED虎dkuhg joyfd ciyaxag,xeobxm ritrimh

有一个技术问题?想报告一个错误吗? 您可以向书记论坛中的书籍的作者提出问题并报告错误 这里.

有关于网上阅读体验反馈给份额? 如果您对UI,UX,高亮反馈,或者我们的在线读者的其他功能,您可以付款给设计团队与下面的表格:

© 2021 Razeware LLC

您正在阅读的自由,以显示为本章的部分 混淆了 文本。解锁这本书,以及我们整个书籍和视频目录,带有Raywenderlich.com的专业订阅。

现在解锁

要突出或记笔记,您需要在订阅中拥有这本书或自行购买。