2个水平放置的UILabel在表视图单元格中。

huangapple go评论113阅读模式
英文:

2 UILabels placed horizontally in a table view cell

问题

var locationNameLabel: UILabel = {
    let label = UILabel()
    label.text = "Location Name:"
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = .systemFont(ofSize: 18, weight: .bold)
    label.numberOfLines = 0
    return label
}()

var locationNameContent: UILabel = {
    let label = UILabel()
    label.translatesAutoresizingMaskIntoConstraints = false
    label.font = .systemFont(ofSize: 18, weight: .regular)
    label.numberOfLines = 0
    label.lineBreakMode = .byWordWrapping
    return label
}()

func createLocationNameContainer(label: UILabel, labelContent: UILabel) -> UIView {
    let containerView = UIView()
    containerView.translatesAutoresizingMaskIntoConstraints = false
    containerView.backgroundColor = .green
    containerView.addSubview(label)
    containerView.addSubview(labelContent)
    NSLayoutConstraint.activate([
        label.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 5),
        label.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 5),
        label.firstBaselineAnchor.constraint(equalTo: labelContent.firstBaselineAnchor),
        labelContent.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 5),
        labelContent.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 5),
        labelContent.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -5),
        labelContent.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -5)
    ])
    return containerView
}

func configure(model: LocationAndPhotoModel) {
    let imageURL = model.locationPhotoModel.data.first?.images.medium.url ?? ""
    locationImage.sd_setImage(with: URL(string: imageURL))
    locationNameContent.text = model.locationDetail.name
    locationAddressContent.text = model.locationDetail.address_obj.address_string
}

// Implementation of tableView
view.addSubview(tableView)

NSLayoutConstraint.activate([
    tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
    tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
    tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
    tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
])

extension SearchResultViewController: UITableViewDelegate, UITableViewDataSource {
    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return arrayOfLocationsAndPhotos?.count ?? 1
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        guard let cell = tableView.dequeueReusableCell(withIdentifier: SearchResultTableViewCell.identifier, for: indexPath) as? SearchResultTableViewCell else {
            return UITableViewCell()
        }
        guard self.arrayOfLocationsAndPhotos != nil else { return UITableViewCell() }
        guard let model = arrayOfLocationsAndPhotos?[indexPath.row] else { return UITableViewCell() }
        cell.configure(model: model)
        return cell
    }
}
英文:

I am working on a table view and in the cell I need to create 2 labels horizontally. The first label has fixed content "Location Name:". The second label will have dynamic content and it can be multiple lines. When I first get to the screen, my cell looks like this:

2个水平放置的UILabel在表视图单元格中。

But when I scroll down and scroll back up, it looks fine:

2个水平放置的UILabel在表视图单元格中。

Here's my code:

var locationNameLabel: UILabel = {
let label = UILabel()
label.text = "Location Name:"
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .systemFont(ofSize: 18, weight: .bold)
label.numberOfLines = 0
return label
}()
var locationNameContent: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .systemFont(ofSize: 18, weight: .regular)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
return label
}()
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
setupUI()
}
func setupUI() {
let locationNameView = createLocationNameContainer(label: locationNameLabel, labelContent: locationNameContent)
contentView.addSubview(locationNameView)
contentView.addSubview(locationImage)
NSLayoutConstraint.activate([
locationImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
locationImage.widthAnchor.constraint(equalToConstant: 200),
locationImage.heightAnchor.constraint(equalToConstant: 200),
locationImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
locationNameView.topAnchor.constraint(equalTo: locationImage.bottomAnchor, constant: 15),
locationNameView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
locationNameView.widthAnchor.constraint(equalToConstant: contentView.frame.width - 50),
locationNameView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5)
])
}
func createLocationNameContainer(label: UILabel, labelContent: UILabel) -> UIView {
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.backgroundColor = .green
containerView.addSubview(label)
containerView.addSubview(labelContent)
NSLayoutConstraint.activate([
label.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 5),
label.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 5),
label.firstBaselineAnchor.constraint(equalTo: labelContent.firstBaselineAnchor),
labelContent.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 5),
labelContent.leadingAnchor.constraint(equalTo: label.trailingAnchor, constant: 5),
labelContent.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -5),
labelContent.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -5)
])
return containerView
}
func configure(model: LocationAndPhotoModel) {
// get the first oject of "data" array of PhotoModel
let imageURL = model.locationPhotoModel.data.first?.images.medium.url ?? ""
locationImage.sd_setImage(with: URL(string: imageURL))
// get location name
locationNameContent.text = model.locationDetail.name
// get location address
locationAddressContent.text = model.locationDetail.address_obj.address_string
}

