36

Note, I'm looking to make a 1px line, not a 1pt line. Meaning it should be 1px regardless of screen scale (so 0.5pt on Retina devices).

I can do this programmatically, but can I do it in the Interface Builder? For example I cannot set a UIView to have a height of less than 1.

If I can do it in IB then I don't have to declare an outlet and manually set the frame in awakeFromNib.

i_am_jorf
  • 53,608
  • 15
  • 131
  • 222
  • 1
    um... then don't do it in IB... you can create custom view that does the drawing and use the custom view? – Bryan Chen May 14 '14 at 22:32
  • Yes I can. But it would be nice if I can do it in IB to be consistent. If it's not possible, that's fine. Seems like it should be possible. – i_am_jorf May 14 '14 at 23:53
  • possible duplicate of [How to Draw a single point line in iOS](http://stackoverflow.com/questions/22693531/how-to-draw-a-single-point-line-in-ios) – Fattie Aug 30 '14 at 07:41
  • Dupe of a number of QA, http://stackoverflow.com/a/22694062/294884 – Fattie Aug 30 '14 at 07:41
  • If you're trying to use them as borders or other things... I think it's better to use `CALayer` (if possible), `UIView`s are not very efficient to use as such thing. – farzadshbfn Jul 03 '16 at 13:47
  • Just curious, why would you want to do it? What's the point of having thicker line on non-retina display, and extremely thin line on retina one. (And take into consideration, that in the future, your 1px, could be even thinner,assuming higher resolution iDevices) – Paweł Brewczynski Jan 31 '17 at 17:35
  • The designers wanted a 1px line. I think they were trying to mimic Apple's table views that have 1px separators (e.g. Mail -> Inbox). – i_am_jorf Jan 31 '17 at 18:30

10 Answers10

52

Just in case someone else comes here wanting to know how it can be done programmatically, heres how you do it:

Interface Builder

Make a height constraint in IB to the desired view and set the constant to 1.

enter image description here

Then you will need to CTRL+Drag from the constraint into your custom view or ViewController.

Whenever the Xib is loaded, be it in awakeFromNib or viewDidLoad, you are going to set the constant of the constraint to the scale of the display:

Swift

onePixelViewHeightConstraint.constant = 1/UIScreen.main.scale

Objective-C

self.onePixelViewHeightConstraint.constant = 1.f/[UIScreen mainScreen].scale;

Enjoy

Daniel Galasko
  • 23,617
  • 8
  • 77
  • 97
43

I created NSLayoutConstraint subclass:

class HairlineConstraint: NSLayoutConstraint {
    override func awakeFromNib() {
        super.awakeFromNib()

        self.constant = 1.0 / UIScreen.main.scale
    }
}

Then simply create your view in interface builder, add height constraint

Custom view with height constraint

and set its class to HairlineConstraint.

Set constraint class

Done.

haXis
  • 33
  • 6
Marius Kažemėkaitis
  • 1,723
  • 19
  • 22
27

By creating this tiny subclass of NSLayoutConstraint I'm now able to add 1px lines in IB:

@implementation NSLayoutConstraintHairline

-(void)awakeFromNib
{
    [super awakeFromNib];
    if ( self.constant == 1 ) self.constant = 1/[UIScreen mainScreen].scale;
}

@end

Any constraint with a value of 1 can be set to class NSLayoutConstraintHairline to make the constant effectively 1px instead of 1pt.

If you ever decide to change the constant to another value, it will just work as any other constraint.

mvds
  • 45,755
  • 8
  • 102
  • 111
27

With Xcode 6 and introduction of @IBInspectable and @IBDesignable keywords it is definitely possible and rather simple. No need to subclass/outlet anything.

You can do an extension (category) for NSLayoutConstraint with following code (swift):

extension NSLayoutConstraint {

    @IBInspectable var preciseConstant: Int {
        get {
            return Int(constant * UIScreen.mainScreen().scale)
        }
        set {
            constant = CGFloat(newValue) / UIScreen.mainScreen().scale
        }
    }
}

Then you can choose needed constraint in your IB.

IB objects navigator part

Go to its properties and set the value.

IB properties of NSLayoutConstraint

In above case it will render a view with 1 px height on 1x, 2x and 3x devices.

pkamb
  • 33,281
  • 23
  • 160
  • 191
Nevs12
  • 599
  • 6
  • 13
  • 2
    This is cool. But rather obscure that you now have two competing fields specifying the actual `constant` field. Is it guaranteed that the "Precise Constant" always wins from the actual Constant? Now and in the future? I've had my share of bugs that originate in the change of execution order between versions X and Y... – mvds Jun 21 '15 at 20:00
  • 1
    Well, as long as @IBInspectable is just a simple wrapper around User Defined Runtime Attributes I hope there won't be any problems with that, because they are always set in awakeFromNib() after initial view load using setValue:forKeyPath: ([apple doc](https://developer.apple.com/library/mac/recipes/xcode_help-interface_builder/Chapters/AddUserDefinedRuntimeAttributes.html)) – Nevs12 Jun 22 '15 at 19:27
14

In Swift:

@IBOutlet var hairlineConstraint: NSLayoutConstraint! {
    didSet {
        hairlineConstraint.constant = 1 / UIScreen.mainScreen().scale
    }
}
Rudolf Adamkovič
  • 31,030
  • 13
  • 103
  • 118
8

EDIT: This answer was for @2x only devices. At that time @3x was not yet on the market!

Nowadays, @mdvs's answer seems to be the cleanest.


Making 1px line in IB is hard even for retina-only devices. Finally I've achieved it using the User Defined Runtime Attributes.

Here's a screenshot for setting the Height Constraint to 0.5 px (which is 1px on retina devices).

Michał Zygar
  • 4,052
  • 1
  • 23
  • 36
5

Based on @Nevs12 's answer and it's comments, I think it makes more sense to use such thing:

extension NSLayoutConstraint {
    @IBInspectable var usePixels: Bool {
        get {
            return false // default Value
        }
        set {
            if newValue {
                constant = constant / UIScreen.mainScreen().scale
            }
        }
    }
}
farzadshbfn
  • 2,710
  • 1
  • 18
  • 38
2

Seems that it is not possible, one must do it programmatically or build a custom view.

i_am_jorf
  • 53,608
  • 15
  • 131
  • 222
0

You can do it in .xib file. Just edit it as text and set constant="0.5" instead of "1" in your view height constraint

<constraints>
<constraint firstAttribute="height" constant="0.5" id="xUN-dm-ggj"/>
</constraints>

In Interface Builder

-8

Add a 0.5 pixel height constraint via Interface Builder:

Xcode 7.3 right down corner: add Height constraint in Pin.

pkamb
  • 33,281
  • 23
  • 160
  • 191
qk514112
  • 9
  • 1