如何使用Swift隐藏QLPreviewController中的共享按钮?

9
我正在使用以下代码在我的应用程序中使用QLPreviewcontroller展示一些文档:
let ql = QLPreviewController()
ql.dataSource = self
//ql.navigationItem.rightBarButtonItems = nil
ql.navigationItem.rightBarButtonItem = nil
presentViewController(ql, animated: true, completion: nil)

我不想在QLPreviewcontroller的右上角显示分享按钮。我尝试将rightBarButtonItem设置为nil,但它没有起作用。如何隐藏它?

也许这些可以帮助:http://stackoverflow.com/questions/22953117/hide-right-button-n-qlpreviewcontroller? - Terry
对我来说运行良好。https://stackoverflow.com/a/45344701/1603380 - Buntylm
10个回答

5
  1. 创建一个QLPreviewController的子类

  2. 将以下代码添加到子类中

Swift:

var toolbars: [UIView] = []

var observations : [NSKeyValueObservation] = []

    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.setRightBarButton(UIBarButtonItem(), animated: false)

    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        navigationController?.toolbar.isHidden = true

        if let navigationToobar = navigationController?.toolbar {
            let observation = navigationToobar.observe(\.isHidden) {[weak self] (changedToolBar, change) in

                if self?.navigationController?.toolbar.isHidden == false {
                     self?.navigationController?.toolbar.isHidden = true
                }
            }
            observations.append(observation)
        }

        toolbars = toolbarsInSubviews(forView: view)

        for toolbar in toolbars {

            toolbar.isHidden = true

            let observation = toolbar.observe(\.isHidden) { (changedToolBar, change) in
                if let isHidden = change.newValue,
                    isHidden == false {
                    changedToolBar.isHidden = true
                }
            }

            observations.append(observation)
        }
    }

    private func toolbarsInSubviews(forView view: UIView) -> [UIView] {

        var toolbars: [UIView] = []

        for subview in view.subviews {
            if subview is UIToolbar {
                toolbars.append(subview)
            }
            toolbars.append(contentsOf: toolbarsInSubviews(forView: subview))
        }
        return toolbars
    }

如果您想要在iOS13中隐藏rightBarButtonItem,则需要在“override func viewDidLoad()”中添加以下代码:navigationItem.rightBarButtonItem = UIBarButtonItem() - leonardosccd

5

在我使用Swift 3 for iOS 10时,这些解决方案都不适用于我。问题在于分享按钮是在viewDidAppear方法之后创建的。

以下是我遵循的步骤来移除分享按钮:

1)对我的QLPreviewController进行子类化

2)在此子类中创建一个打开文档的方法:

func show(controller: UIViewController, url: NSURL) {
    // Refreshing the view
    self.reloadData()
    // Printing the doc
    if let navController = controller.navigationController {
        navController.pushViewController(self, animated: true)
    }
    else {
        controller.show(self, sender: nil)
    }
}

3)在我的viewDidLayoutSubviews方法中,我创建了一个虚拟按钮项来替换分享按钮:

 override func viewDidLayoutSubviews() {
    navigationItem.rightBarButtonItems?[0] = UIBarButtonItem()
}

4) 当我想在另一个 VC 中打开文档时,我会这样调用:

 QLSubclass().show(controller: self, url: path as NSURL)

注意:始终以这种方式调用它,而不是使用您实例化的全局变量,因为您将始终在共享按钮消失之前看到它。


虽然在iPad上运行良好,但iPhone上的共享按钮不在导航栏上,而是在底部。有什么办法可以去掉它吗?我尝试了删除工具栏按钮,但共享按钮仍然存在。 - spaceMonkey
另一个对我非常有效的解决方案是创建自己的 VC,并将 QLPreviewController 的视图作为其子视图添加,这样您就可以摆脱共享按钮 :) - Ugo Marinelli
在iOS 11中,当用户点击导航栏时,它会隐藏,再次点击后会出现分享按钮!有什么解决办法吗? - Besat
1
为什么要传递URL?似乎它在任何地方都没有被使用! - Besat
如何在iOS12.0中隐藏所有新的AR Quicklook? - nOOb iOS
iOS10.3,navigationItem.rightBarButtonItems?[0] = UIBarButtonItem() 显示“Thread 1:致命错误:索引超出范围” - leonardosccd