Here's how I implement my tableView:

view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
])
extension SearchResultViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfLocationsAndPhotos?.count ?? 1
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cell = tableView.dequeueReusableCell(withIdentifier: SearchResultTableViewCell.identifier, for: indexPath) as? SearchResultTableViewCell else {
return UITableViewCell()
}
guard self.arrayOfLocationsAndPhotos != nil else {return UITableViewCell()}
guard let model = arrayOfLocationsAndPhotos?[indexPath.row] else {return UITableViewCell()}
cell.configure(model: model)
return cell
}
}

答案1

得分: 2

以下是您要翻译的代码部分:

首先,在您的单元格类中,`setSelected(...)` 方法将被多次调用。每当显示单元格时... 每当选择或取消选择单元格时... 等等。因此,您不希望在这里添加子视图。

相反,在单元格初始化时设置UI元素

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
    super.init(style: style, reuseIdentifier: reuseIdentifier)
    setupUI()
}
required init?(coder: NSCoder) {
    super.init(coder: coder)
    setupUI()
}

接下来,您可以使用水平的 `UIStackView` 轻松实现您的 "两个标签" 布局。

以下是您的代码 - 经过修改... 我没有您的数据,所以我使用了一个只有 "name" 字符串的简单结构体:

struct LocationAndPhotoModel {
    var name: String = ""
}

class SearchResultTableViewCell: UITableViewCell {

    static let identifier: String = "SearchResultTableViewCell"

    var locationNameLabel: UILabel = {
        let label = UILabel()
        label.text = "Location Name:"
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = .systemFont(ofSize: 18, weight: .bold)
        label.setContentHuggingPriority(.required, for: .horizontal)
        label.setContentCompressionResistancePriority(.required, for: .horizontal)
        return label
    }()

    var locationNameContent: UILabel = {
        let label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        label.font = .systemFont(ofSize: 18, weight: .regular)
        label.numberOfLines = 0
        label.lineBreakMode = .byWordWrapping
        label.setContentHuggingPriority(.required - 1, for: .horizontal)
        label.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
        return label
    }()

    var locationImage: UIImageView = {
        let imgView = UIImageView()
        imgView.translatesAutoresizingMaskIntoConstraints = false
        imgView.backgroundColor = .systemBlue
        return imgView
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupUI()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupUI()
    }

    func setupUI() {
        let locationNameView = createLocationNameContainer(label: locationNameLabel, labelContent: locationNameContent)
        contentView.addSubview(locationNameView)
        contentView.addSubview(locationImage)

        NSLayoutConstraint.activate([
            locationImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
            locationImage.widthAnchor.constraint(equalToConstant: 200),
            locationImage.heightAnchor.constraint(equalToConstant: 100),
            locationImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),

            locationNameView.topAnchor.constraint(equalTo: locationImage.bottomAnchor, constant: 15),
            locationNameView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
            locationNameView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),

            locationNameView.leadingAnchor.constraint(greaterThanOrEqualTo: contentView.leadingAnchor, constant: 5),
            locationNameView.trailingAnchor.constraint(lessThanOrEqualTo: contentView.trailingAnchor, constant: -5),
        ])
    }

    // 配置方法...
}

class SearchResultViewController: UIViewController {
    // 代码继续...
}

// 余下的代码部分不再重复翻译,如有需要,请继续提问。

请告诉我如果您需要任何进一步的翻译或帮助。

英文:

First, in your cell class, setSelected(...) will be called many times. Every time a cell is displayed... every time a cell is selected or deselected... etc. So you do NOT want to be adding subviews there.

Instead, setup the UI elements when the cell is init'd:

override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUI()
}

Next, you can easily accomplish your "two-label" layout with a horizontal UIStackView.

Here is your code - modified... I don't have your data, so I used a simple struct with just the "name" string:

