在 iOS 7 上的 UITableViewCell 之间绘制自定义分隔线

Posted

技术标签:

【中文标题】在 iOS 7 上的 UITableViewCell 之间绘制自定义分隔线【英文标题】:Draw custom separator line between UITableViewCell on iOS 7 【发布时间】:2014-11-12 10:19:03 【问题描述】:

因为我在使用UITableViewCell 之间的默认分隔线时遇到了一些麻烦,我想使用我自己的。因此我使用自动布局。 C# 是我使用的语言。你当然可以在 Objective-C 中提供解决方案。

在我的自定义单元格的构造函数中,我添加了我的视图UIView

separator = new DividerView ();
ContentView.Superview.AddSubview (separator);

必须将其添加到超级视图中,否则它不会覆盖附件区域。在updateConstraints 我设置了我的约束:

separator.TranslatesAutoresizingMaskIntoConstraints = false;

this.ContentView.Superview.AddConstraints (NSLayoutConstraint.FromVisualFormat ("H:|[separator]|", (NSLayoutFormatOptions)0, null, viewsDictionary));
this.ContentView.Superview.AddConstraints (NSLayoutConstraint.FromVisualFormat ("V:|-(82@999)-[separator(1)]|", (NSLayoutFormatOptions)0, null, viewsDictionary));

例如,这适用于 ios 8,但不适用于 iOS 7。此外,此约束 V:[separator(1)]| 将适用于 iOS 8,但不适用于 iOS 7。

【问题讨论】:

只需要在contentView中添加子视图即可。在 iOS 7 上,我认为 contentView 是不透明的。或者可能是子视图无法添加到单元格的视图中...... contentView 不会占用单元格的整个宽度。另一部分 (accessoryView) 未涵盖。我尝试将我的线路也添加到accessoryView,但应用程序随后崩溃。在 iOS 7 上,contentView 似乎没有父级。另一个想法是向 contentView 添加自定义图像(与指示器相同)并对触摸做出反应。另一个想法是将行添加到backgroundView 【参考方案1】:

据我所知,我想到了两种可能来解决这个问题:

    不要使用默认的附件视图,而是根本不使用附件视图。而是通过创建辅助视图所需的图像来伪造辅助视图(视网膜显示的屏幕截图或使用自定义图像或drawing 本身)。如果您有假附件视图,可以将其添加到 contentView 并相应地使用约束对其进行定位。 现在您可以在内容视图中添加一行,同时使用TableView.SeparatorStyle = UITableViewCellSeparatorStyle.None; 禁用默认分隔符。但是您必须将事件添加到创建的包含图像的UIButton,因为AccessoryButtonTapped 将不再被调用。这只是添加分隔线的许多步骤。

    在背景视图上添加分隔线。这是我采取的方法。

首先是 GradientView 类,它使用我的分隔线创建我的渐变背景视图:

public class GradientView : UIView

    // accessors
    private CAShapeLayer line;
    private bool shouldShowSeparatorLine = false;

    private CAGradientLayer gradientLayer 
        // read-only
        get  return (CAGradientLayer)this.Layer; 
    

    public CGColor[] Colors 
        // set the colors of the gradient layer
        get  return this.gradientLayer.Colors; 
        set  this.gradientLayer.Colors = value; 
    

    public GradientView(bool shouldShowSeparatorLine = false)
    
        this.shouldShowSeparatorLine = shouldShowSeparatorLine;

        this.BackgroundColor = UIColor.Clear;
    

    [Export ("layerClass")]
    public static Class LayerClass ()
    
        // use a different Core Animation layer for its backing store
        // normally a CALayer is used for a UIView
        return new Class (typeof(CAGradientLayer));
    


    public override void Draw (RectangleF rect)
    
        base.Draw (rect);

        if (shouldShowSeparatorLines) 

            // get graphics context
            CGContext context = UIGraphics.GetCurrentContext ();

            context.SetStrokeColor(UIColor.FromRGB (21,66,139).CGColor);
            context.SetLineWidth (1.0f);
            context.SetShouldAntialias (false);

            float top = 0;
            if (Util.UserInterfaceIdiomIsPhone) 
                top = 0;
             else 
                top = 1;
            

            // top
            // start point
            context.MoveTo (0, top);
            // end point
            context.AddLineToPoint (rect.Width, top);
            // draw the path
            context.DrawPath (CGPathDrawingMode.Stroke);

            // bottom
            // start point
            context.MoveTo (0, rect.Height);
            // end point
            context.AddLineToPoint (rect.Width, rect.Height);
            // draw the path
            context.DrawPath (CGPathDrawingMode.Stroke);
        
    

你不需要两条分隔线,但对于我的选择问题,我需要两条。

在您的自定义 UITableViewCell 中,您相应地在初始化程序中设置背景:

GradientView background = new GradientView (true);
background.Colors = new CGColor[] 
    UIColor.White.CGColor,
    UIColor.White.CGColor,
    UIColor.Blue.CGColor
;

this.BackgroundView = background;

当然,你不需要渐变的东西,所以你可以把它省掉。比您的 GradientView 仅包含带有几个字段的 Draw 方法。

【讨论】:

【参考方案2】:

此代码适用于我(UITableViewCell 的子类):

