swift4.0 類似頭條頻道拖拽排序

代碼是完整的可以直接用

import UIKit

class TTDataSourceTool: NSObject {

    static var share = TTDataSourceTool.init()
    fileprivate override init() {}
    
    var selectedArr = ["推薦","河北","財經","娛樂","體育","社會","NBA","視頻","汽車","圖片","科技","軍事","國際","數碼","星座","電影","時尚","文化","遊戲","教育","動漫","政務","紀錄片","房產","佛學","股票","理財"]
    
    var unselectedArr = ["有聲","家居","電競","美容","電視劇","搏擊","健康","攝影","生活","旅遊","韓流","探索","綜藝","美食","育兒"]
 
    var isEdit = false
    
    var snapShotCellView:UIView?
    var originalCell:TTChannelSortCell?
    var startPoint:CGPoint?
    var indexPath:IndexPath?
    var nextIndexPath:IndexPath?
}

extension TTDataSourceTool{
    
    
}
import UIKit

class TTChannelSortCell: UICollectionViewCell {
    
    typealias CellGestureCallBack = (_ gesture:UIGestureRecognizer)->()
    
    var cellGCB:CellGestureCallBack?
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        contentView.addSubview(c_title)
        contentView.addSubview(c_image)
        
        self.addGestureRecognizer(self.longG)
        self.addGestureRecognizer(self.panG)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    var isEdit:Bool = false {
        didSet{
            c_image.isHidden = !isEdit
        }
    }
    
    var titles:String?{
        didSet{
            c_title.text = titles
        }
    }
    
    lazy var c_image:UIImageView = {
        let img = UIImageView.init(frame: CGRect.init(x: 0, y: 0, width: 20, height: 20));
        img.image = UIImage.init(named: "close");
        return img
    }()
    
    lazy var c_title:UILabel = {
        let lb = UILabel.init(frame: self.bounds)
        lb.textColor = UIColor.black
        lb.font = UIFont.systemFont(ofSize: 16)
        lb.layer.borderWidth = 1.0
        lb.layer.borderColor = UIColor.lightGray.cgColor
        lb.layer.cornerRadius = 5;
        lb.textAlignment = .center
        return lb
    }()
    
    
   fileprivate lazy var longG:UILongPressGestureRecognizer = {
        let lp = UILongPressGestureRecognizer.init(target: self, action: #selector(gestureAction(gesture:)))
        lp.delegate = self;
        return lp;
    }()
    
   fileprivate lazy var panG:UIPanGestureRecognizer = {
        let lp = UIPanGestureRecognizer.init(target: self, action: #selector(gestureAction(gesture:)))
        lp.delegate = self;
        return lp;
    }()
    
    
}

extension TTChannelSortCell:UIGestureRecognizerDelegate{
    
    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        
        return true
    }
    

    @objc func gestureAction(gesture:UIGestureRecognizer) {
        guard let _ = self.cellGCB else {return}
        self.cellGCB!(gesture)
    }
    
}

import UIKit

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

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

class TTChannelSortVC: UIViewController {

    var selArr = [String]()
    var unselArr = [String]()
    
    init(selected:[String],unselected:[String]) {
        super.init(nibName: nil, bundle: nil)
        selArr = selected
        unselArr = unselected
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
    }

    func setUI(){
        self.view.addSubview(containView)
    }
    
    lazy var containView:UICollectionView = {
        let v = UICollectionView.init(frame: self.view.bounds, collectionViewLayout: TTContainFlowLayout.init())
        v.delegate = self;
        v.dataSource = self;
        v.backgroundColor = UIColor.white
        v.register(TTChannelSortCell.self, forCellWithReuseIdentifier: ChannelViewCellIdentifier)
        v.register(TTSectionHeadView.self, forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, withReuseIdentifier: ChannelViewHeaderIdentifier)
        return v;
    }()

    var isEdit = false
    
