Changing X & Y of Button upon Rotation - iphone

Edited Mar 30 - Note: Monotouch used. When I rotate to LandscapeRight/Left I want to change the location of some of my buttons. Here's what I'm trying:
Have my ShouldAutorotateToInterfaceOrientation returning True.
In my WillRotate (I tried putting this in DidRotate as well) it doesn't show any difference, here's my code:
public override void WillRotate (UIInterfaceOrientation toInterfaceOrientation, double duration)
{
// As a test move one of the buttons somewhere different than where it should be
System.Drawing.RectangleF rect = new System.Drawing.RectangleF(40, 1,
btn2.Bounds.Width, btn2.Bounds.Height);
btn2.Bounds = rect;
}
I figure that changing the bounds may not be the right way, but given that the Bounds.X and Bounds.Y are immutable, this was the only way I could find to change the position.

This is what you want...
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
It can be found here.
The idea is to adjust the X and Y of any objects you want to move around after you determine the direction of the move.

Related

Smooth aspect change during orientation change

When the screen of the iPhone orientation changes, I adjust my projection matrix of my 3D rendering to the new aspect value. However, doing this in either willRotateToInterfaceOrientation or didRotateFromInterfaceOrientation would cause the aspect ratio being wrong during the transition, because at the beginning of the animation, the screen size is still the same as before and is changed to the new bounds gradually while being rotated. Therefore I want the aspect value used for my 3D projection matrix to change gradually as well. To achieve this, I retrieve start time and duration for the rotation animation in willAnimateRotationToInterfaceOrientation:
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
_aspect.isChanging = YES;
_aspect.startedChanging = [[NSDate date] retain];
_aspect.changeDuration = duration;
_aspect.oldValue = self.renderer.aspect;
_aspect.currentValue = fabsf(self.view.bounds.size.width / self.view.bounds.size.height);
}
Note that the view bound size is already set to the new value that will be valid after the animation.
Then, in update, I do the following:
- (void)update
{
if (_aspect.isChanging) {
float f = MIN(1, [[NSDate date] timeIntervalSinceDate:_aspect.startedChanging] / _aspect.changeDuration);
self.renderer.aspect = _aspect.oldValue * (1-f) + _aspect.currentValue * f;
} else {
self.renderer.aspect = _aspect.currentValue;
}
[self.renderer update];
}
This already works quite well, but the render aspect change does not match the actual aspect change, which is because I'm interpolating it linearly. Therefore I tried to match the easing of the actual aspect change by throwing math functions at the problem: The best result I could get was by adding the following line:
f = 0.5f - 0.5f*cosf(f*M_PI);
This results in almost no visible stretching of the image during the rotation, however if you look closely, it still seems to be a bit unmatched somewhere in between. I guess, the end user won't notice it, but I'm asking here if there might be a better solution, so these are my questions:
What is the actual easing function used for the change in aspect ratio during the rotation change animation?
Is there a way to get the actual width and height of the view as it is displayed during the orientation change animation? This would allow me to retrieve the in-between aspect directly.
On the first bullet point, you can use CAMediaTimingFunction (probably with kCAMediaTimingFunctionEaseInEaseOut) to get the control points for the curve that defines the transition. Then just use a cubic bezier curve formula.
On the second bullet point, you can use [[view layer] presentationLayer] to get a version of that view's CALayer with all current animations applied as per their current state. So if you check the dimensions of that you should get the then current values — I guess if you act upon a CADisplayLink callback then you'll be at most one frame behind.

UIScrollView ContentOffset not Reaching Edge of Screen

I'm having a problem with UIScrollView, not sure if it's a bug or not, but it's occurring when I implement a UIScrollView with its delegate and a zoomable / pannable image.
First off, when I pan the image, it's possible that the contentOffset can be a non integer value (.5). For certain zoomScales, when I pan the image all the way to the edge, it's falling a half pixel shy of reaching the edge because of this.
It's a very small thing, but in my app I have to drag objects around the screen, and if I drag an object to the corner, you can notice it.
I've implemented the following to try and correct the problem and make it so the contentOffset has to be a whole value:
- (void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset
{
if (targetContentOffset->x != ceilf(targetContentOffset->x))
{
if (velocity.x > 0)
{
targetContentOffset->x = ceilf(targetContentOffset->x);
}
else
{
targetContentOffset->x = floorf(targetContentOffset->x);
}
}
if (targetContentOffset->y != ceilf(targetContentOffset->y))
{
if (velocity.y > 0)
{
targetContentOffset->y = ceilf(targetContentOffset->y);
}
else
{
targetContentOffset->y = floorf(targetContentOffset->y);
}
}
}
However, it doesn't seem to be working as my targetContentOffset is completely different than the contentOffset property.
Does anyone a) why this bug is occurring or b) how to fix it using the above delegate method or some other means?
Alternatively this method implementation may work for you also.
-(void)scrollViewDidEndScrollingAnimation:(UIScrollView *)scrollView
Looking at your comments below, you may have to implement multiple methods. The one above or the one stated in the other answer post for when it slows to a stop, just to make sure you touch your edge condition, and the method you already have to process for the velocity points.