- (void)awakeFromNib 
    // Initialization code
    [super awakeFromNib];
    PCTableViewCellSeparatorView *sV = [[PCTableViewCellSeparatorView alloc] initWithFrame:CGRectMake(0, 0, 0, 1.0)]; // my custom subclass of UIView for drawing 1px line
    sV.backgroundColor = [UIColor clearColor];
    self.accessoryView.backgroundColor = [UIColor clearColor];
    [sV setTranslatesAutoresizingMaskIntoConstraints:NO];
    [self.contentView addSubview:sV];
    // horizontal
    NSNumber *space     = [NSNumber numberWithFloat:0.0f];
    NSNumber *space2    = [NSNumber numberWithFloat:-64.0f]; // MAGIC HERE
    NSDictionary *views = NSDictionaryOfVariableBindings(sV, self.contentView);
    NSDictionary *metrics = NSDictionaryOfVariableBindings(space, space2);
    NSString *horizontalFormat =@"|-space-[sV]-space2-|";
    NSArray* horizontal = [NSLayoutConstraint constraintsWithVisualFormat:horizontalFormat                                                              options:NSLayoutFormatDirectionLeadingToTrailing
                                                              metrics:metrics
                                                                views:views];
    // height
    NSLayoutConstraint *height = [NSLayoutConstraint constraintWithItem:sV attribute:NSLayoutAttributeHeight relatedBy:NSLayoutRelationEqual toItem:nil attribute:0 multiplier:1.0f constant:1.0f];
    // bottom
    NSLayoutConstraint *vertical1 = [NSLayoutConstraint constraintWithItem: sV
                                                             attribute: NSLayoutAttributeBottom
                                                             relatedBy: NSLayoutRelationEqual
                                                                toItem: self.contentView
                                                             attribute: NSLayoutAttributeBottom
                                                            multiplier: 1.0f
                                                              constant: 0.0f
                                 ];
    [self.contentView addConstraints:horizontal];
    [self.contentView addConstraints:@[vertical1,height]];
    self.separatorView = sV; // my own cell's property

PCTableViewCellSeparatorView的代码:

#import <UIKit/UIKit.h>
@interface PCTableViewCellSeparatorView : UIView

@end

#import "PCTableViewCellSeparatorView.h"
#import "UIColor+Utilities.h"

@implementation PCTableViewCellSeparatorView

// -----------------------------------------------------------------------
#pragma mark - Drawing
// -----------------------------------------------------------------------
- (void)drawRect:(CGRect)rect

    [super drawRect:rect];

    CGFloat inset;
    switch ([UIScreen screenScale]) 
        case ScreenScale2x:
            inset = 0.5f/2.0f;
            break;
        case ScreenScale3x:
            inset = 0.5f/3.0f;
            break;
        default:
            inset = 0.5f;
            break;
    

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    // draw
    CGContextSetLineWidth(context, inset);
    CGContextSetStrokeColorWithColor(context, [UIColor colorWithRGB:PCColorGrey].CGColor);
    CGContextMoveToPoint(context, 0, CGRectGetHeight(rect)-inset);
    CGContextAddLineToPoint(context, CGRectGetWidth(rect), CGRectGetHeight(rect)-inset);
    CGContextStrokePath(context);
    CGContextRestoreGState(context);

@结束

【讨论】:

PCTableViewCellSeparatorView 看起来如何?因此,您要在 contentView 上添加一个单独的视图,并将其放置在高度为 1 的底部。你需要细胞的属性做什么?为什么需要-64.0f?是否将分隔符放入accessoryView 区域?如果苹果改变尺寸怎么办?我必须尝试您的解决方案以测试它是否在所有情况下都有效。目前我有一个解决方案,但如果它“真的”有效,我必须尝试一下。否则,如果我有时间,我会研究您的解决方案。 @testing 自定义视图类 PCTableViewCellSeparatorView :带有自定义 drawRect 的 UIView。我需要单元格的属性来设置分隔符颜色。 -64.0f - 此约束有助于在单元格外画线,上方 accessoryView。可能它不是完美的解决方案,但我在 iPad 和 iPhone 上对其进行了测试——它现在可以工作了。 嗯,正如我所想。如果 PCTableViewCellSeparatorView 不太大,也许您可​​以在答案中包含它。感谢您提供另一种方法/解决方法。正如我所说,如果我有时间,我会研究你的解决方案。目前,我正在与其他 iOS 错误作斗争...... @testing 我做到了。我为 UIScreen 使用了一个类别,但它是 [UIScreen mainScreen].scale 的简单界面包装器 @testing 哦,今天我发现,我的实现自定义分隔符视图会制动单元格的自动布局计算。请继续关注,我会努力解决的。

以上是关于在 iOS 7 上的 UITableViewCell 之间绘制自定义分隔线的主要内容,如果未能解决你的问题,请参考以下文章

UIScrollView 框架在 iOS 8 和 iOS 7 上的大小不同

iOS 7 上的 UIBarButtonSystemItemRefresh

如何在 iOS 7.1 中更改 TabBar 上的图像和标签颜色?

iOS 6 和 iOS 7 上的 UICollectionView 重新加载

在调用 willRotateToInterfaceOrientation 时,iOS 7 与 iOS 8 上的 mainScreen 边界大小不同

iOS 7.1 上的 XLForm 空白