    lazy var dsTool:TTDataSourceTool = {
        let tool = TTDataSourceTool.share;
        return tool;
    }()
}

//MARK:數據源代理
extension TTChannelSortVC:UICollectionViewDataSource{
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return section == 0 ? selArr.count : unselArr.count
    }
    
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 2
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        
        let cell:TTChannelSortCell = collectionView.dequeueReusableCell(withReuseIdentifier: ChannelViewCellIdentifier, for: indexPath) as! TTChannelSortCell
        cell.titles = indexPath.section == 0 ? selArr[indexPath.row] : unselArr[indexPath.row]
        cell.isEdit = isEdit;
        cell.cellGCB = { gesture in
            self.gestureAction(gesture: gesture)
        }
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
        
        let headView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionElementKindSectionHeader, withReuseIdentifier: ChannelViewHeaderIdentifier, for: indexPath) as! TTSectionHeadView
        
        headView.titles = indexPath.section == 0 ? headView.titleArr[0] : headView.titleArr[1]
        headView.callBack = {
            self.isEdit = !self.isEdit
            collectionView.reloadData();
        }
        return headView;
    }
}

//MARK:手勢方法
extension TTChannelSortVC{
    
    ///手勢觸發
    func gestureAction(gesture:UIGestureRecognizer) {
        
        let cell = gesture.view as? TTChannelSortCell
        print("我點擊的",cell?.titles ?? "")
        guard let _ = cell else {return}
        
        let indexPath = containView.indexPath(for: cell!)
        guard indexPath?.section == 0 else {return}

        if gesture.state ==  UIGestureRecognizerState.began{
           
            if gesture.isKind(of: UILongPressGestureRecognizer.self){
                self.isEdit = true
                //修改顯示
                let arr = containView.visibleCells
                arr.forEach { (cell) in
                    let sc = cell as! TTChannelSortCell
                    sc.isEdit = self.isEdit
                }
            }
            guard self.isEdit else{return}
            dsTool.snapShotCellView = cell?.snapshotView(afterScreenUpdates: true)
            dsTool.originalCell = cell;
            dsTool.originalCell?.isHidden = true;
            dsTool.snapShotCellView?.center = (cell?.center)!
            containView.addSubview(dsTool.snapShotCellView!)
            dsTool.startPoint = gesture.location(in: containView)
            dsTool.indexPath = containView.indexPath(for: cell!)
        }else if gesture.state ==  UIGestureRecognizerState.changed{
            guard let _ = dsTool.startPoint else{return}
            guard let _ = dsTool.snapShotCellView else{return}
            let tran_x = gesture.location(ofTouch: 0, in: containView).x - (dsTool.startPoint?.x)!
            let tran_y = gesture.location(ofTouch: 0, in: containView).y - (dsTool.startPoint?.y)!
            dsTool.snapShotCellView?.center = __CGPointApplyAffineTransform((dsTool.snapShotCellView?.center)!, CGAffineTransform.init(translationX: tran_x, y: tran_y));
            dsTool.startPoint = gesture.location(ofTouch: 0, in: containView);
            
            let arrCell = containView.visibleCells;
            for cell in arrCell {
                //跳過自己
                if containView.indexPath(for: cell) == dsTool.indexPath{
                    continue
                }
                //如果相交一半且兩個視圖Y的絕對值小於高度的一半就移動
                let space = sqrt(pow((dsTool.snapShotCellView?.center.x)! - cell.center.x, 2) + pow((dsTool.snapShotCellView?.center.y)! - cell.center.y, 2))
                if space <= (dsTool.snapShotCellView?.bounds.size.width)! * 0.5 && fabs((dsTool.snapShotCellView?.bounds.height)! - cell.bounds.height) <= (dsTool.snapShotCellView?.bounds.height)! * 0.5{
                    dsTool.nextIndexPath = containView.indexPath(for: cell)
                    if (dsTool.nextIndexPath?.item)! > (dsTool.indexPath?.item)!{
                        //更新數據源
                        let i = (dsTool.indexPath?.item)!
                        let ii = (dsTool.nextIndexPath?.item)!
                        for index in i ..< ii{
                            let temp = self.selArr[index]
                            self.selArr[index] = self.selArr[index + 1]
                            self.selArr[index + 1] = temp
                        }
                    }else{
                        //更新數據源
                        let ii = (dsTool.indexPath?.item)!
                        let i = (dsTool.nextIndexPath?.item)!
                        for index in 0 ..< ii - i{
                            guard index < ii else {return}
                            let temp = self.selArr[ii - index]
                            self.selArr[ii - index] = self.selArr[ii - index - 1]
                            self.selArr[ii - index - 1] = temp
                        }
                    }
                    containView.moveItem(at: dsTool.indexPath!, to: dsTool.nextIndexPath!)
                    dsTool.indexPath = dsTool.nextIndexPath
                    break
                }
            }
            
            
        }else if gesture.state ==  UIGestureRecognizerState.ended{
            
            dsTool.snapShotCellView?.removeFromSuperview()
            dsTool.snapShotCellView = nil;
            dsTool.originalCell?.isHidden = false
        }
    }
}


