美文网首页
Swift collectionview实现移动、拖拽

Swift collectionview实现移动、拖拽

作者: 艾欧尼亚 | 来源:发表于2020-06-19 18:20 被阅读0次

import UIKit
import MBProgressHUD

private let SCREEN_WIDTH = UIScreen.main.bounds.width
private let SCREEN_HEIGHT = UIScreen.main.bounds.height

private let ChannelViewCellIdentifier = "ChannelViewCellIdentifier"
private let ChannelViewHeaderIdentifier = "ChannelViewHeaderIdentifier"

let itemW: CGFloat = floor((SCREEN_WIDTH - 60) / 3)

class ChannelViewController: UIViewController {

    var switchoverCallback: ((_ selectedArr: [LeaderboardClassify], _ recommendArr: [LeaderboardClassify], _ index: Int) -> ())?
    var updateClassifyCallback: ((_ selectedArr: [LeaderboardClassify], _ recommendArr: [LeaderboardClassify], _ index: Int) -> Void)?
    var headerArr = [["我的频道","点击添加频道"],["我的频道","点击添加频道"]]
    let descArr = "拖拽可以排序"
    var selectedArr : [LeaderboardClassify] = []
    var recommendArr: [LeaderboardClassify] = []
    var isEdite = false
    
    var indexPath: IndexPath?
    var targetIndexPath: IndexPath?
    var defualtSelectTag: Int = 0
    
    var defaultArr : [LeaderboardClassify] = []
    var currentModel: LeaderboardClassify?
    
    init(a:[LeaderboardClassify], b:[LeaderboardClassify]) {
        selectedArr = a
        recommendArr = b
        super.init(nibName: nil, bundle: nil)
        
        
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    //MARK: - 懒加载collectionView
    private lazy var collectionView: UICollectionView = {
        
        
        let clv = UICollectionView(frame: .zero, collectionViewLayout: ChannelViewLayout())
        clv.backgroundColor = UIColor.white
        clv.delegate = self
        clv.dataSource = self
        clv.register(ChannelViewCell.self, forCellWithReuseIdentifier: ChannelViewCellIdentifier)
        clv.register(ChannelHeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: ChannelViewHeaderIdentifier)
        let longPress = UILongPressGestureRecognizer(target: self, action: #selector(longPressGesture(_:)))
        clv.addGestureRecognizer(longPress)
        
        return clv
    }()
    
    private lazy var dragingItem: ChannelViewCell = {
        let cell = ChannelViewCell(frame: CGRect(x: 0, y: 0, width: itemW, height: 30))
        cell.isHidden = true
        return cell
    }()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        navigationItem.title = "频道管理"
        view.addSubview(collectionView)
        collectionView.addSubview(dragingItem)
        collectionView.snp.makeConstraints { (make) in
            make.edges.equalToSuperview()
        }
    }
    
    func reloadSelectData(a:[LeaderboardClassify], b:[LeaderboardClassify],defaultIndex: Int) {
        selectedArr = a
        recommendArr = b
        self.defualtSelectTag = defaultIndex
        self.currentModel = a[defaultIndex]
        self.defaultArr = a
        self.collectionView.reloadData()
        self.collectionView.contentOffset = CGPoint(x: 0, y: 0)
    }
    
    //MARK: - 长按动作
    @objc func longPressGesture(_ tap: UILongPressGestureRecognizer) {
        
        if !isEdite {
            
            isEdite = !isEdite
            collectionView.reloadData()
            return
        }
        let point = tap.location(in: collectionView)
        
        switch tap.state {
            case UIGestureRecognizerState.began:
                dragBegan(point: point)
            case UIGestureRecognizerState.changed:
                drageChanged(point: point)
            case UIGestureRecognizerState.ended:
                drageEnded(point: point)
            case UIGestureRecognizerState.cancelled:
                drageEnded(point: point)
            default: break
            
        }
        
    }

    //MARK: - 长按开始
    private func dragBegan(point: CGPoint) {
        
        indexPath = collectionView.indexPathForItem(at: point)
        if indexPath == nil || (indexPath?.section)! > 0 || indexPath?.item == 0 || indexPath?.item == 1 || indexPath?.item == 2
        {
            return
        }
        
        let item = collectionView.cellForItem(at: indexPath!) as? ChannelViewCell
        item?.isHidden = true
        dragingItem.isHidden = false
        dragingItem.frame = (item?.frame)!
        dragingItem.text = item!.text
        dragingItem.transform = CGAffineTransform(scaleX: 1.1, y: 1.1)
    }
    //MARK: - 长按过程
    private func drageChanged(point: CGPoint) {
        if indexPath == nil || (indexPath?.section)! > 0 || indexPath?.item == 0 || indexPath?.item == 1 || indexPath?.item == 2
        {
            return
        }
        dragingItem.center = point
        targetIndexPath = collectionView.indexPathForItem(at: point)
        if targetIndexPath == nil || (targetIndexPath?.section)! > 0 || indexPath == targetIndexPath || targetIndexPath?.item == 0 || targetIndexPath?.item == 1 || targetIndexPath?.item == 2 {return}
        // 更新数据
        let obj = selectedArr[indexPath!.item]
        selectedArr.remove(at: indexPath!.row)
        selectedArr.insert(obj, at: targetIndexPath!.item)
        //交换位置
        collectionView.moveItem(at: indexPath!, to: targetIndexPath!)
        indexPath = targetIndexPath
    }
    
    //MARK: - 长按结束
    private func drageEnded(point: CGPoint) {
        
        if indexPath == nil || (indexPath?.section)! > 0 || indexPath?.item == 0 || indexPath?.item == 1 || indexPath?.item == 2
        {
            return
        }
        let endCell = collectionView.cellForItem(at: indexPath!)
        
        UIView.animate(withDuration: 0.25, animations: {
        
            self.dragingItem.transform = CGAffineTransform.identity
            self.dragingItem.center = (endCell?.center)!
            
        }, completion: {
        
            (finish) -> () in
            
            endCell?.isHidden = false
            self.dragingItem.isHidden = true
            self.indexPath = nil
            
        })
        
    }
    



}

//MARK: - UICollectionViewDelegate 方法
extension ChannelViewController: UICollectionViewDelegate, UICollectionViewDataSource {
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return section == 0 ? selectedArr.count : recommendArr.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ChannelViewCellIdentifier, for: indexPath) as! ChannelViewCell
        
