Have you seen on the iOS Facebook application, when sometimes you go check your notifications, the row of the tableView bounce in order to show that you can access actions? (Swipe left)
I would like to do the same, I succeeded to bounce the row left then right, but the actions behind the row don't show up.
I guess this is because nobody calls the method editActionsForRowAt.
My current code to bounce is:
let indexPath = IndexPath(item: 0, section: 0)
let contentView = tableView.cellForRow(at: indexPath)?.contentView
let original = contentView?.frame
var bounceOffset = original
bounceOffset?.origin.x -= 100
UIView.animate(withDuration: 0.5, delay: 0, options: .curveEaseOut, animations: {
contentView?.frame = bounceOffset!}) { _ in
UIView.animate(withDuration: 1, delay: 0, usingSpringWithDamping: 0.75, initialSpringVelocity: 0, options: .curveEaseOut, animations: {
contentView?.frame = original!
}, completion: nil)}
Do you have an idea of how I can do the same as Facebook?
A way to set [UITableViewRowAction]?
Related
I’ve created a draggable button over an UICollectionView, and it works well. However, whenever I pull down the UICollectionView to update data, the draggable button would always be back to the original coordinate.
On the other hand, I also want to set a timer for the draggable button title, it means the title will be updated every second. But the draggable button would be back to original coordinate as well when the title is changed.
I’ve tried to use millisecond for the timeInterval, but it wastes more CPU and battery consumption. So I’d like ask if there’s any better way to deal with it?
【Update】
I recreate another project for this, please refer to the gif as below.
I place the button at the middle of the view, and the title will be added 1 every second. So I was wondering why the button always get back to the original coordinate whenever the title is changed.
Gif Here!
【Second Update】
I set constraints for the button, and use UIPanGestureRecognizer to change the position of the button. Please refer to the following code.
private func setupFloatingBtn() {
view.addSubview(self.floatingBtn)
self.floatingBtn.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
self.floatingBtn.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
self.floatingBtn.widthAnchor.constraint(equalToConstant: 60).isActive = true
self.floatingBtn.heightAnchor.constraint(equalToConstant: 60).isActive = true
self.floatingBtn.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handler)))
}
#objc func handler(gesture: UIPanGestureRecognizer) {
let location = gesture.location(in: self.view)
let draggedView = gesture.view
draggedView?.center = location
if gesture.state == .ended {
if self.floatingBtn.frame.midX >= self.view.layer.frame.width / 2 {
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
self.floatingBtn.center.x = self.view.layer.frame.width - 40
}, completion: nil)
}else{
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
self.floatingBtn.center.x = 40
}, completion: nil)
}
}
}
I have a VideoView (it is a child view of UIView).
By default, it is added to a UIView which is small view in the corner of the screen (I called it ParrentView1).
I have a button to zoom out VideoView. This button performs an action that removes VideoView from ParentView1 and adds it to a bigger view (called ParrentView2).
When I perform the code below, it works but the animation is weird. All I need is a zoom out animation from ParrentView1 to ParrentView2.
Here is my code:
VideoView.removeFromSuperview()
ParrentView2.addSubview(VideoView)
UIView.animate(withDuration: 0.8, delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 1,
options: .curveEaseOut,
animations: {
VideoView.frame = ParrentView2.bounds
}, completion: nil)
thanks for helping
The likely cause is that when adding it to the other view, it gets assigned a different frame. The solution is to make sure the animation starts at the original location. Something like:
CGRect originalRect = ParrentView2.convert(VideoView.frame, from:VideoView.superView);
VideoView.removeFromSuperview()
ParrentView2.addSubview(VideoView)
VideoView.frame = originalRect;
UIView.animate(withDuration: 0.8, delay: 0,
usingSpringWithDamping: 1,
initialSpringVelocity: 1,
options: .curveEaseOut,
animations: {
VideoView.frame = ParrentView2.bounds
}, completion: nil)
An improvement point: note that it is customary in Swift to start variable names with a lower case letter. It gets confusing when they don't.
I would like to animate the tableView cell when the user put is finger on it like in this image
and when the user stop pressing, the cell come back in the original size (my tableView is not using a custom cell but the default UItableViewCell). I looked around the net to find some tutorial or something useful but nothing, someone can tell me how can i do?
You can do it like this:
On Touch Down Event for UITableViewCell:
UIView.animateWithDuration(0.2, delay: 0.1, usingSpringWithDamping: 0.9, initialSpringVelocity: 5, options: [],animations: {
self.contentView.transform = CGAffineTransformMakeScale(0.95, 0.95)
}, completion: { finished in
})
And On Touch Up Event for UITableViewCell:
UIView.animateWithDuration(0.2, delay: 0, usingSpringWithDamping: 0.9, initialSpringVelocity: 5, options: .CurveEaseIn,animations: {
self.contentView.transform = CGAffineTransformMakeScale(1, 1)
},completion: { finished in
})
Hope this will help you.
I programmatically created a UIStackView, which consists of two UICollectionView stacked vertically. One of them is a menubar, and one of them is a grid that displays media content.
let contentStack = UIStackView()
contentStack.addArrangedSubview(menuBar)
contentStack.addArrangedSubview(grid)
self.view.addSubview(contentStack)
I want the UIStackView to appear at the bottom of the screen, once a button is tapped. However, when it appears, I want it to do an animation, so it slides up from below the screen. I have looked at older solutions to posts similar to mine, but I could not find anything helpful because I manually set the constraints like this:
contentStack.translatesAutoresizingMaskIntoConstraints = false
contentStackBotAnchor = contentStack.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 0)
contentStackBotAnchor!.isActive = true
contentStack.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
contentStack.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
contentStack.axis = .vertical
contentStack.spacing = 0
I have attempted solutions like such:
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
self.contentStack.frame = CGRect.init(x: 0, y: self.view.frame.height - self.contentStack.frame.height, width: self.contentStack.frame.width, height: self.contentStack.frame.height)
}, completion: nil)
This didn't work for me.
As Reinier stated, you can animate your constraints. Another option could be using a CGAffineTransform. When the view loads, simply change the y value of your UIStackView with something like:
contentStack.transform = CGAffineTransform(translationX: 0, y: view.frame.height)
And then when you want to animate it, use the animation of your choice:
UIView.animate(withDuration: 0.5, animations: {
contentStack.transform = .identity
})
This is what I prefer in such cases, hope it helps.
If you are using constraint then you must animate using your constraints, Try with this, I am not sure about the values but must be like this
self.view.layoutIfNeeded()
UIView.animate(withDuration: 0.5, delay: 0, usingSpringWithDamping: 1, initialSpringVelocity: 1, options: .curveEaseIn, animations: {
contentStackBotAnchor.constant = (self.contentStack.bounds.size.height * -1)
self.view.layoutIfNeeded()
}, completion: nil)
Hope this helps
To animate a bar opening...
#IBOutlet var barHeight: NSLayoutConstraint!
barHeight.constant = barShut?30:100
self.view.layoutIfNeeded()
t = !barShut?30:100
UIView.animate(withDuration: 0.15,
delay: 0,
options: UIViewAnimationOptions.curveEaseOut,
animations: { () -> Void in
self.barHeight.constant = t
self.view.layoutIfNeeded()
},
completion: {_ in
Screen.barShut = !Screen.barShut
}
)
That's great ...
But how would you make it boing like this?
(The only way I'd know to do this is, use CADisplayLink, with a few lines of code for a spring decaying.) Is this available in UIKit?
You can use the spring animation method that is built in to UIView:
func toggleBar() -> Void {
self.view.layoutIfNeeded()
let newHeight:CGFloat = !barShut ? 30:100
barShut = !barShut
barHeightConstraint.constant = newHeight
UIView.animate(withDuration: 1.5, delay: 0, usingSpringWithDamping: 0.2, initialSpringVelocity: 3, options: [], animations: {
self.view.layoutIfNeeded()
}, completion: nil)
}
You will want a longer animation duration than 0.15 of a second in order for the bounce to seem realistic; I think the values I have look pretty good, but you can play with them to get the exact effect you are after.
Since the animation duration is longer, I found that I could tap the button the triggered the open/shut while the previous animation was still running. Setting barShut in the completion block meant that the bar didn't react to all taps. I moved the toggle outside of the animation to address this.