animating a cell when pressed affects other cells - swift

I want to animate a card when pressed.
I made a table view, and added a custom cell to it.
and in custom cells, I created a UIButton and applied .touchUpInside gesture on the button.
when the button is pressed, the background color of the card will turn to red.
but weird thing is, if I press the first button,
6th, 10th, 15th and more cards' background-color also changed.
I check the function called only once but it happens to several cards.
I assume this might be related to dequeueReusableCell cell but not sure...
can anybody please help me out?
#objc func cardPressed(){
changeCardBackground()
}
private func changeCardBackground(){
var color:UIColor = .red
if(isCardRed){
color = .white
}
isCardRed = !isCardRed
UIView.animate(withDuration: 0.3) {
self.cardButton.backgroundColor = color
}
}

TableviewCells are reused you need to add prepareForReuse Method like :
override func prepareForReuse() {
super.prepareForReuse()
self.cardButton.backgroundColor = defaultColor
}

Related

Cannot display UIActivityIndicatorView

I meet a question. I am using following code to display UIActivityIndicatorView. My requirement is to be able to create an UIActivityIndicatorView and display it when I click the button with tag 1, if I click other buttons the UIActivityIndicatorView will be removed from the super view.
class ViewController: UIViewController {
lazy var acLoad:(UIActivityIndicatorView) = {
let myActivityIndicator = UIActivityIndicatorView(style: UIActivityIndicatorView.Style.white)
myActivityIndicator.center = view.center
myActivityIndicator.hidesWhenStopped = true
myActivityIndicator.startAnimating()
return myActivityIndicator
}()
//more code
#objc func btnAction(sender: UIButton){
switch sender.tag {
case 1:
print("created")
view.addSubview(acLoad)
acLoad.startAnimating()
default:
print("removed")
acLoad.stopAnimating()
acLoad.removeFromSuperview()
}
}
}
The above doesn't work, I can get the print log after click, but UIActivityIndicatorView doesn't display, any ideas?
It seems like your UIActivityIndicatorView might be misplaced (wrong frame value) - so it is not visible to you.
print("created")
view.addSubview(acLoad)
acLoad.startAnimating()
// Add this line in your button tap code
// It will tell you where it is placed inside your view
print(acLoad.frame)
If you find that it's frame is not where you want it to be, just fix your layout code and it will be where you expect it to be.
Another note - myActivityIndicator.hidesWhenStopped = true makes it automatically hide on stopAnimating() call. So you can add it only once, not remove-add every time.
Also check your view.backgroundColor vs acLoad style.

How to animate cells and buttons throughout the app in RxSwift?

I want to make click animations on every button and cell inside my app, basically all the views with actions. On every click I want a grayish blink.
The problem is the following: I made a custom class for button and the buttons across the app are working just fine. The problem is with cells as I try to make the animations rx-like. I have UITableView cells as well as UICollectionView cells and some views here and there, so I tried to do UIView extension which recognizes taps and if there is one - animation is played. I tried to do this with extension:
import UIKit
import RxSwift
extension UIView {
func makeSelectionIndicatable(forInitialBackgroundColor color: UIColor) {
let tapGesture = UILongPressGestureRecognizer()
tapGesture.minimumPressDuration = 0
tapGesture.cancelsTouchesInView = false
addGestureRecognizer(tapGesture)
tapGesture.rx.event.bind(onNext: { [weak self] recognizer in
if recognizer.state == .began {
self?.backgroundColor = .global(color: .athens_gray)
}
if recognizer.state == .ended {
self?.backgroundColor = color
}
if recognizer.state == .cancelled {
self?.backgroundColor = color
}
})
}
}
Obviously there is a dispose missing, but if I add one in extension - nothing will work. My question is: how to make animations rx-like, so that they'll be visible across app? Maybe I'm overthinking it and there are easier ways? Thx in advance
I can recommend RxDataSources
data.bind(to: tableView.rx.items(cellIdentifier: "Cell")) { index, model, cell in
cell.textLabel?.text = model
}
RxDataSources provides two special data source types that automatically take care of animating changes in the bound data source: RxTableViewSectionedAnimatedDataSource and RxCollectionViewSectionedAnimatedDataSource

How do you animate a UICollectionView using auto layout anchors?

