Swift - 給表格添加移動單元格功能(拖動行)

1、給表格 UITableView 添加單元格移動功能

(1)給表格添加長按功能状答,長按后表格進(jìn)入編輯狀態(tài)
(2)在編輯狀態(tài)下冷守,可以看到單元格后面出現(xiàn)拖動按鈕
(3)鼠標(biāo)按住拖動按鈕,可以拖動單元格到任意位置
(4)拖動完畢后惊科,還會觸發(fā) TabelView 對應(yīng)的代理事件

2教沾、效果圖

image.png
import UIKit

class ViewController: UIViewController,UITableViewDelegate,
UITableViewDataSource,UIGestureRecognizerDelegate {
    
    var tableView:UITableView?
    
    var ctrlnames:[String] = ["UILabel 標(biāo)簽","UIButton 按鈕","UIDatePiker 日期選擇器",
                              "UITableView 表格視圖"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //創(chuàng)建表視圖
        self.tableView = UITableView(frame: self.view.frame,
                                     style:.plain)
        self.tableView!.delegate = self
        self.tableView!.dataSource = self
        //創(chuàng)建一個重用的單元格
        self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "SwiftCell")
        self.view.addSubview(self.tableView!)
        
        //綁定對長按的響應(yīng)
        let longPress =  UILongPressGestureRecognizer(target:self,
                                                      action:#selector(tableviewCellLongPressed(gestureRecognizer:)))
        //代理
        longPress.delegate = self
        longPress.minimumPressDuration = 1.0
        //將長按手勢添加到需要實(shí)現(xiàn)長按操作的視圖里
        self.tableView!.addGestureRecognizer(longPress)
    }
    
    //在本例中,只有一個分區(qū)
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    //返回表格行數(shù)(也就是返回控件數(shù))
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.ctrlnames.count
    }
    
    //創(chuàng)建各單元顯示內(nèi)容(創(chuàng)建參數(shù)indexPath指定的單元)
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
            //為了提供表格顯示性能译断,已創(chuàng)建完成的單元需重復(fù)使用
            let identify:String = "SwiftCell"
            //同一形式的單元格重復(fù)使用,在聲明時已注冊
            let cell = tableView.dequeueReusableCell(withIdentifier: identify, for: indexPath)
    as UITableViewCell
            cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
            cell.textLabel?.text = self.ctrlnames[indexPath.row]
            return cell
    }
    
    //長按表格
    @objc func tableviewCellLongPressed(gestureRecognizer:UILongPressGestureRecognizer)
    {
        if (gestureRecognizer.state == UIGestureRecognizer.State.ended)
        {
            print("UIGestureRecognizerStateEnded")
            //在正常狀態(tài)和編輯狀態(tài)之間切換
            if(self.tableView!.isEditing == false){
                self.tableView!.setEditing(true, animated:true)
            }
            else{
                self.tableView!.setEditing(false, animated:true)
            }
        }
    }

    //在編輯狀態(tài)或悲,可以拖動設(shè)置cell位置
    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    //移動cell事件
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath,
                   to destinationIndexPath: IndexPath) {
        if sourceIndexPath != destinationIndexPath{
            //獲取移動行對應(yīng)的值
            let itemValue:String = ctrlnames[sourceIndexPath.row]
            //刪除移動的值
            ctrlnames.remove(at: sourceIndexPath.row)
            //如果移動區(qū)域大于現(xiàn)有行數(shù)孙咪,直接在最后添加移動的值
            if destinationIndexPath.row > ctrlnames.count{
                ctrlnames.append(itemValue)
            }else{
                //沒有超過最大行數(shù),則在目標(biāo)位置添加剛才刪除的值
                ctrlnames.insert(itemValue, at:destinationIndexPath.row)
            }
        }
    }
}

2巡语、讓單元格只能在自己的分區(qū)中拖動

1翎蹈,問題描述

如果我們的 tableView 有多個 section,那么使用上面代碼會發(fā)現(xiàn)男公,單元格 cell 可以自由地在各個分區(qū)間拖動荤堪。比如我們可以把第1個 section 里的 cell 移動到第2個 section 中,反之亦然枢赔。

2澄阳,解決辦法

如果想要限制單元格只能在其所屬的 section 內(nèi)部拖動,可以增加如下代理方法進(jìn)行判斷踏拜。該方法在拖動某行到一個目標(biāo)上方時會被觸發(fā)碎赢,我們可以在方法內(nèi)部判斷是否允許移動,或者進(jìn)行修正速梗。

import UIKit

