SilenceLove / HXPhotoPicker

图片/视频选择器 - 支持LivePhoto、GIF图片选择、3DTouch预览、在线下载iCloud上的资源、编辑图片/视频、浏览网络图片 功能 Imitation wx photo/image picker - support for LivePhoto, GIF image selection, 3DTouch preview, Download the resources on iCloud online, browse the web image function
https://github.com/SilenceLove/HXPhotoPicker
MIT License
3.03k stars 650 forks source link

PhotoBrowser使用 #644

Closed liumengdi666 closed 5 months ago

liumengdi666 commented 5 months ago

Hello, 作者你好, 上次提的几个问题很快修复,非常感谢. 本次用到HXPhotoPicker.PhotoBrowser(4.1.8)的几个功能,遇到几个问题,麻烦看下:

  1. 自定义pageIndicator不生效 看起来虽然外部支持传入自定义pageIndicator,但是内部viewDidLoad已经执行并加载了默认的pageIndicator

  2. 当pageIndicatorType = .titleView时不显示 看起来是viewDidLayoutSubviews时没有设置宽度导致宽度为0

3.我这有个需求, 期望可以自定义左上角dismiss事件用以埋点或其它业务需求

SilenceLove commented 5 months ago

宽度在传入之前可以自己设置的 dismiss 的看看这个

public var viewDidDisappear: ViewLifeCycleHandler?
liumengdi666 commented 5 months ago

可能我描述的场景不太全面,实际上是这样的: 业务需要浏览相册时有横屏按钮,可以手动控制屏幕方向, 所以我定制了pageIndicator, 因为我们的其它页面没有做横屏的适配比较难看, 所以当browser处于横屏时点击左上角返回如果当前是横屏状态需要先切回竖屏,再点一次才返回上一级, 此时viewDidDisappear貌似不能满足我. 从新看了下PhotoBrowser的参数, 看到可以自定义autoDismiss, 于是我尝试使用了这个参数并实现了finishHandler和cancelHandler, 然而发现点击左上角触发的回调是cancelHandler并不受autoDismiss参数影响, 页面依然返回了上一级. 以下是我的部分代码:

      var config = HXPhotoPicker.PhotoBrowser.Configuration()
        let browser = HXPhotoPicker.PhotoBrowser(
            config,
            pageIndex: indexPath.item,
            assets: previewAssets,
            transitionalImage: cell?.photoView.image
        )
        browser.config.shouldAutorotate = false
        browser.config.supportedInterfaceOrientations = .all
        browser.autoDismiss = false
        let rect = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 30)
        let titleView = MyTitleView(frame: rect)
        browser.previewViewController?.navigationItem.titleView = titleView

        let pageIndicator = MyPhotoBrowserPageControlIndicator(frame: rect)
        pageIndicator.pageChanged = { index in
            titleView.titleLabel.text = "\(index+1)"
        }
        browser.pageIndicator = pageIndicator
        browser.show(nil)

        browser.finishHandler =  { result, controller in
            print("finishHandler")
        }

        browser.cancelHandler =  { controller in
            print("cancelHandler")
        }
/// 定制titleView
open class MyTitleView: UIView {
    public var titleLabel: UILabel!
    override init(frame: CGRect) {
        super.init(frame: frame)
        titleLabel = UILabel()
        titleLabel.textColor = .white
        titleLabel.textAlignment = .center
        addSubview(titleLabel)
    }

    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    open override func layoutSubviews() {
        super.layoutSubviews()
        titleLabel.frame = bounds
    }
}

/// 定制PageIndicator
open class MyPhotoBrowserPageControlIndicator: UIView, PhotoBrowserPageIndicator {

    public var pageLabel: UILabel!
    public var bottomButton: UIButton!