how to find the coordinates of an autoresizemasked object after rotation

Hi,
can we find the coordinates of a UI element say UItextfield which is masked after rotation, if yes how is it possible?
Thanx in advance
I'm not sure whether I understand your question. If you want to know the coordinates of a UI element after your device was rotated, here's how you do it:
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
CGRect newFrame = someUIElement.frame;
int x = newFrame.origin.x; // x-Coordinate
int y = newFrame.origin.y; // y-Coordinate
// do stuff with coordinates
}
i have something like fabian answer while rotating the device first called method is - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
then -(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
finally
-(void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
method called so you can get the coordinates in this method.The main thing here is the object origin ll change not the size.this is the thing i am expecting from some sample app.

Position on UIImageView

Me again. I have a simple question. I have an UIImageView like the one shown below.
alt text http://img683.imageshack.us/img683/1999/volumen.png
That UIimageView is supposed to be the knob to control the volume of my iphone project. My question is, how to know the positions of bar on the UIImageView when it is rotated? Because the volume needs to be 0.5 when the little bar on the cercle is vertical.
I got a piece of code which is (in the touchMoved method):
float dx = locationT.x - imgVVolume.center.x;
float dy = locationT.y - imgVVolume.center.y;
CGFloat angleDif = 0.0f;
movedRotationAngle = atan2(dy,dx);
if (beganRotationAngle == 0.0) {
beganRotationAngle = movedRotationAngle;
initialTransform = imgVVolume.transform;
}
else {
angleDif = beganRotationAngle - movedRotationAngle;
CGAffineTransform newTrans = CGAffineTransformRotate(initialTransform, -angleDif);
imgVVolume.transform = newTrans;
}
Help please.
It depends on what input mechanism you want to use to control the rotation.
If the knob is to rotate based on a single finger touch dragging from side to side then you can create a UIPanGestureRecognizer and attach it to the knob UIImageView. The translationInView: method returns a CGPoint which is the amount of X and Y movement from the touch-down point. You can feed that into a formula like the one you post to get an angle of rotation. You'll want to keep track of delta from last position and also check for stop limits (like 0..360) to prevent over-rotation.
OTOH, if you're going to use two finger rotation then you'll want to use a UIRotationGestureRecognizer and look for the rotation value. Just feed that into a CGAffineTransformRotate and set it to the UIImageView transform. That takes care of all of the above for you. Again, you'll want to check for stop limits.

Is there a way to get a position (or center) state from a unfinished UIView animation?

I have a UIView doing a simple animation. It adjusts its y position from 100 to 130 and then reverses. I want it to keep repeating so I have the repeat counter set to 999. Upon user input, I want to take the same UIView and adjust the x position. This is done by means of another UIView animation. The problem is that when the 2nd animation starts, the 1st animation (that goes from 100 to 130 in the y direction) just ends abruptly (as I read that it should). Is there any way to get the final position of the y coordinate of that UIView before it was ended? I would ideally like to have the UIView stay in the same y position that it was in while I translate the x coordinates.
Summary: UIView moves in the y direction from 100-130, reverses and repeats until user input is received. Once received, animation is cut short and UIView jumps to y=130. I would like a way to find out what the final y value was before the animation was cut short, so when new animation with x translation is used, the UIView will not jump to 130, but remain the same position it was in when the 1st animation ended.
I can't seem to see anything that would let you do that. It appears to me that once you set the animation in motion with UIView, then it (and all current state changes) are out of your hands and will only be "returned" to your control and availability once the animation is done and at the designated end point. Is this correct? Any insight would be appreciated. Thank you for your time.
You're looking for the "presentation layer".
Each UIView is rendered using a Core Animation layer, which is accessible from UIView's layer property.
CALayer has a presentationLayer method, which returns a CALayer that represents "a close approximation to the version of the layer that is currently being displayed".
So, to get the current position of your view:
CGRect currentViewFrame = [[myView.layer presentationLayer] frame];
I'm not sure if this is exactly what you want, but UIView's setAnimationBeginsFromCurrentState: used inside a beginAnimations block will cause the x animation to start wherever the y is in progress.
Perhaps for what you are trying to accomplish it would benefit to exercise a little more control over the animation. For this task I would suggestion using an NSTimer scheduled at whatever interval works best for you (1/30 to 1/60) and just adjust the UIView position every time the timer fires. This way you can always access the X and Y components of the view's position.
Something like:
- (void)timerFired:(NSTimer *)timer {
CGPoint p = view.center;
if (p.y >= 130.0) {
positiveMovement = NO;
}
else if (p.y <= 100.0) {
positiveMovement = YES;
}
if (positiveMovement)
p.y++;
else
p.y--;
view.center = p;
}
positiveMovement would just be a BOOL instance variable. You could also then just directly adjust the X value of the view's position elsewhere with user input and it would update accordingly.