decrease speed in upward textview animation (swift3) - ios

My code below scrolls the textview to the top. How can I make the animation half of its current speed. theTextView is the textview i am using.
theTextView.contentOffset = .zero
theTextView.setContentOffset(.zero, animated: true)

How about a simple UIViewAnimation without using the included .setContentOffset method of UiTextView. Could be something like this:
var speed: CGFloat = 0.3 // speed in seconds
UIView.animate(withDuration: speed, animations: {
theTextView.contentOffset = .zero
}, completion: nil)
You can change the animation speed by changing the speed variable.

Related

Slot machine animation using UITableView

I need to implement slot-machine animation according to provided design and timings.
It should perform infinite scroll, until some event will be triggered. After that animation, it should slow down and stop on defined position
For this task I have used next solution:
UITableView with fixed-height cell. It is the same cell with the only difference - icon or text (depends on indexPath.row)
Scroll is only down-to-up that's why I'm using last cell as start point in resetScrollPosition method
If first element reached, scroll position resets to start point
Animation performed as contentOffset change with linear option. In completion block, if animation is still needed, it's called again. If don't needed - slowing animation with easeOut option started
var isRolling: Bool = false
func startScroll() {
isRolling = true
UIView.animate(
withDuration: 0.05,
delay: 0,
options: .curveLinear,
animations: {
self.tableView.contentOffset.y -= self.rowHeight
},
completion: { _ in
if self.isRolling {
self.startScroll()
} else {
self.resetScrollPosition
UIView.animate(
withDuration: 0.7,
delay: 0,
options: .curveEaseOut,
animations: {
self.tableView.contentOffset.y -= 8 * self.rowHeight
},
completion: nil
)
}
})
}
private func resetScrollPosition() {
tableView.reloadData()
tableView.contentOffset.y = startOffset
tableView.reloadData()
}
func stopScroll() {
isRolling = false
}
The problems:
After calling resetScrollPosition, in animations completion block, tableviews contentOffset.y value is updated but tableView stays on the same position. I have tried to change direct contentOffset changing to setContentOffset, scrollToRow, scrollToRect, wrap it in main queue - no changes
Slowing animation should scroll 8 items. It's performed but first 6 items aren't visible during animation, only the last two.
Check the issue gif (jump 2 -> 11 is ok):
Replaced UITableView with UIScrollView
Uploaded code to gist - https://gist.github.com/OlesenkoViktor/76845c5448b421ead0a2303af2b1161d
Thanks #Paulw11 for his idea

How to fix this old frame glitch appearing when animating view?

I have a Header view that contains pager view (FSPagerView), which has an item (FSPagerViewCell) that contains bar chart, 2019, year review texts. I'm trying to scale down Header at certain times with such code:
private func setSelfHeightAnimated(height: CGFloat)
{
UIView.animate(withDuration: 0.2, animations: {
self.selfHeightAnchor.constant = height
self.superview?.layoutIfNeeded()
})
}
private func setPagerHeightAnimated(height: CGFloat)
{
UIView.animate(withDuration: 0.2, animations: {
self.pagerHeightAnchor.constant = height
self.layoutIfNeeded()
// self.pagerView.layoutIfNeeded()
// self.pagerView.layoutSubviews()
// self.pagerView.cellForItem(at: 0)?.layoutIfNeeded()
// self.pagerView.cellForItem(at: 0)?.setNeedsDisplay()
// self.superview?.layoutIfNeeded()
// self.setNeedsDisplay()
// self.pagerView.setNeedsDisplay()
})
}
However, the old frame glitch is very visible. What could be missing? Here is the video: https://streamable.com/owsdi
You have an 1st layout and a 2nd layout, and an animation that leads from the 1st to the 2nd.
Currently, the 1st layout is faded out and the 2nd layout is faded in during the animation, which gives you the „glitch“.
I assume what you want to achieve is:
- The top part (History, 2019, Year review) should keep their height, and
- only the columns below should shrink/expand, while the lower table slides up or down.
A solution probably is that you animate only the height of a subview that contains the 2 columns.
If the header view is set to adopt its height to its contents, then I expect that the required effect is shown without a glitch.
EDIT:
If you definitively had to animate the upper part as a whole, one possibility may be (that I consider as ugly) to set the alpha value of History, 2019, and Year to 0 immediately before the animation begins. Then these texts would only fade in so the glitch with double images at different places would be avoided.
Try like this to avoid glitching.
private func setSelfHeightAnimated(height: CGFloat)
{
self.selfHeightAnchor.constant = height
UIView.animate(withDuration: 0.2, animations: {
self.layoutIfNeeded()
self.viewDidLayoutSubviews()
})
}
private func setPagerHeightAnimated(height: CGFloat)
{
self.pagerHeightAnchor.constant = height
UIView.animate(withDuration: 0.2, animations: {
self.layoutIfNeeded()
self.viewDidLayoutSubviews()
})
}

UITextField text jumps when animating width constraint

