[iOS]UItableViewの順序を変更する-UItableViewReorderControl


発端



上記の設計の順序を変更するためにUIを作成する必要があります.
まず大体の方法は頭の中で見つけましたが、

第一の方法



MelonやYouTube音楽などの音楽アプリやその他の各種アプリで使用される手順変更方法.個別の編集ボタンがあるため、通常はビューモードと編集モードを個別に使用する場合に使用されます.
  • tableViewおよび
  • tableView.editing = true
  • 左ボタン
  • および
  • を削除
  • の右側に表示されるモバイルハンバーガーボタンが閉じます!
  • 4日は疲れた検索が悪いのか英語が悪いのか分からないが、検索キーワードが見つからないので、答えを見つけるのは難しい.検索時に発見されたのは、UItableViewReorderControlが最も正確なキーワードです.

    第2の方法


    長時間クリックしてドラッグして移動する方法
    登録
  • LongPressジェスチャー、
  • コード
  • を記述してユニット
  • を移動する.

    選択!


    元々の企画では団地全体が少し触れても移動できるようにすることを意図していましたが、1つ目の方法の使用性も良かったので、1つ目の方法を採用することにしました.実際にcellを全域に設定することも不可能ではありませんが、一般的にはあまり一般的な方法ではなく、あまり参考にならないので一時的に延期しました.
    遅延の過程で、reorder control画像をカスタマイズするために、グーグルが検索したところ、対応する実現方法が発見された.でも….実機でテストしたところ、スクロールしようとしたが、セルを移動したが、セルをスクロールした場合があったので使用しないことにした.この方法も以下でまとめます.

    展開:reorder control imagecustom


    まず、大きな構造はappbar、tableView、底部のButton View(このうち2つのビュー)なので、ボタンビューを溝領域に伸ばしやすくしたいと思います.
  • 全体構造はSnapkitをコードベースとし,
  • を用いる.
  • tableView Cell、Button Viewはxibを使用して作成およびインポートします.
  • 方法編集=true/moveRowAt設定

    class ViewController: UIViewController {
        private var snsd = [
            ["태연", "890309"],
            ["써니", "890515"],
            ["티파니", "890801"],
            ["효연", "890922"],
            ["유리", "891205"],
            ["수영", "900210"],
            ["윤아", "900530"],
            ["서현", "910628"],
        ]
        
        // 이 안에 있는 설정은 대체로 viewDidLoad 에서 하지만 개인적으로 closure 를 이용해서 생성하는걸 더 좋아해서 이렇게 했다!
        private lazy var tableView: UITableView = {
            let v = UITableView()
            
            let snsdCell = UINib(nibName: "SnsdTableViewCell", bundle: nil)
            v.register(snsdCell, forCellReuseIdentifier: "SnsdCell")
            
            v.isEditing = true // isEditing 설정!!!
            
            v.dataSource = self
            v.delegate = self
            
            return v
        }()
        
        private let btn: UIButton = {
            let btn = UIButton()
            btn.setTitle("적용하기", for: .normal)
            btn.backgroundColor = .orange
            btn.addTarget(self, action: #selector(btnPressed), for: .touchUpInside)
            btn.contentEdgeInsets = UIEdgeInsets(top: -20, left: 0, bottom: 0, right: 0)
            return btn
        }()
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            view.backgroundColor = .white
            view.addSubview(tableView)
            view.addSubview(btn)
            
            tableView.snp.makeConstraints { make in
                make.top.equalTo(view.safeAreaLayoutGuide.snp.top)
                make.left.right.equalToSuperview()
                make.bottom.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-50)
            }
            
            btn.snp.makeConstraints { make in
                make.top.equalTo(view.safeAreaLayoutGuide.snp.bottom).offset(-50)
                make.left.right.bottom.equalToSuperview()
            }
        }
    
    }
    
    extension ViewController: UITableViewDataSource, UITableViewDelegate {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return snsd.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "SnsdCell", for: indexPath) as! SnsdTableViewCell
            
            cell.nameLabel.text = snsd[indexPath.row][0]
            cell.birthLabel.text = snsd[indexPath.row][1]
            
            return cell
        }
        
        // 왼쪽 버튼 없애기
        func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
            return .none
        }
        
        // editing = true 일 때 왼쪽 버튼이 나오기 위해 들어오는 indent 없애기
        func tableView(_ tableView: UITableView, shouldIndentWhileEditingRowAt indexPath: IndexPath) -> Bool {
            return false
        }
        
        // 오른쪽 reorder control 이 나오면서 셀을 이동할 수 있게 됨.
        func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
            let removed = snsd.remove(at: sourceIndexPath.row)
            snsd.insert(removed, at: destinationIndexPath.row)
        }
    }

    結果



    ただ….横から出る本来はデザインの方法があるのですが、どんな方法を使っても右側からreorder controlが出てくるviewは同じで、他の大企業アプリケーションでもフレームを使ったデザインはほとんどないので、フレームを外しました.やれやれ!

    方法EditingAccessyViewじゃないの?


    結論から言うと、そうではありません.
    // ViewController > cellForRowAt
    // customCell 클래스의 awakeFromNib 이나 init 에서 해줘도 같다.
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = tableView.dequeueReusableCell(withIdentifier: "SnsdCell", for: indexPath) as! SnsdTableViewCell
            
            cell.nameLabel.text = snsd[indexPath.row][0]
            cell.birthLabel.text = snsd[indexPath.row][1]
            cell.editingAccessoryView = UIImageView(image: UIImage(named: "reorder"))
            
            return cell
        }

    結果



    それとも...ただreorder controlの隣にAccessory Viewが現れた...だからまず携帯のハンバーガーボタンviewを外したいと思います.

    方法WillDisplay(またはセルのsetEditing)でUItableViewの画像ビューを変更する


    ソース-https://pilvi.tistory.com/2?category=868530
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        // cell 의 subview 에서 UITableViewReorderControl 안의
        // imageView 를 찾아와서
    	let imageView = cell.subviews.first(where: { $0.description.contains("Reorder") })?.subviews.first(where: { $0 is UIImageView }) as? UIImageView
        
        // image 변경
    	imageView?.image = UIImage(named: "reorder")
        
        // imageView 의 frame 변경
    	let size: CGFloat = 20
    	imageView?.frame.size.width = size
    	imageView?.frame.size.height = size
    }
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        for view in cell.subviews {
          if view.self.description.contains("UITableViewCellReorderControl") {
            for sv in view.subviews {
              if (sv is UIImageView) {
                (sv as? UIImageView)?.image = UIImage(named: "reorder")
                (sv as? UIImageView)?.contentMode = .center
                sv.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
              }
            }
          }
        }
      }
    // willDisplay 안에서 cell 안의 subview 를 찾는 것과 같은 효과.
    override func setEditing(_ editing: Bool, animated: Bool) {
        super.setEditing(editing, animated: animated)
    
        if editing {
            for view in subviews where view.description.contains("Reorder") {
                for case let subview as UIImageView in view.subviews {
                    subview.image = UIImage(named: "reorder")
                    subview.frmae = CGRect(x: 0, y: 0, width: 20, height: 20)
                }
            }
        }
    }

    結果



    変更後のreorder画像を適用しましたが...順番を変えようとした瞬間、基本イメージに戻った.上のコードは一定の割合を保っていますが...でもイメージを変えるのも同じです.また、画像は目的の正しい位置に置かれているわけではありません.
    2つのコードは異なるが、意味は同じだが、イメージを変えて比率を維持する理由も興味深い.

    クライシス:reorderイメージ""位置""custom"


    方法以上の方法のイメージです。frame.origin.位置をxに変更


    ソース-https://tutorialmeta.com/question/change-reorder-controls-color-in-table-view-cell-for-ios-15
    private myReorderImage: UIImage?
    
    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        for subView in cell.subviews {
          if (subView.classForCoder.description() == "UITableViewCellReorderControl") {
            for sv in subView.subviews {
              if (sv.isKind(of: UIImageView.classForCoder())) {
              
                // 위처럼 이미지를 수정하는게 아니라 그냥 원래 이미지를 아예 없애버리고
                sv.removeFromSuperview()
                let imageView = UIImageView()
                
                if (self.myReorderImage == nil) {
                  let myImage = imageView.image
                  myReorderImage = myImage?.withRenderingMode(.alwaysTemplate)
                }
                
                // 새로운 이미지로 세팅!
                var frame = imageView.frame
                frame.origin.x = -10
                frame.origin.y = 20
                frame.size = CGSize(width: 24, height: 24)
                self.myReorderImage = UIImage(named: "reorder") // set your image
                imageView.frame = frame
                imageView.image = self.myReorderImage
                subView.addSubview(imageView) // add imageView to reorder control
                break
              }
            }
            break
          }
        }
      }
    しかしこのコードにも問題があります...クリックすると、画像が変わります.
    frame.画像を原点に移動して0以下にすると、画像は所望の位置に…並べ替え制御の範囲を超えた箇所が出てきましたが、その部分で制御しようとすると制御できなくなります…ここまで来るとデザイン通りに合わなくなり、一度デザインを変えたことがありますが...ここまで来ればなんとかなると思い、Google(Google)を再開しました.

    クライマックス:reorder control領域のセル全体を展開し、非表示=元の意図で操作されたコードを検索します。


    方法並べ替え制御をセル全体に拡張


    ソース-http://jike.in/?qa=816545/ios-reordering-uitableview-without-reorder-control
    このコードは上のwillDisplayコードをsetEditingに入れてcellにインポートします!そこで制御を並べ替える
    weak var reorderControl: UIView?
    override func layoutSubviews() {
            super.layoutSubviews()
    
            // Make the cell's `contentView` as big as the entire cell.
            contentView.frame = bounds
    
            // Make the reorder control as big as the entire cell
            // so you can drag from everywhere inside the cell.
            reorderControl?.frame = bounds
        }
    
    override func setEditing(_ editing: Bool, animated: Bool) {
        super.setEditing(editing, animated: false)
        if !editing || reorderControl != nil {
            return
        }
    
        // Find the reorder control in the cell's subviews.
        for view in subviews {
            let className = String(describing: type(of:view))
            if className == "UITableViewCellReorderControl" {
    
                // Remove its subviews so that they don't mess up
                // your own content's appearance.
                for subview in view.subviews {
                    subview.removeFromSuperview()
                }
    
                // Keep a weak reference to it for `layoutSubviews()`.
                reorderControl = view
    
                break
            }
        }
    }
    ReorderControlのフレームワークを変更します.しかし、cellの高さが正しくないと、table viewを転がすとcellが消えてしまう・・・注意...tableView.rowHeight = 72はそうです

    結果



    初めてプールを移動した時以外は、転がりたいです.cellがずっと動いている様子...

    結果:ん?最後の2つが混ざったら…?



    方法本当の最後

        //  reorder control custom
        func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
            for subView in cell.subviews {
                if (subView.classForCoder.description() == "UITableViewCellReorderControl") {
                    
                    // reorder control frame 을 변경해서 세부적인 위치를 맞춰준다. - 오른쪽 간격 맞추기 위해서
                    let reorderControl = subView
                    let frame = reorderControl.frame
                    reorderControl.frame = CGRect(x: self.view.frame.width - 56, y: frame.minY, width: frame.width, height: frame.height)
                    
                    for subViewB in reorderControl.subviews {
                        if (subViewB.isKind(of: UIImageView.classForCoder())) {
                            // reorder control default image 제거
                            subViewB.removeFromSuperview()
                            
                            let imageView = UIImageView()
                            if (self.myReorderImage == nil) {
                                let myImage = imageView.image
                                myReorderImage = myImage?.withRenderingMode(.alwaysTemplate)
                            }
                            
                            // reorder control image 변경
                            var frame = imageView.frame
                            frame.origin.x = 0
                            frame.origin.y = 24
                            frame.size = CGSize(width: 20, height: 20)
                            self.myReorderImage = UIImage(named: "reorder") // set your image
                            imageView.frame = frame
                            imageView.image = self.myReorderImage
                            reorderControl.addSubview(imageView) // add imageView to reorder control
                            
                            break
                        }
                    }
                    break
                }
            }
        }

    完成!!!
    まったく.最初は福贴りを贴りたいだけで勝手に使えないなら他のものを探して...混ざった感じでいいので和音が難しくない和音を理解してみてください

    画像ソース-https://docs.microsoft.com/en-us/dotnet/api/uikit.uitableviewcell?view=xamarin-ios-sdk-12
    この画像からcellのサブビューにはreorder controlがあり、imageがあることがわかります.私たちはコードを利用してそれを見つけて修正しました!!