如何在不显示重新排序控件的情况下重新排序uitableviewcell?

5
我正在为我的iPad应用程序使用spliviewcontroller。我还为位于spliview左侧的uitableview实现了重新排序功能。我想要实现的是,用户可以重新排序tableCell,但不需要触摸三个白色条。用户应该能够在单元格的任何位置触摸并重新排序它。这可能吗?

我遇到了这个答案,可能会有所帮助...这不是一个简单的解决方案,但它应该可以工作:https://dev59.com/sm035IYBdhLWcg3wGMDZ - Zane Claes
可能是重新排序UITableView而没有重新排序控件的重复问题。 - Bo Persson
5个回答

3
下面的类将隐藏重新排序控件,并使整个UITableViewCell可触摸以进行重新排序。此外,它会负责重新调整内容视图至其原始大小,这对于自动布局非常重要。
@interface UITableViewCellReorder : UITableViewCell
{
    __weak UIView *_reorderControl;
}

@implementation UITableViewCellReorder

#define REORDER_CONTROL_CLASSNAME @"UITableViewCellReorderControl"

/*
 Override layoutSubviews to resize the content view's frame to its original size which is the size 
 of the cell. This is important for autolayout!
 Do not call this method on super, as we don't need any further layouting wihtin the cell itself.
 */

- (void)layoutSubviews
{
    self.contentView.frame = CGRectMake(0, 0, self.frame.size.width, self.frame.size.height);
    [self setAndHideReorderControl];
}

/*
 Find the reorder control, store a reference and hide it.
 */

- (void) setAndHideReorderControl
{
    if (_reorderControl)
        return;

    // > iOS 7
    for(UIView* view in [[self.subviews objectAtIndex:0] subviews])
        if([[[view class] description] isEqualToString:REORDER_CONTROL_CLASSNAME])
            _reorderControl = view;

    // < iOS 7
    if (!_reorderControl)
        for(UIView* view in self.subviews)
            if([[[view class] description] isEqualToString:REORDER_CONTROL_CLASSNAME])
                _reorderControl = view;

    if (_reorderControl)
    {
        [_reorderControl setHidden:YES];
    }
}


#pragma mark - Touch magic

/*
 Just perform the specific selectors on the hidden reorder control to fire touch events on the control.
 */

- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (_reorderControl && [_reorderControl respondsToSelector:@selector(beginTrackingWithTouch:withEvent:)])
    {
        UITouch * touch = [touches anyObject];
        [_reorderControl performSelector:@selector(beginTrackingWithTouch:withEvent:) withObject:touch withObject:event];
    }

    [super touchesBegan:touches withEvent:event];
    [self.nextResponder touchesBegan:touches withEvent:event];
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (_reorderControl && [_reorderControl respondsToSelector:@selector(continueTrackingWithTouch:withEvent:)])
    {
        UITouch * touch = [touches anyObject];
        [_reorderControl performSelector:@selector(continueTrackingWithTouch:withEvent:) withObject:touch withObject:event];
    }

    [super touchesMoved:touches withEvent:event];
    [self.nextResponder touchesMoved:touches withEvent:event];
}

- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (_reorderControl && [_reorderControl respondsToSelector:@selector(cancelTrackingWithEvent:)])
    {
        [_reorderControl performSelector:@selector(cancelTrackingWithEvent:) withObject:event];
    }

    [super touchesCancelled:touches withEvent:event];
    [self.nextResponder touchesCancelled:touches withEvent:event];
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (_reorderControl && [_reorderControl respondsToSelector:@selector(endTrackingWithTouch:withEvent:)])
    {
        UITouch * touch = [touches anyObject];
        [_reorderControl performSelector:@selector(endTrackingWithTouch:withEvent:) withObject:touch withObject:event];
    }

    [super touchesEnded:touches withEvent:event];
    [self.nextResponder touchesEnded:touches withEvent:event];
}

@end


1
我从 ANami 的答案中借鉴了一些内容,并将其与另一篇文章合并,以便在 Xcode 7.3 和 iOS 9 上使用 Swift 2.2。我建议将此作为基类:
    //
    //  MoveableTableViewCell.swift
    //  ReorderTableTest
    //
    //  Created by Geoff on 05/06/16.
    //  Copyright © 2016 Think#. MIT License, free to use.
    //

    import UIKit

    class MoveableTableViewCell: UITableViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

    override func setEditing(editing: Bool, animated: Bool) {
        super.setEditing(editing, animated: true)
        //self.showsReorderControl = false

        if (editing) {


            for view in subviews as [UIView] {
                if view.dynamicType.description().rangeOfString("Reorder") != nil {

                    // resized grip
                    let resized = UIView(frame: CGRectMake(0, 0, CGRectGetMaxX(view.frame), CGRectGetMaxY(view.frame)))
                    resized.addSubview(view)
                    self.addSubview(resized)

                    // remove image
                    for img:AnyObject in view.subviews {
                        if (img is UIImageView) {
                            (img as! UIImageView).image = nil
                        }
                    }

                    // determine diff and ratio
                    let diff = CGSizeMake(resized.frame.width - view.frame.width, resized.frame.height - view.frame.height)
                    let ratio = CGSizeMake(resized.frame.width / view.frame.width, resized.frame.height / view.frame.height)

                    // transform!
                    var transform = CGAffineTransformIdentity
                    transform = CGAffineTransformScale(transform, ratio.width, ratio.height)
                    transform = CGAffineTransformTranslate(transform, -diff.width / 2.0, -diff.height / 2.0)
                    resized.transform = transform


                }
            }
        }
    }

}