I'm trying to animate a collectionview by using layout constraints however I cannot get it to work. I have a collectionview that takes up the entire screen and on a button tap I want to essentially move the collectionview up to make room for another view to come in from the bottom - see image below
The incoming UIView animates just fine (the view coming up from the bottom) - The reason I want to move the collectionview is that the incoming UIView obscures the collection view so am just trying to move the collectionview up at the same time as the new view so that all of the content in the collectionview can be displayed without being hidden by the new view - I use a reference view to get the right layout constraints for the final position for the collectionview Image to show what I am trying to achieve Am I going about it the right way?
Nothing happens with the code example below and I am not sure where to go from here - the same approach is used for animating the incoming view and works just fine but doesn't seem to work for the collectionview...
Any help would be kindly appreciated
var colViewBottomToReferenceTop: NSLayoutConstraint?
var colViewBottomToViewBottom: NSLayoutConstraint?
override func viewDidLoad() {
super.viewDidLoad()
colViewBottomToReferenceTop = musicCollectionView.bottomAnchor.constraint(equalTo: referenceView.topAnchor)
colViewBottomToViewBottom = musicCollectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor)
NSLayoutConstraint.active([colViewBottomToViewBottom!])
NSLayoutConstraint.deactivate([colViewBottomToReferenceTop!])
}
func playerShow() {
NSLayoutConstraint.activate([colViewBottomToReferenceTop!])
UIView.animate(withDuration: 0.5, animations: {
self.view.layoutIfNeeded()
})
}
#IBAction func btnTapped(_ sender: UIButton) {
playerShow()
}
You want to deactivate the other before animation
NSLayoutConstraint.deactivate([colViewBottomToViewBottom!])
NSLayoutConstraint.activate([colViewBottomToReferenceTop!])
Look to this Demo

How do I make a UIButton have the correct appearance with image and text?

I have a UIButton that has both an image and text in it. I am quite happy with its appearance except for when it is pressed.
Before it is pressed it looks like this:
After it is pressed it looks like this:
I am used to the appearance darkening the entire button when pressed, but for some reason when I have both an image and text is designates all the coloration to the image. I am quite aware that I can just make the entire button an image, but I am trying to keep this project as away from that style as possible. All of my other button are created with no images.
Is there any way to make the entire button darken as it normally would as it is currently setup?
You have to set the UIButton to Custom type (no System type) and change that properties:
self.yourButton.adjustsImageWhenHighlighted = false
If I get what you want try with that code:
override func viewDidLoad() {
super.viewDidLoad()
self.button.backgroundColor = UIColor.redColor()
}
#IBAction func buttonClicked(sender: UIButton) {
//Touch Up Inside action
sender.backgroundColor = UIColor.redColor()
}
#IBAction func buttonReleased(sender: UIButton) {
//Touch Down action
sender.backgroundColor = UIColor.grayColor()
}
Normal:
Pressed:
The simplest solution would be to match the text's highlight color:
button.setTitleColor(UIColor.gray, for: UIControlState.highlighted)

Table with static cells won't scroll when I set delaysContentTouches = false

The problem: HIGHLIGHT vs SCROLLING
My buttons inside the cell where not getting highlighted when I lightly tap on them. I had to tap hard and for a long time to be able to see the tap state of the button.
So I did this in order to set the delaysContentTouches to false (I didn't manage other way to do it) inside viewDidLoad():
for index in tableView.subviews {
if (index.isKindOfClass(UIScrollView)) {
let scrollViewFound = index as! UIScrollView
scrollViewFound.delegate = self
scrollViewFound.delaysContentTouches = false
scrollViewFound.canCancelContentTouches = true
scrollViewFound.scrollEnabled = true
}
}
This way the buttons highlight correctly but then I cannot scroll the table up or down, unless I start dragging from one of the empty cells --> userInteractionEnable = false in the empty cells
What I need:
To be able to highlight the buttons but also to scroll the table.
Is it even possible to have both, scrollable view and highlighted buttons?
What I have tried
I tried calling this function:
func touchesShouldCancelInContentView(view: UIView) -> Bool {
print("touchesShouldCancelInContentView happening---------")
return true
}
Which never gets called. I tried overriding But it gives an error:
Method does not override any method from its superclass
Which is weird, because UITableViewController inherits from UIScrollView. I also tried adding UIScrollViewDelegate to the class definition, but of course it gives another error that this is redundant.
Extra Information
The class is declared like this:
class Settings: UITableViewController, UITextFieldDelegate { ...
The tableView is made of Static Cells
The cells:
Some are empty: where UserInteractionEnable = false
Some have buttons with text field: I want these buttons to get highlighted. UserInteractionEnable = true. The button action is called by .TouchUpInside
Some have labels and a check image: Their action gets called in didSelectRowAtIndexPath which will change the labels colour and check images
Maybe it is relevant to say that when user clicks on any cell didSelectRowAtIndexPath it will
call a function to dismiss the keyboard.
You tried to subclass the wrong class, that's why it doesn't work. You have to subclass the UITableView class itself, and not the UITableViewController.
Can you try the following ?
- First
Subclass the TableView class in order to override the touchesShouldCancelInContentView function.
class UIDraggableTableView: UITableView {
override func touchesShouldCancelInContentView(view: UIView) -> Bool {
if (view.isKindOfClass(UIButton)) {
return true
}
return super.touchesShouldCancelInContentView(view)
}
}
- Second
In your TableViewController class, when viewDidLoad() is called, append the following right after super.viewDidLoad():
self.tableView = DraggableTableView()
This should solve your issue.
Part of this answer was taken from this StackOverflow post.