I'm rotating a ball based on pan gestures, and I want to add inertia. To do this, I decided to use animateWithDuration when pan gesture finished. The problem is that instead of animating, the position of the ball changes straight away. I'll be posting the code bellow.
func moveByInertia(finalPosition: CGPoint, finalRotation: CGFloat)
{
UIView.animateWithDuration(2, animations:
{
self.tommy.position = finalPosition
self.tommy.zRotation = finalRotation
})
}
The arguments are definitely passed correctly into this function because it moves to the correct position. The problem is that it does so without animating. I couldn't find the same problem with a solution on the internet.
Thanks in advance
Related
I've got a UIView laying right above all others. This UIView has a UIPanGestureRecognizer to drag it around of the screen. If the User stopped panning, the View moves to a calculated Position which is the left screen bounds or the right ones. This works quite good but now I want to consider the velocity the View moved around the screen and when the user lifts his Finger off the screen, the UIView should not stop immediately to move to the endpoint, instead it should do it with a curve.
Edit 1
I think I expressed myself wrongly. I meant that the View should move the direction the user dragged it to but then it should make a curve and move to the desired position. Think of it like gravity. The user will drag the View with a speed from the left bottom corner to the middle of the screen and lifts immediately his finger. Then the View should not stop, else it should move in the last direction und slowly move to the desired location, which is in this case the right bottom corner.
This is the code I already have:
private void DidPan()
{
CGPoint translation = PanGesture.TranslationInView(this.Superview);
CGPoint velocity = PanGesture.VelocityInView(this.Superview);
if (PanGesture.State == UIGestureRecognizerState.Changed)
{
this.Center = new CGPoint(lastLocation.X + translation.X, lastLocation.Y + translation.Y);
}
else if (PanGesture.State == UIGestureRecognizerState.Ended)
{
// Calculates the new position the view will be moving to
var newLocation = new CGPoint(SetX(Superview.Bounds), SetY(Superview.Bounds));
// Animate it to the desired location
UIView.Animate(0.3, () =>
{
this.Center = newLocation;
}, null);
}
}
As you can see we already have the velocity but I don't know how to continue from here. Hopefully someone has the right starting point from here and could help me.
Thanks a lot!
I think UIKit Dynamics can meet your requirement.
refer to this Blog : https://blog.xamarin.com/drag-drop-and-snap-with-uikit-dynamics/
I have a horizontal scrollview with an image which I need to rotate as the user scrolls left or right. It needs to rotate as the user moves the scroll across the screen. So if the user scrolls half way and stops the image should rotate halfway etc. I have looked at few examples but nothing seems to be giving me the correct result. Can some one please help.
Thanks in advance
Vertical scrolling and Swift 5:
func scrollViewDidScroll(_ scrollView: UIScrollView) {
let topOffset = scrollView.contentOffset.y
let angle = -topOffset * 2 * CGFloat(Double.pi / 180)
self.myImageView.transform = CGAffineTransform(rotationAngle: angle)
}
Don't forget to do this in viewDidLoad:
self.scrollView.delegate = self
You'll need to implement the scrollViewDidScroll method and then apply a rotation matrix to the image. To rotate a UIIMage you can do what they outline here. How to Rotate a UIImage 90 degrees?
However, this would be better accomplished in a pan gesture recognizer. The pan gesture will give you information about how far the user panned, and then you can rotate the image based on that distance.
To rotate image is not good for performance. You'd better set image view's rotate transform as user scrolls. Like this:
imageView.transform = CGAffineTransformMakeRotation(CGFloat(M_PI_2))
Im having a really stupid problem with a UIView. I create the UIView programatically and then make it a circle by making the corner radius half the height of the view looks like this:
But when I try to animate the circle to a different location it becomes all deformed like this:
Here is the code I am using to animate the view just a simple UIView.animateWithDuration:
UIView.animateWithDuration(2, delay: 0, options: UIViewAnimationOptions.AllowUserInteraction, animations: {
self.secondDot.frame.origin = CGPoint(x: self.view.frame.size.width - self.secondDot.frame.size.width, y: 0)
self.secondDot.frame.size = self.secondDot.frame.size
}, completion: nil)
I should also add that the circle doesn't always become deformed but more often than not it does. Please help any suggestions would be much appreciated.
EDIT: I should mention that the circle is in motion already before the
UIView.animationWithDuration occurs I don't know if that could be a
problem
What is the point of this line?
self.secondDot.frame.size = self.secondDot.frame.size
You either
want to resize the circle uniformly while moving
or not.
If case 1) the the newSize.width != newSize.height...but thats a problem because your circle is not a "square" anymore behind the scenes.
If case 2) just remove the lines.
I had exactely the same situation.
After some research, I've found comment in header file for setFrame method
// animatable. do not use frame if view is transformed since it will
not correctly reflect the actual location of the view. use bounds +
center instead.
I have decided to use setCenter instead of setFrame which solved the distortion issue.
I am having the hardest time figuring out gesture recognizers and such on iOS. Unfortunately a lot of the documentation by apple appears to be in Objective-C and/or it doesn't give you examples that show what values can go in. Could you show me some examples of how to the the following things.
Get the current position of each touch event on the screen. If the finger isn't down then return false.
Make a direction recognizer other then the 4 main directions. Currently my code looks like this
var leftSwipe = UISwipeGestureRecognizer(target: self, action: Selector("HandleSwipes:"))
leftSwipe.direction = .Left
view.addGestureRecognizer(leftSwipe)
However what if I wanted to detect diagonal movement? Their isn't a .Diagonal. So the detection of a gesture works in the direction (0.5, 0.5).
Going back to the code I put before I have a function that I check the direction in
func HandleSwipes(sender: UISwipeGestureRecognizer) {
if (sender.direction == .Left) {
Label.text = "Left"
}
}
What if I want this swipe to only work for the 2nd finger down? Also how would I get the ending, and starting position of that gesture? (preferably inside of that function)
How can I find out how long it has taken the finger to do the gesture (getting from point A to point B).
I am not that familiar with swift, but in objective-c, this is how you will obtain the current position of a touch event.
CGPoint _originalCenter;
-(void)handlePan:(UIPanGestureRecognizer *)recognizer {
if (recognizer.state == UIGestureRecognizerStateBegan) {
// if the gesture has just started, record the current centre location
_originalCenter = self.center;
}
Hope this helps answer the first part of your question.
I'm trying to implement a paging interaction for one of my views. I thought I would just use UISwipeGestureRecognizers. But through trial and error as well as examination of the documentation it appears that
A swipe is a discrete gesture, and thus the associated action message
is sent only once per gesture.
So while I could trigger the page, I wouldn't be able to hook up animation that occurred during the drag.
Is my only alternative to use a UIPanGestureRecognizer and reimplement the basic filtering/calculations of the swipe?
Update/Redux
In hindsight, what I really should have been asking is how to implement a "flick" gesture. If you're not going to roll your own subclass (may bite that off in a bit), you use a UIPanGestureRecognizer as #Lyndsey 's answer indicates. What I was looking for after that (in the comments) was how to do the flick part, where the momentum of the flick contributes to the decision of whether to carry the motion of the flick through or snap back to the original presentation.
UIScrollView has behavior like that and it's tempting to mine its implementation for details on how one decelerates the momentum in a way that would be consistent, but alas the decelerationRate supplied for UIScrollView is "per iteration" value (according to some). I beat my head on how to properly apply the default value of 0.998 to the end velocity of my pan.
In the end, I used code pulled from sites about "flick" computation and did something like this in my gesture handler:
...
else if (pan.state == UIGestureRecognizerStateEnded) {
CGFloat v = [pan velocityInView: self.view].x;
CGFloat a = -4000.0; // 4 pixels/millisecond, recommended on gavedev
CGFloat decelDisplacement = -(v * v) / (2 * a); // physics 101
// how far have we come plus how far will momentum carry us?
CGFloat totalDisplacement = ABS(translation) + decelDisplacement;
// if that is (or will be) half way across our view, finish the transition
if (totalDisplacement >= self.view.bounds.size.width / 2) {
// how much time would we need to carry remainder across view with current velocity and existing displacement? (capped)
CGFloat travelTime = MIN(0.4, (self.view.bounds.size.width - ABS(translation)) * 2 / ABS(v));
[UIView animateWithDuration: travelTime delay: 0.0 options: UIViewAnimationOptionCurveEaseOut animations:^{
// target/end animation positions
} completion:^(BOOL finished) {
if (finished) {
// any final state change
}
}];
}
else { // put everything back the way it was
...
}
}
Yes, use a UIPanGestureRecognizer if you want the specific speed, angle, changes, etc. of the "swipe" to trigger your animations. A UISwipeGestureRecognizer is indeed a single discrete gesture; similar to a UITapGestureRecognizer, it triggers a single action message upon recognition.
As in physics, the UIPanGestureRecognizer's "velocity" will indicate both the speed and direction of the pan gesture. Here are the docs for velocityInView: method which will help you calculate the horizontal and vertical components of the changing pan gesture in points per second.