objective c - Rotating image using CFAffineMakeRotation - ios

I have been trying to get a UIImageView to rotate around a point when I touch and drag on it. I am having the problem where it jumps back to its original position if I try and rotate it a second time. I have tried the solution here, but that makes the image spin crazily!
What am I doing wrong? Here's my code:
Updated code with fixes:
-(void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
if (CGRectContainsPoint(Game10Wheel.frame, location)) {
Game10Angle = atan2([Game10Wheel center].y - location.y, [Game10Wheel center].x - location.x);
Game10WheelTouched = true;
}
}
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
if (Game10WheelTouched) {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
float theAngle = atan2([Game10Wheel center].y - location.y, [Game10Wheel center].x - location.x);
[Game10Wheel setTransform: CGAffineTransformRotate([Game10Wheel transform], theAngle - Game10Angle)];
Game10Angle = theAngle;
}
}
-(void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
Game10WheelTouched = false;
}
-(void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
Game10WheelTouched = false;
}
Thanks!

Your problem in calculation of the angle of rotation for further transformation. Try use code below.
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
float theAngle = atan2([Game10Wheel center].y - location.y, [Game10Wheel center].x - location.x);
[Game10Wheel setTransform: CGAffineTransformRotate([Game10Wheel transform], theAngle - Game10Angle)];
Game10Angle = theAngle;
}

You need to modify the current transformation of the object, otherwise you are just setting it to an initial value. Using CGAffineTransformMakeRotation creates a new transform object with only the rotation specified applied to it. What you want to do is use CGAffineTransformRotate and pass the current transform of the Game10Wheel object to add the rotation to that current transform.
EDIT: In other words, when you create your rotation, it should start from the current transform of the Game10Wheel, not from a new transformation.

Related

How can I make UITouches offset?