3
let previewController = QLPreviewController()
previewController.navigationItem.rightBarButtonItem = UIBarButtonItem()
self.present(previewController, animated: true, completion: { })

我认为他们试图传达的是,如果你将rightBarbuttonItem分配给一个新的UIBarButtonItem实例(没有任何进一步的配置),它将实现结果。 - The Muffin Man
我认为这是一个很棒的答案! - Fred Faust
2
如果您应用此代码,则QLPreviewController将在底部显示一个工具栏,其中包含刚刚从导航栏右上角删除的相同共享按钮。但是,这段代码不起作用。 - zumzum
这个不起作用。在iPad(iOS 16.3)上测试过。 - Darkwonder

2

我知道这是一个老问题,但我花了很多时间寻找解决方案,并想出了一些可行的方法。

因此,对于任何寻找与我相同内容的人。这是我的解决方案。

代码是用Objective-C编写的,但它可以简单地转换为Swift。

首先,我们创建QLPreviewController的子类,然后在子类中覆盖以下方法。

编辑

Swift:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.navigationItem.rightBarButtonItem = nil
    //For ipads the share button becomes a rightBarButtonItem
    self.navigationController?.toolbar?.isHidden = true
    //This hides the share item
    self.navigationController?.toolbar?.addObserver(self, forKeyPath: "hidden", options: NSKeyValueObservingOptionPrior, context: nil)
}

override func viewWillDisappear(_ animated: Bool) {
    super.viewWillDisappear(animated)
    self.navigationController?.toolbar?.removeObserver(self, forKeyPath: "hidden")
}

override func observeValue(forKeyPath keyPath: String, ofObject object: Any, change: [AnyHashable: Any], context: UnsafeMutableRawPointer) {
    var isToolBarHidden: Bool? = self.navigationController?.toolbar?.isHidden
    // If the ToolBar is not hidden
    if isToolBarHidden == nil {
        DispatchQueue.main.async(execute: {() -> Void in
            self.navigationController?.toolbar?.isHidden = true
        })
    }
}

self.navigationController?.pushViewController(qlPreviewController, animated: true)

Objective-C:

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    self.navigationItem.rightBarButtonItem = nil; //For ipads the share button becomes a rightBarButtonItem
    [[self.navigationController toolbar] setHidden:YES]; //This hides the share item
    [[self.navigationController toolbar] addObserver:self forKeyPath:@"hidden" options:NSKeyValueObservingOptionPrior context:nil];
}

在 viewWillDisappear 中移除观察者

-(void)viewWillDisappear:(BOOL)animated {
    [super viewWillDisappear:animated];
    [[self.navigationController toolbar] removeObserver:self forKeyPath:@"hidden"];
}

观察者模式:必需的。因为当你单击图像以隐藏导航栏和工具栏时,分享按钮会再次在单击时显示。

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{

    BOOL isToolBarHidden = [self.navigationController toolbar].hidden;
    // If the ToolBar is not hidden
    if (!isToolBarHidden) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [[self.navigationController toolbar] setHidden:YES];
        });
    }
}

预览控制器必须从您现有的导航控制器中推送

[self.navigationController pushViewController:qlPreviewController animated:YES];

我们还需要使用子类而不是QLPreviewController。


可以用。你找到了隐藏整个工具栏的方法吗?这只隐藏了分享图标。 - Henrik Hansen
这里有一个关于SO的帖子链接。它可以移除工具栏,但分享按钮会变得可见。请检查一下,如果您有解决方案,请也发布您的解决方案。 - moz ado
似乎这只是在iOS 10中的问题,可能是一个将被修复的错误。在10之前它是隐藏的。 - Henrik Hansen
在iOS 11中,当用户点击导航栏时,它会隐藏,再次点击后会出现分享按钮!有什么解决办法吗? - Besat
这个解决方案在我的iPadOS 16(iPad)上没有起作用。 - Darkwonder

