In my View I have one UILabel and one UITableView.
I want them to animate downwards by 40 pixels. The following is my code
var newFrame = newsStand.Frame;
newFrame = new CGRect (newsStand.Frame.X, newsStand.Frame.Y+40, newsStand.Frame.Width, newsStand.Frame.Height);
UIView.BeginAnimations ("slideAnimation");
UIView.SetAnimationDuration (2);
UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
UIView.SetAnimationDelegate (this);
UIView.SetAnimationDidStopSelector (new Selector ("slideAnimationFinished"));
nfloat newY=searchLabel.Center.Y+40;
searchLabel.Center = new CGPoint (searchLabel.Center.X, newY);
newsStand.Frame = newFrame;
UIView.CommitAnimations ();
newsStand is my UITableView instance and searchLabel, UILabel instance. When this code is executed, searchLabel animates as expected by moving down 40 pixels. But newsStand jumps 40 pixels upwards initially and animates to its original position. I have tried setting center (like I have done for searchLabel) of newsStand instead of Frame also. But the result is same. What is causing this behaviour ?
Your approach is very complex. You can greatly simplify the animation by using UIView.Animate() instead:
var myLabel = new UILabel (new CGRect (100, 100, 100, 40))
{
Text = "Animate me!",
TextColor = UIColor.Yellow
};
window.Add (myLabel);
UIView.Animate (
duration: 0.5,
animation: () => myLabel.Center = new CGPoint (myLabel.Center.X, myLabel.Center.Y + 40),
completion: () => {}
);
Related
I need to animate a CATextLayer's bounds.size.height, position, and fontSize. When I add them to a CAAnimationGroup, the text jitters during the animation, just like this:
https://youtu.be/HfC1ZX-pbyM
The jittering of the text's tracking values (spacing between characters) seems to occur while animating fontSize with bounds.size.height AND/OR position. I've isolated fontSize, and it performs well on its own.
How can I prevent the text from jittering in CATextLayer if I animate bounds and font size at the same time?
EDIT
I've moved on from animating bounds. Now, I only care about fontSize + position. Here are two videos showing the difference.
fontSize only (smooth): https://youtu.be/FDPPGF_FzLI
fontSize + position (jittery): https://youtu.be/3rFTsp7wBzk
Here is the code for that.
let startFontSize: CGFloat = 16
let endFontSize: CGFloat = 30
let startPosition: CGPoint = CGPoint(x: 40, y: 100)
let endPosition: CGPoint = CGPoint(x: 20, y: 175)
// Initialize the layer
textLayer = CATextLayer()
textLayer.string = "Hello how are you?"
textLayer.font = UIFont.systemFont(ofSize: startFontSize, weight: UIFont.Weight.semibold)
textLayer.fontSize = startFontSize
textLayer.alignmentMode = kCAAlignmentLeft
textLayer.foregroundColor = UIColor.black.cgColor
textLayer.contentsScale = UIScreen.main.scale
textLayer.isWrapped = true
textLayer.backgroundColor = UIColor.lightGray.cgColor
textLayer.anchorPoint = CGPoint(x: 0, y: 0)
textLayer.position = startPosition
textLayer.bounds.size = CGSize(width: 450, height: 50)
view.layer.addSublayer(textLayer)
// Animate
let damping: CGFloat = 20
let mass: CGFloat = 1.2
var animations = [CASpringAnimation]()
let fontSizeAnim = CASpringAnimation(keyPath: "fontSize")
fontSizeAnim.fromValue = startFontSize
fontSizeAnim.toValue = endFontSize
fontSizeAnim.damping = damping
fontSizeAnim.mass = mass
fontSizeAnim.duration = fontSizeAnim.settlingDuration
animations.append(fontSizeAnim)
let positionAnim = CASpringAnimation(keyPath: "position.y")
positionAnim.fromValue = textLayer.position.y
positionAnim.toValue = endPosition.y
positionAnim.damping = damping
positionAnim.mass = mass
positionAnim.duration = positionAnim.settlingDuration
animations.append(positionAnim)
let animGroup = CAAnimationGroup()
animGroup.animations = animations
animGroup.duration = fontSizeAnim.settlingDuration
animGroup.isRemovedOnCompletion = true
animGroup.autoreverses = true
textLayer.add(animGroup, forKey: nil)
My device is running iOS 11.0.
EDIT 2
I've broken down each animation (fontSize only, and fontSize + position) frame-by-frame. In each video, I'm progressing 1 frame at a time.
In the fontSize only video (https://youtu.be/DZw2pMjDcl8), each frame yields an increase in fontSize, so there's no choppiness.
In the fontSize + position video (https://youtu.be/_idWte92F38), position is updated in every frame, but not fontSize. There is only an increase in fontSize in 60% of frames, meaning that fontSize isn't animating in sync with position, causing the perceived chopping.
So maybe the right question is: why does fontSize animate in each frame when it's the only animation added to a layer, but not when added as part of CAAnimationGroup in conjunction with the position animation?
Apple DTS believes this issue is a bug. A report has been filed.
In the meantime, I'll be using CADisplayLink to synchronize the redrawing of CATextLayer.fontSize to the refresh rate of the device, which will redraw the layer with the appropriate fontSize in each frame.
Edit
After tinkering with CADisplayLink for a day or so, drawing to the correct fontSize proved difficult, especially when paired with a custom timing function. So, I'm giving up on CATextLayer altogether and going back to UILabel.
In WWDC '17's Advanced Animations with UIKit, Apple recommends "view morphing" to animate between two label states — that is, the translation, scaling, and opacity blending of two views. UIViewPropertyAnimator provides a lot of flexibility for this, like blending multiple timing functions and scrubbing. View morphing is also useful for transitioning between 2 text values without having to fade out the text representation, changing text, and fading back in.
I do hope Apple can beef up CATextLayer support for non-interactive animations, as I'd prefer using one view to animate the same text representation.
So I have a problem and I'm not entirely sure what's going on. I am writing a little application for iOS in Swift.
On a button click I am running an animation to move an element:
UIView.animateWithDuration(0.5, animations: {
self.blurView.alpha = 1.0;
self.logoImage.frame = CGRect(x: 15, y: 65, width: 100, height: 101);
})
loginFormView.hidden = false;
This runs fine and animation but then when I click on the text field it jumps the animated logo to its original position and size.
Ahh i found out what i was doing wrong i was animating an image that had a constraint on it so i just needed to animate the Y constraint.
self.view.layoutIfNeeded();
UIView.animateWithDuration(0.5, animations: {
self.blurView.alpha = 1.0;
self.Yconst.constant = 200;
self.view.layoutIfNeeded();
})
I have a UIView and I've added a UIView inside it as a subview. I'm hoping to expand the subview to fill a portion of the view, as a percentage, for example:
subview.bounds.width = view.bound.width(num1/max)
where num1 changes every second until it reaches max.
A UIView's frame can't be partially changed - to get the result you're looking for, you need to create a new frame, manipulate it, then attach it to your subview, like so:
let newFrame = subview.frame
newFrame.size.width = view.frame.width * num1 / max
subview.frame = newFrame
What I am trying to do is: I have an UIImageView inside a UIScrollView for Zooming purposes. Now when I zoom out, I should be able to move/pan the image anywhere on the screen. For this I have a UIscrollView (parent) which has the UIScrollview(child) with the Image.
The code I used is:
void SetTestImageSettings()
{
//mainScrollView is Parent scrollview.
mainScrollView = new UIScrollView (
new RectangleF (this.mainImgView.Frame.X, this.mainImgView.Frame.Y, this.mainImgView.Frame.Width +50
, this.mainImgView.Frame.Height +50));
mainScrollView.ContentSize = new SizeF (mainScrollView.Frame.Width + 500, mainScrollView.Frame.Height + 500);
mainScrollView.BackgroundColor = UIColor.Red;
mainScrollView.ContentMode = UIViewContentMode.Center;
//I tried implementing these events, but I am not sure, what to set, I mean I know I should add contentOffset, but what value?
mainScrollView.WillEndDragging += HandleWillEndDragging;
mainScrollView.DraggingEnded += HandleDraggingEnded;
// create our scroll view that has Image
scrollView = new UIScrollView (
new RectangleF (this.mainImgView.Frame.X, this.mainImgView.Frame.Y, this.mainImgView.Frame.Width
, this.mainImgView.Frame.Height - toolBar.Frame.Height));
mainScrollView.AddSubview (scrollView);
View.AddSubview (mainScrollView);
// create our image view
imageView = new UIImageView (mainImage);
scrollView.ContentSize = imageView.Image.Size;
scrollView.ContentMode = UIViewContentMode.Center;
scrollView.ShowsHorizontalScrollIndicator = false;
scrollView.ShowsVerticalScrollIndicator = false;
scrollView.AddSubview (imageView);
// set allow zooming
scrollView.MaximumZoomScale = 3f;
scrollView.MinimumZoomScale = .1f;
scrollView.ViewForZoomingInScrollView += (UIScrollView sv) => { return imageView; };
}
Now every time, I drag ends, the child crollview(with image) bounces back at top left corner.
Any help would be appreciated. Also any Objective-C developer's help too would be appreciated. I hope I sound sane and clear with my issue.
Thanks in advance.
The alternative I used is: I got rid of the UIScrollview and added gestures on the UIImageView itself. Pan, and Pinch gesture, where I can zoom, and also Pan/move my image on the screen. It is simpler now, and also under my control :)
Is it possible to animate the frame width of a UISearchBar? I find when I apply uiview animations to widen the bounds of a search bar it pops immediately to the final result as if the object internally is assuming control of how it animates and not allowing me to apply my own animations to it smoothly.
If I animate the position it moves smoothly, but I suspect the fact that the text input adjusts according to the presence of the cancel button might mean we don't have public access to animate the width through UIView animation. The sample snippet below slides the bar from x = 0 to 100 but pops the width to 600 pixels wide.
CGRect searchBarFrame = self.searchViewController.searchBar.frame;
searchBarFrame.origin.x = 100;
searchBarFrame.size.width = 600;
[UIView animateWithDuration:1.0
delay:0.0
options:0
animations:^{
self.searchViewController.searchBar.frame = searchBarFrame;
}
completion:^(BOOL completion){
}];
there is an "issue" with UISearchBar due to the inner views forcing the resize to ignore the animation. However, this can be overcome by the use of - layoutSubviews. I have included the expand and contract code in my project below
[UIView animateWithDuration:.3
animations:^ {
CGRect newBounds = locationSearch.frame;
newBounds.size.width += 215; //newBounds.size.width -= 215; to contract
locationSearch.frame = newBounds;
[locationSearch layoutSubviews];
}];
Hope this helps.
FYI, you can use UIViewAnimationOption instead of calling layoutsubviews explicitly,
So the code would look something like this..
[UIView animateWithDuration:0.5
delay:0
options:UIViewAnimationOptionLayoutSubviews
animations:^{
//Set the frame you want to the search bar
}
completion:^(BOOL finished) {
}];
This is how to overcome enlargement just to the Left side in swift
(This code will enlarge/shrinks the searchBar 93 pixels over the left side when user start/end editing)
SharedNavigationbBar is the UIView that implements the UISearchBarDelegate
searchBarWidth is an outlet to a constrain holding the width of the UISearchBar
An autolayout constrain must exists on your storyboard or nib file to allow resizing into the left side.
In this case, the neighbord left component is an UIButton.
Add the following code as an extension or inside your class to perform the animated resizing.
extension SharedNavigationBar: UISearchBarDelegate
{
//amount of pixels to enlarge to the left
private var offsetSearchBarLeft:CGFloat
{
get {
return 93
}
}
///Enlarges search bar
func searchBarTextDidBeginEditing(searchBar: UISearchBar) {
self.animateSearchBar(self.searchBar, enlarge: true)
}
///Shrinks search bar
func searchBarTextDidEndEditing(searchBar: UISearchBar) {
self.animateSearchBar(self.searchBar, enlarge: false)
}
//shrinks or enlarge the searchbar (this will be the function to call inside the animation)
private func animateSearchBar(searchBar:UISearchBar, enlarge:Bool)
{
///Important here, for this to work, the option and the searchbar size must be handled this way
UIView.animateWithDuration(0.3, delay: 0.0, options: UIViewAnimationOptions.LayoutSubviews, animations: { [weak self] () -> Void in
let multiplier: CGFloat = enlarge ? 1 : -1
let origin = searchBar.frame.origin.x + self!.offsetSearchBarLeft * multiplier
let width = searchBar.frame.width + self!.offsetSearchBarLeft * multiplier
//This Block of code, setting the new frame, needs to be inside the animation in order to work
var newBounds:CGRect = searchBar.frame;
newBounds.origin.x = origin
newBounds.size.width = width
//Sets the new frame
self?.searchBarWidth.constant = width
searchBar.frame = newBounds
}, completion: nil)
}
}