我目前正在我的應用程式中構建一個螢屏,它基本上是一個包含 3 個部分的長 UITableView,每個部分都有不同數量的獨特自定義單元格。設定 tableview 作業正常,我在單元格中添加了一些隨機文本以確保每個單元格都被正確呼叫和定位。我已經從我的專案中完全洗掉了我的故事板,因為它會因某些原因導致以后出現問題。所以我不能通過故事板做任何事情。
下一步是構建自定義單元格。作為初學者,其中一些對我來說相當復雜。這是我的細胞之一:
我想在多個 UIStackViews 中拆分單元格,一個用于圖片和名稱,另一個用于右側的統計資訊,它本身將包含兩個堆疊視圖,其中包含兩行統計資訊中的每一行。然后每個都可以包含另一個嵌入的 stackview,里面有兩個 uiLabels,數字和描述。最重要的是一個切換按鈕。
我似乎無法理解如何定義這一切。正如我所說,我定義了 Tableview 并呼叫了我的正確單元格,cellForRowAt如下所示,例如:
if indexPath.row == 0 && indexPath.section == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: StatsOverViewCell.identifier, for: indexPath) as! StatsOverViewCell
cell.configure()
return cell
} else if ...
我為每個單元格創建了檔案,其中之一是 StatsOverViewCell。在這個檔案中,我有一個與類同名的識別符號。我還添加了我從 tableview 呼叫的 configure 函式,layoutSubviews 函式,用于在單元格內部布局視圖,并且我已經初始化了我需要的每個標簽和影像。我已將檔案精簡為幾個示例,以節省您的時間:
class StatsOverViewCell: UITableViewCell {
//Set identifier to be able to call it later on
static let identifier = "StatsOverViewCell"
let myProfileStackView = UIStackView()
let myImageView = UIImageView()
let myName = UILabel()
let myGenderAndAge = UILabel()
let myStatsStackView = UIStackView()
let oneView = UIStackView()
let oneStat = UILabel()
let oneLabel = UILabel()
let twoStackView = UIStackView()
let twoStat = UILabel()
let twoLabel = UILabel()
//Do this for each of the labels I have in the stats
public func configure() {
myImageView.image = UIImage(named: "person-icon")
myName.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
myImageView.contentMode = .scaleAspectFill
myName.text = "Name."
myName.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
myName.textAlignment = .center
//Add the Name label to the stackview
myProfileStackView.addArrangedSubview(myName)
myProfileStackView.addArrangedSubview(myImageView)
myName.centerXAnchor.constraint(equalTo: myProfileStackView.centerXAnchor).isActive = true
oneStat.text = "5.187"
oneStat.font = UIFont(name: "montserrat", size: 18)
oneLabel.text = "Text"
oneLabel.font = UIFont(name: "montserrat", size: 14)
}
//Layout in the cell
override func layoutSubviews() {
super.layoutSubviews()
contentView.backgroundColor = Utilities.hexStringToUIColor(hex: "#3F454B")
contentView.layer.borderWidth = 1
//Stackview
contentView.addSubview(myProfileStackView)
myProfileStackView.axis = .vertical
myProfileStackView.distribution = .equalSpacing
myProfileStackView.spacing = 3.5
myProfileStackView.backgroundColor = .red
myProfileStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 23).isActive = true
myProfileStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 76).isActive = true
}
如您所見,我在配置方法中將所有排列的子視圖添加到堆疊視圖中,我在表視圖中創建單元格時呼叫該方法。然后我在 layoutsubviews 中設定 stackviews 約束。我沒有收到任何錯誤或任何東西。但是該單元格顯示為完全空的。
我覺得我忘記了一些東西,或者我不明白如何使用 uistackviews 創建單元格。我應該在哪里創建堆疊視圖,我應該在哪里將排列的子視圖添加到這個堆疊視圖以及我在 LayoutSubviews 中做什么?我將非常感謝任何見解。謝謝你的時間!
uj5u.com熱心網友回復:
你做錯了幾件事......
- 您的 UI 元素應該在init 中創建和配置,而不是在
configure()或layoutSubviews() - 您需要完整的約束才能為您的元素提供正確的布局
看看我對你的單元格類所做的更改。它應該讓你上路:
class StatsOverViewCell: UITableViewCell {
//Set identifier to be able to call it later on
static let identifier = "StatsOverViewCell"
let myProfileStackView = UIStackView()
let myImageView = UIImageView()
let myName = UILabel()
let myGenderAndAge = UILabel()
let myStatsStackView = UIStackView()
let oneView = UIStackView()
let oneStat = UILabel()
let oneLabel = UILabel()
let twoStackView = UIStackView()
let twoStat = UILabel()
let twoLabel = UILabel()
//Do this for each of the labels I have in the stats
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
myImageView.image = UIImage(named: "person-icon")
// frame doesn't matter - stack view arrangedSubvies automatically
// set .translatesAutoresizingMaskIntoConstraints = false
//myName.frame = CGRect(x: 0, y: 0, width: 100, height: 100)
myImageView.contentMode = .scaleAspectFill
myName.text = "Name."
myName.textAlignment = .center
//Add the Name label to the stackview
myProfileStackView.addArrangedSubview(myName)
myProfileStackView.addArrangedSubview(myImageView)
// no need for this
//myName.centerXAnchor.constraint(equalTo: myProfileStackView.centerXAnchor).isActive = true
oneStat.text = "5.187"
oneStat.font = UIFont(name: "montserrat", size: 18)
oneLabel.text = "Text"
oneLabel.font = UIFont(name: "montserrat", size: 14)
contentView.backgroundColor = Utilities.hexStringToUIColor(hex: "#3F454B")
contentView.layer.borderWidth = 1
//Stackview
contentView.addSubview(myProfileStackView)
myProfileStackView.axis = .vertical
// no need for equalSpacing if you're explicitly setting the spacing
//myProfileStackView.distribution = .equalSpacing
myProfileStackView.spacing = 3.5
myProfileStackView.backgroundColor = .red
// stack view needs .translatesAutoresizingMaskIntoConstraints = false
myProfileStackView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// stack view leading 23-pts from contentView leading
myProfileStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 23),
// stack view top 76-pts from contentView top
myProfileStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 76),
// need something to set the contentView height
// stack view bottom 8-pts from contentView bottom
myProfileStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),
// set imageView width and height
myImageView.widthAnchor.constraint(equalToConstant: 100.0),
myImageView.heightAnchor.constraint(equalTo: myImageView.widthAnchor),
])
}
public func configure() {
// here you would set the properties of your elements, such as
// label text
// imageView image
// colors
// etc
}
}
編輯
這是一個示例單元格類,它接近您發布的影像中的布局。
請注意,需要的約束很少:
NSLayoutConstraint.activate([
// role element 12-pts from top
myRoleElement.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12.0),
// centered horizontally
myRoleElement.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
// it will probably be using intrinsic height and width, but for demo purposes
myRoleElement.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.4),
myRoleElement.heightAnchor.constraint(equalToConstant: 40.0),
// stack view 24-pts on each side
hStack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 24),
hStack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -24),
// stack view 20-pts on bottom
hStack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20),
// stack view top 20-pts from Role element bottom
hStack.topAnchor.constraint(equalTo: myRoleElement.bottomAnchor, constant: 20),
// set imageView width and height
myImageView.widthAnchor.constraint(equalToConstant: 100.0),
myImageView.heightAnchor.constraint(equalTo: myImageView.widthAnchor),
// we want the two "column" stack views to be equal widths
hStack.arrangedSubviews[1].widthAnchor.constraint(equalTo: hStack.arrangedSubviews[2].widthAnchor),
])
這是完整的單元格類,包括一個示例“UserStruct”……當然,您需要調整字體/大小、間距等:
// sample struct for user data
struct UserStruct {
var profilePicName: String = ""
var name: String = ""
var gender: String = ""
var age: Int = 0
var statValues: [String] = []
}
class StatsOverViewCell: UITableViewCell {
//Set identifier to be able to call it later on
static let identifier = "StatsOverViewCell"
// whatever your "role" element is...
let myRoleElement = UILabel()
let myImageView = UIImageView()
let myName = UILabel()
let myGenderAndAge = UILabel()
var statValueLabels: [UILabel] = []
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
// create 6 Value and 6 text labels
// assuming you have 6 "Text" strings, but for now
// we'll use "Text A", "Text B", etc
let tmp: [String] = [
"A", "B", "C",
"D", "E", "F",
]
var statTextLabels: [UILabel] = []
for i in 0..<6 {
var lb = UILabel()
lb.font = UIFont.systemFont(ofSize: 16, weight: .regular)
lb.textAlignment = .center
lb.textColor = .white
lb.text = "0"
statValueLabels.append(lb)
lb = UILabel()
lb.font = UIFont.systemFont(ofSize: 13, weight: .regular)
lb.textAlignment = .center
lb.textColor = .lightGray
lb.text = "Text \(tmp[i])"
statTextLabels.append(lb)
}
// name and Gender/Age label properties
myName.textAlignment = .center
myGenderAndAge.textAlignment = .center
myName.font = UIFont.systemFont(ofSize: 15, weight: .regular)
myGenderAndAge.font = UIFont.systemFont(ofSize: 15, weight: .regular)
myName.textColor = .white
myGenderAndAge.textColor = .white
// placeholder text
myName.text = "Name"
myGenderAndAge.text = "(F, 26)"
myImageView.contentMode = .scaleAspectFill
// create the "Profile" stack view
let myProfileStackView = UIStackView()
myProfileStackView.axis = .vertical
myProfileStackView.spacing = 2
//Add imageView, name and gender/age labels to the profile stackview
myProfileStackView.addArrangedSubview(myImageView)
myProfileStackView.addArrangedSubview(myName)
myProfileStackView.addArrangedSubview(myGenderAndAge)
// create horizontal stack view to hold
// Profile stack two "column" stack views
let hStack = UIStackView()
// add Profile stack view
hStack.addArrangedSubview(myProfileStackView)
var j: Int = 0
// create two "column" stack views
// each with three "label pair" stack views
for _ in 0..<2 {
let columnStack = UIStackView()
columnStack.axis = .vertical
columnStack.distribution = .equalSpacing
for _ in 0..<3 {
let pairStack = UIStackView()
pairStack.axis = .vertical
pairStack.spacing = 4
pairStack.addArrangedSubview(statValueLabels[j])
pairStack.addArrangedSubview(statTextLabels[j])
columnStack.addArrangedSubview(pairStack)
j = 1
}
hStack.addArrangedSubview(columnStack)
}
// whatever your "Roles" element is...
// here, we'll simulate it with a label
myRoleElement.text = "Role 1 / Role 2"
myRoleElement.textAlignment = .center
myRoleElement.textColor = .white
myRoleElement.backgroundColor = .systemTeal
myRoleElement.layer.cornerRadius = 8
myRoleElement.layer.borderWidth = 1
myRoleElement.layer.borderColor = UIColor.white.cgColor
myRoleElement.layer.masksToBounds = true
// add Role element and horizontal stack view to contentView
contentView.addSubview(myRoleElement)
contentView.addSubview(hStack)
myRoleElement.translatesAutoresizingMaskIntoConstraints = false
hStack.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
// role element 12-pts from top
myRoleElement.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 12.0),
// centered horizontally
myRoleElement.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
// it will probably be using intrinsic height and width, but for demo purposes
myRoleElement.widthAnchor.constraint(equalTo: contentView.widthAnchor, multiplier: 0.4),
myRoleElement.heightAnchor.constraint(equalToConstant: 40.0),
// stack view 24-pts on each side
hStack.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 24),
hStack.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -24),
// stack view 20-pts on bottom
hStack.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -20),
// stack view top 20-pts from Role element bottom
hStack.topAnchor.constraint(equalTo: myRoleElement.bottomAnchor, constant: 20),
// set imageView width and height
myImageView.widthAnchor.constraint(equalToConstant: 100.0),
myImageView.heightAnchor.constraint(equalTo: myImageView.widthAnchor),
// we want the two "column" stack views to be equal widths
hStack.arrangedSubviews[1].widthAnchor.constraint(equalTo: hStack.arrangedSubviews[2].widthAnchor),
])
//contentView.backgroundColor = Utilities.hexStringToUIColor(hex: "#3F454B")
contentView.backgroundColor = UIColor(red: 0x3f / 255.0, green: 0x45 / 255.0, blue: 0x4b / 255.0, alpha: 1.0)
contentView.layer.borderWidth = 1
contentView.layer.borderColor = UIColor.lightGray.cgColor
// since we're setting the image view to explicit 100x100 size,
// we can make it round here
myImageView.layer.cornerRadius = 50
myImageView.layer.masksToBounds = true
}
public func configure(_ user: UserStruct) {
// here you would set the properties of your elements
// however you're getting your profile image
var img: UIImage!
if !user.profilePicName.isEmpty {
img = UIImage(named: user.profilePicName)
}
if img == nil {
img = UIImage(named: "person-icon")
}
if img != nil {
myImageView.image = img
}
myName.text = user.name
myGenderAndAge.text = "(\(user.gender), \(user.age))"
// probably want error checking to make sure we have 6 values
if user.statValues.count == 6 {
for (lbl, s) in zip(statValueLabels, user.statValues) {
lbl.text = s
}
}
}
}
和一個示例表視圖控制器:
class UserStatsTableViewController: UITableViewController {
var myData: [UserStruct] = []
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(StatsOverViewCell.self, forCellReuseIdentifier: StatsOverViewCell.identifier)
// generate some sample data
// I'm using Female "pro1" and Male "pro2" images
for i in 0..<10 {
var user = UserStruct(profilePicName: i % 2 == 0 ? "pro2" : "pro1",
name: "Name \(i)",
gender: i % 2 == 0 ? "F" : "M",
age: Int.random(in: 21...65))
var vals: [String] = []
for _ in 0..<6 {
let v = Int.random(in: 100..<1000)
vals.append("\(v)")
}
user.statValues = vals
myData.append(user)
}
}
override func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: StatsOverViewCell.identifier, for: indexPath) as! StatsOverViewCell
let user = myData[indexPath.row]
cell.configure(user)
return cell
}
}
這是它在運行時的樣子:

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/356465.html
上一篇:單擊iOS中的按鈕時,如何調整FirebaseSnapshotListener限制?
下一篇:從字串中獲取重復子字串的范圍
