I am getting widgets either textField
or textView
in cells of table view based on the provided elements in the array widgetInstockArray
.
And getting placeholder for the widgets from the labelInstcokArray
The problem : The Cell appears with both widgets overlaped, the textField is enclosed within textView on every cell.
What I want : There should be a textField or textView in each cell but not both enclosed & overlapped simultaneously.
Here is what i have done so far:
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.
}
}
Output is overlapped :(
The textFiled is within the textview, both appear in a single cell.
But I want they should not overlap and there should be only one widget in each cell.
UPDATE according to THIS ANSWER
What if i want to add widgets on a button click so live the widgets should be added on each click.
here is what i have done
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)
}
As identified in this answer:
The sample code from the question can be restructured and improved as follows to achieve the desired result.
Define two types for more convenient access to the id, label and widget of a single stock item.
enum StockWidget: String {
case textField
case textView
}
struct StockItem {
let id: IntegerLiteralType
let label: String
let widget: StockWidget
}
Update the sample data accordingly.
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)
]
One with a 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
}
}
and one with a 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
}
}
Register the widget cells with the table view.
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
implementationNow that the cell configuration is split off into two UITableViewCell
subclasses, the implementation of tableView(_, cellForRowAt:)
can be reduced a great deal.
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
}