IOS touch tracking code - ios

I'm making an app for iPhone in Xcode, and It requires a box to follow my finger only on the X axis. I couldn't find any solution online to this, and my coding knowledge isn't that great.
I've been trying to use touchesBegan and touchesMoved.
Could someone please write me up some code please?

First you need the UIGestureRecognizerDelegate on your ViewController.h file:
#interface ViewController : UIViewController <UIGestureRecognizerDelegate>
#end
Then you declare an UIImageView on your ViewController.m, like so, with a BOOL to track if a touch event is occurring inside your UIImageView:
#interface ViewController () {
UIImageView *ballImage;
BOOL touchStarted;
}
Then you initialize the UIImageView on viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
UIImage *image = [UIImage imageNamed:#"ball.png"];
ballImage = [[UIImageView alloc]initWithImage:image];
[ballImage setFrame:CGRectMake(self.view.center.x, self.view.center.y, ballImage.frame.size.width, ballImage.frame.size.height)];
[self.view addSubview:ballImage];
}
After that you can start doing your modifications to what's best for you using these methods:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint touch_point = [touch locationInView:ballImage];
if ([ballImage pointInside:touch_point withEvent:event])
{
touchStarted = YES;
} else {
touchStarted = NO;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if ([touches count]==1 && touchStarted) {
UITouch *touch = [touches anyObject];
CGPoint p0 = [touch previousLocationInView:ballImage];
CGPoint p1 = [touch locationInView:ballImage];
CGPoint center = ballImage.center;
center.x += p1.x - p0.x;
// if you need to move only on the x axis
// comment the following line:
center.y += p1.y - p0.y;
ballImage.center = center;
NSLog(#"moving UIImageView...");
}
}

Related

How to undo multitouch drawing in iOS

Please help me to undo and forward my draw. I store all paths into an pathArray and now I want to undo and foward the path ( like app Notes (Apple) ).
Please help me to solve this!
This is my PathArray class
// PathArray.h
#import <Foundation/Foundation.h>
#interface PathArray : NSObject
#property (nonatomic) CGPoint start;
#property (nonatomic) CGPoint end;
#property (nonatomic) UIColor* color;
#property (nonatomic) CGFloat pathWidth;
- (instancetype) initWithStartPoint: (CGPoint)start andEnd: (CGPoint)end andColor: (UIColor *) color andPathWidth: (CGFloat) pathWidth;
#end
This is my Draw class
- (void)drawRect:(CGRect)rect
{
[strokecolor setStroke];
for (int i=0; i<pathArray.count; i++ ) {
CGContextRef contex = UIGraphicsGetCurrentContext();
CGContextSetLineCap(contex, kCGLineCapRound);
CGContextBeginPath(contex);
CGContextMoveToPoint(contex, pathArray[i].start.x, pathArray[i].start.y);
CGContextAddLineToPoint(contex, pathArray[i].end.x, pathArray[i].end.y);
CGContextSetStrokeColorWithColor(contex, pathArray[i].color.CGColor);
CGContextSetLineWidth(contex, pathArray[i].pathWidth);
CGContextStrokePath(contex);
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* touch = [touches anyObject];
if ([touch type] == UITouchTypeStylus)
{
if(drawable){
[self.delegate changeScrollViewInteraction:NO];
UITouch *touch = [touches anyObject];
lastPoint = [touch locationInView:self];
}
}
else
{
[self.delegate changeScrollViewInteraction:YES];
return;
}
[super touchesBegan: touches withEvent: event];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
if ([touch type] == UITouchTypeStylus) //pencil touch
{
if(drawable){
CGPoint newpoint = [touch locationInView:self];
PathArray *paths = [[PathArray alloc]initWithStartPoint:lastPoint andEnd:newpoint andColor:strokecolor andPathWidth:pathWidth];
[pathArray addObject:paths];
lastPoint = newpoint;
[self setNeedsDisplay];
NSLog(#"%#",pathArray[0]);
}
}
else
{
return;
}
[super touchesMoved: touches withEvent: event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [touches anyObject];
if ([touch type] == UITouchTypeStylus && drawable) //pencil touch
{
[pathEndPointArray addObject:tempEndPointArray];
}
if ([touch type] == UITouchTypeStylus && !drawable)
{
[self.delegate CacheLIView_showPopup_message:#"Already cupped!"];
}
[self touchesMoved:touches withEvent:event];
}
-(void)undo{
}
-(void)foward{
}
-(void)re_draw_after_rotate{ }
I need to create these function.
I would suggest the following (no code here):
create a second array pathUndoArray
Upon undo, remove the last entry from pathArray (if exists) and add it (at the end) to pathUndoArray, then redraw.
Upon redo, remove the last entry from pathUndoArray (if exists) and add it (at the end) to pathArray, then redraw.
Upon a new touch, you'll have to delete the pathUndoArray
You could also take a look at NSUndoManager.

Touched Move UILabel works until the value is fix - Bug or Features?

a very strange result.
Start a Single View Application
Add a UILabel
Put my Code in
import "ViewController.h"
#interface ViewController ()
{
float oldX, oldY;
bool dragging;
__weak IBOutlet UILabel *textLable;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// self.textLable.backgroundColor = [UIColor clearColor];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// get touch event
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if ([touch view] == textLable)
{
int intValue = (int)((touchLocation.y * 24.0)/300.0);
NSString *anyValue = [NSString stringWithFormat:#"%d",intValue];
textLable.center= touchLocation;
// RUN WITHOUT THIS PART .... tochedMoved workt great
//
// Run With this PART ..... touchedMoved is damaged!!!!!
//textLable.text = anyValue;
NSLog(#"%f %f", touchLocation.y, textLable.frame.origin.y);
}
}
#end
Connect label with
__weak IBOutlet UILabel *textLable;
let it RUN
Now you can move the label by touching moving.
Ok...and NOW!!!!
change the change
// RUN WITHOUT THIS PART .... tochedMoved workt great
//
// Run With this PART ..... touchedMoved is damaged!!!!!
//textLable.text = anyValue;
to
// RUN WITHOUT THIS PART .... tochedMoved workt great
//
// Run With this PART ..... touchedMoved is damaged!!!!!
textLable.text = anyValue; //<------------------------------
Run the app and try the move!!! you will see, label jumps between new and start position, if you start touched moving.
I tried by using a UIView as container....same thing: Once you change the value of moved object (UIButton same), moving is not working right.
Report to Appel is already send...no answere!!!
Is it a Bug or a features???
The idea is about your frame and your location touch. You are centering Label to your touch. So nothing is about setting the text.
Try this code, detecting distance between touch and centre text when first touch and adding the center label to this point :
#interface ViewController ()
{
float distanceTouchX, distanceTouchY;
bool dragging;
CGPoint firstLocation;
__weak IBOutlet UILabel *textLable;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
distanceTouchX = textLable.center.x - touchLocation.x;
distanceTouchY = textLable.center.y - touchLocation.y;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// get touch event
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
if ([touch view] == textLable)
{
int intValue = (int)((touchLocation.y * 24.0)/320.0);
NSString *anyValue = [NSString stringWithFormat:#"%d",intValue];
CGPoint newTouchLocation = touchLocation;
newTouchLocation.x = newTouchLocation.x + distanceTouchX;
newTouchLocation.y = newTouchLocation.y + distanceTouchY;
textLable.center= newTouchLocation;
textLable.text = anyValue;
NSLog(#"%f %f", touchLocation.y, textLable.frame.origin.y);
}
}
#end

How to detect a touch in a subview that was dragged there (or fastest way to get which subview is underneath a tap in its superview)

I've got a Super View, and its got a bunch of subviews. I'd like a user to be able to drag their finger inside the super view and when they drag over the subviews, that subview changes.
I need this to be very efficient, because changes can happen really fast.
So far what i've tried, is in the super view I can get the touch events from touchesBegan:withEvent: and touchesMoved:withEvent: These two combined give me all the touches I need. On each call of these methods, I have to iterate through all of the subviews and test like so
for (UIView *view in self.subviews) {
if (CGRectContainsPoint(view.frame, touchPoint) {
return view;
}
}
Then change that view however I want to. Problem is, from my benchmarking this process is just two slow.
My immediate thought is to have the subview's themselves detect the touch and then just post a notification or something like that when they are tapped. This way I don't have to iterate through them all inside the superview every freaking touch event.
The problem I am encountering with this, is that I haven't found a way to get the subviews themselves to detect that they are touched when they are just dragged over and the touch actually originated on a different UIView.
I'm open to any suggestions that either speed up the first process, or have a different way to accomplish this.
Since your subviews are on a Grid and if they are equally sized, you should be able to calculate the highlighted one directly. You just need to store their references on creation in a 2D array, for performance I suggest to use a c-array.
int x = touchPoint.x/viewWidth;
int y = touchPoint.y/viewHeight;
return views[x][y];
Depending on your Layout, some border margins or spacings between the views should be taken into account.
This way you do not need to iterate the subviews array and you do not need to perform all these CGRectContainsPoint calculations.
Should be easy:
MyViewController.h
#import <UIKit/UIKit.h>
#interface MyViewController : UIViewController
#end
MyViewController.m
#import "MyViewController.h"
#define SIDE_LENGTH 60
#define NUM_SQUARES 15
#implementation MyViewController
{
UIView *_selectedView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self populateView];
}
- (void)populateView
{
for (int i = 0; i < 15; ++i)
{
CGRect frame = CGRectMake(drand48() * self.view.frame.size.width - SIDE_LENGTH,
drand48() *self.view.frame.size.height - SIDE_LENGTH,
SIDE_LENGTH,
SIDE_LENGTH);
UIView *view = [[UIView alloc] initWithFrame:frame];
view.backgroundColor = [UIColor colorWithRed:drand48()
green:drand48()
blue:drand48()
alpha:1.0f];
view.layer.cornerRadius = SIDE_LENGTH / 2.0f; // cuz circles r pretty
[self.view addSubview:view];
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
for (UIView *view in self.view.subviews)
{
if (CGRectContainsPoint(view.frame, location)) {
_selectedView = view;
break;
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
_selectedView.center = location;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
_selectedView.center = location;
}
#end
Of course, for you, just get rid of the populateView method. I'm just using it to demonstrate how this works as a drop-in class.
If you're looking for speed, then subclass UIView and do this:
MyView.h
#import <UIKit/UIKit.h>
#class MyView;
#interface MyView : UIView
#end
MyView.m
#implementation MyView
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.superview];
self.center = location;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.superview];
self.center = location;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.superview];
self.center = location;
}
#end
Then MyViewController.m becomes much simpler and faster:
#import "MyViewController.h"
#import "MyView.h"
#define SIDE_LENGTH 60
#define NUM_SQUARES 15
#implementation MyViewController
{
UIView *_selectedView;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self populateView];
}
- (void)populateView
{
for (int i = 0; i < 15; ++i)
{
CGRect frame = CGRectMake(drand48() * self.view.frame.size.width - SIDE_LENGTH,
drand48() *self.view.frame.size.height - SIDE_LENGTH,
SIDE_LENGTH,
SIDE_LENGTH);
MyView *view = [[MyView alloc] initWithFrame:frame];
view.backgroundColor = [UIColor colorWithRed:drand48()
green:drand48()
blue:drand48()
alpha:1.0f];
view.layer.cornerRadius = SIDE_LENGTH / 2.0f;
[self.view addSubview:view];
}
}
#end

how to stop my object to skip by clicking and move just by touch

I have some object on my screen view which moves by touch, but the problem is if I click somewhere else on my screen which has no object on, the last moved object skipped to that clicked position, anyone who know how I can be able to stop that? PostView contains code about my objects
in .h file
#property (weak, nonatomic) IBOutlet PostView *pv;
and .m file
- (void)viewDidLoad
{
[super viewDidLoad];
viewArray = [NSMutableArray arrayWithObjects: nil];
pv.frame = CGRectMake(10, 10, 100, 100);
pv.backgroundColor = [UIColor blackColor];
[viewArray insertObject:pv atIndex:0];
[self.view addSubview:pv];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint firstTouch = [touch locationInView:self.view];
for (PostView *view in viewArray) {
if (CGRectContainsPoint(view.frame, firstTouch)) {
toMove = view;
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.view];
toMove.center = location;
// [_delegate dragViewDidMove:self];
// toMove.center = currentTouch;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
currentTouch = [touch locationInView:self.view];
toMove.center = currentTouch;
}
Set toView to null at the start of touchesBegan:. This ensures that if the user makes a touch that touches nothing (and so toView doesn't get set to anything deliberately), nothing will happen when the touch moves (the setCenter: message will be sent to null which will return null and have no side effects.)

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];
}

Resources