UITableViewCell自定义重新排序控件

15

当UITableView处于编辑模式时,有没有办法更改重新排序控件显示的图像?我有一张UIImage想要显示,而不是通常的灰色条。

我必须子类化UITableViewCell才能实现这个目的吗?


我的回答可能会对你有所帮助:https://dev59.com/B2oy5IYBdhLWcg3wYM2B#56911018 - bqlin
6个回答

9

谢谢。保持旧问题的存活很棒,因为新解决方案出现了,以防有人搜索这个问题! - Raphael Schweikert
@RaphaelSchweikert,这正是我刚刚经历的。 - mattsson
这个问题在发布多年后仍然非常有用。干得好。 - Unome

6

最近我遇到了需要更改重新排序控件图像的需求,因为我子类化了UITableViewCell以提供自己的自定义表格单元。为此,我将单元格的背景更改为与默认颜色不同的颜色。

一切都正常工作,但当我将UITableView设置为编辑模式时,重新排序控件会出现白色背景 - 而不是我用于单元格的背景颜色。这看起来不好,我希望背景匹配。

在各个iOS版本中,UITableViewCell中的视图层次结构已经发生了变化。我采取了一种方法,将遍历整个视图集,直到找到UITableViewCellReorderControl私有类。我相信这将适用于iOS 5和所有随后的iOS版本(截至本答案发布时)。请注意,尽管UITableViewCellReorderControl类本身是私有的,但我没有使用任何私有API来查找它。

首先,这里是扫描重新排序控件的代码;我假设文本“Reorder”将出现在类名中 - 这是苹果未来可能会更改的内容:

-(UIView *) findReorderView:(UIView *) view
{
    UIView *reorderView = nil;
    for (UIView *subview in view.subviews)
    {
        if ([[[subview class] description] rangeOfString:@"Reorder"].location != NSNotFound)
        {
            reorderView = subview;
            break;
        }
        else
        {
            reorderView = [self findReorderView:subview];
            if (reorderView != nil)
            {
                break;
            }
        }
    }
    return reorderView;
}

在您的自定义UITableViewCell子类中,您将重写-(void) setEditing:animated:方法,并在此处查找重新排序控件。如果您尝试在表格不处于编辑模式时查找此控件,则重新排序控件不会出现在该单元格的视图层次结构中。
-(void) setEditing:(BOOL)editing animated:(BOOL)animated
{
    [super setEditing:editing animated:animated];
    if (editing)
    {
        // find the reorder view here
        // place the previous method either directly in your
        // subclassed UITableViewCell, or in a category
        // defined on UIView
        UIView *reorderView = [self findReorderView:self];
        if (reorderView)
        {
            // here, I am changing the background color to match my custom cell
            // you may not want or need to do this
            reorderView.backgroundColor = self.contentView.backgroundColor;
            // now scan the reorder control's subviews for the reorder image
            for (UIView *sv in reorderView.subviews)
            {
                if ([sv isKindOfClass:[UIImageView class]])
                {
                    // and replace the image with one that you want
                    ((UIImageView *)sv).image = [UIImage imageNamed:@"yourImage.png"];
                    // it may be necessary to properly size the image's frame
                    // for your new image - in my experience, this was necessary
                    // the upper left position of the UIImageView's frame
                    // does not seem to matter - the parent reorder control
                    // will center it properly for you
                    sv.frame = CGRectMake(0, 0, 48.0, 48.0);
                }
            }
        }
    }
}

可能会因人而异;希望这对你有用。


2

这是基于Rick Morgan答案的Swift解决方案:

func adjustSize() {
    // we're trying to leverage the existing reordering controls, however that means the table must be kept in editing mode,
    // which shrinks the content area to less than full width to make room for editing controls
    let cellBounds = bounds
    let contentFrame = contentView.convert(contentView.bounds, to: self)

    let leftPadding = contentFrame.minX - cellBounds.minX
    let rightPadding = cellBounds.maxX - contentFrame.maxX

    // adjust actual content so that it still covers the full length of the cell
    contentLeadingEdge.constant = -leftPadding
    // this should pull our custom reorder button in line with the system button
    contentTrailingEdge.constant = -rightPadding

    // make sure we can still see and interact with the content that overhangs
    contentView.clipsToBounds = false

    // recursive search of the view tree for a reorder control
    func findReorderControl(_ view: UIView) -> UIView? {
        // this is depending on a private API, retest on every new iPad OS version
        if String(describing: type(of: view)).contains("Reorder") {
            return view
        }
        for subview in view.subviews {
            if let v = findReorderControl(subview) {
                return v
            }
        }
        return nil
    }

    // hunt down the system reorder button and make it invisible but still operable
    findReorderControl(self)?.alpha = 0.05   // don't go too close to alpha 0, or it will be considered hidden
}

这个方法效果不错。 contentLeadingEdgecontentTrailingEdge 是我在Interface Builder中设置的布局约束,用于contentView和实际内容之间。我的代码从tableView(_:willDisplay:forRowAt:)委托方法中调用adjustSize方法。
然而,最终我采用了Clifton的建议,只是覆盖了重新排序控件。 我在awakeFromNib中直接向单元格添加了UIImageView(而不是contentView),将其定位,并且当调用adjustSize时,我只需将图像视图置于前端即可,它就可以覆盖重新排序控件,而无需依赖任何私有API。

1

最近我花了一些时间在这个问题上,但是没有得到解决。我尝试设置自己的editingAccessoryView,但无法改变重新排序控件。很奇怪。

我猜测这可能与UITableviewCell文档中关于showsReorderControl的以下注释有关:

如果值为YES,则重新排序控件会暂时替换任何附加视图。

换句话说,编辑附件视图被重新排序控件视图替换,这可能是我们无法覆盖重新排序控件的原因。希望有人能找到解决方法。


0

您可以将单元格的 editingAccessoryView 属性设置为包含所需图像的图像视图。

顺便提一句,当您这样做时,请注意小心。当您用自定义图像代替重新排序图形等系统标准时,存在严重混淆用户的风险。标准 UI 语法告诉他们在重新排序时期望标准图形,他们可能不理解您自定义图像的意义。


它与默认视图并没有太大的区别;线条是波浪形而不是直线... - Raphael Schweikert
我需要在哪里做这个?如果我在实例化单元格时这样做,我得到的唯一结果是在默认重新排序视图左侧留下一个额外的视图。当拖动新图像时,我也无法重新排序单元格。我尝试设置 cell.editingAccessoryType = UITableViewCellEditingStyleNone; 但没有用。 - Raphael Schweikert
文档中提到要使用 UITableViewCellAccessoryDetailDisclosureButton,否则编辑附件视图将不会出现或响应。请阅读UITableView文档以获取详细信息。 - TechZen

0
也许我们都想得太多了。 :)
只需将自定义的 UIImageView 放在默认移动附件的顶部,以覆盖它。完成。

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