In the image below, I draw and the result is at point A, right where my finger touches.
How can I make the image appear about 40pt above my actual touch. (B)
I'm using the classic coreGraphic UITouch code, like so:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
// add the first touch
UITouch *touch = [touches anyObject];
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
//transform = CGAffineTransformTranslate(self.transform, 5.0, 10.0)
// init the bezier path
self.currentTool = [self toolWithCurrentSettings];
self.currentTool.lineWidth = self.lineWidth;
self.currentTool.lineColor = self.lineColor;
self.currentTool.lineAlpha = self.lineAlpha;
[self.pathArray addObject:self.currentTool];
[self.undoStates addObject:[self.currentTool captureToolState]];
[self.currentTool setInitialPoint:currentPoint];
}
// call the delegate
if ([self.delegate respondsToSelector:#selector(drawingView:willBeginDrawUsingTool:)]) {
[self.delegate drawingView:self willBeginDrawUsingTool:self.currentTool];
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// save all the touches in the path
UITouch *touch = [touches anyObject];
previousPoint2 = previousPoint1;
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
[self.currentTool moveFromPoint:previousPoint1 toPoint:currentPoint];
[self setNeedsDisplay];
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// make sure a point is recorded
[self touchesMoved:touches withEvent:event];
CGPoint point = [[touches anyObject] locationInView:self];
[self.currentTool setInitialPoint:point];
self.draggableTextView = ((ACEDrawingDraggableTextTool *)self.currentTool).labelView;
[self.pathArray addObject:self.currentTool];
[self finishDrawing];
[self finishDrawing];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
// make sure a point is recorded
[self touchesEnded:touches withEvent:event];
}
previousPoint1 = [touch previousLocationInView:self];
currentPoint = [touch locationInView:self];
// add these 2 lines below:
previousPoint1 = CGPointMake(previousPoint1.x, previousPoint1.y+40);
currentPoint = CGPointMake(currentPoint.x, currentPoint.y+40);

Rotating a wheel?

I have read here a few examples about that, but couldn't make it work.
I have some UIView called Wheel , in which i want to rotate while touch and drag.
It should work like a real wheel, so if i touch at some point it will NOT rotate to that point, only when i drag my finger, i will get rotation .
I tried this,but i get a full rotation for every little move i do. I would like to ADD the angel to the view, not ROTATE to the new angel ..
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self];
CGPoint center=wheel.center;
float xLeg = fabs(center.x - touchPoint.x);
float yLeg = fabs(center.y-touchPoint.y);
float angle = atan(xLeg / yLeg);
NSLog(#"%f",angle);
wheel.transform = CGAffineTransformMakeRotation( angleInDegree );
}
This should do the trick. Notice how I store the first touch point in touchesBegan:withEvent:. This allows me to subtract the first touch point from every touch point I get while dragging, and thus gives me the real angle I need to rotate.
EDIT
I've done some adjustments, so that it is now smooth and regular even after several touches.
Demo
WheelViewController.m
#interface WheelViewController () {
CGPoint startPoint;
CGFloat startAngle;
CGFloat endAngle;
}
#end
#implementation WheelViewController
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
startPoint = [touch locationInView:self.view];
startAngle = [self angleForTouchPoint:startPoint] - endAngle;
NSLog(#"\r\nStart angle: %f", startAngle);
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
CGFloat touchAngle = [self angleForTouchPoint:touchPoint];
NSLog(#"Touch angle: %f", touchAngle);
self.wheel.transform = CGAffineTransformMakeRotation(fmodf(touchAngle - startAngle, 2 * M_PI));
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchPoint = [touch locationInView:self.view];
endAngle = [self angleForTouchPoint:touchPoint] - startAngle;
NSLog(#"End angle: %f", endAngle);
}
- (CGFloat)angleForTouchPoint:(CGPoint)touchPoint {
CGPoint center = self.wheel.center;
float xLeg = touchPoint.x - center.x;
float yLeg = touchPoint.y - center.y;
float angle = fmodf(atan(yLeg/xLeg), (2 * M_PI));
if (xLeg < 0) {
angle += M_PI;
}
return angle;
}

how to make an object draggable?

hey guys i was wondering if there was away to make an object like a UIImageView draggable. I am aware of the UITouch and touches i.e.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *drag=[[event allTouches] anyObject];
player.center=[drag locationInView:self.view];
}
but in this way it is possible for the user to make the object jump across the screen to where he or she touches the screen but i want the user to have to manually drag the object across the screen.
please explain with code and let me know if i have to be more specific or clear...
You can do this:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
CGPoint location = [aTouch locationInView:self.view];
if(CGRectContainsPoint(self.playerView.frame,location)) {
[UIView beginAnimations:#"Dragging A DraggableView" context:nil];
self.playerView.center = location;
[UIView commitAnimations];
}
}
This should give you a smooth animation.
if you want your user to drag&drop, first you have to check if the touch is inside the imageview rect frame. To improve the user experience, you can detect the touch offset from the imageview center; a good place to do this is inside the touchesBegan:withEvent:. After that, you have to change the position of the imageview, like this:
CGPoint touchOffset; //insert this inside your interface private iVars
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *drag=[[event allTouches] anyObject];
CGPoint touchLocation = [drag locationInView:self.view];
touchOffset = CGPointMake(player.center.x-touchLocation.x,player.center.y-touchLocation.y)
if(CGRectContainsPoint(player.frame,touchLocation)
player.center = CGPointMake(touchLocation.x+touchOffset.x,touchLocation.y+touchOffset.y);
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *drag=[[event allTouches] anyObject];
CGPoint touchLocation = [drag locationInView:self.view];
if(CGRectContainsPoint(player.frame,touchLocation)
player.center = CGPointMake(touchLocation.x+touchOffset.x,touchLocation.y+touchOffset.y);
}
P.S. - Next time try to search similar questions...
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* aTouch = [touches anyObject];
UIView* aView = [aTouch view];
if (aView != self.view) {
[self.view bringSubviewToFront:aView];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* aTouch = [touches anyObject];
UIView* aView = [aTouch view];
if (aView != self.view) {
aView.center = [aTouch locationInView:self.view];
}
}

TouchesMoved with UITouch

I'm trying to create a simple application where you can move your UIImageView by touching him and dragging him around.
my UIImageView is called imv
-(void ) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch * touch = [touches anyObject];
if([touch view] == self.imv){
CGPoint location = [touch locationInView:self.view];
self.imv.center = location;
}
}
-(void ) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch * touch = [touches anyObject];
if([touch view] == self.imv){
CGPoint location = [touch locationInView:self.view];
self.imv.center = location;
}
}
i'am trying to solve this like whole day and i don't know what is wrong. If i disable if statement it's working else not. What can i do?
Thanks for the answers
Unless you've subclassed UIImageView (unlikely), your view is receiving the touch events.
These days it's simpler & more usual to use a UIGestureRecognizer for this kind of thing, in this case a UIPanGestureRecognizer.
e.g.
UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(dragImageView:)];
[self.imv addGestureRecognizer:pan];
- (void)dragImageView:(UIPanGestureRecognizer *)dragImageView {
if(UIGestureRecognizerStateBegan == state) {
originalCenter = self.imv.center; // add CGPoint originalCenter; member
} else if(UIGestureRecognizerStateChanged == state) {
CGPoint translate = [pan translationInView:self.imv.superview];
self.imv.center = CGPointMake(originalCenter.x + translate.x, originalCenter.y + translate.y);
}
}
From a bit of experimenting, it seems that the [touch view] is returning the main UIView and not your subview, hence the problem with the if statement not working (I added the UIImageView in a storyboard xib). EDIT- it's because UIImageViews don't handle touch events by default - see here . When adding a regular UIView in the viewDidLoad seems to work as you would expect.
Anyway, this adapted version of your code works for me
-(void)moveImageForTouches:(NSSet*)touches
{
UITouch * touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
if(CGRectContainsPoint(self.imv.frame, location))
{
self.imv.center = location;
}
}
-(void ) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[self moveImageForTouches:touches];
}
-(void ) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
[self moveImageForTouches:touches];
}

