neo
neo

Reputation: 1404

How to draw parallelogram like figure in iOS?

I should achieve following result:

enter image description here

As you see, it contains list of parallelograms(not rectangular) with label inside of it. Also, it can be dynamic, which means I can use stackview. First of all, let's draw our parallelogram like view:

class ParallelogramView: UIView {

override init(frame: CGRect) {
    super.init(frame: frame)
    backgroundColor = .clear
}


override func draw(_ rect: CGRect) {
    super.draw(rect)
    let path = UIBezierPath()
    /// let's start from this point
    path.move(to: CGPoint(x: 8, y: 0))
    /// drawing horizontal top line till we can
    path.addLine(to: CGPoint(x: rect.maxX, y: 0))
    /// drawing to bottom but little bit to left
    path.addLine(to: CGPoint(x: rect.maxX - 16, y: rect.maxY))
    /// drawing from right to left
    path.addLine(to: CGPoint(x: 0, y: rect.maxY))
    /// connecting all
    path.close()
    
    /// just for sample filling it with some color. I don't know how to change it later :(
    UIColor.red.setFill()
    
    path.fill()
}
}

All code are commented. After that, let's define a LabelView which contains our parallelogram with label inside of it.

class LabelView: UIView {

/// out text
lazy var label: UILabel = {
    let label = UILabel()
    label.numberOfLines = 0
    label.translatesAutoresizingMaskIntoConstraints = false
    return label
}()

/// our parallelogramView
lazy var plView: ParallelogramView = {
    let trView = ParallelogramView()
    trView.translatesAutoresizingMaskIntoConstraints = false
    return trView
}()

override init(frame: CGRect) {
    super.init(frame: frame)
    
    /// adding label to paralleogram
    plView.addSubview(label)
    addSubview(plView)
    
    NSLayoutConstraint.activate([
        plView.leadingAnchor.constraint(equalTo: leadingAnchor),
        plView.trailingAnchor.constraint(equalTo: trailingAnchor),
        plView.bottomAnchor.constraint(equalTo: bottomAnchor),
        plView.topAnchor.constraint(equalTo: topAnchor),
        
        label.leadingAnchor.constraint(equalTo: plView.leadingAnchor, constant: 16),
        label.trailingAnchor.constraint(equalTo: plView.trailingAnchor, constant: -16),
        label.bottomAnchor.constraint(equalTo: plView.bottomAnchor),
        label.topAnchor.constraint(equalTo: plView.topAnchor)
        
        
    ])
    
}

}

Okay. Our view is ready. Now, we should add it to the horizontal stackview with alignment fill.

for item in ["Text", "Text", "Text"] {
        let labelView = LabelView()
        labelView.label.text = item
        stackView.addArrangedSubview(labelView)
    }

Here is the result we got.

enter image description here

It is not like desired result, because it has rational issues. As I understood, each view's frame in iOS is rectangle and it cannot be changed. Even my stackview's spacing is 0, I still have kind of spacing (actually there is no), because the view is rectangle anyway. So, how to achieve result like in screenshot? What am I doing wrong?

Upvotes: 1

Views: 307

Answers (1)

jrturton
jrturton

Reputation: 119242

You have a couple of problems here.

First, you're drawing your parallelogram a bit wonky, with a difference of 8 x on the left side and 16 x on the trailing side, so they're not going to line up. You can fix that like this:

/// drawing to bottom but little bit to left
        path.addLine(to: CGPoint(x: rect.maxX - 8, y: rect.maxY))

The second is that each view should overlap, since the parallelogram is currently completely within the bounds. You can do this in a stack view by setting negative spacing:

stackView.spacing = -8

An alternative approach is to make the parallelogram extend outside of the bounds of the superview, then you can still use the original size as a reference for other layouts.

You can't use draw(_ rect:) to draw outside of the bounds of a view, so you can't just expand the drawing that way.

To have a custom colour for the parallelogram, give it a property, then use that property in your drawing code:

class ParallelogramView: UIView {

    //...

    var colour: UIColor = .red

    //...

    override func draw(_ rect: CGRect) {
        //... the rest of your drawing code
        colour.setFill()
        path.fill()
    }
}

labelView.plView.colour = .blue

Upvotes: 1

Related Questions