You are able to do this with a resizableImage.
We’ll begin with this picture (clipped out of your posted picture):
It’s 11 x 32
(pixels).
We will make it “stretchable” utilizing func resizableImage(withCapInsets capInsets: UIEdgeInsets) -> UIImage
(docs) like this:
.resizableImage(withCapInsets: .init(high: 12.0, left: 0.0, backside: 12.0, proper: 0.0))
Now the highest 12-pixels and backside 12-pixels will not stretch … solely the center half will:
Pattern code:
class StretchTestVC: UIViewController {
override func viewDidLoad() {
tremendous.viewDidLoad()
view.backgroundColor = .systemBackground
guard let img = UIImage(named: "stretch1") else {
fatalError("Couldn't load picture!!!")
}
// create a resizable model
let stretchImg = img.resizableImage(withCapInsets: .init(high: 12.0, left: 0.0, backside: 12.0, proper: 0.0))
// now let's add 8 picture views with rising heights
var x: CGFloat = 40.0
var h: CGFloat = 60.0
for _ in 1...8 {
let imgView = UIImageView()
imgView.picture = stretchImg
imgView.body = .init(x: x, y: 100.0, width: 11.0, peak: h)
view.addSubview(imgView)
x += 30.0
h += 50.0
}
}
}
Edit – actually fast instance with variable peak desk view cells…
class StretchCellViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
let rowsInCell: [Int] = [
2, 3, 7, 5, 2, 4, 8, 5, 9, 6,
]
override func viewDidLoad() {
tremendous.viewDidLoad()
view.backgroundColor = .systemBackground
let tableView = UITableView()
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
let g = view.safeAreaLayoutGuide
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
tableView.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
tableView.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
tableView.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0),
])
tableView.register(StretchImageCell.self, forCellReuseIdentifier: StretchImageCell.identifier)
tableView.dataSource = self
tableView.delegate = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection part: Int) -> Int {
return rowsInCell.rely
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let c = tableView.dequeueReusableCell(withIdentifier: StretchImageCell.identifier, for: indexPath) as! StretchImageCell
c.fillData(numRows: rowsInCell[indexPath.row])
return c
}
}
class StretchImageCell: UITableViewCell {
static let identifier: String = "StretchImageCell"
non-public let stack = UIStackView()
override init(fashion: UITableViewCell.CellStyle, reuseIdentifier: String?) {
tremendous.init(fashion: fashion, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
tremendous.init(coder: coder)
commonInit()
}
non-public func commonInit() {
guard let img = UIImage(named: "stretch1") else {
fatalError("Couldn't load picture named "stretch1"!!!")
}
// create a resizable model
let stretchImg = img.resizableImage(withCapInsets: .init(high: 12.0, left: 0.0, backside: 12.0, proper: 0.0))
let imgView = UIImageView()
imgView.picture = stretchImg
stack.axis = .vertical
stack.spacing = 8
imgView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(imgView)
stack.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(stack)
let g = contentView.layoutMarginsGuide
NSLayoutConstraint.activate([
imgView.topAnchor.constraint(equalTo: self.topAnchor, constant: 8.0),
imgView.leadingAnchor.constraint(equalTo: g.leadingAnchor),
imgView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -8.0),
imgView.widthAnchor.constraint(equalToConstant: 11.0),
stack.topAnchor.constraint(equalTo: g.topAnchor),
stack.leadingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: 4.0),
stack.trailingAnchor.constraint(equalTo: g.trailingAnchor),
stack.bottomAnchor.constraint(equalTo: g.bottomAnchor),
])
for _ in 1...10 {
let v = UILabel()
v.font = .systemFont(ofSize: 24.0, weight: .gentle)
v.backgroundColor = .init(white: 0.95, alpha: 1.0)
stack.addArrangedSubview(v)
}
}
public func fillData(numRows: Int) {
// conceal all of the labels within the stack view
for v in stack.arrangedSubviews {
v.isHidden = true
}
// restrict to 10 label rows
let n = min(10, numRows)
// now set label textual content and un-hide
for i in 0..
End result: