How to Draw a single point line in iOS

前端 未结 5 666
北恋
北恋 2020-12-01 19:00

I was wondering what is the best way to draw a single point line? My goal is to draw this line in a tableViewCell to make it look just like the native cell separator. I don\

相关标签:
5条回答
  • 2020-12-01 19:18

    Addition to Rémy Virin's answer, using Swift 3.0 Creating LineSeparator class:

    import UIKit
    
    class LineSeparator: UIView {
    
    override func awakeFromNib() {
    
        let sortaPixel: CGFloat = 1.0/UIScreen.main.scale
    
        let topSeparatorView = UIView()
        topSeparatorView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: sortaPixel)
    
        topSeparatorView.isUserInteractionEnabled = false
        topSeparatorView.backgroundColor = self.backgroundColor
    
        self.addSubview(topSeparatorView)
        self.backgroundColor = UIColor.clear
    
        self.isUserInteractionEnabled = false   
        }
    }
    
    0 讨论(0)
  • 2020-12-01 19:29
    shapeLayer.lineWidth = 0.5f;
    

    That's a common mistake and is the reason this is working only some of the time. Sometimes this will overlap pixels on the screen exactly and sometimes it won't. The way to draw a single-point line that always works is to draw a one-point-thick rectangle on integer boundaries, and fill it. That way, it will always match the pixels on the screen exactly.

    To convert from points to pixels, if you want to do that, use the view's scale factor.

    Thus, this will always be one pixel wide:

    CGContextFillRect(con, CGRectMake(0,0,desiredLength,1.0/self.contentScaleFactor));
    

    Here's a screen shot showing the line used as a separator, drawn at the top of each cell:

    enter image description here

    The table view itself has no separators (as is shown by the white space below the three existing cells). I may not be drawing the line in the position, length, and color that you want, but that's your concern, not mine.

    0 讨论(0)
  • 2020-12-01 19:32

    AutoLayout method:

    I use a plain old UIView and set its height constraint to 1 in Interface Builder. Attached it to the bottom via constraints. Interface builder doesn't allow you to set the height constraint to 0.5, but you can do it in code.

    Make a connector for the height constraint, then call this:

    // Note: This will be 0.5 on retina screens
    self.dividerViewHeightConstraint.constant =  1.0/[UIScreen mainScreen].scale 
    

    Worked for me.

    FWIW I don't think we need to support non-retina screens anymore. However, I am still using the main screen scale to future proof the app.

    0 讨论(0)
  • 2020-12-01 19:37

    You have to take into account the scaling due to retina and that you are not referring to on screen pixels. See Core Graphics Points vs. Pixels.

    0 讨论(0)
  • 2020-12-01 19:44

    I did the same with a UIView category. Here are my methods :

    #define SEPARATOR_HEIGHT 0.5
    
    - (void)addSeparatorLinesWithColor:(UIColor *)color
    {
        [self addSeparatorLinesWithColor:color edgeInset:UIEdgeInsetsZero];
    }
    
    
    - (void)addSeparatorLinesWithColor:(UIColor *)color edgeInset:(UIEdgeInsets)edgeInset
    {
    
        UIView *topSeparatorView = [[UIView alloc] initWithFrame:CGRectMake(edgeInset.left, - SEPARATOR_HEIGHT, self.frame.size.width - edgeInset.left - edgeInset.right, SEPARATOR_HEIGHT)];
        [topSeparatorView setBackgroundColor:color];
        [self addSubview:topSeparatorView];
    
        UIView *separatorView = [[UIView alloc] initWithFrame:CGRectMake(edgeInset.left, self.frame.size.height + SEPARATOR_HEIGHT, self.frame.size.width - edgeInset.left - edgeInset.right, SEPARATOR_HEIGHT)];
        [separatorView setBackgroundColor:color];
        [self addSubview:separatorView];
    }
    

    Just to add to Rémy's great answer, it's perhaps even simpler to do this. Make a class UILine.m

    @interface UILine:UIView
    @end
    @implementation UILine
    -(id)awakeFromNib
        {
        // careful, contentScaleFactor does NOT WORK in storyboard during initWithCoder.
        // example, float sortaPixel = 1.0/self.contentScaleFactor ... does not work.
        // instead, use mainScreen scale which works perfectly:
        float sortaPixel = 1.0/[UIScreen mainScreen].scale;
        UIView *topSeparatorView = [[UIView alloc] initWithFrame:
            CGRectMake(0, 0, self.frame.size.width, sortaPixel)];
    
        topSeparatorView.userInteractionEnabled = NO;
        [topSeparatorView setBackgroundColor:self.backgroundColor];
        [self addSubview:topSeparatorView];
    
        self.backgroundColor = [UIColor clearColor];
        self.userInteractionEnabled = NO;
        }
    @end
    

    In IB, drop in a UIView, click identity inspector and rename the class to a UILine. Set the width you want in IB. Set the height to 1 or 2 pixels - simply so you can see it in IB. Set the background colour you want in IB. When you run the app it will become a 1-pixel line, that width, in that colour. (You probably should not be affected by any default autoresize settings in storyboard/xib, I couldn't make it break.) You're done.

    Note: you may think "Why not just resize the UIView in code in awakeFromNib?" Resizing views upon loading, in a storyboard app, is problematic - see the many questions here about it!

    Interesting gotchya: it's likely you'll just make the UIView, say, 10 or 20 pixels high on the storyboard, simply so you can see it. Of course it disappears in the app and you get the pretty one pixel line. But! be sure to remember self.userInteractionEnabled = NO, or it might get over your other, say, buttons!


    2016 solution ! https://stackoverflow.com/a/34766567/294884

    0 讨论(0)
提交回复
热议问题