英文:
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:
But when I scroll down and scroll back up, it looks fine:
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:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论