├── .gitignore ├── Classes └── DragableTableExtension.swift ├── DraggableTableView.podspec ├── DraggableTableView.xcodeproj └── project.pbxproj ├── DraggableTableView ├── AppDelegate.swift ├── Assets.xcassets │ └── AppIcon.appiconset │ │ └── Contents.json ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── CustomTableViewCell.swift ├── CustomTableViewCell.xib ├── DefaultController.swift ├── DragSpecialUIControlCell.swift ├── DragSpecialUIControlCell.xib ├── DragSpecialUIControlController.swift ├── FixFirstCellController.swift ├── Info.plist ├── edit.png └── image2.jpg ├── LICENSE ├── README.md └── ScreenShot ├── 1.gif ├── 2.gif └── 3.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # For Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData 18 | .idea/ 19 | # If you use cocoa pod 20 | Pods -------------------------------------------------------------------------------- /Classes/DragableTableExtension.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DragableTableExtension.swift 3 | // DragableTableExtension 4 | // 5 | // Created by huangwenchen on 16/9/8. 6 | // Copyright © 2016年 Leo. All rights reserved. 7 | 8 | import Foundation 9 | import ObjectiveC 10 | import UIKit 11 | 12 | 13 | @objc public protocol DragableTableDelegate:AnyObject{ 14 | 15 | /** 16 | A cell is moved from FromIndexPath to toIndexPath,you need to adjust your model here 17 | - parameter tableView: tableview 18 | - parameter fromIndexPath: from indexPath 19 | - parameter toIndexPath: toIndexPath 20 | - returns: void 21 | */ 22 | func tableView(_ tableView:UITableView, dragCellFrom fromIndexPath:IndexPath, toIndexPath:IndexPath) 23 | 24 | /** 25 | A cell is moved from FromIndexPath over overIndexPath, you need to adjust your model here 26 | - parameter tableView: tableview 27 | - parameter fromIndexPath: from indexPath 28 | - parameter overIndexPath: overIndexPath 29 | - returns: void 30 | */ 31 | @objc optional func tableView(_ tableView:UITableView, dragCellFrom fromIndexPath:IndexPath, overIndexPath:IndexPath) 32 | 33 | /** 34 | Weather a cell is dragable 35 | 36 | - parameter tableView: tableView 37 | - parameter indexPath: target indexPath 38 | - parameter point: point that in tableview Cell 39 | 40 | - returns: dragable or not 41 | */ 42 | @objc optional func tableView(_ tableView: UITableView, canDragCellFrom indexPath: IndexPath, withTouchPoint point:CGPoint) -> Bool 43 | 44 | /** 45 | Weather a cell is sticky during dragging 46 | 47 | - parameter tableView: tableview 48 | - parameter indexPath: toIndex 49 | 50 | - returns: sticky or not 51 | */ 52 | @objc optional func tableView(_ tableView: UITableView, canDragCellTo indexPath: IndexPath) -> Bool 53 | 54 | /** 55 | Weather a cell is sticky during dragging 56 | 57 | - parameter tableView: tableview 58 | - parameter indexPath: toIndex 59 | 60 | - returns: sticky or not 61 | */ 62 | @objc optional func tableView(_ tableView: UITableView, canDragCellFrom fromIndexPath: IndexPath, over overIndexPath: IndexPath) -> Bool 63 | 64 | /** 65 | Called when the screenshot imageView center change 66 | 67 | - parameter tableView: tableView 68 | - parameter imageView: screenshot 69 | */ 70 | @objc optional func tableView(_ tableView: UITableView,dragableImageView imageView: UIImageView) 71 | 72 | 73 | @objc optional func tableView(_ tableView: UITableView, endDragCellTo indexPath: IndexPath) 74 | } 75 | 76 | /// A class to hold propertys 77 | private class DragableHelper:NSObject,UIGestureRecognizerDelegate{ 78 | 79 | weak var draggingCell:UITableViewCell? 80 | let displayLink: _DisplayLink 81 | let gesture: UILongPressGestureRecognizer 82 | let floatImageView: UIImageView 83 | 84 | weak var attachTableView:UITableView? 85 | var scrollSpeed: CGFloat = 0.0 86 | init(tableView: UITableView, displayLink:_DisplayLink, gesture:UILongPressGestureRecognizer,floatImageView:UIImageView) { 87 | self.displayLink = displayLink 88 | self.gesture = gesture 89 | self.floatImageView = floatImageView 90 | self.attachTableView = tableView 91 | super.init() 92 | self.gesture.delegate = self 93 | } 94 | @objc func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { 95 | guard let attachTableView = attachTableView else{ 96 | return false 97 | } 98 | return attachTableView.lh_gestureRecognizerShouldBegin(gestureRecognizer) 99 | } 100 | } 101 | public extension UITableView{ 102 | fileprivate struct OBJC_Key{ 103 | static var dragableDelegateKey = 0 104 | static var dragableHelperKey = 1 105 | static var dragableKey = 2 106 | static var dragablePaddingTopKey = 3 107 | } 108 | // MARK: - Associated propertys - 109 | public var dragableDelegate:DragableTableDelegate?{ 110 | get{ 111 | return objc_getAssociatedObject(self, &OBJC_Key.dragableDelegateKey) as? DragableTableDelegate 112 | } 113 | set{ 114 | objc_setAssociatedObject(self, &OBJC_Key.dragableDelegateKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN) 115 | } 116 | } 117 | public var dragable:Bool{ 118 | get{ 119 | let number = objc_getAssociatedObject(self, &OBJC_Key.dragableKey) as! NSNumber 120 | return number.boolValue 121 | } 122 | set{ 123 | if newValue { 124 | setupDragable() 125 | }else{ 126 | cleanDragable() 127 | } 128 | let number = NSNumber(value: newValue as Bool) 129 | objc_setAssociatedObject(self, &OBJC_Key.dragableDelegateKey, number, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN) 130 | } 131 | } 132 | /// The padding you want before trigger scroll up 133 | public var paddingTop:CGFloat{ 134 | get{ 135 | let number = objc_getAssociatedObject(self, &OBJC_Key.dragablePaddingTopKey) as? NSNumber 136 | guard let num = number else{ 137 | return 0.0; 138 | } 139 | return CGFloat(num.floatValue) 140 | } 141 | set{ 142 | let number = NSNumber(value: Float(newValue) as Float) 143 | objc_setAssociatedObject(self, &OBJC_Key.dragablePaddingTopKey, number, objc_AssociationPolicy.OBJC_ASSOCIATION_ASSIGN) 144 | } 145 | } 146 | fileprivate var dragableHelper:DragableHelper?{ 147 | get{ 148 | return objc_getAssociatedObject(self, &OBJC_Key.dragableHelperKey) as? DragableHelper 149 | } 150 | set{ 151 | objc_setAssociatedObject(self, &OBJC_Key.dragableHelperKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN) 152 | } 153 | } 154 | // MARK: - Private set up - 155 | fileprivate func setupDragable(){ 156 | if dragableHelper != nil{ 157 | cleanDragable() 158 | } 159 | let longPressGesture = UILongPressGestureRecognizer(target: self, action: #selector(UITableView.handleLongPress)) 160 | addGestureRecognizer(longPressGesture) 161 | let displayLink = _DisplayLink{ [unowned self] in 162 | guard let dragableHelper = self.dragableHelper else{ 163 | return 164 | } 165 | self.contentOffset.y = min(max(0.0, self.contentOffset.y + dragableHelper.scrollSpeed),self.contentSize.height - self.frame.height) 166 | self.adjusFloatImageViewCenterY(dragableHelper.gesture.location(in: self).y) 167 | } 168 | 169 | let imageView = UIImageView() 170 | let helper = DragableHelper(tableView:self,displayLink: displayLink, gesture: longPressGesture, floatImageView: imageView) 171 | dragableHelper = helper 172 | } 173 | fileprivate func cleanDragable(){ 174 | guard let helper = dragableHelper else{ 175 | return 176 | } 177 | removeGestureRecognizer(helper.gesture) 178 | dragableHelper = nil 179 | } 180 | 181 | // MARK: - Handle gesture and display link- 182 | @objc fileprivate func handleLongPress(_ gesture: UILongPressGestureRecognizer){ 183 | assert(dragableDelegate != nil, "You must set delegate") 184 | guard let dragableHelper = dragableHelper else{ 185 | return 186 | } 187 | let location = gesture.location(in: self) 188 | switch gesture.state { 189 | case .began: 190 | guard let currentIndexPath = indexPathForRow(at: location),let currentCell = cellForRow(at: currentIndexPath) else { 191 | return 192 | } 193 | if let selectedRow = indexPathForSelectedRow{ 194 | deselectRow(at: selectedRow, animated: false) 195 | } 196 | allowsSelection = false 197 | currentCell.isHighlighted = false 198 | dragableHelper.draggingCell = currentCell 199 | //Configure imageview 200 | let screenShot = currentCell.lh_screenShot() 201 | dragableHelper.floatImageView.image = screenShot 202 | 203 | dragableHelper.floatImageView.frame = currentCell.bounds 204 | dragableHelper.floatImageView.center = currentCell.center 205 | self.dragableDelegate?.tableView?(self, dragableImageView: dragableHelper.floatImageView) 206 | dragableHelper.floatImageView.layer.shadowRadius = 5.0 207 | dragableHelper.floatImageView.layer.shadowOpacity = 0.2 208 | dragableHelper.floatImageView.layer.shadowOffset = CGSize.zero 209 | dragableHelper.floatImageView.layer.shadowPath = UIBezierPath(rect: dragableHelper.floatImageView.bounds).cgPath 210 | addSubview(dragableHelper.floatImageView) 211 | 212 | UIView.animate(withDuration: 0.2, animations: { 213 | dragableHelper.floatImageView.transform = CGAffineTransform(scaleX: 1.1, y: 1.1) 214 | dragableHelper.floatImageView.alpha = 0.5 215 | }) 216 | currentCell.isHidden = true 217 | case .changed: 218 | adjusFloatImageViewCenterY(location.y) 219 | dragableHelper.scrollSpeed = 0.0 220 | //Refer from here https://github.com/okla/QuickRearrangeTableView/blob/master/QuickRearrangeTableView.swift 221 | if contentSize.height > frame.height { 222 | let halfCellHeight = dragableHelper.floatImageView.frame.size.height / 2.0 223 | let cellCenterToTop = dragableHelper.floatImageView.center.y - bounds.origin.y - paddingTop 224 | self.dragableDelegate?.tableView?(self, dragableImageView: dragableHelper.floatImageView) 225 | if cellCenterToTop < halfCellHeight { 226 | dragableHelper.scrollSpeed = 5.0*(cellCenterToTop/halfCellHeight - 1.1) 227 | } 228 | else if cellCenterToTop > frame.height - halfCellHeight { 229 | dragableHelper.scrollSpeed = 5.0*((cellCenterToTop - frame.height)/halfCellHeight + 1.1) 230 | } 231 | dragableHelper.displayLink.paused = (dragableHelper.scrollSpeed == 0) 232 | } 233 | default: 234 | allowsSelection = true 235 | dragableHelper.displayLink.paused = true 236 | if adjustFinalCellOrderIfNecessary() { 237 | UIView.animate(withDuration: 0.2, 238 | animations: { 239 | dragableHelper.floatImageView.transform = CGAffineTransform.identity 240 | dragableHelper.floatImageView.alpha = 1.0 241 | }, 242 | completion: { (completed) in 243 | dragableHelper.floatImageView.removeFromSuperview() 244 | dragableHelper.draggingCell?.isHidden = false 245 | dragableHelper.draggingCell = nil 246 | if let currentIndexPath = self.indexPathForRow(at: location) { 247 | self.dragableDelegate?.tableView?(self, endDragCellTo: currentIndexPath) 248 | } 249 | }) 250 | } else { 251 | UIView.animate(withDuration: 0.2, 252 | animations: { 253 | dragableHelper.floatImageView.transform = CGAffineTransform.identity 254 | dragableHelper.floatImageView.alpha = 1.0 255 | dragableHelper.floatImageView.frame = dragableHelper.draggingCell!.frame 256 | }, 257 | completion: { (completed) in 258 | dragableHelper.floatImageView.removeFromSuperview() 259 | dragableHelper.draggingCell?.isHidden = false 260 | dragableHelper.draggingCell = nil 261 | if let currentIndexPath = self.indexPathForRow(at: location) { 262 | self.dragableDelegate?.tableView?(self, endDragCellTo: currentIndexPath) 263 | } 264 | }) 265 | } 266 | } 267 | } 268 | func lh_gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { 269 | let location = gestureRecognizer.location(in: self) 270 | guard let currentIndexPath = indexPathForRow(at: location),let currentCell = cellForRow(at: currentIndexPath) else{ 271 | return false 272 | } 273 | let pointInCell = convert(location, to: currentCell) 274 | guard let canDrag = dragableDelegate?.tableView?(self, canDragCellFrom: currentIndexPath, withTouchPoint: pointInCell) else{ 275 | return true 276 | } 277 | return canDrag 278 | } 279 | 280 | // MARK: - Private method - 281 | func adjusFloatImageViewCenterY(_ newY:CGFloat){ 282 | guard let floatImageView = dragableHelper?.floatImageView else{ 283 | return 284 | } 285 | floatImageView.center.y = min(max(newY, bounds.origin.y), bounds.origin.y + bounds.height) 286 | self.dragableDelegate?.tableView?(self, dragableImageView: floatImageView) 287 | adjustCellOrderIfNecessary() 288 | } 289 | 290 | func adjustCellOrderIfNecessary(){ 291 | guard let dragableDelegate = dragableDelegate,let floatImageView = dragableHelper?.floatImageView,let toIndexPath = indexPathForRow(at: floatImageView.center) else{ 292 | return 293 | } 294 | guard let draggingCell = dragableHelper?.draggingCell,let dragingIndexPath = indexPath(for: draggingCell) else{ 295 | return 296 | } 297 | guard (dragingIndexPath as NSIndexPath).compare(toIndexPath) != ComparisonResult.orderedSame else{ 298 | return 299 | } 300 | if let canDragTo = dragableDelegate.tableView?(self, canDragCellTo: toIndexPath) { 301 | if !canDragTo { 302 | return 303 | } 304 | } 305 | let destinationCell = cellForRow(at: toIndexPath)! 306 | let sign = CGFloat((toIndexPath.row - dragingIndexPath.row >= 0) ? 1 : -1) 307 | 308 | if ((floatImageView.center.y - destinationCell.center.y) * sign < destinationCell.frame.height / 3) { 309 | return 310 | } 311 | 312 | draggingCell.isHidden = true 313 | beginUpdates() 314 | dragableDelegate.tableView(self, dragCellFrom: dragingIndexPath, toIndexPath: toIndexPath) 315 | moveRow(at: dragingIndexPath, to: toIndexPath) 316 | endUpdates() 317 | } 318 | 319 | func adjustFinalCellOrderIfNecessary() -> Bool { 320 | guard let dragableDelegate = dragableDelegate,let floatImageView = dragableHelper?.floatImageView,let toIndexPath = indexPathForRow(at: floatImageView.center) else{ 321 | return false 322 | } 323 | guard let draggingCell = dragableHelper?.draggingCell,let dragingIndexPath = indexPath(for: draggingCell) else{ 324 | return false 325 | } 326 | guard (dragingIndexPath as NSIndexPath).compare(toIndexPath) != ComparisonResult.orderedSame else{ 327 | return false 328 | } 329 | if let canDragOver = dragableDelegate.tableView?(self, canDragCellFrom: dragingIndexPath, over: toIndexPath) { 330 | if !canDragOver { 331 | return false 332 | } 333 | } 334 | 335 | let destinationCell = cellForRow(at: toIndexPath)! 336 | let sign = CGFloat((toIndexPath.row - dragingIndexPath.row >= 0) ? 1 : -1) 337 | 338 | if ((floatImageView.center.y - destinationCell.center.y) * sign > destinationCell.frame.height / 3) { 339 | return false 340 | } 341 | draggingCell.isHidden = true 342 | beginUpdates() 343 | dragableDelegate.tableView?(self, dragCellFrom: dragingIndexPath, overIndexPath: toIndexPath) 344 | //deleteRows(at: [dragingIndexPath], with: .automatic) 345 | endUpdates() 346 | return true 347 | } 348 | } 349 | private class _DisplayLink{ 350 | var paused:Bool{ 351 | get{ 352 | return _link.isPaused 353 | } 354 | set{ 355 | _link.isPaused = newValue 356 | } 357 | } 358 | fileprivate init (_ callback: @escaping (Void) -> Void) { 359 | _callback = callback 360 | _link = CADisplayLink(target: _DisplayTarget(self), selector: #selector(_DisplayTarget._callback)) 361 | _link.add(to: RunLoop.main, forMode: RunLoopMode.commonModes) 362 | _link.isPaused = true 363 | } 364 | 365 | fileprivate let _callback: (Void) -> Void 366 | 367 | fileprivate var _link: CADisplayLink! 368 | 369 | deinit { 370 | _link.invalidate() 371 | } 372 | } 373 | 374 | /// Retained by CADisplayLink. 375 | private class _DisplayTarget { 376 | 377 | init (_ link: _DisplayLink) { 378 | _link = link 379 | } 380 | 381 | weak var _link: _DisplayLink! 382 | 383 | @objc func _callback () { 384 | _link?._callback() 385 | } 386 | } 387 | private extension UIView{ 388 | /** 389 | Get the screenShot of a UIView 390 | 391 | - returns: Image of self 392 | */ 393 | func lh_screenShot()->UIImage?{ 394 | let mask = layer.mask 395 | layer.mask = nil 396 | UIGraphicsBeginImageContextWithOptions(CGSize(width: frame.width, height: frame.height), false, 0.0) 397 | layer.render(in: UIGraphicsGetCurrentContext()!) 398 | let image = UIGraphicsGetImageFromCurrentImageContext() 399 | UIGraphicsEndImageContext(); 400 | layer.mask = mask 401 | return image 402 | } 403 | } 404 | -------------------------------------------------------------------------------- /DraggableTableView.podspec: -------------------------------------------------------------------------------- 1 | 2 | Pod::Spec.new do |s| 3 | s.name = 'DraggableTableView' 4 | s.version = '0.2.2' 5 | s.summary = 'Extension for the UITableView that allows a user to move cells with long press and drop' 6 | s.description = <<-DESC 7 | Extension for the UITableView that allows a user to move cells with long press and drop,it is a "Drop to use" library. 8 | DESC 9 | 10 | s.homepage = 'https://github.com/LeoMobileDeveloper/DraggableTableView' 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { 'Leo' => 'leomobiledeveloper@gmail.com' } 13 | s.source = { :git => 'https://github.com/LeoMobileDeveloper/DraggableTableView', :tag => s.version.to_s } 14 | s.ios.deployment_target = '8.0' 15 | s.source_files = 'Classes/**/*' 16 | end 17 | -------------------------------------------------------------------------------- /DraggableTableView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 522046311D8A64740038834B /* DragableTableExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 522046301D8A64740038834B /* DragableTableExtension.swift */; }; 11 | 52A70E151D868CF20091D1AC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A70E0A1D868CF20091D1AC /* AppDelegate.swift */; }; 12 | 52A70E161D868CF20091D1AC /* CustomTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A70E0B1D868CF20091D1AC /* CustomTableViewCell.swift */; }; 13 | 52A70E171D868CF20091D1AC /* CustomTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 52A70E0C1D868CF20091D1AC /* CustomTableViewCell.xib */; }; 14 | 52A70E181D868CF20091D1AC /* DefaultController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A70E0D1D868CF20091D1AC /* DefaultController.swift */; }; 15 | 52A70E191D868CF20091D1AC /* DragSpecialUIControlCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A70E0E1D868CF20091D1AC /* DragSpecialUIControlCell.swift */; }; 16 | 52A70E1A1D868CF20091D1AC /* DragSpecialUIControlCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 52A70E0F1D868CF20091D1AC /* DragSpecialUIControlCell.xib */; }; 17 | 52A70E1B1D868CF20091D1AC /* DragSpecialUIControlController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A70E101D868CF20091D1AC /* DragSpecialUIControlController.swift */; }; 18 | 52A70E1C1D868CF20091D1AC /* edit.png in Resources */ = {isa = PBXBuildFile; fileRef = 52A70E111D868CF20091D1AC /* edit.png */; }; 19 | 52A70E1D1D868CF20091D1AC /* FixFirstCellController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 52A70E121D868CF20091D1AC /* FixFirstCellController.swift */; }; 20 | 52A70E1E1D868CF20091D1AC /* image2.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 52A70E131D868CF20091D1AC /* image2.jpg */; }; 21 | 52A70E1F1D868CF20091D1AC /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 52A70E141D868CF20091D1AC /* Info.plist */; }; 22 | 52A70E211D868D3F0091D1AC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 52A70E201D868D3F0091D1AC /* Assets.xcassets */; }; 23 | 52A70E261D868D800091D1AC /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 52A70E221D868D800091D1AC /* LaunchScreen.storyboard */; }; 24 | 52A70E271D868D800091D1AC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 52A70E241D868D800091D1AC /* Main.storyboard */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXFileReference section */ 28 | 522046301D8A64740038834B /* DragableTableExtension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DragableTableExtension.swift; sourceTree = ""; }; 29 | 52A70E0A1D868CF20091D1AC /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppDelegate.swift; path = DraggableTableView/AppDelegate.swift; sourceTree = SOURCE_ROOT; }; 30 | 52A70E0B1D868CF20091D1AC /* CustomTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CustomTableViewCell.swift; path = DraggableTableView/CustomTableViewCell.swift; sourceTree = SOURCE_ROOT; }; 31 | 52A70E0C1D868CF20091D1AC /* CustomTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = CustomTableViewCell.xib; path = DraggableTableView/CustomTableViewCell.xib; sourceTree = SOURCE_ROOT; }; 32 | 52A70E0D1D868CF20091D1AC /* DefaultController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DefaultController.swift; path = DraggableTableView/DefaultController.swift; sourceTree = SOURCE_ROOT; }; 33 | 52A70E0E1D868CF20091D1AC /* DragSpecialUIControlCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DragSpecialUIControlCell.swift; path = DraggableTableView/DragSpecialUIControlCell.swift; sourceTree = SOURCE_ROOT; }; 34 | 52A70E0F1D868CF20091D1AC /* DragSpecialUIControlCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = DragSpecialUIControlCell.xib; path = DraggableTableView/DragSpecialUIControlCell.xib; sourceTree = SOURCE_ROOT; }; 35 | 52A70E101D868CF20091D1AC /* DragSpecialUIControlController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DragSpecialUIControlController.swift; path = DraggableTableView/DragSpecialUIControlController.swift; sourceTree = SOURCE_ROOT; }; 36 | 52A70E111D868CF20091D1AC /* edit.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = edit.png; path = DraggableTableView/edit.png; sourceTree = SOURCE_ROOT; }; 37 | 52A70E121D868CF20091D1AC /* FixFirstCellController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = FixFirstCellController.swift; path = DraggableTableView/FixFirstCellController.swift; sourceTree = SOURCE_ROOT; }; 38 | 52A70E131D868CF20091D1AC /* image2.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; name = image2.jpg; path = DraggableTableView/image2.jpg; sourceTree = SOURCE_ROOT; }; 39 | 52A70E141D868CF20091D1AC /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = DraggableTableView/Info.plist; sourceTree = SOURCE_ROOT; }; 40 | 52A70E201D868D3F0091D1AC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = DraggableTableView/Assets.xcassets; sourceTree = SOURCE_ROOT; }; 41 | 52A70E231D868D800091D1AC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = DraggableTableView/Base.lproj/LaunchScreen.storyboard; sourceTree = SOURCE_ROOT; }; 42 | 52A70E251D868D800091D1AC /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = DraggableTableView/Base.lproj/Main.storyboard; sourceTree = SOURCE_ROOT; }; 43 | 52D762971D813A4300A057A9 /* DraggableTableView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DraggableTableView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 44 | 52D762AD1D813AA800A057A9 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = SOURCE_ROOT; }; 45 | /* End PBXFileReference section */ 46 | 47 | /* Begin PBXFrameworksBuildPhase section */ 48 | 52D762941D813A4300A057A9 /* Frameworks */ = { 49 | isa = PBXFrameworksBuildPhase; 50 | buildActionMask = 2147483647; 51 | files = ( 52 | ); 53 | runOnlyForDeploymentPostprocessing = 0; 54 | }; 55 | /* End PBXFrameworksBuildPhase section */ 56 | 57 | /* Begin PBXGroup section */ 58 | 5220462F1D8A64740038834B /* Classes */ = { 59 | isa = PBXGroup; 60 | children = ( 61 | 522046301D8A64740038834B /* DragableTableExtension.swift */, 62 | ); 63 | path = Classes; 64 | sourceTree = SOURCE_ROOT; 65 | }; 66 | 52D7628E1D813A4300A057A9 = { 67 | isa = PBXGroup; 68 | children = ( 69 | 52D762AD1D813AA800A057A9 /* README.md */, 70 | 52D762991D813A4300A057A9 /* DraggableTableView */, 71 | 52D762981D813A4300A057A9 /* Products */, 72 | ); 73 | sourceTree = ""; 74 | }; 75 | 52D762981D813A4300A057A9 /* Products */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | 52D762971D813A4300A057A9 /* DraggableTableView.app */, 79 | ); 80 | name = Products; 81 | sourceTree = ""; 82 | }; 83 | 52D762991D813A4300A057A9 /* DraggableTableView */ = { 84 | isa = PBXGroup; 85 | children = ( 86 | 5220462F1D8A64740038834B /* Classes */, 87 | 52F0E8231D865693001B9DEA /* Example */, 88 | ); 89 | name = DraggableTableView; 90 | path = DragableTableExtension; 91 | sourceTree = ""; 92 | }; 93 | 52F0E8231D865693001B9DEA /* Example */ = { 94 | isa = PBXGroup; 95 | children = ( 96 | 52A70E0A1D868CF20091D1AC /* AppDelegate.swift */, 97 | 52A70E0B1D868CF20091D1AC /* CustomTableViewCell.swift */, 98 | 52A70E0C1D868CF20091D1AC /* CustomTableViewCell.xib */, 99 | 52A70E0D1D868CF20091D1AC /* DefaultController.swift */, 100 | 52A70E0E1D868CF20091D1AC /* DragSpecialUIControlCell.swift */, 101 | 52A70E0F1D868CF20091D1AC /* DragSpecialUIControlCell.xib */, 102 | 52A70E101D868CF20091D1AC /* DragSpecialUIControlController.swift */, 103 | 52A70E221D868D800091D1AC /* LaunchScreen.storyboard */, 104 | 52A70E241D868D800091D1AC /* Main.storyboard */, 105 | 52A70E111D868CF20091D1AC /* edit.png */, 106 | 52A70E121D868CF20091D1AC /* FixFirstCellController.swift */, 107 | 52A70E131D868CF20091D1AC /* image2.jpg */, 108 | 52A70E141D868CF20091D1AC /* Info.plist */, 109 | 52A70E201D868D3F0091D1AC /* Assets.xcassets */, 110 | ); 111 | name = Example; 112 | sourceTree = ""; 113 | }; 114 | /* End PBXGroup section */ 115 | 116 | /* Begin PBXNativeTarget section */ 117 | 52D762961D813A4300A057A9 /* DraggableTableView */ = { 118 | isa = PBXNativeTarget; 119 | buildConfigurationList = 52D762A91D813A4300A057A9 /* Build configuration list for PBXNativeTarget "DraggableTableView" */; 120 | buildPhases = ( 121 | 52D762931D813A4300A057A9 /* Sources */, 122 | 52D762941D813A4300A057A9 /* Frameworks */, 123 | 52D762951D813A4300A057A9 /* Resources */, 124 | ); 125 | buildRules = ( 126 | ); 127 | dependencies = ( 128 | ); 129 | name = DraggableTableView; 130 | productName = DragableTableExtension; 131 | productReference = 52D762971D813A4300A057A9 /* DraggableTableView.app */; 132 | productType = "com.apple.product-type.application"; 133 | }; 134 | /* End PBXNativeTarget section */ 135 | 136 | /* Begin PBXProject section */ 137 | 52D7628F1D813A4300A057A9 /* Project object */ = { 138 | isa = PBXProject; 139 | attributes = { 140 | LastSwiftUpdateCheck = 0730; 141 | LastUpgradeCheck = 0730; 142 | ORGANIZATIONNAME = Leo; 143 | TargetAttributes = { 144 | 52D762961D813A4300A057A9 = { 145 | CreatedOnToolsVersion = 7.3.1; 146 | DevelopmentTeam = NULGQZ4NMG; 147 | LastSwiftMigration = 0810; 148 | }; 149 | }; 150 | }; 151 | buildConfigurationList = 52D762921D813A4300A057A9 /* Build configuration list for PBXProject "DraggableTableView" */; 152 | compatibilityVersion = "Xcode 3.2"; 153 | developmentRegion = English; 154 | hasScannedForEncodings = 0; 155 | knownRegions = ( 156 | en, 157 | Base, 158 | ); 159 | mainGroup = 52D7628E1D813A4300A057A9; 160 | productRefGroup = 52D762981D813A4300A057A9 /* Products */; 161 | projectDirPath = ""; 162 | projectRoot = ""; 163 | targets = ( 164 | 52D762961D813A4300A057A9 /* DraggableTableView */, 165 | ); 166 | }; 167 | /* End PBXProject section */ 168 | 169 | /* Begin PBXResourcesBuildPhase section */ 170 | 52D762951D813A4300A057A9 /* Resources */ = { 171 | isa = PBXResourcesBuildPhase; 172 | buildActionMask = 2147483647; 173 | files = ( 174 | 52A70E1E1D868CF20091D1AC /* image2.jpg in Resources */, 175 | 52A70E1C1D868CF20091D1AC /* edit.png in Resources */, 176 | 52A70E1F1D868CF20091D1AC /* Info.plist in Resources */, 177 | 52A70E271D868D800091D1AC /* Main.storyboard in Resources */, 178 | 52A70E171D868CF20091D1AC /* CustomTableViewCell.xib in Resources */, 179 | 52A70E261D868D800091D1AC /* LaunchScreen.storyboard in Resources */, 180 | 52A70E211D868D3F0091D1AC /* Assets.xcassets in Resources */, 181 | 52A70E1A1D868CF20091D1AC /* DragSpecialUIControlCell.xib in Resources */, 182 | ); 183 | runOnlyForDeploymentPostprocessing = 0; 184 | }; 185 | /* End PBXResourcesBuildPhase section */ 186 | 187 | /* Begin PBXSourcesBuildPhase section */ 188 | 52D762931D813A4300A057A9 /* Sources */ = { 189 | isa = PBXSourcesBuildPhase; 190 | buildActionMask = 2147483647; 191 | files = ( 192 | 52A70E1D1D868CF20091D1AC /* FixFirstCellController.swift in Sources */, 193 | 52A70E191D868CF20091D1AC /* DragSpecialUIControlCell.swift in Sources */, 194 | 52A70E1B1D868CF20091D1AC /* DragSpecialUIControlController.swift in Sources */, 195 | 52A70E161D868CF20091D1AC /* CustomTableViewCell.swift in Sources */, 196 | 52A70E151D868CF20091D1AC /* AppDelegate.swift in Sources */, 197 | 522046311D8A64740038834B /* DragableTableExtension.swift in Sources */, 198 | 52A70E181D868CF20091D1AC /* DefaultController.swift in Sources */, 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | }; 202 | /* End PBXSourcesBuildPhase section */ 203 | 204 | /* Begin PBXVariantGroup section */ 205 | 52A70E221D868D800091D1AC /* LaunchScreen.storyboard */ = { 206 | isa = PBXVariantGroup; 207 | children = ( 208 | 52A70E231D868D800091D1AC /* Base */, 209 | ); 210 | name = LaunchScreen.storyboard; 211 | sourceTree = ""; 212 | }; 213 | 52A70E241D868D800091D1AC /* Main.storyboard */ = { 214 | isa = PBXVariantGroup; 215 | children = ( 216 | 52A70E251D868D800091D1AC /* Base */, 217 | ); 218 | name = Main.storyboard; 219 | sourceTree = ""; 220 | }; 221 | /* End PBXVariantGroup section */ 222 | 223 | /* Begin XCBuildConfiguration section */ 224 | 52D762A71D813A4300A057A9 /* Debug */ = { 225 | isa = XCBuildConfiguration; 226 | buildSettings = { 227 | ALWAYS_SEARCH_USER_PATHS = NO; 228 | CLANG_ANALYZER_NONNULL = YES; 229 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 230 | CLANG_CXX_LIBRARY = "libc++"; 231 | CLANG_ENABLE_MODULES = YES; 232 | CLANG_ENABLE_OBJC_ARC = YES; 233 | CLANG_WARN_BOOL_CONVERSION = YES; 234 | CLANG_WARN_CONSTANT_CONVERSION = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INT_CONVERSION = YES; 239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 240 | CLANG_WARN_UNREACHABLE_CODE = YES; 241 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 242 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 243 | COPY_PHASE_STRIP = NO; 244 | DEBUG_INFORMATION_FORMAT = dwarf; 245 | ENABLE_STRICT_OBJC_MSGSEND = YES; 246 | ENABLE_TESTABILITY = YES; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_DYNAMIC_NO_PIC = NO; 249 | GCC_NO_COMMON_BLOCKS = YES; 250 | GCC_OPTIMIZATION_LEVEL = 0; 251 | GCC_PREPROCESSOR_DEFINITIONS = ( 252 | "DEBUG=1", 253 | "$(inherited)", 254 | ); 255 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 256 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 257 | GCC_WARN_UNDECLARED_SELECTOR = YES; 258 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 259 | GCC_WARN_UNUSED_FUNCTION = YES; 260 | GCC_WARN_UNUSED_VARIABLE = YES; 261 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 262 | MTL_ENABLE_DEBUG_INFO = YES; 263 | ONLY_ACTIVE_ARCH = YES; 264 | SDKROOT = iphoneos; 265 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 266 | TARGETED_DEVICE_FAMILY = "1,2"; 267 | }; 268 | name = Debug; 269 | }; 270 | 52D762A81D813A4300A057A9 /* Release */ = { 271 | isa = XCBuildConfiguration; 272 | buildSettings = { 273 | ALWAYS_SEARCH_USER_PATHS = NO; 274 | CLANG_ANALYZER_NONNULL = YES; 275 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 276 | CLANG_CXX_LIBRARY = "libc++"; 277 | CLANG_ENABLE_MODULES = YES; 278 | CLANG_ENABLE_OBJC_ARC = YES; 279 | CLANG_WARN_BOOL_CONVERSION = YES; 280 | CLANG_WARN_CONSTANT_CONVERSION = YES; 281 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 282 | CLANG_WARN_EMPTY_BODY = YES; 283 | CLANG_WARN_ENUM_CONVERSION = YES; 284 | CLANG_WARN_INT_CONVERSION = YES; 285 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 286 | CLANG_WARN_UNREACHABLE_CODE = YES; 287 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 288 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 289 | COPY_PHASE_STRIP = NO; 290 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 291 | ENABLE_NS_ASSERTIONS = NO; 292 | ENABLE_STRICT_OBJC_MSGSEND = YES; 293 | GCC_C_LANGUAGE_STANDARD = gnu99; 294 | GCC_NO_COMMON_BLOCKS = YES; 295 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 296 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 297 | GCC_WARN_UNDECLARED_SELECTOR = YES; 298 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 299 | GCC_WARN_UNUSED_FUNCTION = YES; 300 | GCC_WARN_UNUSED_VARIABLE = YES; 301 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 302 | MTL_ENABLE_DEBUG_INFO = NO; 303 | SDKROOT = iphoneos; 304 | TARGETED_DEVICE_FAMILY = "1,2"; 305 | VALIDATE_PRODUCT = YES; 306 | }; 307 | name = Release; 308 | }; 309 | 52D762AA1D813A4300A057A9 /* Debug */ = { 310 | isa = XCBuildConfiguration; 311 | buildSettings = { 312 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 313 | DEVELOPMENT_TEAM = NULGQZ4NMG; 314 | INFOPLIST_FILE = "$(SRCROOT)/DraggableTableView/Info.plist"; 315 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 316 | PRODUCT_BUNDLE_IDENTIFIER = Leo.DraggableTableView; 317 | PRODUCT_NAME = DraggableTableView; 318 | SWIFT_VERSION = 3.0; 319 | }; 320 | name = Debug; 321 | }; 322 | 52D762AB1D813A4300A057A9 /* Release */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 326 | DEVELOPMENT_TEAM = NULGQZ4NMG; 327 | INFOPLIST_FILE = "$(SRCROOT)/DraggableTableView/Info.plist"; 328 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 329 | PRODUCT_BUNDLE_IDENTIFIER = Leo.DraggableTableView; 330 | PRODUCT_NAME = DraggableTableView; 331 | SWIFT_VERSION = 3.0; 332 | }; 333 | name = Release; 334 | }; 335 | /* End XCBuildConfiguration section */ 336 | 337 | /* Begin XCConfigurationList section */ 338 | 52D762921D813A4300A057A9 /* Build configuration list for PBXProject "DraggableTableView" */ = { 339 | isa = XCConfigurationList; 340 | buildConfigurations = ( 341 | 52D762A71D813A4300A057A9 /* Debug */, 342 | 52D762A81D813A4300A057A9 /* Release */, 343 | ); 344 | defaultConfigurationIsVisible = 0; 345 | defaultConfigurationName = Release; 346 | }; 347 | 52D762A91D813A4300A057A9 /* Build configuration list for PBXNativeTarget "DraggableTableView" */ = { 348 | isa = XCConfigurationList; 349 | buildConfigurations = ( 350 | 52D762AA1D813A4300A057A9 /* Debug */, 351 | 52D762AB1D813A4300A057A9 /* Release */, 352 | ); 353 | defaultConfigurationIsVisible = 0; 354 | defaultConfigurationName = Release; 355 | }; 356 | /* End XCConfigurationList section */ 357 | }; 358 | rootObject = 52D7628F1D813A4300A057A9 /* Project object */; 359 | } 360 | -------------------------------------------------------------------------------- /DraggableTableView/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // DragableTableExtension 4 | // 5 | // Created by huangwenchen on 16/9/8. 6 | // Copyright © 2016年 Leo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /DraggableTableView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /DraggableTableView/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /DraggableTableView/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /DraggableTableView/CustomTableViewCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // CustomTableViewCell.swift 3 | // DragableTableExtension 4 | // 5 | // Created by huangwenchen on 16/9/9. 6 | // Copyright © 2016年 Leo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class CustomTableViewCell: UITableViewCell { 12 | 13 | @IBOutlet weak var customLabel: UILabel! 14 | override func awakeFromNib() { 15 | super.awakeFromNib() 16 | // Initialization code 17 | } 18 | 19 | override func setSelected(_ selected: Bool, animated: Bool) { 20 | super.setSelected(selected, animated: animated) 21 | 22 | // Configure the view for the selected state 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /DraggableTableView/CustomTableViewCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /DraggableTableView/DefaultController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DefaultController.swift 3 | // DragableTableExtension 4 | // 5 | // Created by huangwenchen on 16/9/12. 6 | // Copyright © 2016年 Leo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DefaultController: UITableViewController,DragableTableDelegate{ 12 | 13 | var dataArray:NSMutableArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18] 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "cell") 18 | //Set up dragable 19 | self.tableView.dragable = true 20 | self.tableView.dragableDelegate = self 21 | } 22 | // MARK: - DragableTableDelegate 23 | func tableView(_ tableView: UITableView, dragCellFrom fromIndexPath: IndexPath, toIndexPath: IndexPath) { 24 | dataArray.exchangeObject(at: fromIndexPath.row, withObjectAt: toIndexPath.row) 25 | } 26 | func tableView(_ tableView: UITableView, dragCellFrom fromIndexPath: IndexPath, overIndexPath: IndexPath) { 27 | dataArray.removeObject(at: fromIndexPath.row) 28 | } 29 | // MARK: - Table view data source 30 | override func numberOfSections(in tableView: UITableView) -> Int { 31 | return 1 32 | } 33 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 34 | return dataArray.count 35 | } 36 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 37 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CustomTableViewCell 38 | cell?.customLabel?.text = "\(dataArray[indexPath.row])" 39 | return cell! 40 | } 41 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 42 | return 100.0 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /DraggableTableView/DragSpecialUIControlCell.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DragSpecialUIControlCell.swift 3 | // DragableTableExtension 4 | // 5 | // Created by huangwenchen on 16/9/12. 6 | // Copyright © 2016年 Leo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DragSpecialUIControlCell: UITableViewCell { 12 | func longPressValid(_ point:CGPoint)->Bool{ 13 | return editImageView.frame.contains(point) 14 | } 15 | @IBOutlet weak var editImageView: UIImageView! 16 | @IBOutlet weak var customLabel: UILabel! 17 | override func awakeFromNib() { 18 | super.awakeFromNib() 19 | // Initialization code 20 | } 21 | 22 | override func setSelected(_ selected: Bool, animated: Bool) { 23 | super.setSelected(selected, animated: animated) 24 | 25 | // Configure the view for the selected state 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /DraggableTableView/DragSpecialUIControlCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 38 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /DraggableTableView/DragSpecialUIControlController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // DragSpecialUIControlController.swift 3 | // DragableTableExtension 4 | // 5 | // Created by huangwenchen on 16/9/12. 6 | // Copyright © 2016年 Leo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class DragSpecialUIControlController: UITableViewController,DragableTableDelegate{ 12 | 13 | var dataArray:NSMutableArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18] 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | tableView.register(UINib(nibName: "DragSpecialUIControlCell", bundle: nil), forCellReuseIdentifier: "cell") 18 | //Set up dragable 19 | self.tableView.dragable = true 20 | self.tableView.dragableDelegate = self 21 | } 22 | // MARK: - DragableTableDelegate 23 | func tableView(_ tableView: UITableView, dragCellFrom fromIndexPath: IndexPath, toIndexPath: IndexPath) { 24 | dataArray.exchangeObject(at: fromIndexPath.row, withObjectAt: toIndexPath.row) 25 | } 26 | func tableView(_ tableView: UITableView, canDragCellFrom indexPath: IndexPath, withTouchPoint point: CGPoint) -> Bool { 27 | let cell = tableView.cellForRow(at: indexPath) as! DragSpecialUIControlCell 28 | return cell.longPressValid(point) 29 | } 30 | // MARK: - Table view data source 31 | override func numberOfSections(in tableView: UITableView) -> Int { 32 | return 1 33 | } 34 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 35 | return dataArray.count 36 | } 37 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 38 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? DragSpecialUIControlCell 39 | cell?.customLabel?.text = "\(dataArray[indexPath.row])" 40 | return cell! 41 | } 42 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 43 | return 100.0 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /DraggableTableView/FixFirstCellController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TableViewController.swift 3 | // DragableTableExtension 4 | // 5 | // Created by huangwenchen on 16/9/8. 6 | // Copyright © 2016年 Leo. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | 12 | class TableViewController: UITableViewController,DragableTableDelegate { 13 | 14 | var dataArray:NSMutableArray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18] 15 | override func viewDidLoad() { 16 | super.viewDidLoad() 17 | 18 | tableView.register(UINib(nibName: "CustomTableViewCell", bundle: nil), forCellReuseIdentifier: "cell") 19 | //Set up dragable 20 | self.tableView.dragable = true 21 | self.tableView.dragableDelegate = self 22 | 23 | } 24 | 25 | // MARK: - DragableTableDelegate - 26 | func tableView(_ tableView: UITableView, canDragCellTo indexPath: IndexPath) -> Bool { 27 | return indexPath.row > 0 28 | } 29 | func tableView(_ tableView: UITableView, canDragCellFrom indexPath: IndexPath, withTouchPoint point: CGPoint) -> Bool { 30 | return indexPath.row > 0 31 | } 32 | func tableView(_ tableView: UITableView, dragCellFrom fromIndexPath: IndexPath, toIndexPath: IndexPath) { 33 | dataArray.exchangeObject(at: fromIndexPath.row, withObjectAt: toIndexPath.row) 34 | } 35 | // MARK: - Table view data source 36 | override func numberOfSections(in tableView: UITableView) -> Int { 37 | return 1 38 | } 39 | 40 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 41 | return dataArray.count 42 | } 43 | 44 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 45 | let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as? CustomTableViewCell 46 | cell?.customLabel?.text = "\(dataArray[indexPath.row])" 47 | return cell! 48 | } 49 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 50 | return 100.0 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /DraggableTableView/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /DraggableTableView/edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeoMobileDeveloper/DraggableTableView/556ae44793706cd8fd72d3594c39e13392aaf612/DraggableTableView/edit.png -------------------------------------------------------------------------------- /DraggableTableView/image2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeoMobileDeveloper/DraggableTableView/556ae44793706cd8fd72d3594c39e13392aaf612/DraggableTableView/image2.jpg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 Leo 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # DraggableTableView 3 | 4 | [![Version](https://img.shields.io/cocoapods/v/DraggableTableView.svg?style=flat)](http://cocoapods.org/pods/DraggableTableView) [![Platform](http://img.shields.io/badge/platform-ios-blue.svg?style=flat 5 | )](https://developer.apple.com/iphone/index.action) 6 | [![Language](http://img.shields.io/badge/language-swift-brightgreen.svg?style=flat 7 | )](https://developer.apple.com/swift) 8 | [![License](http://img.shields.io/badge/license-MIT-lightgrey.svg?style=flat 9 | )](http://mit-license.org) 10 | 11 | DraggableTableView is a `UITableView` extesntion to make tableview draggable by long press. 12 | 13 | ## Features 14 | - [x] Default 15 | 16 | 17 | 18 | 19 | 20 | - [x] Special cell fixed 21 | 22 | 23 | 24 | - [x] Only subview in cell is dragable 25 | 26 | 27 | 28 | ## Require 29 | 30 | - iOS 8 31 | - Swift 3 32 | 33 | 34 | ## Install 35 | 36 | CocoaPod 37 | 38 | ``` 39 | pod "DraggableTableView" 40 | ``` 41 | 42 | 43 | ## Useage 44 | 45 | Enable dragable and set delegate 46 | 47 | ``` 48 | self.tableView.dragable = true 49 | self.tableView.dragableDelegate = self 50 | ``` 51 | 52 | In delegate method, 53 | 54 | ``` 55 | //Required, manage data source here 56 | func tableView(tableView: UITableView, dragCellFrom fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) 57 | 58 | //Optional, decide if a cell can be draged from 59 | func tableView(tableView: UITableView, canDragCellTo indexPath: NSIndexPath) -> Bool 60 | 61 | //Optional, decide if a cell can be draged to 62 | func tableView(tableView: UITableView, canDragCellFrom indexPath: NSIndexPath, withTouchPoint point: CGPoint) 63 | ``` 64 | 65 | ## Author 66 | 67 | Leo, leomobiledeveloper@gmail.com 68 | 69 | ## License 70 | 71 | DraggableTableView is available under the MIT license. See the LICENSE file for more info. 72 | 73 | -------------------------------------------------------------------------------- /ScreenShot/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeoMobileDeveloper/DraggableTableView/556ae44793706cd8fd72d3594c39e13392aaf612/ScreenShot/1.gif -------------------------------------------------------------------------------- /ScreenShot/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeoMobileDeveloper/DraggableTableView/556ae44793706cd8fd72d3594c39e13392aaf612/ScreenShot/2.gif -------------------------------------------------------------------------------- /ScreenShot/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeoMobileDeveloper/DraggableTableView/556ae44793706cd8fd72d3594c39e13392aaf612/ScreenShot/3.gif --------------------------------------------------------------------------------