class ViewController: UIViewController,UITableViewDelegate,
UITableViewDataSource,UIGestureRecognizerDelegate {
    
    var tableView:UITableView?
    
    var ctrlnames:[[String]] = [["UILabel 標(biāo)簽","UIButton 按鈕","UIDatePiker 日期選擇器",
                              "UITableView 表格視圖"],["UIImageView 圖片","UITableVIew 列表","UIDatePiker 日期選擇器",
                              "UITableView 表格視圖"]]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //創(chuàng)建表視圖
        self.tableView = UITableView(frame: self.view.frame,
                                     style:.grouped)
        self.tableView!.delegate = self
        self.tableView!.dataSource = self
        //創(chuàng)建一個重用的單元格
        self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "SwiftCell")
        self.view.addSubview(self.tableView!)
        
        //綁定對長按的響應(yīng)
        let longPress =  UILongPressGestureRecognizer(target:self,
                                                      action:#selector(tableviewCellLongPressed(gestureRecognizer:)))
        //代理
        longPress.delegate = self
        longPress.minimumPressDuration = 1.0
        //將長按手勢添加到需要實(shí)現(xiàn)長按操作的視圖里
        self.tableView!.addGestureRecognizer(longPress)
    }
    
    //在本例中肮塞,只有一個分區(qū)
    func numberOfSections(in tableView: UITableView) -> Int {
        return 2
    }
    
    //返回表格行數(shù)(也就是返回控件數(shù))
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return self.ctrlnames[section].count
    }
    
    //創(chuàng)建各單元顯示內(nèi)容(創(chuàng)建參數(shù)indexPath指定的單元)
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
        -> UITableViewCell {
            //為了提供表格顯示性能襟齿,已創(chuàng)建完成的單元需重復(fù)使用
            let identify:String = "SwiftCell"
            //同一形式的單元格重復(fù)使用,在聲明時已注冊
            let cell = tableView.dequeueReusableCell(withIdentifier: identify, for: indexPath)
    as UITableViewCell
            cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator
            cell.textLabel?.text = self.ctrlnames[indexPath.section][indexPath.row]
            return cell
    }
    
    //長按表格
    @objc func tableviewCellLongPressed(gestureRecognizer:UILongPressGestureRecognizer)
    {
        if (gestureRecognizer.state == UIGestureRecognizer.State.ended)
        {
            print("UIGestureRecognizerStateEnded")
            //在正常狀態(tài)和編輯狀態(tài)之間切換
            if(self.tableView!.isEditing == false){
                self.tableView!.setEditing(true, animated:true)
            }
            else{
                self.tableView!.setEditing(false, animated:true)
            }
        }
    }

    //在編輯狀態(tài)枕赵,可以拖動設(shè)置cell位置
    func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    //移動cell事件
    func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath,
                   to destinationIndexPath: IndexPath) {
        if sourceIndexPath != destinationIndexPath{
            let values: [String] = self.ctrlnames[sourceIndexPath.section]
            //獲取移動行對應(yīng)的值
            let itemValue:String = values[sourceIndexPath.row] as String
            print(itemValue)
            //刪除移動的值
            ctrlnames[sourceIndexPath.section].remove(at: sourceIndexPath.row)
            //如果移動區(qū)域大于現(xiàn)有行數(shù)猜欺,直接在最后添加移動的值
            if destinationIndexPath.row > ctrlnames.count{
                ctrlnames[destinationIndexPath.section].append(itemValue)
            }else{
                //沒有超過最大行數(shù),則在目標(biāo)位置添加剛才刪除的值
                ctrlnames[destinationIndexPath.section].insert(itemValue, at:destinationIndexPath.row)
            }
        }
    }
    
    //拖拽某行到一個目標(biāo)上方時觸發(fā)該方法拷窜,詢問是否移動或者修正
    func tableView(_ tableView: UITableView,
                   targetIndexPathForMoveFromRowAt sourceIndexPath: IndexPath,
                   toProposedIndexPath proposedDestinationIndexPath: IndexPath) -> IndexPath {
        //如果目標(biāo)位置和拖動行不是同一個分區(qū)开皿,則拖動行返回自己原來的分區(qū)
        if sourceIndexPath.section != proposedDestinationIndexPath.section {
            var row = 0
            //如果是往下面的分區(qū)拖動,則回到原分區(qū)末尾
            //如果是往上面的分區(qū)拖動装黑,則會到原分區(qū)開頭位置
            if sourceIndexPath.section < proposedDestinationIndexPath.section {
                row = tableView.numberOfRows(inSection: sourceIndexPath.section)-1
            }
            return IndexPath(row: row, section: sourceIndexPath.section)
        }
        return proposedDestinationIndexPath
    }
}

參考:www.hangge.com

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末副瀑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子恋谭,更是在濱河造成了極大的恐慌糠睡,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件疚颊,死亡現(xiàn)場離奇詭異狈孔,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)材义,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門均抽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人其掂,你說我怎么就攤上這事油挥。” “怎么了款熬?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵深寥,是天一觀的道長。 經(jīng)常有香客問我贤牛,道長惋鹅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任殉簸,我火速辦了婚禮闰集,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘般卑。我一直安慰自己武鲁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布蝠检。 她就那樣靜靜地躺著洞坑,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蝇率。 梳的紋絲不亂的頭發(fā)上迟杂,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天刽沾,我揣著相機(jī)與錄音,去河邊找鬼排拷。 笑死侧漓,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的监氢。 我是一名探鬼主播布蔗,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼浪腐!你這毒婦竟也來了纵揍?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤议街,失蹤者是張志新(化名)和其女友劉穎泽谨,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體特漩,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吧雹,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了涂身。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片雄卷。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖蛤售,靈堂內(nèi)的尸體忽然破棺而出丁鹉,到底是詐尸還是另有隱情,我是刑警寧澤悴能,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布揣钦,位于F島的核電站,受9級特大地震影響搜骡,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜佑女,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一记靡、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧团驱,春花似錦摸吠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至紊选,卻和暖如春啼止,著一層夾襖步出監(jiān)牢的瞬間道逗,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工献烦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留滓窍,地道東北人。 一個月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓巩那,卻偏偏與公主長得像吏夯,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子即横,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355