i Have a table view and use custom cells for this. now i have set a clear button in my Bar. now on click of that UIBarButton i want to clear all the text inside the text field in the cells. How can i do this..??
var DataSource = [NewAssessmentModel]()
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.DataSource.count
}
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let model = self.DataSource[indexPath.row]
switch(model.assessmentControlType)
{
case .text:
let cell = (tableView.dequeueReusableCellWithIdentifier("QuestionWithTextField", forIndexPath: indexPath) as? QuestionWithTextField)!
cell.model = model
cell.indexPath = indexPath
cell.txtAnswer.delegate = self
cell.lblQuestion.text = model.labelText
cell.indexPath = indexPath
return cell
}
}
now cell contains a txtAnswer as a UITextField. How can i clear the text fields of txtAnswer.
for clearing the fields:
func clearView(sender:UIButton)
{
print("Clear Button clicked")
}
The above code applies only for the cells that are visible.The cell values won't be cleared if it is not visible in the phone.
For this you need to loop through every table view cells. I think this one is the one of the good option for you.
func clearView(sender:UIButton)
{
print("Clear Button clicked")
for view: UIView in tableView.subviews {
for subview: Any in view.subviews {
if (subview is UITableViewCell) {
let cell = subview as? UITableViewCell
// do something with your cell
if let questioncell = cell as? QuestionWithTextField
{
questioncell.txtField.text = ""
}
// you can access any cells
}
}
}
}
You can get all visible cell of tableView.
#IBAction func deleteText(_ sender: Any) {
for cell in tableView.visibleCells {
if let questionCell = cell as? QuestionWithTextField {
// Hide your label here.
// questionCell.lblQuestion.hidden = true
}
}
}
Related
I have a segment outlet in a tableview cell in a VC. There are two indexes: 1 and 2.
When I click on 2, I want to tell the collection view within another tableviewcell to reload another view.
And when I click back to 1, I want the same collection view to reload again and display the original content.
Here are my View Controller Functions:
class MyProfileTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource,segment
{
//Variable selection to determine what is selected - 1 by default
var viewSelected = "1"
//Segment Function - viewSelected is used to tell VC what index it's on
func segmentSelected(tag: Int, type: String) {
if type == "1" {
print("1")
viewSelected = "1"
} else if type == "2" {
print("2")
viewSelected = "2"
}
}
//Cell For Row - tells tableviewcell to look at viewSelected
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = AboutTableView.dequeueReusableCell(withIdentifier: "ProfileSegmentTableViewCell", for: indexPath) as! ProfileSegmentTableViewCell
cell.segmentCell = self
return cell
} else {
let cell = AboutTableView.dequeueReusableCell(withIdentifier: "1_2Cell", for: indexPath) as! 1_2Cell
cell.viewSelected = viewSelected
return cell
}
Here is the Segment Control TableviewCell
//protocol used to delegate
protocol segment: UIViewController {
func segmentSelected(tag: Int, type: String)
}
class ProfileSegmentTableViewCell: UITableViewCell {
#IBOutlet weak var profileSegmentControl: UISegmentedControl!
var segmentCell: segment?
#IBAction func segmentPressed(_ sender: Any) {
profileSegmentControl.changeUnderlinePosition()
let Index = self.profileSegmentControl.selectedSegmentIndex
if Index == 0
{
segmentCell?.segmentSelected(tag: (sender as AnyObject).tag, type: "1")
)
} else {
segmentCell?.segmentSelected(tag: (sender as AnyObject).tag, type: "2")
}
}
CollectionView
//variable by default
var viewSelected = "1"
//viewDidLoad
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
cView.delegate = self
cView.dataSource = self
get {
self.cView.reloadData()
self.cView.layoutIfNeeded()
}
}
func get(_ completionHandler: #escaping () -> Void) {
getCount.removeAll()
if viewSelected = "1" {
print("1") } else {
print("2)
}
completionHandler()
}
Here's a very simple example of using a closure so your segmented-control cell can communicate with your table view controller.
Your cell class might look like this:
class ProfileSegmentTableViewCell: UITableViewCell {
#IBOutlet var profileSegmentControl: UISegmentedControl!
var callback: ((Int)->())?
#IBAction func segmentPressed(_ sender: Any) {
guard let segControl = sender as? UISegmentedControl else { return }
// tell the controller that the selected segment changed
callback?(segControl.selectedSegmentIndex)
}
}
When the user changes the selected segment, the cell uses the callback closure to inform the controller that a segment was selected.
Then, in your controller, you could have a var to track the currently selected segment index:
// track selected segment index
var currentIndex: Int = 0
and your cellForRowAt code would look like this:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
// first row - use cell with segemented control
let cell = tableView.dequeueReusableCell(withIdentifier: "ProfileSegmentTableViewCell", for: indexPath) as! ProfileSegmentTableViewCell
// set the segemented control's selected index
cell.profileSegmentControl.selectedSegmentIndex = self.currentIndex
// set the callback closure
cell.callback = { [weak self] idx in
guard let self = self else {
return
}
// update the segment index tracker
self.currentIndex = idx
// reload row containing collection view
self.tableView.reloadRows(at: [IndexPath(row: 1, section: 0)], with: .automatic)
}
return cell
} else if indexPath.row == 1 {
// second row - use cell with collection view
let cell = tableView.dequeueReusableCell(withIdentifier: "1_2Cell", for: indexPath) as! My_1_2Cell
// tell the cell which segment index is selected
cell.setData(currentIndex)
return cell
}
// all other rows - use simple Basic cell
let cell = tableView.dequeueReusableCell(withIdentifier: "PlainCell", for: indexPath) as! PlainCell
cell.textLabel?.text = "Row \(indexPath.row)"
return cell
}
Here is a complete example you can run and examine: https://github.com/DonMag/ClosureExample
You can use NotificationCenter.default.addObserver... method and NotificationCenter.default.post..... Read about them. And don't forget to remove observers in deinit
I am new to swift I have a tableView with a custom cell. When I hit the cell, it should expand the cell and show all the data. I tried but I am not able to get the proper result. I have to show a custom table view cell when I will show all the data
data. I have the data coming from json.
Custom xib table view cell:
class ExpandTableViewCell: UITableViewCell {
#IBOutlet weak var timeLable: UILabel!
var item: ExpandTableViewCell? {
didSet {
}
}
static var nib:UINib {
return UINib(nibName: identifier, bundle: nil)
}
static var identifier: String {
return String(describing: self)
}
}
Register into the viewDidLoad():
tableView?.register(ExpandTableViewCell.nib, forCellReuseIdentifier: ExpandTableViewCell.identifier)
The tableView methods:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if section == 1 {
if storeDetailsDictionary != nil{
return (storeDetailsDictionary?.count)!
} else {
return 0
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if(indexPath.section == 1) {
//address cell
let cell = tableView.dequeueReusableCell(withIdentifier: ExpandTableViewCell.identifier, for: indexPath) as? ExpandTableViewCell
var timing:String = String.init(htmlEncodedString: storeDetailsDictionary!["timing"] as? String ?? "")
cell?.timeLable.text = timing//?.replacingOccurrences(of:", ", with: ",\n")
return cell!
}
}
How can I expand the table view cell?
check this tutorial it's helpful for creating expandable list:
https://medium.com/ios-os-x-development/ios-how-to-build-a-table-view-with-collapsible-sections-96badf3387d0
I have a tableview with one textfield in each cell. I added a target like this:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customLevelCell") as! LevelTableViewCell
cell.cellTextField.addTarget(self, action: #selector(ViewController.TextfieldEditAction), for: .editingDidEnd)
return cell
}
But found out that I'm not able to use the indexpath.row / sender.tag to get the specific textfield text
#objc func TextfieldEditAction(sender: UIButton) {
}
So my question is how can I get the text after the user has edited one of the textfields.
Also how can i get the indexpath.row or sender.tag which will be used to collect the text they added to that specific textfield.
The easiest way to handle this is probably to use a delegate protocol…
In your cell
protocol LevelTableViewCellDelegate: class {
func levelTableViewCell(_ levelTableViewCell: LevelTableViewCell, didEndEditingWithText: String?)
}
class LevelTableViewCell: UITableViewCell {
#IBOutlet private weak var cellTextField: UITextField!
var delegate: LevelTableViewCellDelegate?
override func awakeFromNib() {
cellTextField.addTarget(self, action: #selector(didEndEditing(_:)), for: .editingDidEnd)
}
#objc func didEndEditing(_ sender: UITextField) {
delegate?.levelTableViewCell(self, didEndEditingWithText: sender.text)
}
}
In your view controller
class TableViewController: UITableViewController {
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "LevelTableViewCell") as! LevelTableViewCell
cell.delegate = self
return cell
}
}
extension TableViewController: LevelTableViewCellDelegate {
func levelTableViewCell(_ levelTableViewCell: LevelTableViewCell, didEndEditingWithText: String?) {
let indexPath = tableView.indexPath(for: levelTableViewCell)
// Now you have the cell, indexPath AND the string
}
Also, note that the view outlet is be private. You'll find that you write cleaner code if you follow this rule
Following is the extension of UIView that can be used to get the cell or indexPath of the cell enclosing textField
extension UIView {
var tableViewCell : UITableViewCell? {
var subviewClass = self
while !(subviewClass is UITableViewCell){
guard let view = subviewClass.superview else { return nil }
subviewClass = view
}
return subviewClass as? UITableViewCell
}
func tableViewIndexPath(_ tableView: UITableView) -> IndexPath? {
if let cell = self.tableViewCell {
return tableView.indexPath(for: cell)
}
return nil
}
}
Example :-
#objc func TextfieldEditAction(sender: UITextField) {
//replace tableView with the name of your tableView
guard let indexPath = sender.tableViewIndexPath(tableView) else {return}
}
I put UITextField inside UITableViewCell and want to make highlight tableViewCell and unselected tableViewCell goes original color if user key-in inside each UITextField. So, I did like that.
func textFieldDidBeginEditing(_ textField: UITextField) {
defaultIndex = textField.tag
dynamicFormTable.reloadData()
}
But problem is Keyboard is not showing when I've added dynamicFormTable.reloadData(). Please let me know how to resolve it. Thanks.
Following code will give good result, to avoid reloads
var cellBGColr = [Int : UIColor]()
var previouselectedRow = [Int]()
override func viewDidLoad() {
super.viewDidLoad()
for i in 0..<70 // numberOfRows
{
cellBGColr[i] = UIColor.white
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 70
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "table", for: indexPath) as! TblTableViewCell
cell.backgroundColor = cellBGColr[indexPath.row]
cell.selectionStyle = .none
return cell
}
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool {
let cellPosition = textView.superview?.convert(CGPoint.zero, to: tblView)
let indPath : IndexPath = tblView.indexPathForRow(at: cellPosition!)!
let cell = tblView.cellForRow(at: indPath) as! TblTableViewCell
var previousSelectedCellRow : Int = -1 // FOR VALIDATION
if previouselectedRow.count == 0 // FIRST EDIT
{
previouselectedRow.append(indPath.row)
}
else
{
previousSelectedCellRow = previouselectedRow[0]
if previousSelectedCellRow == indPath.row // SAME ROW EDITING AGAIN
{
}
else // NEW ROW
{
let previousIndPath : IndexPath = IndexPath(row: previousSelectedCellRow, section: 0)
if (tblView.indexPathsForVisibleRows?.contains(previousIndPath))!
{
let previousCell = tblView.cellForRow(at: previousIndPath) as! TblTableViewCell
previousCell.backgroundColor = UIColor.white
cellBGColr[previousSelectedCellRow] = UIColor.white
}
else
{
cellBGColr[previousSelectedCellRow] = UIColor.white
}
previouselectedRow.remove(at: 0)
previouselectedRow.append(indPath.row)
}
}
cell.backgroundColor = UIColor.red // HERE YOU CAN CHANGE UR CELL COLOR
cellBGColr[indPath.row] = UIColor.red // HERE STORED IN DICT
return true
}
On scrolling your tableview, or somewhere you try to reload, cell background color will not change / reuse.
When reloadData is called it resigns first responder. But you can use beginUpdates/endUpdates methods:
dynamicFormTable.beginUpdates()
dynamicFormTable.reloadRows(at: [IndexPath(row: defaultIndex, section: 0)], with .none)
dynamicFormTable.endUpdates()
I'm using custom tableview cells. I've 2 sections, first is a custom cell which contains a dynamic height textview and second section custom cell contains labels with firstrow having StartDate and secondrow having EndDate. When a row in second section(DateCell) is selected a date picker is shown which is in a cell of type DatePickerCell.
Both StartDate and EndDate rows use custom cell of type DateCell.
The problem is when tableview is scrolled the same data is appearing in both StartDate and EndDate.
I'm loading the cells from storyboard so the cells will not be nil.
I'm using different reuseidentifiers for StartDate and EndDate but still the problem exists.
Also, can anyone suggest what should be done in prepareForReuse method in this case.
Please find the code below.
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) ->Int{
if section == 1 {
if isDatePickerVisible == true {
return 3
}
return 2
}
return 1
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
var identifier = ""
switch indexPath.section {
case 0 : identifier = kTextViewCellID
case 1 :
if datePickerIndexPath == indexPath && isDatePickerVisible == true {
identifier = kDatePickerCellID
}
else if indexPath.row == 0 {
identifier = kStartDateCellID
}
else {
identifier = kEndDateCellID
}
default: identifier = ""
}
let cell = tableView.dequeueReusableCellWithIdentifier(identifier, forIndexPath: indexPath)
if let c = cell as? TextCell {
//do something
}
//Both StartDate and EndDate are DateCell type
else if let c = cell as? DateCell {
c.dateLable.text = … //some text
c.dateValue?.text = … // some date in string format
}
else if let c = cell as? DatePickerCell {
//show DatePicker
}
return cell
}
class DateCell : UITableViewCell {
#IBOutlet weak var dateValue: UITextField?
#IBOutlet weak var dateLable: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
}
func setSomeColor() {
dateValue?.textColor = UIColor.redColor()
}
func clearDateValue (clear: Bool) {
//...
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
}
You make changes on "c" variable, but return "cell" variable. You should return "c" variable or make changes on "cell" variable.