table 视图 swift ios 的单元格中的小部件相互重叠

Widgets overlap each other in the cells of table view swift ios

我正在根据数组 widgetInstockArray 中提供的元素在 table 视图的单元格中获取 textFieldtextView 小部件。 并从 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) 这将始终为真,因为 wTextFieldwTextView 都在数组 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 中隐藏其中一个视图时,其他元素会自动相应地设置

希望对您有所帮助,如有疑问请告诉我

更新

不相关,但保留两个数组来填充表视图不是好的做法,这可能对未来的更新代码有问题。

更好的解决方案是创建 structclass

喜欢

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
}