123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392 |
- //
- // TLPhontoPreviewView.swift
- // RainbowPlanet
- //
- // Created by 南鑫林 on 2019/8/25.
- // Copyright © 2019 RainbowPlanet. All rights reserved.
- //
- import UIKit
- import PhotosUI
- import Kingfisher
- extension TLPhontoPreviewView {
-
- private class scrollView: UIScrollView, UIScrollViewDelegate {
-
- private enum imageDirection {
- case equal
- case transversal
- case lengthwise
- }
-
- required init?(coder aDecoder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- public let imageView = UIImageView()
-
- override init(frame: CGRect) {
- super.init(frame: frame)
- backgroundColor = .clear
- showsVerticalScrollIndicator = false
- showsHorizontalScrollIndicator = false
- alwaysBounceVertical = true
- alwaysBounceHorizontal = true
- maximumZoomScale = 3.0
- clipsToBounds = true
- if #available(iOS 11.0, *) {
- contentInsetAdjustmentBehavior = .never
- }
- addSubview(imageView)
- delegate = self
- }
-
- private var _isSquare = false
-
- override open var frame: CGRect {
- set {
- if frame.size != newValue.size {
- let windowSize = newValue.size
- _isSquare = floor(windowSize.width) == floor(windowSize.height)
- _imageDirection = _imageDirection(from: _imageSize, windowSize)
- }
- if _isNeedLayoutSubviews {
- zoomScale = 1.0
- contentOffset = .zero
- }
- super.frame = newValue
- }
- get {
- return super.frame
- }
- }
-
- private var _isNeedLayoutSubviews = true
-
- public func set(frame: CGRect, isNeedLayoutSubviews: Bool) {
- _isNeedLayoutSubviews = isNeedLayoutSubviews
- self.frame = frame
- }
-
- open var itemModel: KSMediaPickerItemModel? {
- didSet {
- guard let k_itemModel = itemModel else {
- return
- }
- let asset = k_itemModel.asset
- let floatWidth = CGFloat(asset.pixelWidth)
- let floatHeight = CGFloat(asset.pixelHeight)
- _imageSize = CGSize(width: floatWidth, height: floatHeight)
- }
- }
-
- var _imageSize = CGSize.zero {
- didSet {
- _imageDirection = _imageDirection(from: _imageSize, frame.size)
- _isNeedLayoutSubviews = true
- setNeedsLayout()
- }
- }
-
- override func layoutSubviews() {
- super.layoutSubviews()
- guard _isNeedLayoutSubviews || imageView.frame.size == .zero else {
- return
- }
- _isNeedLayoutSubviews = false
- let offset: CGPoint
- if _imageDirection == .equal {
- imageView.frame = bounds
- offset = .zero
- } else if _imageSize != .zero {
- let windowSize = frame.size
- let windowWidth = windowSize.width
- let windowHeight = windowSize.height
- let floatZore = CGFloat(0.0)
- let viewX: CGFloat
- let viewY: CGFloat
- let viewW: CGFloat
- let viewH: CGFloat
-
- let imageWidth = _imageSize.width
- let imageHeight = _imageSize.height
-
- if _imageDirection == .transversal {
- viewH = windowHeight
- viewW = imageWidth/imageHeight*viewH
- viewY = floatZore
- viewX = (windowWidth-viewW)*0.5
- } else {
- viewW = windowWidth
- viewH = imageHeight/imageWidth*viewW
- viewX = floatZore
- viewY = (windowHeight-viewH)*0.5
- }
- imageView.frame = CGRect(origin: .zero, size: CGSize(width: viewW, height: viewH))
- offset = CGPoint(x: -viewX, y: -viewY)
- } else {
- offset = .zero
- }
- contentSize = imageView.frame.size
- zoomScale = itemModel?.zoomScale ?? 1.0
- contentOffset = itemModel?.contentOffset ?? offset
-
- let minimumZoomScale: CGFloat
- if _isSquare {
- switch _imageDirection {
- case .equal:
- minimumZoomScale = 1.0
- break
- case .transversal:
- minimumZoomScale = frame.size.width/imageView.frame.size.width
- break
- case .lengthwise:
- minimumZoomScale = frame.size.height/imageView.frame.size.height
- break
- }
- } else {
- minimumZoomScale = 1.0
- }
- self.minimumZoomScale = minimumZoomScale
- }
-
- private func _imageDirection(from imageSize: CGSize, _ superSize: CGSize) -> TLPhontoPreviewView.scrollView.imageDirection {
- let superWidth = floor(superSize.width)
- let superHeight = floor(superSize.height)
- let imageWidth = floor(imageSize.width)
- let imageHeight = floor(imageSize.height)
- let constrainImageHeight = floor(imageHeight/imageWidth*superWidth)
- let dirction: TLPhontoPreviewView.scrollView.imageDirection
- if superHeight == constrainImageHeight {
- dirction = .equal
- } else {
- let maxHeight = max(superHeight, constrainImageHeight)
- if maxHeight == superHeight {
- dirction = .transversal
- } else {
- dirction = .lengthwise
- }
- }
- return dirction
- }
-
- private var _imageDirection = TLPhontoPreviewView.scrollView.imageDirection.equal
-
- func viewForZooming(in scrollView: UIScrollView) -> UIView? {
- return imageView
- }
-
- func scrollViewDidZoom(_ scrollView: UIScrollView) {
- let contentSize = scrollView.contentSize
- let contentSizeWidth = floor(contentSize.width)
- let contentSizeHeight = floor(contentSize.height)
- let size = scrollView.frame.size
-
- var center = scrollView.center
- if contentSizeWidth >= floor(size.width) {
- center.x = contentSizeWidth*0.5
- }
- if contentSizeHeight >= floor(size.height) {
- center.y = contentSizeHeight*0.5
- }
- imageView.center = center
- }
- }
- }
- import Photos
- open class TLPhontoPreviewView: UIView {
-
- required public init?(coder aDecoder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- private var _photoLibrary = TLPhotoLibrary()
-
- private let _videoView = {() -> KSVideoPlayerBaseView in
- let videoView = KSVideoPlayerBaseView()
- videoView.videoGravity = .resizeAspect
- videoView.videoPlaybackFinished = {[weak videoView] in
- videoView?.play()
- }
- videoView.isHidden = true
- return videoView
- }()
-
- private let _scrollview = TLPhontoPreviewView.scrollView()
-
- private let _changeSizeButton = {() -> UIButton in
- let changeSizeButton = UIButton(type: .custom)
- changeSizeButton.setImage(UIImage(named: "icon_mediaPicker_preview_nocut"), for: .normal)
- changeSizeButton.setImage(UIImage(named: "icon_mediaPicker_preview_cut"), for: .selected)
- changeSizeButton.backgroundColor = .clear
- return changeSizeButton
- }()
-
- override public init(frame: CGRect) {
- super.init(frame: frame)
- backgroundColor = .black
- clipsToBounds = true
- addSubview(_scrollview)
-
- _changeSizeButton.addTarget(self, action: #selector(_didClick(changeSizeButton:)), for: .touchUpInside)
- addSubview(_changeSizeButton)
-
- addSubview(_videoView)
- }
-
- override open func layoutSubviews() {
- super.layoutSubviews()
- let bounds = self.bounds
- _videoView.frame = bounds
-
- let windowSize = bounds.size
- let windowWidth = windowSize.width
- let windowHeight = windowSize.height
-
- let scrollviewSize = _scrollview.frame.size
- var viewW = scrollviewSize.width
- var viewH = scrollviewSize.height
- var viewX = (windowWidth-viewW)*0.5
- var viewY = (windowHeight-viewH)*0.5
- _scrollview.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
-
- viewW = 30.0
- viewH = viewW
- viewX = CGFloat(10.0)
- viewY = windowHeight-viewH-10.0
- _changeSizeButton.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
- // _changeSizeButton.layer.cornerRadius = viewH*0.5
- }
-
- @objc private func _didClick(changeSizeButton: UIButton) {
- let isChangedSize = changeSizeButton.isSelected
- changeSizeButton.isSelected = !isChangedSize
- let frame: CGRect
- if isChangedSize {
- frame = bounds
- } else {
- let windowSize = bounds.size
- let windowWidth = windowSize.width
- let windowHeight = windowSize.height
-
- let viewW = _minScrollViewSize.width
- let viewH = _minScrollViewSize.height
- let viewX = (windowWidth-viewW)*0.5
- let viewY = (windowHeight-viewH)*0.5
- frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
- }
- UIView.animate(withDuration: 0.2, delay: 0.0, usingSpringWithDamping: 1.0, initialSpringVelocity: 1.0, options: .layoutSubviews, animations: {[weak self] in
- self?._scrollview.set(frame: frame, isNeedLayoutSubviews: true)
- }, completion: nil)
- }
-
- static private let _minScale = CGFloat(3.0/4.0)
-
- private var _minScrollViewSize = CGSize.zero
- private var _normalScrollViewSize = CGSize.zero
-
- var _asset : TLPHAsset? {
- didSet {
- guard let asset = _asset else {
- return
- }
- if asset.type == .video {
- _videoView.isHidden = false
- _scrollview.isHidden = true
- _changeSizeButton.isHidden = true
- _ = _photoLibrary.videoAsset(asset: asset.phAsset!, size: CGSize(width: kScreenWidth, height: kScreenWidth), progressBlock: { (double, error, unsafeMutablePointer, dict) in
-
- }) { [weak self] (avPlayerItem, dict) in
- guard let videoView = self?._videoView else {
- return
- }
- if Thread.current.isMainThread {
- videoView.playerItem = avPlayerItem
- videoView.play()
- } else {
- DispatchQueue.main.async {
- videoView.playerItem = avPlayerItem
- videoView.play()
- }
- }
- }
- }else if asset.type == .photo || asset.type == .livePhoto {
- let mainSize = UIScreen.main.bounds.size
- _videoView.isHidden = true
- if _videoView.isPlaying {
- _videoView.pause()
- }
- _scrollview.isHidden = false
- let pixelWidth = asset.phAsset?.pixelWidth
- let pixelHeight = asset.phAsset?.pixelHeight
-
- _scrollview._imageSize = CGSize(width: pixelWidth ?? 0, height: pixelHeight ?? 0)
-
- let windowWidth = mainSize.width
- if _isStandard {
- _normalScrollViewSize = CGSize(width: windowWidth, height: windowWidth)
- if pixelWidth == pixelHeight {
- _changeSizeButton.isHidden = true
- _minScrollViewSize = _normalScrollViewSize
- } else {
- _changeSizeButton.isHidden = false
- let maxWidth = max(pixelHeight ?? 0, pixelWidth ?? 0)
- let minScale = TLPhontoPreviewView._minScale
- let floatWidth = CGFloat(pixelWidth ?? 0)
- let floatHeight = CGFloat(pixelHeight ?? 0)
- let scrollViewSize: CGSize
- if maxWidth == pixelWidth {//横向
- let scale = floatHeight/floatWidth
- let minHeight: CGFloat
- let minWidth = windowWidth
- if scale > minScale {
- minHeight = floor(floatHeight*minWidth/floatWidth)
- } else {
- minHeight = floor(minWidth*minScale)
- }
- scrollViewSize = CGSize(width: minWidth, height: minHeight)
- } else {//纵向
- let scale = floatWidth/floatHeight
- let minWidth: CGFloat
- let minHeight = windowWidth
- if scale > minScale {
- minWidth = floor(floatWidth*minHeight/floatHeight)
- } else {
- minWidth = floor(minHeight*minScale)
- }
- scrollViewSize = CGSize(width: minWidth, height: minHeight)
- }
- _minScrollViewSize = scrollViewSize
- }
- } else {
- _changeSizeButton.isHidden = true
- }
- _scrollview.set(frame: CGRect(origin: .zero, size: _changeSizeButton.isSelected ? _minScrollViewSize : _normalScrollViewSize), isNeedLayoutSubviews: true)
- setNeedsLayout()
- self._scrollview.imageView.image = asset.fullResolutionImage
- }
- }
- }
-
- private var _isStandard = true
-
- open var isStandard: Bool {
- return _isStandard
- }
-
- public func videoPlay() {
- if !_videoView.isHidden {
- _videoView.play()
- }
- }
- public func videoPause() {
- if !_videoView.isHidden || _videoView.isPlaying {
- _videoView.pause()
- }
- }
- }
|