在另一个视图中嵌入共享图标

时间:2017-06-01 00:52:57

标签: ios iphone swift cocoa-touch

我正在尝试实施"分享"我的iOS应用中的功能与Google相册iOS应用的外观和感觉相似:

enter image description here

底部两排图标是我关心的。它们看起来几乎与使用UIActivityViewController时显示的相同。

在Google相册应用中,这些图标会与"选择照片"屏幕的一部分(例如,您仍然可以与屏幕的上半部分进行交互)。但是,UIActivityViewController的文档声明"在iPhone和iPod touch上,您必须以模态方式显示[视图控制器]。"

这对我来说非常重要 - 我喜欢"分享"图标与我的其他内容一起显示内联,而不是在我的内容之上显示模式。

是否可以使用UIActivityViewController来实现上面屏幕截图中显示的类似效果?如果没有,是否有推荐的方法可以用来实现这种功能?

2 个答案:

答案 0 :(得分:1)

好的,我想到了这一点,我在网上进行了一些深入研究,但似乎没有人需要像你想要的那样修改它。所以我猜测Google工程师是如何解决这个问题的:

  1. 他们反向设计了UIActivityViewController并调用了一些私有API来显示相同​​的图标和重新排序的控制器
  2. 他们使用UIViewController转换API并破解模式呈现的UIActivityViewController的视图层次结构,删除取消按钮并在其视图顶部添加一些自定义视图
  3. 第二个选项的指标可能是所呈现的"表格的顶部"有白色背景,底部有灰色。

    不幸的是,我不太适合过渡API,因为我正要学习它但我的理解是你可以提供一个自定义对象作为过渡代表。

    当您呈现/关闭或推送/弹出UIViewController时,将调用此对象。它将获得对呈现和呈现的视图控制器的参考,您可以获得他们的两种观点的乐趣。

    这应该使它"安静"容易删除并添加一些子视图,更改框架和颜色等,同时仍然具有所有默认行为。

    我希望这个答案能帮助你实现自己想要的目标。但是,请注意控制器的结构可能随时发生变化,因此请务必再次测试再次测试,这样当苹果发布破坏用户界面的更新时,您不会感到惊讶。 :)

答案 1 :(得分:1)

正如另一个答案中所讨论的,逆向工程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有答案。

enter image description here

我尝试将此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),
    ])

只有在您首先加载/展示UIActivityViewController时,它才会正确显示。

我能够使用静音现场/解雇电话来实现这一目标 -

self.present(activityVC, animated: false, completion: {
    self.dismiss(animated: false, completion: nil)
})

这个应用程序存储安全吗? - 很可能不是。

一旦您开始从view(s)的标准组件中窃取viewController(s)UIKit,行为就不稳定,并且肯定会破坏即将发布的更新。

Google相片所拥有的是更先进的逆向工程的结果。在上述实施中,您无法看到更多选项屏幕。层次结构UIActivityViewController预期会被破坏。

希望这有帮助。