在另一个视图中内联嵌入共享图标
Embedding Share Icons Inline Within Another View
我正在尝试在我的 iOS 应用程序中实现一个 "Share" 功能,其外观和感觉与 Google 照片 iOS 应用程序相似:
下面两行图标是我关心的。它们看起来与使用 UIActivityViewController
时显示的几乎相同。
在 Google 照片应用中,这些图标显示在屏幕的 "select photos" 部分(例如,您仍然可以与屏幕的上半部分进行交互)。但是,UIActivityViewController
的文档指出 "On iPhone and iPod touch, you must present [the view controller] modally."
这是对我来说真正重要的区别 -- 我希望 "share" 图标与我的其余内容内联显示,而不是在顶部显示模式我的内容。
是否可以使用 UIActivityViewController
来实现与上面屏幕截图类似的效果?如果没有,是否有推荐的方法可用于实现此类功能?
好吧,我考虑过这个问题,并且在网上做了一些深入的研究,但似乎从来没有人需要像您想要的那样修改它。所以这是我的猜测 Google 工程师是如何解决这个问题的:
- 他们对 UIActivityViewController 进行了逆向工程,并调用了一些私有 API 以显示相同的图标并重新排序控制器
- 他们使用 UIViewController 转换 API 并破解模态呈现的 UIActivityViewController 的视图层次结构,删除取消按钮和在其视图之上添加一些自定义视图
第二个选项的指标可能是所呈现的 "sheet" 的顶部为白色背景,而底部为灰色。
不幸的是,我不太适应转换 API,因为我正要学习它,但我的理解是您可以提供自定义对象作为转换委托。
当您 present/dismiss 或 push/pop 一个 UIViewController 时,此对象将被调用。它将获得对呈现视图控制器和呈现视图控制器的引用,您可以从它们的两个视图中获得乐趣。
这将使 "quiet" 易于删除和添加一些子视图、更改框架和颜色等,同时仍然具有所有默认行为。
我希望这个答案能帮助你实现你想要的。但是,请注意控制器的结构随时可能发生变化,因此请始终确保再次测试测试版,这样当苹果发布更新破坏您的 UI 时,您就不会感到意外。 :)
正如另一个答案中所讨论的那样,逆向工程 UIActivityViewController
是实现类似效果的唯一选择。我使用 iPhone 6s - 10.3 Simulator 进行了尝试。对于 iOS 9.x 或 11.x 或更高版本,以下结果可能不准确。
一个。找出 UIActivityViewController
的所有内部变量
var variablesCount: UInt32 = 0
let variables = class_copyIvarList(UIActivityViewController.self, &variablesCount)
for i in 0..<variablesCount {
if let variable = variables?[Int(i)] {
let name = String(cString: ivar_getName(variable))
let typeEncoding = String(cString: ivar_getTypeEncoding(variable))
print("\(name)\n\(typeEncoding)\n\n")
}
}
free(variables)
第一眼引起我注意的是(按顺序)-
_activityViewController
@"UIViewController"
_contentController
@"_UIActivityViewControllerContentController"
_activityAlertController
@"UIAlertController"
进一步检查后,我发现 _contentController
是我们应该寻找的那个。我们需要在层次结构中更深入地查看一层,以便 UICollectionViewController
到达我们想要的位置。
if let activityContentController = activityVC.value(forKeyPath: "_contentController") as? UIViewController {
print("Found _contentController!")
for child in activityContentController.childViewControllers {
print(String(describing: child))
if child is UICollectionViewController {
print("Found UICollectionViewController!")
break
}
}
}
我为什么要找 UICollectionViewController
?
Debug View Hierarchy
对此有答案。
我尝试将此作为 childViewController
添加到我的 UIViewController
-
self.addChildViewController(child)
child.didMove(toParentViewController: self)
self.view.addSubview(child.view)
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: self.view.topAnchor),
child.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
child.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
child.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
只有当您首先 LOADED/PRESENTED UIActivityViewController
时才会正确显示。
我能够使用静默 present/dismiss 调用实现此目的 -
self.present(activityVC, animated: false, completion: {
self.dismiss(animated: false, completion: nil)
})
这个应用商店安全吗? - 很可能不安全。
一旦您开始从 UIKit
的标准组件中窃取 view(s)
或 viewController(s)
,行为就会不稳定,并且肯定会随着即将到来的更新而中断。
Google Photos 所具有的是更高级逆向工程的结果。 在上面的实现中,您看不到 更多 选项屏幕。 UIActivityViewController
预期的层次结构已损坏。
希望这对您有所帮助。
我正在尝试在我的 iOS 应用程序中实现一个 "Share" 功能,其外观和感觉与 Google 照片 iOS 应用程序相似:
下面两行图标是我关心的。它们看起来与使用 UIActivityViewController
时显示的几乎相同。
在 Google 照片应用中,这些图标显示在屏幕的 "select photos" 部分(例如,您仍然可以与屏幕的上半部分进行交互)。但是,UIActivityViewController
的文档指出 "On iPhone and iPod touch, you must present [the view controller] modally."
这是对我来说真正重要的区别 -- 我希望 "share" 图标与我的其余内容内联显示,而不是在顶部显示模式我的内容。
是否可以使用 UIActivityViewController
来实现与上面屏幕截图类似的效果?如果没有,是否有推荐的方法可用于实现此类功能?
好吧,我考虑过这个问题,并且在网上做了一些深入的研究,但似乎从来没有人需要像您想要的那样修改它。所以这是我的猜测 Google 工程师是如何解决这个问题的:
- 他们对 UIActivityViewController 进行了逆向工程,并调用了一些私有 API 以显示相同的图标并重新排序控制器
- 他们使用 UIViewController 转换 API 并破解模态呈现的 UIActivityViewController 的视图层次结构,删除取消按钮和在其视图之上添加一些自定义视图
第二个选项的指标可能是所呈现的 "sheet" 的顶部为白色背景,而底部为灰色。
不幸的是,我不太适应转换 API,因为我正要学习它,但我的理解是您可以提供自定义对象作为转换委托。
当您 present/dismiss 或 push/pop 一个 UIViewController 时,此对象将被调用。它将获得对呈现视图控制器和呈现视图控制器的引用,您可以从它们的两个视图中获得乐趣。
这将使 "quiet" 易于删除和添加一些子视图、更改框架和颜色等,同时仍然具有所有默认行为。
我希望这个答案能帮助你实现你想要的。但是,请注意控制器的结构随时可能发生变化,因此请始终确保再次测试测试版,这样当苹果发布更新破坏您的 UI 时,您就不会感到意外。 :)
正如另一个答案中所讨论的那样,逆向工程 UIActivityViewController
是实现类似效果的唯一选择。我使用 iPhone 6s - 10.3 Simulator 进行了尝试。对于 iOS 9.x 或 11.x 或更高版本,以下结果可能不准确。
一个。找出 UIActivityViewController
var variablesCount: UInt32 = 0
let variables = class_copyIvarList(UIActivityViewController.self, &variablesCount)
for i in 0..<variablesCount {
if let variable = variables?[Int(i)] {
let name = String(cString: ivar_getName(variable))
let typeEncoding = String(cString: ivar_getTypeEncoding(variable))
print("\(name)\n\(typeEncoding)\n\n")
}
}
free(variables)
第一眼引起我注意的是(按顺序)-
_activityViewController
@"UIViewController"
_contentController
@"_UIActivityViewControllerContentController"
_activityAlertController
@"UIAlertController"
进一步检查后,我发现 _contentController
是我们应该寻找的那个。我们需要在层次结构中更深入地查看一层,以便 UICollectionViewController
到达我们想要的位置。
if let activityContentController = activityVC.value(forKeyPath: "_contentController") as? UIViewController {
print("Found _contentController!")
for child in activityContentController.childViewControllers {
print(String(describing: child))
if child is UICollectionViewController {
print("Found UICollectionViewController!")
break
}
}
}
我为什么要找 UICollectionViewController
?
Debug View Hierarchy
对此有答案。
我尝试将此作为 childViewController
添加到我的 UIViewController
-
self.addChildViewController(child)
child.didMove(toParentViewController: self)
self.view.addSubview(child.view)
child.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
child.view.topAnchor.constraint(equalTo: self.view.topAnchor),
child.view.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
child.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
child.view.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
])
只有当您首先 LOADED/PRESENTED UIActivityViewController
时才会正确显示。
我能够使用静默 present/dismiss 调用实现此目的 -
self.present(activityVC, animated: false, completion: {
self.dismiss(animated: false, completion: nil)
})
这个应用商店安全吗? - 很可能不安全。
一旦您开始从 UIKit
的标准组件中窃取 view(s)
或 viewController(s)
,行为就会不稳定,并且肯定会随着即将到来的更新而中断。
Google Photos 所具有的是更高级逆向工程的结果。 在上面的实现中,您看不到 更多 选项屏幕。 UIActivityViewController
预期的层次结构已损坏。
希望这对您有所帮助。