    public var pageChanged: ((Int) -> Void)?
    var currentPage = 0
    var numberOfPages = 0
    override init(frame: CGRect) {
        super.init(frame: frame)
        pageLabel = UILabel()
        pageLabel.textColor = .white
        pageLabel.textAlignment = .center
        addSubview(pageLabel)
        bottomButton = UIButton()
        bottomButton.setTitle("test", for: .normal)
        bottomButton.titleLabel?.textColor = .white
        bottomButton.addTarget(self, action: #selector(onTap), for: .touchUpInside)
        addSubview(bottomButton)
    }

    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @objc func onTap() {
        if LDevice.isLandscape {
            LDevice.setInterfaceOrientation(.portrait)
        }else {
            LDevice.setInterfaceOrientation(.landscapeRight)
        }
    }

    public func reloadData(numberOfPages: Int, pageIndex: Int) {
        self.numberOfPages = numberOfPages
        self.currentPage = pageIndex
    }

    public func didChanged(pageIndex: Int) {
        self.currentPage = pageIndex
        pageLabel.text = "\(currentPage + 1)/\(numberOfPages)"
        pageChanged?(pageIndex)
    }

    open override func layoutSubviews() {
        super.layoutSubviews()
        pageLabel.frame = bounds
        bottomButton.frame = CGRectMake(width-100, 0, 100, height)
    }
}

/// 屏幕旋转
enum LDevice {
    /// 强制旋转屏幕
    public static func setInterfaceOrientation(_ orientation: UIInterfaceOrientation) {
        if #available(iOS 16.0, *) {
            guard let scence = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
                return
            }
            var orientationMask: UIInterfaceOrientationMask = .portrait
            switch orientation {
            case .portrait:
                orientationMask = .portrait
            case .landscapeLeft:
                orientationMask = .landscapeLeft
            case .landscapeRight:
                orientationMask = .landscapeRight
            case .portraitUpsideDown:
                orientationMask = .portraitUpsideDown
            default:
                orientationMask = .allButUpsideDown
            }
            let geometryPreferencesIOS = UIWindowScene.GeometryPreferences.iOS(interfaceOrientations: orientationMask)

            scence.requestGeometryUpdate(geometryPreferencesIOS)
        } else {

            UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
            UIViewController.attemptRotationToDeviceOrientation()
        }
    }

    /// 当前scene的interface是否竖屏
    public static var isPortrait: Bool {
        UIApplication.shared.windows
                        .first?
                        .windowScene?
                        .interfaceOrientation
                        .isPortrait ?? true
    }
    /// 当前scene的interface是否横屏
    public static var isLandscape: Bool {
        UIApplication.shared.windows
                        .first?
                        .windowScene?
                        .interfaceOrientation
                        .isLandscape ?? true
    }
}
SilenceLove commented 5 months ago

可能我描述的场景不太全面,实际上是这样的: 业务需要浏览相册时有横屏按钮,可以手动控制屏幕方向, 所以我定制了pageIndicator, 因为我们的其它页面没有做横屏的适配比较难看, 所以当browser处于横屏时点击左上角返回如果当前是横屏状态需要先切回竖屏,再点一次才返回上一级, 此时viewDidDisappear貌似不能满足我. 从新看了下PhotoBrowser的参数, 看到可以自定义autoDismiss, 于是我尝试使用了这个参数并实现了finishHandler和cancelHandler, 然而发现点击左上角触发的回调是cancelHandler并不受autoDismiss参数影响, 页面依然返回了上一级. 以下是我的部分代码:

      var config = HXPhotoPicker.PhotoBrowser.Configuration()
        let browser = HXPhotoPicker.PhotoBrowser(
            config,
            pageIndex: indexPath.item,
            assets: previewAssets,
            transitionalImage: cell?.photoView.image
        )
        browser.config.shouldAutorotate = false
        browser.config.supportedInterfaceOrientations = .all
        browser.autoDismiss = false
        let rect = CGRect(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 30)
        let titleView = MyTitleView(frame: rect)
        browser.previewViewController?.navigationItem.titleView = titleView

        let pageIndicator = MyPhotoBrowserPageControlIndicator(frame: rect)
        pageIndicator.pageChanged = { index in
            titleView.titleLabel.text = "\(index+1)"
        }
        browser.pageIndicator = pageIndicator
        browser.show(nil)

        browser.finishHandler =  { result, controller in
            print("finishHandler")
        }

        browser.cancelHandler =  { controller in
            print("cancelHandler")
        }