        cell.text = indexPath.section == 0 ? selectedArr[indexPath.item].title : recommendArr[indexPath.item].title
        if indexPath.section == 0 {
            cell.isAdd = false
            if selectedArr[indexPath.item].title == "推荐" || selectedArr[indexPath.item].title == "附近" || selectedArr[indexPath.item].title == "电商" {
                cell.edite = false
            }else{
                cell.edite = isEdite
            }
            if indexPath.item == self.defualtSelectTag {
                cell.isselected = true
            }else{
                cell.isselected = false
            }
        }else{
            cell.edite = true
            cell.isAdd = true
            cell.isselected = false
        }
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
                
        if indexPath.section > 0 {
            
            // 更新数据
            let obj = recommendArr[indexPath.item]
            recommendArr.remove(at: indexPath.item)
            selectedArr.append(obj)
            collectionView.moveItem(at: indexPath, to: NSIndexPath(item: selectedArr.count - 1, section: 0) as IndexPath)
            if let cell = collectionView.cellForItem(at: NSIndexPath(item: selectedArr.count - 1, section: 0) as IndexPath) as? ChannelViewCell {
                cell.isAdd = false
            }
            // 更改编辑状态
            if self.isEdite != true {
                self.isEdite = true
                UIView.performWithoutAnimation {
                    self.collectionView.reloadSections(IndexSet.init(integer: 0))
                    
                }
            }
        } else {
            if isEdite {
                if selectedArr[indexPath.item].title == "推荐" || selectedArr[indexPath.item].title == "附近" || selectedArr[indexPath.item].title == "电商" {
                    return
                }
                // 更新数据
                let obj = selectedArr[indexPath.item]
                selectedArr.remove(at: indexPath.item)
                recommendArr.insert(obj, at: 0)
                
                collectionView.moveItem(at: indexPath, to: NSIndexPath(item: 0, section: 1) as IndexPath)
                if let cell = collectionView.cellForItem(at: NSIndexPath(item: 0, section: 1) as IndexPath) as? ChannelViewCell {
                    cell.isAdd = true
                }
            } else {
                if switchoverCallback != nil {
                    switchoverCallback!(selectedArr, recommendArr, indexPath.item)
                    _ = navigationController?.popViewController(animated: true)
                }
            }
        }
    }
    
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        
        let header = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: ChannelViewHeaderIdentifier, for: indexPath) as! ChannelHeaderView
        header.text = isEdite ? headerArr[1][indexPath.section] : headerArr[0][indexPath.section]
        header.descText = indexPath.section == 0 ? descArr : ""
        header.button.isSelected = isEdite
        if indexPath.section > 0 {header.button.isHidden = true} else {header.button.isHidden = false}
        
        header.clickCallback = {[weak self] in
            guard let `self` = self else { return }
            guard header.button.isSelected else {
                self.isEdite = !(self.isEdite)
                self.collectionView.reloadData()
                return
            }
            
            guard !self.judgeDataChange() else {
                self.isEdite = !(self.isEdite)
                self.collectionView.reloadData()
                return
            }
            
            let selectArr = self.selectedArr.map({ (model) -> String in
                return model.title ?? ""
            })
            var currentIndex : Int = 1
            if let current = self.currentModel,self.selectedArr.contains(current){
                _ = self.selectedArr.enumerated().map { (index,model) in
                    if model == current {
                        currentIndex = index
                        self.defualtSelectTag = index
                    }
                }
            }else{
                currentIndex = 1
                self.defualtSelectTag = 1
            }
            let arrStr = selectArr.joined(separator: ",")
            self.updateNetWorking(names:arrStr , completion: { (finish) in
                if finish {
                    self.updateClassifyCallback?(self.selectedArr ,self.recommendArr, currentIndex)
                    self.isEdite = !(self.isEdite)
                    self.collectionView.reloadData()
                }
            })
        }
        return header
        
    }
    
    func updateNetWorking(names: String, completion:@escaping ((Bool) -> Void)) {
        let session = NetworkingSession<HomePageApi>()
        session.request(.updateHomeClassify(classifyNames: names), model: NormalModel.self, success: { (response) in
            if response.isSuccess {
                completion(true)
            }else{
                MBProgressHUD.xy_show(response.msg ?? "更新失败")
                completion(false)
            }
        }) { (error) in
            completion(false)
            MBProgressHUD.xy_show("更新失败")
        }
    }
    
    func judgeDataChange() -> Bool {
        if self.defaultArr.count == self.selectedArr.count {
            return self.defaultArr == self.selectedArr
        }else{
            return false
        }
    }
}


