UITableViewCell 自定义重新排序控件

Posted

技术标签:

【中文标题】UITableViewCell 自定义重新排序控件【英文标题】:UITableViewCell custom reorder control 【发布时间】:2010-08-23 11:45:07 【问题描述】:

有什么方法可以改变 UITableView 处于编辑模式时显示的重新排序控件的图像?我想显示一个 UIImage,而不是通常的灰色条。

我是否必须继承 UITableViewCell 才能做到这一点?

【问题讨论】:

我的回答可能对你有所帮助:***.com/questions/8603359/…> 【参考方案1】:

我猜你现在已经过了很长一段路,但这已经出现在一个新问题中。

在这里查看我的答案:

Change default icon for moving cells in UITableView

【讨论】:

谢谢。当新的解决方案出现时,让老问题保持活力真是太好了,以防有人搜索这个问题! @RaphaelSchweikert,这正是我刚刚发生的事情。 这个问题在发布数年后仍然有用。干得好。【参考方案2】:

我最近遇到了更改重新排序控件的图像的需要,因为我将UITableViewCell 子类化以提供我自己的自定义表格单元格。作为这项工作的一部分,我将单元格的背景更改为默认颜色以外的其他颜色。

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

ios 的各个版本的过程中,UITableViewCell 中的视图层次结构发生了变化。我采取了一种遍历整个视图集的方法,直到找到UITableViewCellReorderControl 私有类。我相信这将适用于 iOS 5 和所有后续 iOS 版本。请注意,虽然 UITableViewCellReorderControl 类本身是私有的,但我没有使用任何私有 API 来查找它。

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

-(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);
                
            
        
    

您的里程可能会有所不同;我希望这对你有用。

【讨论】:

【参考方案3】:

这是我基于 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 的单元格(不是contentView)中直接添加了一个UIImageView,将其定位,当adjustSize 被调用时,我只需将图像视图放在前面,它覆盖了重新排序控件而不必依赖任何私有 API。

【讨论】:

【参考方案4】:

我最近在这方面做了一些工作,但没有完成。我尝试设置自己的editingAccesoryView,但无法更改重新排序控件。奇怪的。

我的猜测是它与 UITableviewCell 文档中的以下评论有关:showsReorderControl

如果值为 YES ,则重新排序 控制暂时取代任何 附件视图。

换句话说,editingAccessoryView 正在被重新排序控件视图所取代,这可能是我们无法覆盖重新排序控件的原因。希望有人能找到解决方法。

【讨论】:

【参考方案5】:

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

顺便说一句,我会提醒您在执行此操作时要小心。当您将自定义图形替换为系统标准(例如重新排序图形)时,您将面临使用户感到困惑的严重风险。标准 UI 语法告诉他们在重新排序时期待标准图形,他们可能不理解您的自定义图形的重要性。

【讨论】:

和默认视图没什么区别;线条是波浪形的,而不是直线的…… 我需要在哪里执行此操作?如果我在实例化单元格时这样做,我唯一得到的是默认重新排序视图左侧的附加视图。拖动新图像时,我也无法重新排列单元格。我尝试设置cell.editingAccessoryType = UITableViewCellEditingStyleNone;,但无济于事。 文档说使用UITableViewCellAccessoryDetailDisclosureButton 或编辑附件视图永远不会出现或响应。阅读 UITableView 文档了解详细信息。【参考方案6】:

也许我们都想多了。 :)

只需将自定义 UIImageView 放在默认移动附件的顶部,以便将其覆盖。完成。

【讨论】:

以上是关于UITableViewCell 自定义重新排序控件的主要内容,如果未能解决你的问题,请参考以下文章

进入编辑/重新排序模式时的 UITableViewCell 自定义绘图和动画

编辑自定义 UITableViewCell 时不出现插入/删除编辑控件

实现 willTransitionToState: 时自定义 UITableViewCell 不显示编辑控件

##DAY12 UITableViewCell自定义

自定义UITableViewCell

在运行时重新加载自定义 UITableViewCell 的 Nib