Reputation: 1404
I should achieve following result:
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.
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
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