//MARK: - 自定义cell
class ChannelViewCell: UICollectionViewCell {
    
    var edite = true {
        didSet {
            
            imageView.isHidden = !edite
        }
    }
    
    var isAdd : Bool? {
        didSet {
            if self.isAdd == true {
                imageView.image = UIImage(named: "icon_home_add")
            }else{
                imageView.image = UIImage(named: "icon_home_close")
            }
        }
    }
    
    var isselected: Bool? {
        didSet {
            if self.isselected == true {
                contentView.layer.cornerRadius = 3
                contentView.layer.borderWidth = 1
                contentView.layer.borderColor = UIColor(hexString: "#ff314a")?.cgColor
                contentView.backgroundColor = UIColor(hexString: "#fef8f8")
                self.label.textColor = UIColor(hexString: "#ff314a")
            }else{
                contentView.layer.cornerRadius = 3
                contentView.layer.borderWidth = 1
                contentView.layer.borderColor = UIColor(hexString: "#dddddd")?.cgColor
                contentView.backgroundColor = .white
                if label.text == "推荐" || label.text == "附近" || label.text == "电商" {
                    label.textColor = UIColor(hexString: "#8a8a8a")
                }else{
                    label.textColor = UIColor(hexString: "#343434")
                }

            }
        }
    }
    