1
我知道这是一个老问题,但这里有一个可以帮助未来冒险者的Swift助手。
/*
    THIS IS A HACK!
    It uses undocumented controls and class names, and will need to be revised with every iOS release.

    Usage:
        Call the 'transform' method after the cell is displayed - i.e. tableView(tableView: UITableView!, willDisplayCell cell: UITableViewCell! ...

    Adopted from:
        http://b2cloud.com.au/how-to-guides/reordering-a-uitableviewcell-from-any-touch-point

    In case of failure: 
        - print names of all subviews
        - find the new 'UITableViewCellReorderControl' and reflect changes to the code below
*/
struct MovableTableViewCell {
    static func transform(cell:UITableViewCell) {
        var reorder = cell.getSubviewByName("UITableViewCellReorderControl")

        if (reorder == nil) {
            println("UITableViewCellReorderControl was not found. Reorder control will remain unchanged.")
            return
        }

        // resized grip
        var resized = UIView(frame: CGRectMake(0, 0, CGRectGetMaxX(reorder!.frame), CGRectGetMaxY(reorder!.frame)))
        resized.addSubview(reorder!)
        cell.addSubview(resized)

        // remove image
        for img:AnyObject in reorder!.subviews {
            if (img is UIImageView) {
                (img as UIImageView).image = nil
            }
        }

        // determine diff and ratio
        var diff = CGSizeMake(resized.frame.width - reorder!.frame.width, resized.frame.height - reorder!.frame.height)
        var ratio = CGSizeMake(resized.frame.width / reorder!.frame.width, resized.frame.height / reorder!.frame.height)

        // transform!
        var transform = CGAffineTransformIdentity
        transform = CGAffineTransformScale(transform, ratio.width, ratio.height)
        transform = CGAffineTransformTranslate(transform, -diff.width / 2.0, -diff.height / 2.0)
        resized.transform = transform
    }
}


extension UIView {
    func getSubviewByName(name:String) -> UIView? {

        if (object_getClassName(self) == name.bridgeToObjectiveC().UTF8String) {
            return self
        }

        for v in (self.subviews as Array<UIView>) {
            var child = v.getSubviewByName(name)

            if (child != nil) {
                return child
            }
        }

        return nil
    }
}

+1 很好,为什么不制作一个库并托管,并在你的回答中提到 :) - mAc

0

这里是我编写的一些代码,可以让用户基于点击单元格的任何部分对其进行重新排序。我使用了UITableView的子类,并使用touchesBegantouchesEnded方法来确定被点击的单元格并将其来回移动。这是相当基础的代码,如果您有任何问题,请告诉我。

class ReorderTableView: UITableView {

var customView:UIImageView?
var oldIndexPath:NSIndexPath?

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    guard let touch1 = touches.first else{
        return
    }

    oldIndexPath = self.indexPathForRowAtPoint(touch1.locationInView(self))
    guard (oldIndexPath != nil) else{
        return
    }
    let oldCell = self.cellForRowAtIndexPath(self.oldIndexPath!)

    customView = UIImageView(frame: CGRectMake(0, touch1.locationInView(self).y - 20, self.frame.width, 40))
    customView?.image = screenShotView(oldCell!)
    customView?.layer.shadowColor = UIColor.blackColor().CGColor
    customView?.layer.shadowOpacity = 0.5
    customView?.layer.shadowOffset = CGSizeMake(1, 1)

    self.addSubview(customView!)
    oldCell?.alpha = 0
}

override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {

    guard let touch1 = touches.first else{
        return
    }
    let newIndexPath = self.indexPathForRowAtPoint(touch1.locationInView(self))
    guard newIndexPath != nil else{
        return
    }
    guard oldIndexPath != nil else{
        return
    }
    if newIndexPath != oldIndexPath{
        self.moveRowAtIndexPath(oldIndexPath!, toIndexPath: newIndexPath!)
        oldIndexPath = newIndexPath
        self.cellForRowAtIndexPath(self.oldIndexPath!)!.alpha = 0
    }
    self.customView!.frame.origin = CGPointMake(0, touch1.locationInView(self).y - 20)
}

override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
    self.customView?.removeFromSuperview()
    self.customView = nil
    guard (oldIndexPath != nil) else{
        return
    }
    self.cellForRowAtIndexPath(self.oldIndexPath!)!.alpha = 1
}

func screenShotView(view: UIView) -> UIImage? {

    let rect = view.bounds
    UIGraphicsBeginImageContextWithOptions(rect.size,true,0.0)
    let context = UIGraphicsGetCurrentContext()

    CGContextTranslateCTM(context, 0, -view.frame.origin.y);
    self.layer.renderInContext(context!)
    let capturedImage = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext()
    return capturedImage
}

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接