我使用以下initLayout函数初始化了UITableViewCell:
contentView.addSubview(horizontalStack)
horizontalStack.addArrangedSubview(imageToView)
imageToView.contentMode = .scaleAspectFit
verticalStack.addArrangedSubview(petName)
verticalStack.addArrangedSubview(petDescription)
horizontalStack.addArrangedSubview(verticalStack)
但这给了我以下结果。图片太大了,线条都弄乱了,标题的上方是顶部:
我希望视图看起来像这样。注意所有元素的对称性
到目前为止,我已经尝试过:
有人可以帮我吗?
答案 0 :(得分:1)
堆栈视图在安排子视图方面做得很好-但是您必须给它们提供足够的信息,以便他们知道 如何 您希望它们进行安排。
首先,我假设您添加了horizontalStack
的约束条件(否则,您的屏幕截图将看不到任何内容)。
在不提供任何其他约束的情况下,堆栈视图使用子视图的intrinsicContentSize
处理该安排。如果您没有给UIImageView
任何约束,则其固有大小将是图像的大小。
假设您要使图像为正方形(比例为1:1),请为其设置heightAnchor = widthAnchor
约束。
imageToView.heightAnchor.constraint(equalTo: imageToView.widthAnchor)
然后,确定您想要的宽度。定点宽度-例如80?
imageToView.widthAnchor.constraint(equalToConstant: 80.0)
还是相对宽度(例如标签宽度的1/2)?
imageToView.widthAnchor.constraint(equalTo: verticalStack.widthAnchor, multiplier: 0.5)
您还需要决定如何在horizontalStack
中对齐。
这里有几个例子。第一部分使用horizontalStack.alignment = .center
,第二部分使用horizontalStack.alignment = .top
(右侧的图像具有背景色,并且在堆栈视图周围具有虚线边框,以便于查看帧):
这是我使用的代码-没有@IBoutlet
连接或原型单元,因此只需添加一个表视图控制器并将该类分配给PatroTableViewController
:
class PatroCell: UITableViewCell {
static let identifier: String = "patroCell"
let horizontalStack: UIStackView = {
let v = UIStackView()
v.spacing = 8
v.alignment = .center
return v
}()
let verticalStack: UIStackView = {
let v = UIStackView()
v.axis = .vertical
v.spacing = 8
return v
}()
let imageToView: UIImageView = {
let v = UIImageView()
return v
}()
let petName: UILabel = {
let v = UILabel()
v.font = UIFont.systemFont(ofSize: 16.0)
return v
}()
let petDescription: UILabel = {
let v = UILabel()
v.font = UIFont.systemFont(ofSize: 15.0)
v.textColor = .lightGray
v.numberOfLines = 0
return v
}()
// so we can see the frame of the horizontal stack view
let stackOutlineView: DashedOutlineView = {
let v = DashedOutlineView()
return v
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func commonInit() -> Void {
stackOutlineView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(stackOutlineView)
horizontalStack.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(horizontalStack)
horizontalStack.addArrangedSubview(imageToView)
imageToView.contentMode = .scaleAspectFit
verticalStack.addArrangedSubview(petName)
verticalStack.addArrangedSubview(petDescription)
horizontalStack.addArrangedSubview(verticalStack)
let g = contentView.layoutMarginsGuide
// this will avoid auto-layout warnings
let hsBottom = horizontalStack.bottomAnchor.constraint(equalTo: g.bottomAnchor, constant: 0.0)
hsBottom.priority = UILayoutPriority(rawValue: 999)
NSLayoutConstraint.activate([
// constrain horizontal stack to all 4 sides - use margins
horizontalStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 0.0),
horizontalStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 0.0),
horizontalStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: 0.0),
// the bottom anchor with priority 999
hsBottom,
// image view should be square - 1:1 ratio
imageToView.heightAnchor.constraint(equalTo: imageToView.widthAnchor),
// image view should be 80 x 80?
//imageToView.widthAnchor.constraint(equalToConstant: 80.0),
// or, maybe, image view width should be 1/2 the width of the labels?
imageToView.widthAnchor.constraint(equalTo: verticalStack.widthAnchor, multiplier: 0.5),
// constrain the outline view
stackOutlineView.topAnchor.constraint(equalTo: horizontalStack.topAnchor, constant: 0.0),
stackOutlineView.leadingAnchor.constraint(equalTo: horizontalStack.leadingAnchor, constant: 0.0),
stackOutlineView.trailingAnchor.constraint(equalTo: horizontalStack.trailingAnchor, constant: 0.0),
stackOutlineView.bottomAnchor.constraint(equalTo: horizontalStack.bottomAnchor, constant: 0.0),
])
stackOutlineView.isHidden = true
// change to "if true" to see the frames
if false {
// so we can see the UI element frames
imageToView.backgroundColor = .red
petName.backgroundColor = .green
petDescription.backgroundColor = .yellow
petDescription.textColor = .black
stackOutlineView.isHidden = false
}
}
}
class PatroTableViewController: UITableViewController {
let descriptions: [String] = [
"One-line description",
"This is the description of the pet in this cell. It is enough text that it will cause word-wrapping.",
"This description will be much longer... It will wrap onto many lines so we can see how the cell layout will look when the description text makes the label taller than the image view on the left. Note the differences between \".alignment = .center\" vs \".alignment = .top\""
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(PatroCell.self, forCellReuseIdentifier: PatroCell.identifier)
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 2
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return descriptions.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: PatroCell.identifier, for: indexPath) as! PatroCell
cell.petName.text = "Dog"
cell.petDescription.text = descriptions[indexPath.row]
cell.imageToView.image = UIImage(named: "dog")
if indexPath.section == 0 {
// set horizontal stack alignment to center
cell.horizontalStack.alignment = .center
} else {
// set horizontal stack alignment to top
cell.horizontalStack.alignment = .top
}
return cell
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
if section == 0 {
return "Alignment: Center"
}
return "Alignment: Top"
}
}
class DashedOutlineView: UIView {
var shapeLayer: CAShapeLayer!
override class var layerClass: AnyClass {
return CAShapeLayer.self
}
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func commonInit() -> Void {
shapeLayer = self.layer as? CAShapeLayer
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeColor = UIColor(red: 0.0, green: 0.75, blue: 0.0, alpha: 1.0).cgColor
shapeLayer.lineWidth = 1.0
shapeLayer.lineDashPattern = [8,8]
}
override func layoutSubviews() {
super.layoutSubviews()
shapeLayer.path = UIBezierPath(rect: bounds).cgPath
}
}