    var text: String? {
        didSet {
            label.text = text
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupUI()
    }
    
    private func setupUI() {
        
        contentView.addSubview(label)
        contentView.addSubview(imageView)
        contentView.layer.cornerRadius = 3
        contentView.layer.borderWidth = 1
        contentView.layer.borderColor = UIColor(hexString: "#dddddd")?.cgColor
        contentView.backgroundColor = .white
        
        imageView.snp.makeConstraints { (make) in
            make.size.equalTo(CGSize(width: 10, height: 10))
            make.top.equalToSuperview().offset(6)
            make.right.equalToSuperview().offset(-6)
        }
    }
    
    lazy var label: UILabel = {
        
        let label = UILabel(frame: self.bounds)
        label.textAlignment = NSTextAlignment.center
        label.font = UIFont.rt.font(size: 12)
        label.textColor = UIColor(hexString: "#343434")
        return label
    }()

    private lazy var imageView: UIImageView = {
       
        let image = UIImageView(frame: .zero)
        image.image = UIImage(named: "close")
        image.isHidden = true
        return image
        
    }()
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}
//MARK: - 自定义头视图
class ChannelHeaderView: UICollectionReusableView {
    
    var clickCallback: (() -> ())?
    
    var text: String? {
        didSet {
            label.text = text
        }
    }
    
    var descText: String? {
        didSet {
            descLab.text = descText
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        
        setupUI()
    }
    
    private func setupUI() {
        
        addSubview(label)
        addSubview(button)
        addSubview(descLab)
        backgroundColor = .white
        
        label.snp.makeConstraints { (make) in
            make.centerY.equalToSuperview()
            make.left.equalToSuperview().offset(20)
            make.height.equalTo(20)
        }
        
        descLab.snp.makeConstraints { (make) in
            make.centerY.equalToSuperview()
            make.left.equalTo(label.snp.right).offset(20)
            make.height.equalTo(20)
        }
    }
    
    @objc func buttonClick() {
        if (clickCallback != nil) { clickCallback!() }
    }
    
    
    private lazy var label: UILabel = {
        
        let label = UILabel(frame: .zero)
        label.font = UIFont.rt.font(size: 16)
        return label
    }()
    
    private lazy var descLab: UILabel = {
        
        let label = UILabel(frame: .zero)
        label.font = UIFont.rt.font(size: 14)
        label.textColor = UIColor(hexString: "#8a8a8a")
        return label
    }()
    
    lazy var button: UIButton = {
        
        let btn = UIButton(type: UIButton.ButtonType.custom)
        btn.setTitle("编辑", for: .normal)
        btn.setTitle("完成", for: .selected)
        btn.setTitleColor(UIColor.blue, for: .normal)
        btn.titleLabel?.font = UIFont.rt.font(size: 14)
        btn.setTitleColor(UIColor(hexString: "#ff314a"), for: .normal)
        btn.frame = CGRect(x: SCREEN_WIDTH - 80, y: 0, width: 80, height: self.frame.height)
        btn.addTarget(self, action: #selector(buttonClick), for: .touchUpInside)
        return btn
        
    }()

    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
}
//MARK: - 自定义布局属性
class ChannelViewLayout: UICollectionViewFlowLayout {
    
    override func prepare() {
        super.prepare()
        
        headerReferenceSize = CGSize(width: SCREEN_WIDTH, height: 40)
        itemSize = CGSize(width: itemW, height: 30)
        minimumLineSpacing = 15
        minimumInteritemSpacing = 10
        sectionInset = UIEdgeInsets(top: 10, left: 20, bottom: 10, right: 20)
        
    }
    
}

相关文章

网友评论

      本文标题:Swift collectionview实现移动、拖拽

      本文链接:https://www.haomeiwen.com/subject/skjbxktx.html