123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300 |
- //
- // KSMediaPickerView.swift
- //
- //
- // Created by kinsun on 2019/3/1.
- //
- import UIKit
- open class KSMediaPickerView: UIView {
-
- required public init?(coder aDecoder: NSCoder) {
- fatalError("init(coder:) has not been implemented")
- }
-
- public let albumNavigationView = KSMediaPickerView.navigationView()
-
- var jumpType: KSMediaPickerController.jumpType?
-
- public let collectionView = {() -> KSMediaPickerCollectionView in
- let layout = UICollectionViewFlowLayout()
- layout.scrollDirection = .vertical
-
- let collectionView = KSMediaPickerCollectionView(frame: .zero, collectionViewLayout: layout)
- collectionView.backgroundColor = .clear
- collectionView.alwaysBounceVertical = true
- collectionView.clipsToBounds = true
- collectionView.bounces = false
- if #available(iOS 11.0, *) {
- collectionView.contentInsetAdjustmentBehavior = .never
- }
- return collectionView
- }()
-
- public let previewView = KSMediaPickerPreviewView()
-
- private let _toolBarSafeAreaView = {() -> UIView in
- let toolBarSafeAreaView = UIView()
- toolBarSafeAreaView.backgroundColor = .clear
- return toolBarSafeAreaView
- }()
-
- private let _blackBackgroundLayer = {() -> CALayer in
- let blackBackgroundLayer = CALayer()
- blackBackgroundLayer.opacity = 0.0
- blackBackgroundLayer.backgroundColor = UIColor.ks_black.cgColor
- return blackBackgroundLayer
- }()
-
- override public init(frame: CGRect) {
- super.init(frame: frame)
- backgroundColor = .ks_white
- layer.addSublayer(_blackBackgroundLayer)
-
- addSubview(collectionView)
- addSubview(previewView)
- albumNavigationView.nextButton.isEnabled = false
- addSubview(albumNavigationView)
-
- collectionView.handlePanCallback = {[weak self] (pan) in
- self?._collectionView(did: pan)
- }
- collectionView.scrollViewDidScrollCallback = {[weak self] (scrollView) in
- self?._collectionViewDidScroll(scrollView)
- }
- collectionView.scrollViewDidEndDraggingCallback = {[weak self] (scrollView, decelerate) in
- self?._collectionViewDidEndDragging(scrollView, decelerate: decelerate)
- }
- }
-
- override open func layoutSublayers(of layer: CALayer) {
- super.layoutSublayers(of: layer)
- _blackBackgroundLayer.frame = layer.bounds
- }
-
- override open func layoutSubviews() {
- super.layoutSubviews()
- let bounds = self.bounds
- let safeArea = UIEdgeInsets.safeAreaInsets
-
- let windowSize = bounds.size
- let windowWidth = windowSize.width
- let windowHeight = windowSize.height
- let floatZore = CGFloat(0.0)
- let safeBottomMargin = safeArea.bottom
-
- var viewW = windowWidth
- var viewH = safeBottomMargin+48.0
- var viewX = floatZore
- var viewY = windowHeight-viewH
- _toolBarSafeAreaView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
-
- let margin = CGFloat(3.0)
- let columnCount = UInt(4)
- let itemW = floor((windowWidth-margin*CGFloat(columnCount-1))/CGFloat(columnCount))
- let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
- layout.itemSize = CGSize(width: itemW, height: itemW)
- layout.minimumLineSpacing = margin
- layout.minimumInteritemSpacing = margin
- layout.sectionInset = .zero
-
- viewX = floatZore
- viewY = floatZore
- viewW = windowWidth
- viewH = UIView.statusBarNavigationBarSize.height
- albumNavigationView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
-
- let navHeight = albumNavigationView.frame.maxY
- let baseY = previewView.frame.origin.y
- viewX = floatZore
- if baseY == 0 {
- viewY = navHeight
- _baseY = viewY
- } else {
- viewY = baseY
- }
- viewW = windowWidth
- viewH = viewW
- previewView.frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
-
- let previewViewFrameMaxY = previewView.frame.maxY
- viewY = floatZore
- viewH = previewViewFrameMaxY+20.0
- _previewGestureCorrespondingArea = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
-
- let toolBarSafeAreaViewHeight = _toolBarSafeAreaView.bounds.size.height
-
- viewX = floatZore
- viewY = floatZore
- viewW = windowWidth
- viewH = windowHeight-toolBarSafeAreaViewHeight
-
- if jumpType == .publishEdit {
- let frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH + kTabBarTotalHeight)
- collectionView.frame = frame
- }else {
- let frame = CGRect(x: viewX, y: viewY, width: viewW, height: viewH)
- collectionView.frame = frame
- }
-
- let conetntInset = UIEdgeInsets(top: previewViewFrameMaxY+3.0, left: 0.0, bottom: 0.0, right: 0.0)
- collectionView.contentInset = conetntInset
- collectionView.scrollIndicatorInsets = conetntInset
-
- }
-
- private var _baseY: CGFloat?
- private var _previewGestureCorrespondingArea: CGRect?
- private var _isInGestureCorrespondingArea = false
-
- private var _panBeginLocationY = CGFloat(0)
- private var _isScrollDown = false
- private var _isRetract = false {
- didSet {
- if albumNavigationView.isHidden != _isRetract {
- let trans = CATransition()
- trans.duration = 0.2
- trans.type = .push
- trans.subtype = _isRetract ? .fromTop : .fromBottom
- albumNavigationView.isHidden = _isRetract
- albumNavigationView.layer.add(trans, forKey: nil)
- }
- }
- }
-
- private func _collectionView(did pan: UIPanGestureRecognizer) {
- switch pan.state {
- case .began:
- _panBeginLocationY = pan.location(in: self).y
- break
- case .changed:
- // FIXME: preview视图收起展示逻辑
- // guard let baseY = _baseY else {
- // return
- // }
- // let location = pan.location(in: self)
- // let locationY = location.y
- // _isScrollDown = locationY > _panBeginLocationY
- // _isInGestureCorrespondingArea = _previewGestureCorrespondingArea != nil && _previewGestureCorrespondingArea!.contains(location)
- // if _isInGestureCorrespondingArea {
- // var previewFrame = previewView.frame
- // var y = locationY-previewFrame.size.height
- // if y >= baseY {
- // y = baseY
- // }
- // previewFrame.origin.y = y
- // previewView.frame = previewFrame
- //
- // _previewGestureCorrespondingArea!.size.height = previewFrame.maxY+20.0
- // }
- // _panBeginLocationY = locationY
- break
- case .cancelled, .ended, .failed:
- guard _isInGestureCorrespondingArea, let baseY = _baseY else {
- return
- }
- var previewFrame = previewView.frame
- let maxY = previewFrame.maxY
- let boundary = (previewFrame.size.height+baseY)*(_isScrollDown ? 0.2 : 0.8)
- if maxY < boundary {
- _isRetract = true
- previewFrame.origin.y = baseY-previewFrame.size.height
- } else {
- _isRetract = false
- previewFrame.origin.y = baseY
- }
-
- let height = previewFrame.maxY
- _previewGestureCorrespondingArea!.size.height = height+20.0
-
- var topPoint: CGPoint? = nil
- let offsetY = -collectionView.contentOffset.y
- if offsetY > height {
- topPoint = CGPoint(x: 0.0, y: -(height+3.0))
- }
- UIView.animate(withDuration: 0.2, animations: {[weak self, weak previewView] in
- previewView?.frame = previewFrame
- guard let k_topPoint = topPoint else {
- return
- }
- self?.collectionView.contentOffset = k_topPoint
- })
- break
- default:
- break
- }
- }
-
- private func _collectionViewDidScroll(_ scrollView: KSMediaPickerCollectionView) {
- guard !_isInGestureCorrespondingArea, _isScrollDown, _isRetract, let baseY = _baseY else {
- return
- }
- let offsetY = -(scrollView.contentOffset.y)
- if offsetY >= baseY {
- var previewFrame = previewView.frame
- var y = offsetY-previewFrame.size.height
- if y >= baseY {
- y = baseY
- }
- previewFrame.origin.y = y
- previewView.frame = previewFrame
-
- _previewGestureCorrespondingArea!.size.height = previewFrame.maxY+20.0
- }
- }
-
- private func _collectionViewDidEndDragging(_ scrollView: KSMediaPickerCollectionView, decelerate: Bool) {
- var previewFrame = previewView.frame
- let maxY = previewFrame.maxY
- guard scrollView.contentOffset.y <= -maxY, !_isInGestureCorrespondingArea, let baseY = _baseY else {
- return
- }
- let boundary = (previewFrame.size.height+baseY)*(_isScrollDown ? 0.2 : 0.8)
- if maxY < boundary && !_isRetract {
- _isRetract = true
- previewFrame.origin.y = baseY-previewFrame.size.height
- } else if _isRetract {
- _isRetract = false
- previewFrame.origin.y = baseY
- } else {
- return
- }
-
- let height = previewFrame.maxY
- _previewGestureCorrespondingArea!.size.height = height+20.0
-
- let topPoint = CGPoint(x: 0.0, y: -(height+3.0))
- UIView.animate(withDuration: 0.2, animations: {[weak self, weak previewView] in
- previewView?.frame = previewFrame
- self?.collectionView.contentOffset = topPoint
- })
- }
-
- public func showPreview(_ animated: Bool) {
- var previewFrame = previewView.frame
- previewFrame.origin.y = _baseY ?? 0
- _isRetract = false
- if animated {
- UIView.animate(withDuration: 0.2, animations: {[weak self] in
- self?.previewView.frame = previewFrame
- }) {[weak self] (finish) in
- self?.setNeedsLayout()
- }
- } else {
- setNeedsLayout()
- }
- }
-
- public func collectionViewScrollToTop() {
- let point = CGPoint(x: 0.0, y: -collectionView.contentInset.top)
- if !point.equalTo(collectionView.contentOffset) {
- collectionView.setContentOffset(point, animated: false)
- showPreview(false)
- }
- }
-
- }
|