In a tableview’s section. I have some selectable rows.
Inside the section’s header I have a Deselect All button.
The deselect all button needs to get enabled if a row is selected and disabled if no row is selected.
The button is enabled/disabled by reading a boolean value. I have a didSet on that boolean:
var shouldEnableDeselectButton = false
{
didSet{
if oldValue != shouldEnableDeselectButton{
DispatchQueue.main.async {
self.notesTable.reloadSections([self.indexofFilter], with: .none)
}
}
}
}
If I do absolutely nothing in the didSet then it only gets updated by being dequeued/scrolling up or down and getting off the screen.
See below:
If I do self.notesTable.reloadSections([someSection], with: .none) then it longer requires the section header to get dequeued. Yet if I select one of the last rows, then it jitters badly:
See below:
I looked online and found solutions mentioned Reload tableview section without scroll or animation but they both still jitter
2 things were needed:
Get a reference/pointer to the headerView. E.g. this answer.
Have your button as a property. I was originally having it just as a subview. That wasn't enough!
To do such I made my sectionHeader a UITableViewHeaderFooterView subclass and then added the button as a property.
Then I was simply able to change the isEnabled property of the button.
Related
I'm trying to build a UICollectionView for a messaging application, where each UICollectionViewCell in the UICollectionView corresponds to a message. I am using MessageKit, which extends UICollectionView, to handle the messages. When the user taps a message, I want to reveal information about the message (time sent, user reactions to the message, etc.).
GroupMe does this in a very elegant way by (1) expanding the message vertically to reveal information, and (2) dimming the rest of the messages in the view and disabling user interaction for them. Note that the highlighted cell is still interaction enabled. See before/after images below.
Before tapping message
After tapping message
Here I am focused on achieving (2), i.e. when a message is tapped, I want to dim all other cells and disable user interaction for them. I also want to be able to animate this change so that it dims all the other cells over some short duration. When the user taps anywhere in the view, I'd like the highlighted cell to 'unhighlight', and user interaction to be re-enabled for all cells, and similarly animate the revert.
I'm a little stumped on how to achieve this behavior - any ideas on how to implement this in Swift? Any pointers that could get me started in the right direction would be greatly appreciated!
You could add a UIView for each Cell’s subview, except for the one selected. This view could be animated by changing the alpha value with fading/appearing effect.
You can override isSelected property in your custom UICollectionViewCell to handle the user interaction and alpha on cell selection, i.e.
class CollectionViewCell: UICollectionViewCell {
override var isSelected: Bool {
didSet {
self.isUserInteractionEnabled = self.isSelected
self.alpha = self.isSelected ? 1.0 : 0.5
}
}
//rest of the code...
}
what is the different between isSelected method of tableviewcell and selectRow(at:animated:scrollPosition:) of tableview when i want to set a cell to be selected?
i.e.
cell.isSelected = true vs tableview.selectRow(at:index, animated: false, scrollPosition: .none)
I found most people use the latter,but i do not known why
one Work on the cell : means that you have pointer to it (mainly it is done in didSelectRow to unselect the row after pushing a detail view for example). The other tell the table view to select the cell not having to have a reference to it.
selectRow(at:animated:scrollPosition:)
Selects a row in the table view identified by index path, optionally scrolling the row to a location in the table view.
cell.isSelected
isSelected bool affects the appearance of the cell. the default value is false.
For more info:
https://developer.apple.com/documentation/uikit/uitableviewcell/1623263-isselected
https://developer.apple.com/documentation/uikit/uitableview/1614875-selectrow
I have a UITableViewController with dynamic cells.
in my tableViewCellForRowAtIndexPath I set the indexPath.row as tag to one of my subviews from that cell. This subview has an IBAction when one clicks on it.
In my custom TableViewCell I call a listener when this subview is clicked and give the value of the tag as parameter, so that my TableViewController can act on it.
This is what I do then: (it is in java, because I am using multi-os-engine but it is very similar to swift/obj-c)
#Override
public void onOrderClicked(long index) {
OrdersTableViewCell cell = (OrdersTableViewCell) ordersList().cellForRowAtIndexPath(NSIndexPath.indexPathForRowInSection(index, 0));
if (cell.arrowView().image().equals(UIImage.imageNamed("downarrow"))) {
cell.arrowView().setImage(UIImage.imageNamed("uparrow"));
cell.orderDetailsView().setHidden(false);
}
else {
cell.arrowView().setImage(UIImage.imageNamed("downarrow"));
cell.orderDetailsView().setHidden(true);
}
Basically I just change the hidden state of one subview in my cell. Actually this works fine. BUT when clicking on one of my elements, the subview hidden state sometimes changes not only from this cell, but also from another one. I don't understand why. For more information: There are multiple cells so, that I even have to scroll to see them all. And when clicking on one of my cells, the hidden state of another cell changes too, which is not in the screen atm.
Anyone has a hint what I am doing wrong or why this is happening?
I have an expandable tableview with custom headers. I need to change a text of a label in the header when the table is expanding. I used below code for this.
func toggleSection(header: SuperHeaderDelegate, section: Int) {
sections[section].expanded = !sections[section].expanded
tableView.beginUpdates()
tableView.reloadSections([section], with: .automatic)
tableView.endUpdates()
if let head = header as? SavingAccountHeaderView {
head.accNoLabel.text = "HIIIIIII"
}
else { print("NOPE") }
}
When I use this code it changes the accNoLabel text to new text and change it back to the old text again.
I have tried the tableView.reloadData() instead of the tableView.reloadSections(), then the code worked fine. The accNoLabel didn't change back to its old text. But I really need to use the tableView.reloadSections() to use the animation.
So could anyone tell me what I'm doing wrong?
Couple of things you should check:
Is your 'expanded' toggle happening at the right place (and time)?
reloadSections() is an asynchronous function. So you can't expect your text to be updated 'after' the updates have been completed.
I would suggest toggling your label's text inside the viewForHeader function, because at this point you can be sure that the reloadSections() method is being called and the section's state has already been updated.
I have a UITableView with a custom UITalbeCellView. Every cell has a title a body and a date. When I fetch the data some of the titles must be red so there is a Bool that is set to true for those cells which title has to be red.
The first time the data is fetched it looks fine, but as you scroll up and down a few times all of the titles end up being red.
Im using an array of structures to store the data and on the cellForRowAtIndexPath there is an if and if the boolean in that position of the array is true I change the color to red:
let cell = tableView.dequeueReusableCellWithIdentifier("CommentsRowTVC", forIndexPath: indexPath) as! CommentsRowTVC
let single_comment = self.AOS[indexPath.row]
cell.titulo_comentario?.text = single_comment.titulo_comment
if single_comment.flag == true {
cell.titulo_comentario.textColor = UIColor.redColor()
}
Im gessing it reuses Views or something like that. Does this have any easy fix? Or do I have to implement my own TableView to prevent this from happening?
Im also thinking the method dequeueReusableCellWithIdentifier might be the one causing my problem... but Im new on swift and cant think of any replacement for that.
It is happening similar thing on buttons there are on the cells, when you click a button from a cell it changes its color and disables it, but just the one on that cell. However when clicking on a cell, buttons from other cells are also suffering those changes.
Since cells get reused you end up with cells that were previously red because they hadsingle_comment.flag == true and are now used for another row where there actually is single_comment.flag == false. You have to reset the color in the else branch again:
if single_comment.flag == true {
cell.titulo_comentario.textColor = UIColor.redColor()
} else {
cell.titulo_comentario.textColor = UIColor.whiteColor()
}
UITableViews reuse their cells, meaning that you will get cells inside your cellForRowAtIndexPath which have previously been used before, maybe have have set the textColor to red. Your job is it now to revert the color of the text to its original state.
In general whatever change you make inside the if-branch of cell-customization has to be undone in the else-branch. If you remove a label in the if, add it in the else.