Ios 在另一个视图中内嵌共享图标

Ios 在另一个视图中内嵌共享图标,ios,iphone,swift,cocoa-touch,Ios,Iphone,Swift,Cocoa Touch,我正在尝试在我的iOS应用程序中实现一个与Google Photos iOS应用程序外观相似的“共享”功能: 下面两行图标是我所关心的。它们看起来与使用时显示的几乎相同 在谷歌照片应用程序中,这些图标显示在屏幕的“选择照片”部分(例如,您仍然可以与屏幕的上部交互)。但是,UIActivityViewController的文档说明“在iPhone和iPod touch上,您必须以模式显示[视图控制器]。” 这是对我来说非常重要的区别——我希望“共享”图标与我的其他内容一起显示,而不是在我的内容顶

我正在尝试在我的iOS应用程序中实现一个与Google Photos iOS应用程序外观相似的“共享”功能:

下面两行图标是我所关心的。它们看起来与使用时显示的几乎相同

在谷歌照片应用程序中,这些图标显示在屏幕的“选择照片”部分(例如,您仍然可以与屏幕的上部交互)。但是,UIActivityViewController的文档说明“在iPhone和iPod touch上,您必须以模式显示[视图控制器]。”

这是对我来说非常重要的区别——我希望“共享”图标与我的其他内容一起显示,而不是在我的内容顶部显示一个模式


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

好的,我考虑过这一点,在网上做了一些深入的研究,但似乎没有人需要像你想的那样修改它。下面是我对谷歌工程师如何解决这个问题的猜测:

  • 他们对UIActivityViewController进行了反向工程,并调用一些私有API来获得相同的图标以显示和重新排序控制器
  • 他们使用UIViewController转换API并破解了一个以模态方式呈现的UIActivityViewController的视图层次结构,删除了“取消”按钮并在其视图顶部添加了一些自定义视图
  • 第二个选项的指标可能是呈现的“工作表”的顶部有白色背景,而底部有灰色背景

    不幸的是,我不太适合转换API,因为我正要学习它,但我的理解是,您可以提供一个自定义对象作为转换委托

    然后,当您呈现/取消或推送/弹出UIViewController时,将调用此对象。它将同时获得对演示和演示视图控制器的引用,您可以从它们的两个视图中获得乐趣

    这将使删除和添加一些子视图、更改帧和颜色等变得“安静”,同时仍保留所有默认行为


    我希望这个答案能帮助你实现你想要的。但是,请注意,控制器的结构可能随时发生变化,因此始终确保再次测试betas,以便在苹果发布破坏用户界面的更新时,您不会感到意外。:)

    好吧,我考虑过这个问题,在网上做了一些深入的研究,但似乎从来没有人需要像你想的那样修改它。下面是我对谷歌工程师如何解决这个问题的猜测:

  • 他们对UIActivityViewController进行了反向工程,并调用一些私有API来获得相同的图标以显示和重新排序控制器
  • 他们使用UIViewController转换API并破解了一个以模态方式呈现的UIActivityViewController的视图层次结构,删除了“取消”按钮并在其视图顶部添加了一些自定义视图
  • 第二个选项的指标可能是呈现的“工作表”的顶部有白色背景,而底部有灰色背景

    不幸的是,我不太适合转换API,因为我正要学习它,但我的理解是,您可以提供一个自定义对象作为转换委托

    然后,当您呈现/取消或推送/弹出UIViewController时,将调用此对象。它将同时获得对演示和演示视图控制器的引用,您可以从它们的两个视图中获得乐趣

    这将使删除和添加一些子视图、更改帧和颜色等变得“安静”,同时仍保留所有默认行为


    我希望这个答案能帮助你实现你想要的。但是,请注意,控制器的结构可能随时发生变化,因此始终确保再次测试betas,以便在苹果发布破坏用户界面的更新时,您不会感到意外。:)

    如另一个答案所述,反向工程
    UIActivityViewController
    是实现类似效果的唯一选择。我用iphone6s-10.3模拟器试过这个。对于iOS 9.x或11.x或更高版本,以下发现可能不准确

    A.找出
    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)
    
    进一步检查后,我发现
    \u 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

    调试视图层次结构
    对此有答案

    我尝试将其作为
    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)
    })
    
    此应用商店安全吗?-很可能不安全

    一旦您开始从
    UIKit
    的标准组件中窃取
    视图
    viewController
    ,行为就不稳定,肯定会随着即将到来的更新而中断

    Google Photos的功能是更先进的逆向工程的结果。在上面的实现中,你看不到更多选项屏幕。层次结构
    UIActivityViewController
    预期已损坏


    希望这有帮助。

    正如另一个答案中所讨论的,反向工程
    UIActivityViewController
    是实现类似效果的唯一选项。我试着用这个<
    self.present(activityVC, animated: false, completion: {
        self.dismiss(animated: false, completion: nil)
    })