struct LocationAndPhotoModel {
var name: String = ""
}
class SearchResultTableViewCell: UITableViewCell {
static let identifier: String = "SearchResultTableViewCell"
var locationNameLabel: UILabel = {
let label = UILabel()
label.text = "Location Name:"
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .systemFont(ofSize: 18, weight: .bold)
// we don't want to allow the label to be squeezed or stretched
label.setContentHuggingPriority(.required, for: .horizontal)
label.setContentCompressionResistancePriority(.required, for: .horizontal)
return label
}()
var locationNameContent: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .systemFont(ofSize: 18, weight: .regular)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
// we don't want to allow the label to be squeezed or stretched
//	but this is the multiline label, so we ue required - 1
label.setContentHuggingPriority(.required - 1, for: .horizontal)
label.setContentCompressionResistancePriority(.required - 1, for: .horizontal)
return label
}()
var locationImage: UIImageView = {
let imgView = UIImageView()
imgView.translatesAutoresizingMaskIntoConstraints = false
imgView.backgroundColor = .systemBlue
return imgView
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setupUI()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setupUI()
}
// DO NOT implement setSelected, unless you want to customize the
//	appearance when a cell is selected
//override func setSelected(_ selected: Bool, animated: Bool) {
//	super.setSelected(selected, animated: animated)
//
//	// DEFINITELY do not do this here!!!
//	//setupUI()
//}
func setupUI() {
let locationNameView = createLocationNameContainer(label: locationNameLabel, labelContent: locationNameContent)
contentView.addSubview(locationNameView)
contentView.addSubview(locationImage)
NSLayoutConstraint.activate([
locationImage.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 10),
locationImage.widthAnchor.constraint(equalToConstant: 200),
// I made the image view shorter so we can see more rows
//	change back to 200 when ready
locationImage.heightAnchor.constraint(equalToConstant: 100),
locationImage.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
locationNameView.topAnchor.constraint(equalTo: locationImage.bottomAnchor, constant: 15),
locationNameView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
locationNameView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -5),
// keep at least 5-points on each side
locationNameView.leadingAnchor.constraint(greaterThanOrEqualTo: contentView.leadingAnchor, constant: 5),
locationNameView.trailingAnchor.constraint(lessThanOrEqualTo: contentView.trailingAnchor, constant: -5),
])
}
func createLocationNameContainer(label: UILabel, labelContent: UILabel) -> UIView {
let containerView = UIView()
containerView.translatesAutoresizingMaskIntoConstraints = false
containerView.backgroundColor = .green
let stackView = UIStackView()
stackView.axis = .horizontal
// alignment top, so the left-side label will stay at the top
//	when the right-side label has multiple lines
stackView.alignment = .top
stackView.spacing = 8
// add the labels to the stack view
stackView.addArrangedSubview(label)
stackView.addArrangedSubview(labelContent)
stackView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(stackView)
NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: containerView.topAnchor, constant: 5),
stackView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 5),
stackView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -5),
stackView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor, constant: -5)
])
return containerView
}
func configure(model: LocationAndPhotoModel) {
// get the first oject of "data" array of PhotoModel
//let imageURL = model.locationPhotoModel.data.first?.images.medium.url ?? ""
//locationImage.sd_setImage(with: URL(string: imageURL))
// get location name
locationNameContent.text = model.name // model.locationDetail.name
}
}
class SearchResultViewController: UIViewController {
let tableView = UITableView()
var arrayOfLocationsAndPhotos: [LocationAndPhotoModel] = []
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemBackground
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 10),
tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
])
tableView.register(SearchResultTableViewCell.self, forCellReuseIdentifier: SearchResultTableViewCell.identifier)
tableView.dataSource = self
tableView.delegate = self
// let's add some sample data
var m = LocationAndPhotoModel(name: "Short")
arrayOfLocationsAndPhotos.append(m)
m = LocationAndPhotoModel(name: "Longer Name Here")
arrayOfLocationsAndPhotos.append(m)
m = LocationAndPhotoModel(name: "Long enough name that it will probably need to wrap onto multiple lines.")
arrayOfLocationsAndPhotos.append(m)
m = LocationAndPhotoModel(name: "Medium Name")
arrayOfLocationsAndPhotos.append(m)
// let's repeat those 3 times so we have enough to scroll
for _ in 1...3 {
arrayOfLocationsAndPhotos.append(contentsOf: arrayOfLocationsAndPhotos)
}
}
}
extension SearchResultViewController: UITableViewDelegate, UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return arrayOfLocationsAndPhotos.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: SearchResultTableViewCell.identifier, for: indexPath) as! SearchResultTableViewCell
cell.configure(model: arrayOfLocationsAndPhotos[indexPath.row])
return cell
}
}

When run, it will look like this:

2个水平放置的UILabel在表视图单元格中。

I don't have your images, so the image view is blue, and I set its height to 100 so we can see more rows.

huangapple
  • 本文由 发表于 2023年5月22日 11:37:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/76302901.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定