I have a View named AlarmView and a tableview named alarmtableview inside AlarmView , also I have a textfield
Now What I want is when a user enters any number in textfield , tableview will be reloaded with number of rows equal to that number entered by the user.
I have set the AlarmView height as 0 initially , so that when the textfield is empty AlarmView remains invisible from the users.
And after reloading the alarmtableview , I am updating the detailview's height equal to tableview's height.
But when I run the app the view's height is not updated. it remains invisible from the users even after reloading the tableview
Below Is the code I have written to achieve the same
#IBOutlet weak var AlarmViewHeightConstraint: NSLayoutConstraint!
#IBOutlet weak var AlarmView: UIView!
#IBOutlet weak var AlarmTableView: UITableView!
#IBOutlet weak var FrequencyField: CustomUITextField!
func textFieldDidEndEditing(textField: UITextField) {
print("textFieldDidEndEditing called")
if textField === FrequencyField{
self.AlarmToggleAction(self.AlarmSwitch)
}
}
//MARK: ALARM Actions
#IBAction func AlarmToggleAction(sender: UISwitch) {
if sender.on{
if let count = Int(self.FrequencyField.text!) {
print("ON state")
alarmCount = count
AlarmTableView.reloadData()
print("AlarmTableView.frame.height : \(AlarmTableView.frame.height)")
AlarmViewHeightConstraint.constant = AlarmTableView.frame.height
}
}
else{
print("OFF state")
alarmCount = 0
//AlarmTableView.reloadData()
//AlarmViewHeightConstraint.constant = 0
}
}
//MARK: Tableview Actions
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("numberOfRowsInSection called alarmCount : \(alarmCount)")
return alarmCount
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
print("cellForRowAtIndexPath called")
let cell = tableView.dequeueReusableCellWithIdentifier("AlarmCell") as! AlarmCell
cell.TimeLabel.text = "Alarm \(indexPath.row + 1)"
cell.TimeField.tag = indexPath.row
cell.TimeSwitch.tag = indexPath.row
return cell
}
Please help me out of this problem.
Thanks in advance
Try using contentSize instead of frame size like:
AlarmViewHeightConstraint.constant = AlarmTableView.contentSize.height
Related
I'm having problems with my app. I have a table view where every cell consists of a textfield. When i write in it and scroll down, than scroll back up, the data i wrote in it disappears.
These are some of my functions in ViewController
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate, UITextFieldDelegate, UIScrollViewDelegate {
var arrayOfNames : [String] = [String]()
var rowBeingEdited : Int? = nil
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return initialNumberOfRows
}
var count: Int = 0;
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
if(arrayOfNames.count > 0 && count < arrayOfNames.count) {
cell.TextField.text = self.arrayOfNames[indexPath.row]
}else{
cell.TextField.text = ""
}
count += 1
cell.TextField.tag = indexPath.row
cell.TextField.delegate = self
return cell
}
func textFieldDidEndEditing(_ textField: UITextField) {
let row = textField.tag
if row >= arrayOfNames.count {
for _ in ((arrayOfNames.count)..<row+1) {
arrayOfNames.append("") // this adds blank rows in case the user skips rows
}
}
arrayOfNames[row] = textField.text!
rowBeingEdited = nil
}
func textFieldDidBeginEditing(_ textField: UITextField) {
rowBeingEdited = textField.tag
}
}
As you can see, I'm saving all of my written text in the textfield into an array. Any help would be appreciated.
Thanks in advance
When you scroll back up tableView(tableView: cellForRowAt:) gets called again. Inside that method you increment count every time that is called, thus instead of using the first condition it goes to the second conditional statement that sets cell.TextField.text = "" as count is probably greater than arrayOfNames.count. What are you using count for? Maybe rethink how you could code that part a little better.
You cells are recreated. So you lose them. You could use the method PrepareForReuse to set the text back when they are recreated.
I have two UITextFields on the UITableViewCell and their IBOutlets are connected in the custom UITableViewCell class called as "CustomCell.swift".
The Enter button is there on the UIView of ViewController and its IBAction is there in the UIViewController class called as "ViewController".
On click of the Enter button I want to see if the two textFields are empty. How do I do it? Please help
create a Bool variable in your class where you have the button action
var isTextFieldTextEmpty: Bool!
then in your table view dataSource method cellForRowAtIndexPath add
if myCell.myTextField.text?.isEmpty == true {
self.isTextFieldTextEmpty = true
} else {
self.isTextFieldTextEmpty = false
}
then in the IBAction of your (Enter) button add
self.myTableView.reloadData()
self.myTableView.layoutIfNeeded()
print(self.isTextFieldTextEmpty)
if all text fields in all cells of the table view have text, it will print false, else if only one text fields among all the text fields has no text, it will print true
Here is a simple solution. It will work for any number of cells.
What you need to do is iterate through the cells and figure out if the textField that particular cell is holding is empty or not. Now the question is how will you iterate through the cells, is there any delegate for that? The answer is No.
You have to manually construct the indexPaths to get the cells from the Table.
Here is a simple walk through. Your set up is quite right. You should have a tableview in your ViewController. So, the IBOutlet of the tableview should be there. I named my TableView "myTableView". And the textField's Outlet should be inside the TableViewCell which is also right. At the end the action method for the Enter button should be in the view controller.
Make sure, you properly connect all the outlets.
Here is the sample custom TableViewCell -
import UIKit
class CustomTableViewCell: UITableViewCell {
#IBOutlet weak var internalTextField : UITextField!
override func awakeFromNib() {
super.awakeFromNib()
}
}
And now just go to the ViewController.swift-
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
#IBOutlet weak var myTableView : UITableView!
var numberOfCells = 2 //you can update it to be any number
override func viewDidLoad() {
super.viewDidLoad()
self.myTableView.dataSource! = self //assign the delegate
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfCells
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell : CustomTableViewCell = tableView.dequeueReusableCellWithIdentifier("customCell", forIndexPath: indexPath) as! CustomTableViewCell
return cell;
}
#IBAction func pressedEnter(){
var row = 0
while row < numberOfCells { //iterate through the tableview's cells
let indexPath : NSIndexPath = NSIndexPath(forRow: row, inSection: 0) //Create the indexpath to get the cell
let cell : CustomTableViewCell = self.myTableView.cellForRowAtIndexPath(indexPath) as! CustomTableViewCell
if cell.internalTextField.text!.isEmpty{
print("TextField is Cell \(row) is Empty")
}
else{
print("TextField is Cell \(row) is NOT Empty")
}
row += 1
}
}
}
There are comments which explains everything. Hope this helps.
With VoiceOver switched-on, when focus comes on a UIButton/UITableViewCell/UICollectionViewCell, VoiceOver reads it's accessibility label once.
Then as soon as user double taps to select that UIButton/UITableViewCell/UICollectionViewCell, VoiceOver reads the same accessibility label again besides performing action (navigation etc) on UIButton/UITableViewCell/UICollectionViewCell selection.
I've searched a lot but not able to find a way to stop/disable VoiceOver reading accessibility label on UIButton/UITableViewCell/UICollectionViewCell selection.
Any help would be highly appreciated.
Let's see how to stop the VoiceOver accessibility reading for the UIButton and the UITableViewCell elements.
UIBUTTON : just create your own button class and override the accessibilityActivate method.
class BoutonLabelDoubleTap: UIButton {
override func accessibilityActivate() -> Bool {
accessibilityLabel = ""
return true
}
}
UITABLEVIEWCELL : two steps to be followed.
Create a custom UIAccessibilityElement overriding the accessibilityActivate method.
class TableViewCellLabelDoubleTap: UIAccessibilityElement {
override init(accessibilityContainer container: Any) {
super.init(accessibilityContainer: container)
}
override var accessibilityTraits: UIAccessibilityTraits {
get { return UIAccessibilityTraitNone }
set { }
}
override func accessibilityActivate() -> Bool {
accessibilityLabel = ""
return true
}
}
Use the previous created class to implement your table view cells in the view controller.
class TestButtonTableViewController: UIViewController,UITableViewDataSource,UITableViewDelegate {
#IBOutlet weak var myTableView: UITableView!
#IBOutlet weak var bottomButton: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self as UITableViewDelegate
myTableView.dataSource = self as UITableViewDataSource
}
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int {
return 2
}
func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let zeCell = tableView.dequeueReusableCell(withIdentifier: "myPersoCell",
for: indexPath)
zeCell.accessibilityElements = nil
var elements = [UIAccessibilityElement]()
let a11yEltCell = TableViewCellLabelDoubleTap(accessibilityContainer: zeCell)
a11yEltCell.accessibilityLabel = "cell number " + String(indexPath.row)
a11yEltCell.accessibilityFrameInContainerSpace = CGRect(x: 0,
y: 0,
width: zeCell.contentView.frame.size.width,
height: zeCell.contentView.frame.size.height)
elements.append(a11yEltCell)
zeCell.accessibilityElements = elements
return zeCell
}
}
I haven't tried for a UICollectionViewCell but it should be the same rationale as the UITableViewCell's.
Following these code snippets, you're now able to decide if VoiceOver should stop reading out the desired elements labels when selected.
Swift 5
What worked for me was setting myElementIWantSilent.accessibilityTraits = .none
EDIT: I should note that these are also present:
viewContainingSilentElement.isAccessibilityElement = true
viewContainingSilentElement.accessibilityTraits = .image
viewContainingSilentElement.accessibilityLabel = "some text i want read aloud"
iPhone 8
iOS 14.5.1
XCode 12.5
I have TableView with cells and I have button on each cell. I want to add some functionality - when user presses button in cell some request is made to server and cell disappears from TableView.
How i can perform this? I know method to delete cell from tableView but to use it i need to get access to tableView from it's cell.
One way could be to add a callback closure to a custom cell and execute it upon cell selection. your view controller would hook this callback up in tableView(_,cellForIndexPath:) or tableView(_, cellWillAppear:)
import UIKit
class SelectionCallbackTableViewCell: UITableViewCell {
var selectionCallback: (() -> Void)?
#IBOutlet weak var button: UIButton!
#IBAction func buttonTapped(sender: UIButton) {
self.selectionCallback?()
}
override func layoutSubviews() {
super.layoutSubviews()
self.contentView.addSubview(self.button)
}
}
register the cell for the tableview. I did it in the storyboard.
import UIKit
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
#IBOutlet weak var tableView: UITableView!
var array = [1,1]
override func viewDidLoad() {
super.viewDidLoad()
for x in stride(from: 2, through: 30, by: 1){
let i = array[x-2]
let j = array[x-1]
array.append(i+j)
}
}
func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}
func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return array.count
}
func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath) as! SelectionCallbackTableViewCell
cell.selectionCallback = {
println("\(self.array[indexPath.row]) at \(indexPath.row) on \(tableView) selected")
}
cell.textLabel?.text = "\(self.array[indexPath.row])"
return cell
}
}
Now implement the callback closure as needed
cell.selectionCallback = {
println("\(self.array[indexPath.row]) at \(indexPath.row) on \(tableView) selected")
}
will result in logs like
832040 at 29 on <UITableView: 0x7fe290844200; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = RM+BM; gestureRecognizers = <NSArray: 0x7fe2907878e0>; layer = <CALayer: 0x7fe290711e60>; contentOffset: {0, 697}; contentSize: {375, 1364}> selected
all possible helpful information are present:
indexPath
datasource object
table view
cell
if you want delete the cell after successfully informing your server, for a simple solution do:
cell.selectionCallback = {
println("\(self.array[indexPath.row]) at \(indexPath.row) on \(tableView) selected")
self.apiManager.deleteObject(obj, success: { response in
self.array.removeAtIndex(indexPath.row)
tableView.reloadData()
}, failure:{ error in
// handle error
})
}
Disclaimer:
Personally I don't recommend to implement datasources as UIViewController. It violates the SOLID principles.
Instead datasources should reside in their own classes.
For my own Projects I use an architecture I call "OFAPopulator", that allows me to create independent datasources for each section of a table or collection view.
I chose to implement it inside the view controller here for brevity.
I missed the button part. edited.
Example code: https://github.com/vikingosegundo/CellSelectionCallback
I'm creating online tutorial app.In that i have 40 questions.I want to display the result for that questions using green image for correct and red color image for incorrect answers.I need to display this 40 images inside the single prototype cell.I want to know in swift.
A table view is designed to show multiple items in a scrolling list, not just one item. It sounds more like you want to have a table view with 40 rows, each of which displays the answer given for the question. You could set that up easily like so:
// This is your prototype cell configured in interface builder
class ResultTableViewCell: UITableViewCell {
#IBOutlet weak var answerImageView: UIImageView!
var correct: Bool = false {
didSet {
let imageName = self.correct ? "correct_image" : "incorrect_image"
if let image = UIImage(named: imageName ) {
self.answerImageView.image = image
}
}
}
}
class MyTableViewCell: UITableViewController {
#IBOutlet weak var collectionView: UICollectionView!
struct Answer {
let isCorrect: Bool
}
var answers = [Answer]() {
didSet {
self.tableView.reloadData()
}
}
// MARK: - UITableViewDataSource
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
if let cell = tableView.dequeueReusableCellWithIdentifier( "resultCell", forIndexPath: indexPath ) as? ResultTableViewCell {
cell.correct = self.answers[ indexPath.row ].isCorrect
return cell
}
fatalError( "Could not load cell" )
}
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.answers.count
}
}