Translate uiview in direction of touch moved, iphone

I want to translate UIView in same direction as touch moves .
Please suggest.
Modify the touchesBegan and touchesMoved methods to be like the following
float oldX, oldY;
BOOL dragging;
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (CGRectContainsPoint(window.frame, touchLocation)) {
dragging = YES;
oldX = touchLocation.x;
oldY = touchLocation.y;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if (dragging) {
CGRect frame = window.frame;
frame.origin.x = window.frame.origin.x + touchLocation.x - oldX;
frame.origin.y = window.frame.origin.y + touchLocation.y - oldY;
window.frame = frame;
}
oldX = touchLocation.x;
oldY = touchLocation.y;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
dragging = NO;
}
Hope it help
Try to do like the code below. I'm not sure if it is a best solution for all direction translation.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count] != 1) return;
_swipeStartInX = [[touches anyObject] locationInView:self].x;
_swipeStartInY = [[touches anyObject] locationInView:self].y;
_swiping = YES;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!_swiping || [touches count] != 1) return;
CGFloat swipeDistanceInX = [[touches anyObject] locationInView:self].x - _swipeStartInX;
CGFloat swipeDistanceInY = [[touches anyObject] locationInView:self].y - _swipeStartInY;
CGSize contentSize = self.frame.size;
[_yourView setFrame:CGRectMake(swipeDistanceInX - contentSize.width, swipeDistanceInY - contentSize.width, contentSize.width, contentSize.height)];
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (!_swiping) return;
// You can set the last position when touches end.
// E.g. You can set positions like slide page does, just the the origin of _yourView.
}
If you just want translate in vertical and horizontal direction, you can use UIScrolView instead. :)
You can just add this method to your subclassed UIView class.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
UITouch *touch = [touches anyObject];
CGPoint currentLocation = [touch locationInView:self];
CGPoint previousLocation= [touch previousLocationInView:self];
CGFloat deltaX = currentLocation.x - previousLocation.x;
CGFloat deltaY = currentLocation.y - previousLocation.y;
self.frame = CGRectMake(self.frame.origin.x + deltaX, self.frame.origin.y + deltaY, self.frame.size.width, self.frame.size.height);
}

Resources