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

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

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.

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

Why won't my ImageView move?

All in all I am trying to get a result when one image touches another image. That is not the problem I am having though. I can't get the UIImageView to even move when I click on it and drag. Below is the code I am using! Please let me know if you can help me! Thanks!
.h
{
IBOutlet UIImageView *image1;
IBOutlet UIImageView *image2;
}
#property (nonatomic, retain) UIImageView *image1;
#property (nonatomic, retain) UIImageView *image2;
-(void)collision;
.m
#synthesize image1, image2;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch1 = [touches anyObject];
[self collision];
if ([touch1 view] != self.image1) {
return;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch1 = [touches anyObject];
// If the touch was in the placardView, move the placardView to its location.
if ([touch1 view] == self.image1) {
CGPoint location = [touch1 locationInView:image1];
self.image1.center = location;
return;
}
}
-(void)collision
{
if (CGRectIntersectsRect(image1.frame, image2.frame)) {
NSLog(#"Touched");
}
}
** I was able to get the code to work where I am able to move the UIImageView.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch1 = [[event allTouches] anyObject];
image1.center = [touch1 locationInView:self.view];
return;
}
The only problem with this is that where ever I touch on the screen the image moves to that location. How may I have it where you have to touch the actual UIImageView to move it? Thanks!!
UIImageView default userInteraction is false, so u are just enable userInteraction is True for
both image view.

IOS touch tracking code

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...");
}
}

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.)

Resources