在 iOS 中将 Peek 和 Pop 与 Popover 相结合
Combine Peek and Pop with Popover in iOS
是否可以在 iOS 中将 peek 和 pop 与 popover 相结合?
我想在支持 3D Touch 的 iPhone 上使用 peek 和 pop,同时在 iPad 上使用 popover。
当我尝试将它组合到情节提要中时,出现错误 "Couldn't compile connection"。
我自己找到了答案
问题是,PopOver的锚点指向动态创建的原型单元格,因此系统无法确定哪个单元格是锚点。
因此解决方案如下:
- 将弹出窗口的锚点设置为 table 视图
- 从故事板 segue 中删除 peek & pop 功能,因为我们需要在代码中执行此操作。
- 转到您的
UITableViewDataSource
(在我的例子中是视图控制器)并使用单元格作为源视图将以下内容添加到您的 cellForRowAt()
:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCellIdentifier", for: indexPath) as! MyTableViewCell
let item = items[indexPath.row]
// Pass the item here...
registerForPreviewing(with: self, sourceView: cell) // <== Add this
return cell
}
- 之后你必须像这样遵守协议
UIViewControllerPreviewingDelegate
:
extension ListeningVC: UIViewControllerPreviewingDelegate {
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = tableView.indexPathForRow(at: location) else {
return nil
}
// get the item you want to pass using the index path
let item = items[indexPath.row]
// get the destination view controller
let destination = UIStoryboard(name: "...", bundle: nil).instantiateInitialViewController()
// Pass the item here...
return destination // return the destination view controller
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
// either present the view controller or add it to your navigation controller here
present(viewControllerToCommit, animated: true)
}
}
- 如果需要,可以将锚点(源视图)稍微居中:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.identifier {
case "mySegueIdentifier":
guard let cell = sender as? MyTableViewCell else { return }
guard let indexPath = tableView.indexPath(for: cell) else { return }
let item = items[indexPath.row]
let destination = segue.destination
// Pass the item here...
if let popOver = segue.destination.popoverPresentationController {
// set the cell as source view
let origin = CGPoint(x: 100, y: cell.frame.origin.y)
let size = CGSize(width: 200, height: cell.frame.height)
popOver.sourceView = tableView
popOver.sourceRect = CGRect(origin: origin, size: size)
}
default:
break
}
}
- 很高兴这可行,并对这个答案投赞成票。 :)
是否可以在 iOS 中将 peek 和 pop 与 popover 相结合?
我想在支持 3D Touch 的 iPhone 上使用 peek 和 pop,同时在 iPad 上使用 popover。
当我尝试将它组合到情节提要中时,出现错误 "Couldn't compile connection"。
我自己找到了答案
问题是,PopOver的锚点指向动态创建的原型单元格,因此系统无法确定哪个单元格是锚点。
因此解决方案如下:
- 将弹出窗口的锚点设置为 table 视图
- 从故事板 segue 中删除 peek & pop 功能,因为我们需要在代码中执行此操作。
- 转到您的
UITableViewDataSource
(在我的例子中是视图控制器)并使用单元格作为源视图将以下内容添加到您的cellForRowAt()
:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCellIdentifier", for: indexPath) as! MyTableViewCell
let item = items[indexPath.row]
// Pass the item here...
registerForPreviewing(with: self, sourceView: cell) // <== Add this
return cell
}
- 之后你必须像这样遵守协议
UIViewControllerPreviewingDelegate
:
extension ListeningVC: UIViewControllerPreviewingDelegate {
func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? {
guard let indexPath = tableView.indexPathForRow(at: location) else {
return nil
}
// get the item you want to pass using the index path
let item = items[indexPath.row]
// get the destination view controller
let destination = UIStoryboard(name: "...", bundle: nil).instantiateInitialViewController()
// Pass the item here...
return destination // return the destination view controller
}
func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) {
// either present the view controller or add it to your navigation controller here
present(viewControllerToCommit, animated: true)
}
}
- 如果需要,可以将锚点(源视图)稍微居中:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.identifier {
case "mySegueIdentifier":
guard let cell = sender as? MyTableViewCell else { return }
guard let indexPath = tableView.indexPath(for: cell) else { return }
let item = items[indexPath.row]
let destination = segue.destination
// Pass the item here...
if let popOver = segue.destination.popoverPresentationController {
// set the cell as source view
let origin = CGPoint(x: 100, y: cell.frame.origin.y)
let size = CGSize(width: 200, height: cell.frame.height)
popOver.sourceView = tableView
popOver.sourceRect = CGRect(origin: origin, size: size)
}
default:
break
}
}
- 很高兴这可行,并对这个答案投赞成票。 :)