I'm experiencing a glitch where my UITextField's text jumps to its final position (it doesn't animate) when animating the textfield's width constraint. Take a look at this gif:
When the "Grow" button is tapped, the textfield's width grows. But "hello world" jumps immediately to the center instead of gliding there. When the "Shrink" button is tapped, "hello world" jumps immediately back to the left.
My animation function looks like this:
func animateGrowShrinkTextFields(grow: Bool) {
if grow {
UIView.animate(withDuration: 0.5, animations: {
self.widthConstraint.constant = 330
self.view.layoutIfNeeded()
}, completion: nil)
} else {
UIView.animate(withDuration: 0.5, animations: {
self.widthConstraint.constant = 100
self.view.layoutIfNeeded()
}, completion: nil)
}
}
I have tried the following list suggestions; none of them worked.
I called self.view.layoutIfNeeded() and self.helloWorldTextField.layoutIfNeeded() before and within the animation block as suggested in this answer: https://stackoverflow.com/a/32996503/2179970
I tried self.view.layoutSubviews and self.helloWorldTextField.layoutSubview as suggested in this answer: https://stackoverflow.com/a/30845306/2179970
Also tried setNeedsLayout() UITextField text jumps iOS 9
I even tried changing the font as suggested here: https://stackoverflow.com/a/35681037/2179970
I tried resignFirstResponder (although though I never tap or edit the textfield in my tests, so it should not involve the firstResponder) as suggested here: https://stackoverflow.com/a/33334567/2179970
I tried subclassing UITextField as seen here: https://stackoverflow.com/a/40279630/2179970
I also tried using a UILabel and got the same jumpy result.
The following question is also very similar to mine but does not have an answer yet: UITextfield text position not animating while width constraint is animated
Here is my project on Github: https://github.com/starkindustries/ConstraintAnimationTest
Solution Demo
I've found a working solution. It feels a little hackish but it works. Here is a gif of the final result. Notice that helloWorldTextField has a blue border to show its location within the second textfield behind it.
Instructions
Make two textfields: helloWorldTextField (the original from the question) and borderTextField (a new textfield). Remove helloWorldTextFields's border and background color. Keep borderTextField's border and background color. Center helloWorldTextField within borderTextField. Then animate the width of borderTextField.
Github link and Code
Here is the project on Github: https://github.com/starkindustries/ConstraintAnimationTest
Here is the code within MyViewController class. Everything else is setup in the storyboard which can be viewed on Github at the link above.
class MyViewController: UIViewController {
// Hello World TextField Border var
#IBOutlet weak var borderTextFieldWidth: NSLayoutConstraint!
// Button Vars
#IBOutlet weak var myButton: UIButton!
var grow: Bool = false
func animateGrowShrinkTextFields(grow: Bool, duration: TimeInterval) {
if grow {
UIView.animate(withDuration: duration, animations: {
self.borderTextFieldWidth.constant = 330
self.view.layoutIfNeeded()
}, completion: { (finished: Bool) in
print("Grow animation complete!")
})
} else {
UIView.animate(withDuration: duration, animations: {
self.borderTextFieldWidth.constant = 115
self.view.layoutIfNeeded()
}, completion: { (finished: Bool) in
print("Shrink animation complete!")
})
}
}
#IBAction func toggle(){
let duration: TimeInterval = 1.0
grow = !grow
let title = grow ? "Shrink" : "Grow"
myButton.setTitle(title, for: UIControlState.normal)
animateGrowShrinkTextFields(grow: grow, duration: duration)
}
}
Notes and References
What led me to this solution was #JimmyJames's comment: "You are just animating the UITextField width, but the content inside is not animated."
I researched how to animate font changes and came across this question: Is there a way to animate changing a UILabel's textAlignment?
In that question #CSmith mentioned that "you can animate the FRAME, not the textAlignment" https://stackoverflow.com/a/19251634/2179970
The accepted answer in that question suggests to use a UILabel within another frame. https://stackoverflow.com/a/19251735/2179970
Hope this helps anyone else who comes across this problem. If anyone has another way to solve this, please post a comment or another answer. Thanks!
Another solution for the issue is set yourLabel.contentMode = .center on init, and animate in animation block as usually

UILabel decrease height, auto layout weird animation

I have expandable UILabel:
func expandDescriptionLabel() {
let calculatedHeightDescriptionLabel = lblDescription.sizeThatFits(CGSizeMake(lblDescription.frame.width, CGFloat.max)).height
expanded = true
UIView.animateWithDuration(0.3, animations: {
self.cnsDescriptionHeight.constant = calculatedHeightDescriptionLabel
self.hideMoreButton()// this line means nothing, results are the same with this line commented out
self.view.layoutIfNeeded()
})
}
func reduceDescriptionLabel() {
expanded = false
self.cnsDescriptionHeight.constant = 60
UIView.animateWithDuration(0.3, animations: {
self.showMoreButton() // this line means nothing, results are the same with this line commented out
self.lblDescription.setNeedsLayout();
self.view.layoutIfNeeded()
})
}
When expanding animation looks just fine, but when height is decreasing strange things happen. Look at GIF below. I tried already CGAffineTransformScale and putting UILabel in UIView and then animating a UIView.
Question is how to make the last part of animation more smooth.
As you can see when Labels height is decreasing, text is moving up and then suddenly appear in correct place(without animation).

moving a button vertically (Swift)

I am making a wac a mole game in swift and need to know how to make a button (Mole image) move up and down popping out and back into its hole (Above and back behind a imageview).
Change the button's frame to incrementally move up and down with animation. Here is some sample code (yAxisMovement is a positive number to move the button up or a negative number to move the image down):
var duration: NSTimeInterval = 1.0
UIView.animateWithDuration(duration, animations: { () -> Void in
button.frame = CGRectMake(
button.frame.origin.x,
button.frame.origin.y - yAxisMovement,
button.frame.size.width,
button.frame.size.height)
})
The answer above doesn't work anymore due to deprecated methods
let duration: TimeInterval = 1.0
UIView.animate(withDuration: duration, animations: {
self.yourImage.frame.origin.y = -50
}, completion: nil)
use -50 to make it move downwards and 50 to make it move upwards

Resources