swift 类微信朋友圈九宫格拖拽图
2020-03-11 本文已影响0人
单抽律化娜
import UIKit
class MomentsViewController: UIViewController {
private var vMoments: MomentsView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = .white
vMoments = MomentsView()
// vMoments.rowCount = 4
// vMoments.maxCount = 7
view.addSubview(vMoments)
vMoments.snp.makeConstraints { (make) in
make.left.equalTo(20)
make.top.equalTo(100)
make.right.equalTo(-20)
make.height.equalTo(100)
}
/// 更新高度
vMoments.heightBlock = { [weak self] height in
self?.vMoments.snp.updateConstraints { (make) in
make.height.equalTo(height)
}
}
/// 点击按钮
vMoments.btnPostBlock = { [weak self] in
self?.uploadImage()
}
/// 添加长按操作
let gesture = UILongPressGestureRecognizer(target: self, action: #selector(longPress(_ :)))
gesture.minimumPressDuration = 0.5
view.addGestureRecognizer(gesture)
/// 添加删除区域
let vDeleteArea = MomentsDeleteView()
vDeleteArea.isDelete = false
view.addSubview(vDeleteArea)
vDeleteArea.snp.makeConstraints { (make) in
make.left.right.bottom.equalToSuperview()
make.height.equalTo(60)
}
vDeleteArea.hideView()
vMoments.vDeleteArea = vDeleteArea
}
/// 添加拖动手势
@objc private func longPress(_ gesture: UILongPressGestureRecognizer) {
vMoments.longPress(gesture)
}
func uploadImage() {
vMoments.arrData.append(UIImage(named: "fengjingtu\(getRandom(1, 4))")!)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
class MomentsView: UIView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
/// collectionView
private lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = itemSpace
layout.minimumInteritemSpacing = itemSpace
let collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = .clear
collectionView.register(MomentsViewCell.self, forCellWithReuseIdentifier: "MomentsViewCell")
addSubview(collectionView)
return collectionView
}()
/// 上传按钮
private lazy var btnPost: MomentsPostButton = {
$0.addTarget(self, action: #selector(btnPostClick(_:)), for: .touchUpInside)
$0.isHidden = true
addSubview($0)
return $0
}(MomentsPostButton())
/// 长按拖拽元素
private lazy var dragingItem: UIImageView = {
$0.contentMode = .scaleAspectFill
$0.layer.masksToBounds = true
superview?.insertSubview($0, aboveSubview: self)
return $0
}(UIImageView())
/// 拖拽位置
private var indexPath: IndexPath?
/// 宽高
private var itemLength: CGFloat = 0 {
willSet {
btnPost.snp.updateConstraints { (make) in
make.size.equalTo(CGSize(width: newValue, height: newValue))
}
}
didSet {
numberOfLines = 0
}
}
/// 行数
private var numberOfLines: Int = -1 {
willSet {
heightBlock?(itemLength + CGFloat(newValue) * (itemLength + itemSpace))
}
}
/// 是否能删除
private var canDelete: Bool = false
/// 最大个数
var maxCount: Int = 9
/// 一行个数
var rowCount: Int = 3
/// 间隔
var itemSpace: CGFloat = 10
/// 高度变化
var heightBlock: ((CGFloat)->Void)?
/// 按钮回调
var btnPostBlock: (()->Void)?
/// 删除区域
weak var vDeleteArea: MomentsDeleteView?
/// 数据
var arrData: [UIImage] = [] {
didSet {
collectionView.reloadData()
}
}
/// 初始化
override init(frame: CGRect) {
super.init(frame: frame)
btnPost.snp.makeConstraints { (make) in
make.left.top.equalTo(0)
make.size.equalTo(CGSize.zero)
}
collectionView.snp.makeConstraints { (make) in
make.left.top.right.bottom.equalToSuperview()
}
}
/// 上传按钮点击回调
@objc private func btnPostClick(_ sender: UIButton) {
btnPostBlock?()
}
/// cell个数
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
let count = arrData.count
if (count > 0 && count < maxCount) {
let lines = count / rowCount
if (lines != numberOfLines) {
numberOfLines = lines
}
}
return min(count + 1, maxCount)
}
/// cell样式
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "MomentsViewCell", for: indexPath) as! MomentsViewCell
cell.imageView.image = indexPath.row < arrData.count ? arrData[indexPath.row] : nil
return cell
}
/// cell将要展示
func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
if indexPath.row == arrData.count && indexPath.row < maxCount {
let pos = convert(cell.frame.origin, from: collectionView)
btnPost.snp.updateConstraints { (make) in
make.top.equalTo(pos.y)
make.left.equalTo(pos.x)
}
}
btnPost.isHidden = arrData.count + 1 > maxCount
}
/// cell宽高
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
if (itemLength == 0) {
itemLength = (collectionView.frame.width - itemSpace * CGFloat(rowCount - 1)) / CGFloat(rowCount)
}
return CGSize(width: itemLength, height: itemLength)
}
/// 长按事件
public func longPress(_ gesture: UILongPressGestureRecognizer) {
guard let target = gesture.view, isUserInteractionEnabled else {
return
}
switch gesture.state {
case .began:
beginInteractiveMovement(target, position: gesture.location(in: target))
case .changed:
updateInteractiveMovement(target, position: gesture.location(in: target))
case .ended:
endInteractiveMovement(target)
case .cancelled:
endInteractiveMovement(target)
default:
break
}
}
/// 长按开始
private func beginInteractiveMovement(_ target: UIView, position: CGPoint) {
guard let indexPath = collectionView.indexPathForItem(at: target.convert(position, to: collectionView)), indexPath.row < arrData.count else {
return
}
let cell: MomentsViewCell = collectionView.cellForItem(at: indexPath) as! MomentsViewCell
cell.isHidden = true
dragingItem.frame = CGRect(origin: collectionView.convert(cell.frame.origin, to: target), size: cell.frame.size)
dragingItem.image = cell.imageView.image
dragingItem.isHidden = false
UIView.animate(withDuration: 0.1, animations: {
self.dragingItem.center = position
self.dragingItem.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
self.vDeleteArea?.showView()
}) { (finished) in
self.indexPath = indexPath
}
}
/// 长按过程
private func updateInteractiveMovement(_ target: UIView, position: CGPoint) {
guard let indexPath = indexPath else {
return
}
dragingItem.center = position
if let vDeleteArea = vDeleteArea {
if vDeleteArea.frame.contains(position) {
canDelete = true
vDeleteArea.isDelete = true
} else {
canDelete = false
vDeleteArea.isDelete = false
}
}
guard let targetIndexPath = collectionView.indexPathForItem(at: target.convert(position, to: collectionView)), targetIndexPath.row < arrData.count else {
return
}
/// 交换位置
collectionView.moveItem(at: indexPath, to: targetIndexPath)
let obj = arrData[indexPath.row]
arrData.remove(at: indexPath.row)
arrData.insert(obj, at: targetIndexPath.row)
self.indexPath = targetIndexPath
}
/// 长按结束
private func endInteractiveMovement(_ target: UIView) {
guard let indexPath = indexPath, let cell = collectionView.cellForItem(at: indexPath) else {
return
}
isUserInteractionEnabled = false
if (canDelete) {
UIView.animate(withDuration: 0.1, animations: {
self.vDeleteArea?.hideView()
}, completion: { (finished) in
self.arrData.remove(at: indexPath.row)
self.collectionView.reloadData()
cell.isHidden = false
self.dragingItem.isHidden = true
self.indexPath = nil
self.vDeleteArea?.isDelete = false
self.isUserInteractionEnabled = true
})
} else {
let center = target.convert(cell.center, from: collectionView)
UIView.animate(withDuration: 0.25, animations: {
self.dragingItem.transform = .identity
self.dragingItem.center = center
self.vDeleteArea?.hideView()
}, completion: { (finished) in
cell.isHidden = false
self.dragingItem.isHidden = true
self.indexPath = nil
self.vDeleteArea?.isDelete = false
self.isUserInteractionEnabled = true
})
}
}
/// 判断是不是按钮点击
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
if !btnPost.isHidden && (collectionView.convert(btnPost.frame, from: self).contains(point)) {
return btnPost
}
return super.hitTest(point, with: event)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class MomentsViewCell: UICollectionViewCell {
var imageView: UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.layer.masksToBounds = true
addSubview(imageView)
imageView.snp.makeConstraints { (make) in
make.left.right.top.bottom.equalToSuperview()
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
/// 上传按钮
class MomentsPostButton: UIButton {
override init(frame: CGRect) {
super.init(frame: frame)
let borderWidth: CGFloat = 2
let borderColor: UIColor = .gray
backgroundColor = UIColor.groupTableViewBackground
/// 横
let vHorizontal = UIView()
vHorizontal.backgroundColor = borderColor
addSubview(vHorizontal)
vHorizontal.snp.makeConstraints { (make) in
make.center.equalToSuperview()
make.width.equalToSuperview().multipliedBy(0.25)
make.height.equalTo(borderWidth)
}
/// 竖
let vVertical = UIView()
vVertical.backgroundColor = borderColor
addSubview(vVertical)
vVertical.snp.makeConstraints { (make) in
make.width.equalTo(borderWidth)
make.center.equalToSuperview()
make.height.equalToSuperview().multipliedBy(0.25)
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class MomentsDeleteView: UILabel {
let normalText = "拖到此处删除"
let normalColor = UIColor(hex: "ff0033").withAlphaComponent(0.9)
let deleteText = "松手即可删除"
let deleteColor = UIColor(hex: "cc0000").withAlphaComponent(0.9)
var isDelete: Bool = false {
didSet {
if isDelete {
text = deleteText
backgroundColor = deleteColor
} else {
text = normalText
backgroundColor = normalColor
}
}
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = normalColor
text = normalText
textColor = .white
font = UIFont.systemFont(ofSize: 14)
textAlignment = .center
}
func showView() {
transform = .identity
}
func hideView() {
transform = CGAffineTransform(translationX: 0, y: 60)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}