//MARK:代理
extension TTChannelSortVC:UICollectionViewDelegate{
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        if indexPath.section == 1{
            let obj = unselArr[indexPath.row]
            selArr.append(obj)
            unselArr.remove(at: indexPath.row)
            collectionView.moveItem(at: indexPath, to: NSIndexPath.init(item: selArr.count - 1, section: 0) as IndexPath)
        }else if indexPath.section == 0{
            guard isEdit else{return}
            let obj = selArr[indexPath.row]
            unselArr.append(obj)
            selArr.remove(at: indexPath.row)
            collectionView.moveItem(at: indexPath, to: NSIndexPath.init(item: unselArr.count - 1, section: 1) as IndexPath)
        }
    }
}

//MARK:佈局
class TTContainFlowLayout: UICollectionViewFlowLayout {
    override func prepare() {
        headerReferenceSize = CGSize.init(width: SCREEN_WIDTH, height: 64.0)
        itemSize = CGSize.init(width:(SCREEN_WIDTH - 50) * 0.25 , height: 40)
        minimumLineSpacing = 10
        minimumInteritemSpacing = 10
        sectionInset = UIEdgeInsetsMake(10, 10, 10, 10)
    }
}

//MARK:分組頭部
class TTSectionHeadView: UICollectionReusableView {
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.lightGray
        addSubview(c_title)
        addSubview(bt)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    var callBack:(()->())?
    
    
    var isEdit:Bool = false {
        didSet{
            bt.isSelected = isEdit
        }
    }
    
    var titleArr = ["   我的頻道","   推薦頻道"]
    
    
    var titles:String?{
        didSet{
            c_title.text = titles
            if titles == "   推薦頻道"{
                bt.isHidden = true
            }else{
                bt.isHidden = false
            }
        }
    }
    
    lazy var bt:UIButton = {
        let bt = UIButton.init(type: UIButtonType.custom)
        bt.frame = CGRect.init(x: SCREEN_WIDTH - 75, y: 17, width: 60, height: 30)
        bt.addTarget(self, action: #selector(btAction(bt:)), for: UIControlEvents.touchUpInside)
        bt.setTitle("編輯", for: UIControlState.normal)
        bt.setTitle("完成", for: UIControlState.selected)
        bt.layer.borderWidth = 1;
        bt.layer.borderColor = UIColor.white.cgColor;
        bt.layer.cornerRadius = 5;
        return bt
    }()
    
    
    @objc func btAction(bt:UIButton){
        if callBack != nil {
            callBack!()
        }
    }
    
    lazy var c_title:UILabel = {
        let lb = UILabel.init(frame: self.bounds)
        lb.textColor = UIColor.white
        lb.font = UIFont.systemFont(ofSize: 16)
        return lb
    }()
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章