0

Because I had some troubles using the default separator line between the UITableViewCell I want to use my own. Therefore I'm using auto layout. C# is the language I used. You can of course provide solutions in Objective-C.

In the constructor of my custom cell I add my view UIView:

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

One has to add it to the superview otherwise it doesn't cover the accessory area. In updateConstraints I set up my constraints:

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

This for example, does work on iOS 8 but not on iOS 7. Also this constraint V:[separator(1)]| would work on iOS 8 but not on iOS 7.

Julian E.
  • 4,687
  • 6
  • 32
  • 49
testing
  • 19,681
  • 50
  • 236
  • 417
  • You need to add subview only in contentView. On iOS 7, I think, contentView in opaque. Or may be subviews can't be added to cell's view... – Sound Blaster Dec 07 '14 at 20:39
  • But the `contentView` doesn't takes the whole width of the cell. The other part (`accessoryView`) is not covered. I tried to adding my line also to the `accessoryView`, but the app crashes then. It seems that there is no parent for the `contentView` on iOS 7. Another idea would be to add a custom image (the same as the indicator) to the contentView and react on touches. Another idea would be to add the line to the `backgroundView`. – testing Dec 09 '14 at 10:20

2 Answers2

0

With my knowledge two possibilites come to my mind to solve this:

  1. Instead of using the default accessory views, use no accessory view at all. Instead fake the accessory views by creating the images needed for the acessory views (screenshot of retina display or using a custom image or drawing itself). If you have your fake accessory view one can add it to the contentView and position it with constraints accordingly. Now you can add a line to the content view while disabling the default separator with TableView.SeparatorStyle = UITableViewCellSeparatorStyle.None;. But you have to add events to the created UIButton which holds the image because AccessoryButtonTapped will not be called anymore. That are many steps only for adding a separator line.

  2. Add the separator line on the background view. This is the approach I took.

First the GradientView class which creates my gradient background view with my separator lines:

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

You don't need two separator lines, but for my selection problem I needed both.

In your custom UITableViewCell you set the background in the initializer accordingly:

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

this.BackgroundView = background;

Of course you don't need the gradient thing so you can leave it out. Than your GradientView will only contain the Draw methow with a few fields.

testing
  • 19,681
  • 50
  • 236
  • 417
0

This code works for me (subclass of 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
}

Code of 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);
}

@end

Sound Blaster
  • 4,778
  • 1
  • 24
  • 32
  • How does `PCTableViewCellSeparatorView` does look like? So you are adding a separate view on the `contentView` and place it at the bottom with height one. For what do you need the cell's property? Why does one need `-64.0f`? Is it to get the separator into the `accessoryView` area? What if Apple would change sizes? I'd have to try your solution out to test if it works under all circumstances. Currently I have a solution but I have to try it out if it "really" works. Otherwise if I have the time I'll look into your solution. – testing Dec 10 '14 at 11:45
  • @testing Custom view class PCTableViewCellSeparatorView : UIView with custom drawRect. Cell's property is needed for me to set separator color. `-64.0f` – this constraint helps to draw line ouside the cell, upper `accessoryView`. May be it's not perfect solution, but I tested it on iPad and iPhone - it's working now. – Sound Blaster Dec 10 '14 at 12:42
  • Ahh OK as I thought. Perhaps you can include PCTableViewCellSeparatorView in your answer if it's not too big. Thanks for providing another approach/workaround. As I said I'll look into your solution if I have the time. Currently, I'm struggling with other iOS bugs ... – testing Dec 10 '14 at 13:02
  • @testing I did it. I use a category for UIScreen but it's simple interface wrapper for [UIScreen mainScreen].scale – Sound Blaster Dec 11 '14 at 12:32
  • @testing Oh, today I found, that my implementation custom separator view brakes cell's auto layout calculation. Stay tuned, I will try to fix it. – Sound Blaster Dec 18 '14 at 09:34