I have a collection view and each cell has a button,
I added an IB-action that is called when the button is pressed.
My issue is that when a certain button is tapped I want to change not only the background color of that button, I want to change all buttons in all the cells
I'm not sure how to implement this...
Thanks.
Try Somthg like this
Take a var selectedIndex : Int = -1
in cellForItemAt
cell.button.tag = indexpath.item
if selectedIndex == indexPath.item{
cell.button.backgroundColor = UIColor.blue // New Color
}
else{
cell.button.backgroundColor = UIColor.gray // Deafult color
}
in Button Action
selectedIndex = sender.tag
collectionView.ReloadData()
When you pressed to the button you should notify your collectionView class holder (by delegate pattern or using a closure) that right now all buttons should be changed. Then you should force change all visible buttons (take all visibleCells of collectionView and change the buttons style) and also in the cellForItemAtIndexPath method change the button style for every other buttons which is invisible right now.
Related
Let say I have a UICollectionViewCell and below is my layout of the cell
LabelOne || LabelTwo || Button
In my CollectionViewController, I set cellForRowAtIndexPath = 30. Now, I want to show a label named labelThree under label two and increase my cell height = 60 after button pressed. Below is the layout what I want to accomplish after button press
LabelOne || LabelTwo || Button
Label Three
Does anyone have any suggestions? Thanks in advance!
Create custom cell using auto-layout and make sure to set the height of each label and button. Also make sure to set set the top and
bottom constraints for all components. This way, the cell will have
it's height.
At start, set the visibility of Label Three as hidden.
Set the visibility of Label Three as visible on button click.
Call cell.layoutIfNeeded just after that to reset the cell height.
In cellForRow atIndexPath:
cell.updateConstraint = {
self.collectionView.beginUpdates()
self.collectionView.endUpdates()
}
In collectionview Cell:
var updateConstraint: () -> Void = {}
func addLabel() {
// add three label
// make cell new constraint
self.updateConstraint()
}
I have a button in custom UITableViewCell class. It shows/hides a view (part of same cell). The height of cell should change on doing that.
This is the button action (in UITableViewCell custom class):
#IBAction func showHideCartView(sender: UIButton)
{
if sender.tag == 1
{
// Show cart view
self.buttonArrow.tag = 2
self.viewAddToCart.isHidden = false
self.constraint_Height_viewAddToCart.constant = 50
self.buttonArrow.setImage(UIImage(named: "arrowUp.png"), for: .normal)
}
else
{
// Hide cart view
self.buttonArrow.tag = 1
self.viewAddToCart.isHidden = true
self.constraint_Height_viewAddToCart.constant = 0
self.buttonArrow.setImage(UIImage(named: "arrowDown.png"), for: .normal)
}
self.setNeedsUpdateConstraints()
self.setNeedsLayout()
self.layoutIfNeeded()
}
The height of cell remains unchanged. It is only when I scroll the UITableView and revisit the cell, it's height gets updated.
Add the following method to the viewController with the tableView to refresh the table when a cell is expanded:
func refreshTableAfterCellExpansion() {
self.tableView.beginUpdates()
self.tableView.setNeedsDisplay()
self.tableView.endUpdates()
}
Call the method after the constraints have been updated. If the button manipulates the constraints inside the cell, you will need to notify the viewController about the change so that you can call the method. Either use a delegate pattern (or pass directly a tableView reference to each expandable cell - just remember to store it as weak variable), or post a notification using NotificationCenter.default.
As this code is in the TableViewCell, You need to make a action method for your cell in the TableViewController so when the button is clicked you would know. You can keep a reference of your button in your tableviewCell and then inside the cell cellForRowAt you can do
cell.yourButtonRef.addTarget(self, action: #selector(expandButtonTapped(_:)), for: .touchDown)
and the make a function called "expandButtonTapped" and add the tableview beign and end update there
#objc func expandButtonTapped(_ button: UIButton) {
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
Please let me know if this has worked or not
I'm writing in swift, using the storyboard, and I'm working with iOS 10.
I have a UITableViewCell composed of some subviews (they're UIViews). Some of those subviews have a background color.
The selection style on the cell is Default (gray).
When I tap the cell, the cell becomes gray. Good. However, the background color of each subview in the cell is also changed automatically to match the selection color (gray) of the cell. Not good.
How can I best prevent this behavior? I don't want the background colors of the subviews in the cell to change.
NOTE: I don't consider it a very good solution to do my own selection by listening for the didSelectRowAtIndexPath delegate method and then setting the background color of the cell's content view. Perhaps this is the only way, but I want to see if there are other options first.
UPDATE:
Just to clarify, another reason I don't like the above solution of listening for the delegate is that it fixes the issue per cell. So if I have other custom cells that use the same subviews, I would have to implement the same fix. I want something that fixes this at the view level, rather than the cell level. So that when I use those same views in other custom cells for different table views, I don't have to worry about it.
This way is better than listening to the didSelectRowAtIndexPath for sure.
Play with these properties in your custom cell class:
override var isSelected: Bool {
didSet {
if isSelected {
//play with colors
print("selected")
} else {
//play with colors
print("deselected")
}
}
}
override var isHighlighted: Bool {
didSet {
if isHighlighted {
//play with colors
print("highlighted")
} else {
//play with colors
print("not highlighted")
}
}
}
Disable selection style:
cell.selectionStyle = UITableViewCellSelectionStyleNone
And tricky one:
cell.selectedBackgroundView = UIView()
I would like to put an image on my UITableViewCell, and make the cell moved to detail view controller when an user taps on the cell. However, I also want to let the cell NOT move to the detail VC when an user taps on the image which is put on only the part of the cell. The cell looks something like the follows:
[cell.textLabel myImage accessoryType] <- UITableViewCell
However, when I implement my code like below, an user must be moved to the detail VC when she taps on the cell, even if she taps on the tiny portion covered by the image. Is it possible to disable the didSelectRowAtIndexPath: when she taps on the image?
tableView:didSelectRowAtIndexPath:
var cell = self.tableView.dequeueReusableCellWithIdentifier(CellReuseIdentifier, forIndexPath: indexPath) as! UITableViewCell
var list = listArray[indexPath.row]
cell.textLabel?.text = list.name
cell.accessoryType = UITableViewCellAccessoryType.DetailButton
let image = UIImage(named: "myImage.png")
var imageView = UIImageView(image: image)
imageView.frame = CGRectMake(280, 4, 36, 36)
cell.addSubview(imageView)
return cell
I tried imageView.userInteractionEnabled = false but the result didn't change.
Also note that the image is not accessory view since I also want to use accessory type (both can't be used) so you can't use tableView:accessoryButtonTappedForRowWithIndexPath: delegate method.
You have three approaches to accomplish it:
Add UITapGestureRecognizer to your UIImageView. It will forces the UITableView dont call didSelectRowAtIndexPath if you tap over UIImageView.
If you are using storyboard, you can override override func shouldPerformSegueWithIdentifier(identifier: String!, sender: AnyObject!) -> Bool and avoid it.
Or as #DuncanLowrie said:
use a UIButton instead of an image view, or overlay the the image with a button. The button doesn't have to do anything, but will intercept the touch.
One way to achieve this would be to use a UIButton instead of an image view, or overlay the the image with a button. The button doesn't have to do anything, but will intercept the touch.
I have a custom tableviewcell with the standard disclosure indicator positioned in the centre vertically by default. How can I move this standard disclosure indicator vertically like in the iOS mail app?
You can adjust the position of the default accessory by subclassing your cell and finding the UIButton in the cell's subviews (which represents the indicator) and holding a reference to it. You can then simply update the frame of the accessoryButton in layoutSubviews or wherever you choose like so:
class CellSubclass: UITableViewCell {
var accessoryButton: UIButton?
override func awakeFromNib() {
super.awakeFromNib()
accessoryType = .DisclosureIndicator
accessoryButton = subviews.flatMap { $0 as? UIButton }.first
}
override func layoutSubviews() {
super.layoutSubviews()
accessoryButton?.frame.origin.y = 8
}
}
You can not move standard disclosure indicator vertically.
If you want to achieve this functionality, then you need to use your custom cell and use image of disclosure indicator and then you can set this image with button on where ever you want to place.
Or you can use view also as a accessory indicator and add as a subview of UITableViewCell
[cell.contentView addSubview:aView];
You can read more over here disclosure indicator
You can modify the Layout Margins to Fixed on TableViewCell in the .xib and then set the right margin to the desired value.