/// 定制titleView
open class MyTitleView: UIView {
    public var titleLabel: UILabel!
    override init(frame: CGRect) {
        super.init(frame: frame)
        titleLabel = UILabel()
        titleLabel.textColor = .white
        titleLabel.textAlignment = .center
        addSubview(titleLabel)
    }

    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    open override func layoutSubviews() {
        super.layoutSubviews()
        titleLabel.frame = bounds
    }
}

/// 定制PageIndicator
open class MyPhotoBrowserPageControlIndicator: UIView, PhotoBrowserPageIndicator {

    public var pageLabel: UILabel!
    public var bottomButton: UIButton!

    public var pageChanged: ((Int) -> Void)?
    var currentPage = 0
    var numberOfPages = 0
    override init(frame: CGRect) {
        super.init(frame: frame)
        pageLabel = UILabel()
        pageLabel.textColor = .white
        pageLabel.textAlignment = .center
        addSubview(pageLabel)
        bottomButton = UIButton()
        bottomButton.setTitle("test", for: .normal)
        bottomButton.titleLabel?.textColor = .white
        bottomButton.addTarget(self, action: #selector(onTap), for: .touchUpInside)
        addSubview(bottomButton)
    }

    required public init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    @objc func onTap() {
        if LDevice.isLandscape {
            LDevice.setInterfaceOrientation(.portrait)
        }else {
            LDevice.setInterfaceOrientation(.landscapeRight)
        }
    }

    public func reloadData(numberOfPages: Int, pageIndex: Int) {
        self.numberOfPages = numberOfPages
        self.currentPage = pageIndex
    }

    public func didChanged(pageIndex: Int) {
        self.currentPage = pageIndex
        pageLabel.text = "\(currentPage + 1)/\(numberOfPages)"
        pageChanged?(pageIndex)
    }

    open override func layoutSubviews() {
        super.layoutSubviews()
        pageLabel.frame = bounds
        bottomButton.frame = CGRectMake(width-100, 0, 100, height)
    }
}

/// 屏幕旋转
enum LDevice {
    /// 强制旋转屏幕
    public static func setInterfaceOrientation(_ orientation: UIInterfaceOrientation) {
        if #available(iOS 16.0, *) {
            guard let scence = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
                return
            }
            var orientationMask: UIInterfaceOrientationMask = .portrait
            switch orientation {
            case .portrait:
                orientationMask = .portrait
            case .landscapeLeft:
                orientationMask = .landscapeLeft
            case .landscapeRight:
                orientationMask = .landscapeRight
            case .portraitUpsideDown:
                orientationMask = .portraitUpsideDown
            default:
                orientationMask = .allButUpsideDown
            }
            let geometryPreferencesIOS = UIWindowScene.GeometryPreferences.iOS(interfaceOrientations: orientationMask)

            scence.requestGeometryUpdate(geometryPreferencesIOS)
        } else {

            UIDevice.current.setValue(orientation.rawValue, forKey: "orientation")
            UIViewController.attemptRotationToDeviceOrientation()
        }
    }

    /// 当前scene的interface是否竖屏
    public static var isPortrait: Bool {
        UIApplication.shared.windows
                        .first?
                        .windowScene?
                        .interfaceOrientation
                        .isPortrait ?? true
    }
    /// 当前scene的interface是否横屏
    public static var isLandscape: Bool {
        UIApplication.shared.windows
                        .first?
                        .windowScene?
                        .interfaceOrientation
                        .isLandscape ?? true
    }
}

需要界面退出之后的回调吗?

liumengdi666 commented 5 months ago

需要界面退出之后的回调现在是有的,实际上我们只想自定义左上角返回按钮事件,我用了个比较非常规的方法:

        browser.show(nil)
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
            guard let self = self else { return }
            var item = browser.previewViewController?.navigationItem.leftBarButtonItem
            item?.action = #selector(didCancelItemClick1)
            item?.target = self
        }

这样也替换了左上角事件, 我自己来控制dismiss, 结合自定义cell单击事件,也勉强达到了想要的效果.