table 视图 swift ios 的单元格中的小部件相互重叠
Widgets overlap each other in the cells of table view swift ios
我正在根据数组 widgetInstockArray
中提供的元素在 table 视图的单元格中获取 textField
或 textView
小部件。
并从 labelInstcokArray
获取小部件的占位符
问题:Cell 出现时两个小部件重叠,textField 包含在每个单元格的 textView 中。
我想要的:每个单元格中应该有一个 textField 或 textView,但不能同时包含和重叠。
这是我到目前为止所做的:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate {
var widgetInstockArray = [String]()
var labelInstockArray = [String]()
var idInstockArray = [IntegerLiteralType]()
var newLabel = UITextField()
var newTextView = UITextView()
let wTextField = "textField"
let wTextView = "textView"
@IBOutlet weak var firstTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
widgetInstockArray = [wTextView, wTextField, wTextView, wTextField, wTextField, wTextView, wTextField]
idInstockArray = [1,2,3,4,5,6,7]
labelInstockArray = ["1ok","2ok","3ok","4ok","5ok","6ok","7ok"]
firstTableView.delegate = self
firstTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return widgetInstockArray.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var Cell : UITableViewCell?
var instockTag : Int = 1
Cell = firstTableView.dequeueReusableCell(withIdentifier: "firstCell")! as UITableViewCell
if widgetInstockArray.count == 0 && labelInstockArray.isEmpty {
print("no textFields in instock")
}
else {
print("widget process i in winstock loop")
for i in widgetInstockArray {
print("widget process i in winstock loopok so here is \(i)")
let indexOfA = widgetInstockArray.index(of: i)
print("her is the index of i of widgets \(String(describing: indexOfA))")
if i.contains(wTextField) {
print("textField was placed")
newLabel = UITextField(frame: CGRect(x: 10, y: 10, width: 200, height: 30))
newLabel.textColor = UIColor.gray
newLabel.tag = instockTag
print("You have a instock textLabel with tag \(newLabel.tag)")
if labelInstockArray.isEmpty || idInstockArray.count != labelInstockArray.count {
newLabel.text = " "
} else {
newLabel.placeholder = labelInstockArray[indexPath.row]
newLabel.layer.cornerRadius = 3
newLabel.layer.borderColor = UIColor.gray.cgColor
newLabel.layer.borderWidth = 1
instockTag += 1
print("\(widgetInstockArray.count)")
Cell?.contentView.addSubview(newLabel)
}
}
if i.contains(wTextView) {
print("textView was placed")
newTextView = UITextView(frame: CGRect(x:10, y: 10, width: 200, height: 60))
newTextView.textAlignment = NSTextAlignment.justified
newTextView.textColor = UIColor.black
newTextView.backgroundColor = UIColor.white
newTextView.font = UIFont.systemFont(ofSize: 15)
newTextView.tag = instockTag
print("You have a instock textView with tag \(newTextView.tag)")
if labelInstockArray.isEmpty || idInstockArray.count != labelInstockArray.count {
} else {
//newTextView.text = labelInstockArray[indexPath.row]
newTextView.layer.cornerRadius = 3
newTextView.layer.borderColor = UIColor.gray.cgColor
newTextView.layer.borderWidth = 1
instockTag += 1
print("\(widgetInstockArray.count)")
Cell?.contentView.addSubview(newTextView)
}
}
}
print("could not add widgets")
}
return Cell!
}
func textViewDidBeginEditing(_ textView: UITextView) {
if newTextView.textColor == UIColor.lightGray {
newTextView.text = nil
newTextView.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if newTextView.text.isEmpty {
for i in labelInstockArray {
newTextView.text = i
}
newTextView.textColor = UIColor.lightGray
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
输出重叠:(
textFiled 在 textview 中,两者都出现在一个单元格中。
但我希望它们不应该重叠,并且每个单元格中应该只有一个小部件。
更新根据
如果我想在单击按钮时添加小部件怎么办,这样每次单击时都应该添加小部件。
这是我所做的
var idWidgetIs = IntegerLiteralType()
var labelWidget = String()
var widgetName = String()
let stockArray: [StockItem] = [ StockItem(id: idWidgetIs, label: labelWidget, widget: widgetName)]
@IBAction func textViewAct(_ sender: Any) {
idWidgetIs += 1
labelWidget = "placeholder"
StockItem.init(id: idWidgetIs, label: labelWidget, widget: .textView)
}
@IBAction func textFieldAct(_ sender: Any) {
idWidgetIs += 1
labelWidget = "placeholder"
StockItem.init(id: idWidgetIs, label: labelWidget, widget: .textField)
}
问题
1) 您正在以编程方式添加子视图。由于单元格被重复使用,因此您每次都在创建 TextField 和 TextView
2) 我在您的代码中看到的另一个问题是 i.contains(wTextField)
和 i.contains(wTextView)
这将始终为真,因为 wTextField
和 wTextView
都在数组 widgetInstockArray
中并且两个框架都是 CGRect(x: 10, y: 10, width: 200, height: 30)
所以你得到它重叠
更好的解决方案是使用 UIStackView
使用 UIStackview
创建自定义单元格
现在将一个 UITextField
和一个 UITextView
添加到 UIStackview
.
下一步是 cellForRow
方法。只需隐藏其他元素,如
if i == wTextField {
cell.wTextView.isHidden = true
cell.wTextField.isHidden = false
} else {
cell.wTextField.isHidden = true
cell.wTextView.isHidden = false
}
当您在 UIStackView
中隐藏其中一个视图时,其他元素会自动相应地设置
希望对您有所帮助,如有疑问请告诉我
更新
不相关,但保留两个数组来填充表视图不是好的做法,这可能对未来的更新代码有问题。
更好的解决方案是创建 struct
或 class
喜欢
enum Widget {
case TextField
case TextView
}
struct StockArray {
var type : Widget
var labelInstockArray = [String]()
var idInstockArray = [IntegerLiteralType]()
}
现在您可以创建 StockArray
的数组并且非常容易维护
宾果!!!
如果我对您的 code/need 理解正确,添加子视图是 而不是 重叠问题。 多次添加子视图是问题所在
for i in widgetInstockArray {
cellForRowAt
方法中的行是问题所在。基本上,对于循环遍历的每个单元格 (7 times = 3 for wTextView and 4 for wTextField)
,这意味着您要在视图上添加视图。
建议:删除 for i in widgetInstockArray {
和
let i = widgetInstockArray[indexPath.row]
并使用
进行比较
if i == wTextField {
对于 wTextView 也是如此。
如 中所述:
- 每次 table 视图请求单元格时,都会创建一个新的文本字段/文本视图
- 在创建单元格时循环遍历 widgetInStockArray 将导致多个文本字段和文本视图被添加到该单元格
问题中的示例代码可以按如下方式重组和改进,以达到预期的效果。
重构库存信息
定义两种类型,方便获取单个库存商品的id、label、widget。
enum StockWidget: String {
case textField
case textView
}
struct StockItem {
let id: IntegerLiteralType
let label: String
let widget: StockWidget
}
相应地更新示例数据。
let stockArray: [StockItem] = [
StockItem(id: 1, label: "1ok", widget: .textView),
StockItem(id: 2, label: "2ok", widget: .textField),
StockItem(id: 3, label: "3ok", widget: .textView),
StockItem(id: 4, label: "4ok", widget: .textField),
StockItem(id: 5, label: "5ok", widget: .textField),
StockItem(id: 6, label: "6ok", widget: .textView),
StockItem(id: 7, label: "7ok", widget: .textField)
]
定义特定单元格
一个 UITextField
:
class TextFieldWidgetCell: UITableViewCell {
let textField: UITextField
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
let field = UITextField(frame: CGRect(x: 10, y: 10, width: 200, height: 30))
field.layer.borderColor = UIColor.gray.cgColor
field.layer.borderWidth = 1.0
field.layer.cornerRadius = 3.0
field.textColor = UIColor.gray
textField = field
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(textField)
}
override func prepareForReuse() {
super.prepareForReuse()
textField.placeholder = nil
textField.text = nil
}
}
还有一个 UITextView
:
class TextViewWidgetCell: UITableViewCell {
let textView: UITextView
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
let view = UITextView(frame: CGRect(x:10, y: 10, width: 200, height: 60))
view.backgroundColor = UIColor.white
view.font = UIFont.systemFont(ofSize: 15)
view.layer.borderColor = UIColor.gray.cgColor
view.layer.borderWidth = 1.0
view.layer.cornerRadius = 3.0
view.textAlignment = NSTextAlignment.justified
view.textColor = UIColor.black
textView = view
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(textView)
}
override func prepareForReuse() {
super.prepareForReuse()
textView.text = nil
}
}
使用 table 视图注册小部件单元格。
override func viewDidLoad() {
super.viewDidLoad()
firstTableView.dataSource = self
firstTableView.delegate = self
firstTableView.register(TextFieldWidgetCell.self, forCellReuseIdentifier: StockWidget.textField.rawValue)
firstTableView.register(TextViewWidgetCell.self, forCellReuseIdentifier: StockWidget.textView.rawValue)
}
适应UITableViewDataSource
实施
现在单元配置被拆分成两个 UITableViewCell
子类,tableView(_, cellForRowAt:)
的实现可以大大减少。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return stockArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let stockItem = stockArray[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: stockItem.widget.rawValue)
switch stockItem.widget {
case .textField:
if let cell = cell as TextFieldWidgetCell {
cell.textField.placeholder = stockItem.label
}
case .textView:
if let cell = cell as TextViewWidgetCell {
cell.textView.text = stockItem.label
}
}
return cell
}
我正在根据数组 widgetInstockArray
中提供的元素在 table 视图的单元格中获取 textField
或 textView
小部件。
并从 labelInstcokArray
问题:Cell 出现时两个小部件重叠,textField 包含在每个单元格的 textView 中。
我想要的:每个单元格中应该有一个 textField 或 textView,但不能同时包含和重叠。
这是我到目前为止所做的:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UITextViewDelegate {
var widgetInstockArray = [String]()
var labelInstockArray = [String]()
var idInstockArray = [IntegerLiteralType]()
var newLabel = UITextField()
var newTextView = UITextView()
let wTextField = "textField"
let wTextView = "textView"
@IBOutlet weak var firstTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
widgetInstockArray = [wTextView, wTextField, wTextView, wTextField, wTextField, wTextView, wTextField]
idInstockArray = [1,2,3,4,5,6,7]
labelInstockArray = ["1ok","2ok","3ok","4ok","5ok","6ok","7ok"]
firstTableView.delegate = self
firstTableView.dataSource = self
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return widgetInstockArray.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
var Cell : UITableViewCell?
var instockTag : Int = 1
Cell = firstTableView.dequeueReusableCell(withIdentifier: "firstCell")! as UITableViewCell
if widgetInstockArray.count == 0 && labelInstockArray.isEmpty {
print("no textFields in instock")
}
else {
print("widget process i in winstock loop")
for i in widgetInstockArray {
print("widget process i in winstock loopok so here is \(i)")
let indexOfA = widgetInstockArray.index(of: i)
print("her is the index of i of widgets \(String(describing: indexOfA))")
if i.contains(wTextField) {
print("textField was placed")
newLabel = UITextField(frame: CGRect(x: 10, y: 10, width: 200, height: 30))
newLabel.textColor = UIColor.gray
newLabel.tag = instockTag
print("You have a instock textLabel with tag \(newLabel.tag)")
if labelInstockArray.isEmpty || idInstockArray.count != labelInstockArray.count {
newLabel.text = " "
} else {
newLabel.placeholder = labelInstockArray[indexPath.row]
newLabel.layer.cornerRadius = 3
newLabel.layer.borderColor = UIColor.gray.cgColor
newLabel.layer.borderWidth = 1
instockTag += 1
print("\(widgetInstockArray.count)")
Cell?.contentView.addSubview(newLabel)
}
}
if i.contains(wTextView) {
print("textView was placed")
newTextView = UITextView(frame: CGRect(x:10, y: 10, width: 200, height: 60))
newTextView.textAlignment = NSTextAlignment.justified
newTextView.textColor = UIColor.black
newTextView.backgroundColor = UIColor.white
newTextView.font = UIFont.systemFont(ofSize: 15)
newTextView.tag = instockTag
print("You have a instock textView with tag \(newTextView.tag)")
if labelInstockArray.isEmpty || idInstockArray.count != labelInstockArray.count {
} else {
//newTextView.text = labelInstockArray[indexPath.row]
newTextView.layer.cornerRadius = 3
newTextView.layer.borderColor = UIColor.gray.cgColor
newTextView.layer.borderWidth = 1
instockTag += 1
print("\(widgetInstockArray.count)")
Cell?.contentView.addSubview(newTextView)
}
}
}
print("could not add widgets")
}
return Cell!
}
func textViewDidBeginEditing(_ textView: UITextView) {
if newTextView.textColor == UIColor.lightGray {
newTextView.text = nil
newTextView.textColor = UIColor.black
}
}
func textViewDidEndEditing(_ textView: UITextView) {
if newTextView.text.isEmpty {
for i in labelInstockArray {
newTextView.text = i
}
newTextView.textColor = UIColor.lightGray
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
输出重叠:(
textFiled 在 textview 中,两者都出现在一个单元格中。
但我希望它们不应该重叠,并且每个单元格中应该只有一个小部件。
更新根据
如果我想在单击按钮时添加小部件怎么办,这样每次单击时都应该添加小部件。
这是我所做的
var idWidgetIs = IntegerLiteralType()
var labelWidget = String()
var widgetName = String()
let stockArray: [StockItem] = [ StockItem(id: idWidgetIs, label: labelWidget, widget: widgetName)]
@IBAction func textViewAct(_ sender: Any) {
idWidgetIs += 1
labelWidget = "placeholder"
StockItem.init(id: idWidgetIs, label: labelWidget, widget: .textView)
}
@IBAction func textFieldAct(_ sender: Any) {
idWidgetIs += 1
labelWidget = "placeholder"
StockItem.init(id: idWidgetIs, label: labelWidget, widget: .textField)
}
问题
1) 您正在以编程方式添加子视图。由于单元格被重复使用,因此您每次都在创建 TextField 和 TextView
2) 我在您的代码中看到的另一个问题是 i.contains(wTextField)
和 i.contains(wTextView)
这将始终为真,因为 wTextField
和 wTextView
都在数组 widgetInstockArray
中并且两个框架都是 CGRect(x: 10, y: 10, width: 200, height: 30)
所以你得到它重叠
更好的解决方案是使用 UIStackView
使用 UIStackview
创建自定义单元格
现在将一个 UITextField
和一个 UITextView
添加到 UIStackview
.
下一步是 cellForRow
方法。只需隐藏其他元素,如
if i == wTextField {
cell.wTextView.isHidden = true
cell.wTextField.isHidden = false
} else {
cell.wTextField.isHidden = true
cell.wTextView.isHidden = false
}
当您在 UIStackView
中隐藏其中一个视图时,其他元素会自动相应地设置
希望对您有所帮助,如有疑问请告诉我
更新
不相关,但保留两个数组来填充表视图不是好的做法,这可能对未来的更新代码有问题。
更好的解决方案是创建 struct
或 class
喜欢
enum Widget {
case TextField
case TextView
}
struct StockArray {
var type : Widget
var labelInstockArray = [String]()
var idInstockArray = [IntegerLiteralType]()
}
现在您可以创建 StockArray
的数组并且非常容易维护
宾果!!!
如果我对您的 code/need 理解正确,添加子视图是 而不是 重叠问题。 多次添加子视图是问题所在
for i in widgetInstockArray {
cellForRowAt
方法中的行是问题所在。基本上,对于循环遍历的每个单元格 (7 times = 3 for wTextView and 4 for wTextField)
,这意味着您要在视图上添加视图。
建议:删除 for i in widgetInstockArray {
和
let i = widgetInstockArray[indexPath.row]
并使用
进行比较 if i == wTextField {
对于 wTextView 也是如此。
如
- 每次 table 视图请求单元格时,都会创建一个新的文本字段/文本视图
- 在创建单元格时循环遍历 widgetInStockArray 将导致多个文本字段和文本视图被添加到该单元格
问题中的示例代码可以按如下方式重组和改进,以达到预期的效果。
重构库存信息
定义两种类型,方便获取单个库存商品的id、label、widget。
enum StockWidget: String {
case textField
case textView
}
struct StockItem {
let id: IntegerLiteralType
let label: String
let widget: StockWidget
}
相应地更新示例数据。
let stockArray: [StockItem] = [
StockItem(id: 1, label: "1ok", widget: .textView),
StockItem(id: 2, label: "2ok", widget: .textField),
StockItem(id: 3, label: "3ok", widget: .textView),
StockItem(id: 4, label: "4ok", widget: .textField),
StockItem(id: 5, label: "5ok", widget: .textField),
StockItem(id: 6, label: "6ok", widget: .textView),
StockItem(id: 7, label: "7ok", widget: .textField)
]
定义特定单元格
一个 UITextField
:
class TextFieldWidgetCell: UITableViewCell {
let textField: UITextField
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
let field = UITextField(frame: CGRect(x: 10, y: 10, width: 200, height: 30))
field.layer.borderColor = UIColor.gray.cgColor
field.layer.borderWidth = 1.0
field.layer.cornerRadius = 3.0
field.textColor = UIColor.gray
textField = field
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(textField)
}
override func prepareForReuse() {
super.prepareForReuse()
textField.placeholder = nil
textField.text = nil
}
}
还有一个 UITextView
:
class TextViewWidgetCell: UITableViewCell {
let textView: UITextView
override init(style: UITableViewCellStyle, reuseIdentifier: String!) {
let view = UITextView(frame: CGRect(x:10, y: 10, width: 200, height: 60))
view.backgroundColor = UIColor.white
view.font = UIFont.systemFont(ofSize: 15)
view.layer.borderColor = UIColor.gray.cgColor
view.layer.borderWidth = 1.0
view.layer.cornerRadius = 3.0
view.textAlignment = NSTextAlignment.justified
view.textColor = UIColor.black
textView = view
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(textView)
}
override func prepareForReuse() {
super.prepareForReuse()
textView.text = nil
}
}
使用 table 视图注册小部件单元格。
override func viewDidLoad() {
super.viewDidLoad()
firstTableView.dataSource = self
firstTableView.delegate = self
firstTableView.register(TextFieldWidgetCell.self, forCellReuseIdentifier: StockWidget.textField.rawValue)
firstTableView.register(TextViewWidgetCell.self, forCellReuseIdentifier: StockWidget.textView.rawValue)
}
适应UITableViewDataSource
实施
现在单元配置被拆分成两个 UITableViewCell
子类,tableView(_, cellForRowAt:)
的实现可以大大减少。
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return stockArray.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let stockItem = stockArray[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: stockItem.widget.rawValue)
switch stockItem.widget {
case .textField:
if let cell = cell as TextFieldWidgetCell {
cell.textField.placeholder = stockItem.label
}
case .textView:
if let cell = cell as TextViewWidgetCell {
cell.textView.text = stockItem.label
}
}
return cell
}