1
如果仍然有人想要删除分享选项或自定义QLPreviewController的导航栏,他们可以尝试创建一个UIViewController并根据需要进行自定义,然后创建QLPreviewController对象并将其添加为子视图控制器。
这将允许您摆脱分享按钮,并自定义导航栏颜色等。这对我有效。
要了解如何添加子视图控制器,您可以参考this

1

Swift 5解决方案:

子类化QLPreviewController:

final class CustomQLPreviewController: QLPreviewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.rightBarButtonItem = UIBarButtonItem()
    }

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        (children[0] as? UINavigationController)?.setToolbarHidden(true, animated: false)
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        (children[0] as? UINavigationController)?.setToolbarHidden(true, animated: false)
    }
}

然后在你想要展示这个子类的地方,按照以下方式进行:

let previewController = QLVideoController()
present(controller, animated: true, completion: nil)

使用此方法,您将看到“朋友圈”分享按钮。

6s,iOS 13.5,children[0]会崩溃,所以我将其更改为children.first,但似乎代码没有执行,工具栏显示。 - leonardosccd
无法正常工作,分享按钮仍然可见且可用。 - Steven B.
这在我的iPadOS 16.3上不起作用。 - Darkwonder

0
override func viewDidLoad() {
    super.viewDidLoad()
    /* Move "Share" Button to bottom */
    navigationItem.rightBarButtonItem = UIBarButtonItem()
}

override func viewWillLayoutSubviews() {
    super.viewWillLayoutSubviews()
    /* Hide toolbar to hide "Share" button  */
    self.navigationController?.toolbar.isHidden = true
}

重写函数 viewWillLayoutSubviews() { super.viewWillLayoutSubviews() navigationController?.toolbar.isHidden = true navigationItem.rightBarButtonItem = nil } - sumsong
3
欢迎来到SO并感谢您的贡献!如果您在代码片段周围提供一些额外的上下文来解释它们的作用和/或如何回答问题,那通常会很有帮助。对于那些试图将您的代码适应稍微不同情况的人来说,链接到源或参考资料也非常有帮助。 - Matthew
此答案无效。 - grantespo

0

这是我想出的最佳解决方案。

诀窍在于在隐藏工具栏时将动画设置为true。否则,我们会看到分享按钮显示然后消失。

final class NoSharePreviewController: QLPreviewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.rightBarButtonItem = UIBarButtonItem()
    }

    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        navigationController?.setToolbarHidden(true, animated: true)
    }
}

-1

这对我来说很有效

   class QLSPreviewController : QLPreviewController {

        override func viewDidLoad() {
            super.viewDidLoad()



        }
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)

        }
        override func viewDidAppear(_ animated: Bool) {
            super.viewDidAppear(true )
            //This hides the share item
            let add =  self.childViewControllers.first as! UINavigationController
            let layoutContainerView  = add.view.subviews[1] as! UINavigationBar
             layoutContainerView.subviews[2].subviews[1].isHidden = true

        }
    }

强烈不建议使用子视图索引引用视图,以保证向前兼容性。 - ekscrypto

-1

Swift5 的优雅解决方案:

class QLPreviewVC: QLPreviewController {
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if let add = self.children.first as? UINavigationController {
            if let navBar = add.view.subviews.compactMap({ $0 as? UINavigationBar }).first {
                navBar.topItem?.rightBarButtonItem?.isHidden = true
            }
        }
    }
}

private extension UIBarButtonItem {
    var isHidden: Bool {
        get {
            return !isEnabled && tintColor == .clear
        }
        set {
            tintColor = newValue ? .clear : nil
            isEnabled = !newValue
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接