2017-06-01 67 views
0

我试图实现“共享”功能在我的iOS应用程序具有相似的外观和感觉,谷歌照片的iOS应用:嵌入分享图标内嵌在另一个浏览

enter image description here

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

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

这是对我来说非常重要的差异 - 我希望“共享”图标与我的其余内容一起内联显示,而不是在我的内容上显示一个模式。

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

回答

1

正如在另一个答案中所讨论的,逆向工程UIActivityViewController是唯一的选择,以便能够实现类似的效果。我试过这个使用iPhone 6s - 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) 

的那些那些了我的注意一见钟情是(按顺序) -

_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

我尝试添加这是一个childViewControllerUIViewController -

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), 
    ]) 

IT只有正确如果您装入/ PRESENTED UIActivityViewController FIRST显示出来。

我能够使用这种无声的存在以获得/解雇呼叫 -

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

IS THIS APP STORE安全吗? - 最有可能不是。

当您开始从UIKit的标准组件中盗取view(s)viewController(s)时,行为并不稳定,并且会随着即将到来的更新而中断。

谷歌的照片是什么是更先进的逆向工程的结果。在上面的实现中,您看不到更多选项屏幕。等级UIActivityViewController预计会中断。

希望这会有所帮助。

+0

尽管我希望能有比这更完整的东西,但我花了很多时间试图找到工作解决方案,然后继续颁发奖金。谢谢你的努力。 – Donut

1

好吧,我想到了这一点,我在网上做了一些深入的研究,但似乎没有人需要像你想要的那样修改它。因此,这里是我的猜测谷歌的工程师是如何解决这样的:

  1. 他们逆向工程的UIActivityViewController和调用一些私人API来获得相同的图标显示出来,并重新排序控制器
  2. 他们使用的UIViewController过渡API和黑客一个模态的视图层次呈现UIActivityViewController,除去取消按钮和在其视图的顶部加入一些自定义视图

第二种选择的指示器可能是所呈现的“片”的顶部具有一个白色背景而底部则呈灰色。

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

当您呈现/解散或推送/弹出UIViewController时,此对象会被调用。它将得到对提交和呈现的视图控制器的引用,并且你可以在他们的两个视图中获得乐趣。

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

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

+0

这绝对有可能;然而,无论他们正在使用什么,实际上尊重用户的系统偏好,关于共享图标的顺序以及实际启用了哪些图标。例如,如果您通过点击“更多”图标访问“活动”屏幕(如下所述:https://www.howtogeek.com/232489/how-to-customize-the-ios-sharing-menu/ ),相同的偏好将反映在使用相同共享控制的其他应用程序(例如,照片库应用程序)中。所以大概这是iOS的一个功能..但我怎么能做同样的事情?如果不是UIActivityViewController,那么是什么? – Donut

+0

也许他们正在阅读一些私人apis,不知何故设法将控制器子类化或将其嵌入到自定义容器视图控制器中,并通过移动其子视图来侵入其视图层次结构。 – xxtesaxx

+0

可能,虽然当我试图用'UIActivityViewController'做任何事情,而不是以模态方式呈现它(如文档状态),我得到了一个运行时错误,基本上说明了同样的事情...因此赏金:) – Donut