Imagine that i drag an ImageView in TouchesMoved,how can i recognize that in which direction i dragged it from code ?
You can store a temporary Point from touchesBegan. Add a iVar in "YourImageView" interface.
#interface YourImageView : UIImageView
{
CGPoint previousPt;
//Other iVars.
}
#end
#implementation YourImageView
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
previousPt = [[touches anyObject] locationInView:self.view];
}
- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
const CGPoint p = [[touches anyObject] locationInView:self.view];
if (previousPt.x > p.x)
{
//Dragged right to left
}
else if (previousPt.x < p.x)
{
//Dragged left to right
}
else
{
//no move
}
//Do the same thing for y-direction
}
I would extract a method out of it. But I hope you got the idea.
If you subtract the old position from the new position of the ImageView, then you will get a direction vector. If you want a unit vector, just normalize it.
Related
I am using core data to save the text that is added to the labels, each of these labels is on view that can be moved. I am currently saving the text with an entity that is a string, which works fine. How would I use core data to save the CGPoint of the views when moved, to be then loaded back into the saved position when the view is opened again.
The code is as follows.
-CGPoint firstTouchPoint;
//xd = distance between image center and my touch center
float xd;
float yd;
#implementation BlankViewController
-(BOOL)prefersStatusBarHidden
{
return YES;
}
#synthesize name;
-(NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
(IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.name) {
[self.name setValue:self.nameTextField.text forKey:#"name"];
[self.name setValue:self.Label1.text forKey:#"label1"];
[self.name setValue:self.Label2.text forKey:#"label2"];
}
else{
// Create a new managed object
NSManagedObject *newName = [NSEntityDescription insertNewObjectForEntityForName:#"Maths" inManagedObjectContext:context];
[newName setValue:self.nameTextField.text forKey:#"name"];
[newName setValue:self.Label1.text forKey:#"label1"];
[newName setValue:self.Label2.text forKey:#"label2"];
}
- (void)viewDidLoad {
[super viewDidLoad];
if (self.name) {
[self.nameTextField setText:[self.name valueForKey:#"name"]];
[self.Label1 setText:[self.name valueForKey:#"label1"]];
[self.Label2 setText:[self.name valueForKey:#"label2"]]; }}
Code to move the views:
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* bTouch = [touches anyObject];
if ([bTouch.view isEqual:[self imgTest]]) {
firstTouchPoint = [bTouch locationInView:[self view]];
xd = firstTouchPoint.x - [[bTouch view]center].x;
yd = firstTouchPoint.y - [[bTouch view]center].y;
[self.view bringSubviewToFront:self.imgTest];
}
else if ([bTouch.view isEqual:[self imgTest2]]) {
firstTouchPoint = [bTouch locationInView:[self view]];
xd = firstTouchPoint.x - [[bTouch view]center].x;
yd = firstTouchPoint.y - [[bTouch view]center].y;
[self.view bringSubviewToFront:self.imgTest2];
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch* mTouch = [touches anyObject];
if (mTouch.view == [self imgTest]) {
CGPoint cp = [mTouch locationInView:[self view]];
[[mTouch view]setCenter:CGPointMake(cp.x-xd, cp.y-yd)];
}
else if (mTouch.view == [self imgTest2]) {
CGPoint cp = [mTouch locationInView:[self view]];
[[mTouch view]setCenter:CGPointMake(cp.x-xd, cp.y-yd)];
}
}
If you just need to store a single CGPoint with your entity, I would add two required float attributes to your entity (say x and y) and store the point like that.
With the latest Xcode, you can have it generate model objects for you which is easier than dealing with the plain NSManagedObject. With that model object it would also be easy to add a category that defines a point property that you can use to convert the Core Data attributes to a CGPoint and vice versa.
How can I move multiple UIImage views around a view controller?
I have managed to use this code;
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
printf("touch began --------- |n");
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
printf("touch moved --------- |n");
UITouch *myTouch = [touches anyObject];
startPoint = [myTouch locationInView:self.view];
ball.center = CGPointMake(startPoint.x, startPoint.y);
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
printf("touch end --------- |n");
}
This code above has made it so that I can move one UIImage view around with touch, however, I want to be able to move 100's around. This code also, currently, when you move your finger around an area of the screen the image jumps to your finger.
Is this the best way to do it? Or is a pan gesture better?
Please help me make it so I can move multiple images around my view controller with touch and if you use the code above, please stop the image from jumping!
Please help!
.H FILE FOR ANSWER REFERRAL;
#interface CMViewController : UIViewController {
CGPoint startPoint;
}
#property CGPoint startPoint;
#property (strong, nonatomic) IBOutlet UIImageView *smyImageView;
#property (strong, nonatomic) IBOutlet UIImageView *smyImageView1;
#end
Thanks
You can use below. I used this for multiple images moving on screen. It's working for me.
UIPanGestureRecognizer *span=[[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(onsPan:)];
[smyImageView addGestureRecognizer:span];
UIPanGestureRecognizer *span1=[[UIPanGestureRecognizer alloc]initWithTarget:self action:#selector(onsPan1:)];
[smyImageView1 addGestureRecognizer:span1];
Moving (Pan):
- (void)onsPan:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
- (void)onsPan1:(UIPanGestureRecognizer *)recognizer {
CGPoint translation = [recognizer translationInView:self.view];
recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x,
recognizer.view.center.y + translation.y);
[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];
}
This will teach you everything you need to know for what you want to do.
http://www.raywenderlich.com/44270/sprite-kit-tutorial-how-to-drag-and-drop-sprites
This is another answer that may help you
I am trying to implement an undo/redo method using NSUndoManager. I have asked other questions on this, but am still stuck.
Where I am at the moment is as follows:
.h
NSUndoManager *undoManager;
#property(nonatomic,retain) NSUndoManager *undoManager;
.m
#synthesize undoManager;
[undoManager setLevelsOfUndo:99];
viewdidload:
NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
[dnc addObserver:self selector:#selector(undoButtonTapped) name:#"undo" object:nil];
[dnc addObserver:self selector:#selector(redoButtonTapped) name:#"redo" object:nil];
- (void)resetTheImage:(UIImage*)image
{
NSLog(#"%s", __FUNCTION__);
// image = savedImage.image;
if (image != drawImage.image)
{
[[undoManager prepareWithInvocationTarget:self] resetTheImage];
image = drawImage.image ;
} else {
NSLog(#"That didn't work");
}
}
- (void)undoButtonTapped {
NSLog(#"%s", __FUNCTION__);
[undoManager undo];
}
I get "That didn't work"...
I would appreciate help. I will post the answer to my original question when I figure out what I'm doing wrong.
---EDIT---
I have changed resetTheImage as follows:
- (void)resetTheImage:(UIImage*)image
{
NSLog(#"%s", __FUNCTION__);
image = savedImage.image;
if (image != drawImage.image)
{
drawImage.image = image;
savedImage.image = image;
NSLog(#"undo image");
[[self.undoManager prepareWithInvocationTarget:drawImage.image] image];
} else {
NSLog(#"same image");
savedImage.image = image;
}
}
However, confusion rains - it may help if someone (Brad?, Justin?) can provide a bullet point list of the steps I need to take to get this working. For example:
. Add notifications in ...
. Trigger notifications....
. Have undo /redo buttons point to...
. What methods/functions I really need to build..
....
I wish SO would allow me to give you more points than 1..
(It doesn't help that my "o" key is getting wonky)
It does help that I had a baby granddaughter yesterday :))))
First, I want to thank everyone for any/all assistance. I solved this finally although I'm not sure if it's the best solution.
I made a UIView called from the UIViewController. The controls (colors and brushes) remain in the VC. The drawing methods move to the View Method.
The View Method calls a Drawing method to actually perform the draw, and the View method controls the undo/redo.
Here are some code snippets:
-(void)undoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.currentArray count] == 0) {
//nothing to undo
return;
}
DrawingPath *undonePath = [self.currentArray lastObject];
[self.currentArray removeLastObject];
[self.redoStack addObject:undonePath];
[self setNeedsDisplay];
}
-(void)redoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.redoStack count] == 0) {
// nothing to redo
return;
}
DrawingPath *redonePath = [self.redoStack lastObject];
[self.redoStack removeLastObject];
[self.currentArray addObject:redonePath];
[self setNeedsDisplay];
}
Let me know if anyone wants clarification. Thanks all again..
UPDATE as requested:
These are some headers:
DrawingViewController *mvc;
NSMutableArray *pathArray;
NSMutableArray *colorArray;
NSMutableArray *bufferArray;
NSMutableArray *currentArray;
UIBezierPath *myPath;
NSString *brushSize;
CGPoint lastPoint;
int colorIndex;
NSString *colorKey;
SoundEffect *erasingSound;
SoundEffect *selectSound;
BOOL swiped;
int moved;
UIColor *currentColor;
NSString *result;
}
#property(nonatomic,assign) NSInteger undoSteps;
#property (strong, nonatomic) NSString *result;
#property (strong,nonatomic) UIColor *currentColor;
#property (strong,nonatomic) NSMutableArray *currentArray;
#property (strong,nonatomic) NSMutableArray *bufferArray;
#property (strong,nonatomic) DrawingPath *currentColoredPath;
#property (strong,nonatomic) NSMutableArray *redoStack;
#property (strong, nonatomic) NSString *colorKey;
and here are some more of the methods.. The currentArray then keeps track of points, brush and color in a sort of stack. Undo removes from the stack, and adds into a temp stack that can be used to Redo.
-(void)undoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.currentArray count] == 0) {
//nothing to undo
return;
}
DrawingPath *undonePath = [self.currentArray lastObject];
[self.currentArray removeLastObject];
[self.redoStack addObject:undonePath];
[self setNeedsDisplay];
}
-(void)redoButtonClicked
{
//NSLog(#"%s", __FUNCTION__);
if ([self.redoStack count] == 0) {
// nothing to redo
return;
}
DrawingPath *redonePath = [self.redoStack lastObject];
[self.redoStack removeLastObject];
[self.currentArray addObject:redonePath];
[self setNeedsDisplay];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
self.currentColoredPath = [[DrawingPath alloc] init];
[self.currentColoredPath setColor:self.currentColor];
UITouch *touch= [touches anyObject];
[self.currentColoredPath.path moveToPoint:[touch locationInView:self]];
[self.currentArray addObject:self.currentColoredPath];
// Remove all paths from redo stack
[self.redoStack removeAllObjects];
lastPoint = [touch locationInView:self];
lastPoint.y -= 20;
if ([touch tapCount] == 2) {
[self alertOKCancelAction];
return;
}
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
UITouch *touch = [touches anyObject];
[self.currentColoredPath.path addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
lastPoint = currentPoint;
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
//NSLog(#"%s", __FUNCTION__);
self.currentColoredPath = nil;
}
I have a simple drawing class. There is a view controller that includes a color selection bar. Then a UIView that has the CGRect draw functions.
I can draw ok, but when I change the color, all existing strokes are changed. What have I messed up? I want to only change colors for new strokes.
Any help would be welcome. Here are some relevant code snippets:
- (void)drawRect:(CGRect)rect
{
[currentColor setStroke];
for (UIBezierPath *_path in pathArray)
[_path strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
#pragma mark - Touch Methods
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
swiped = NO;
myPath=[[UIBezierPath alloc]init];
myPath.lineWidth=10;
UITouch *touch= [touches anyObject];
[myPath moveToPoint:[touch locationInView:self]];
[pathArray addObject:myPath];
if ([touch tapCount] == 2) {
[self eraseButtonClicked];
return;
}
lastPoint = [touch locationInView:self];
lastPoint.y -= 20;
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
swiped = YES;
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self];
currentPoint.y -= 20;
[myPath addLineToPoint:[touch locationInView:self]];
[self setNeedsDisplay];
UIGraphicsBeginImageContext(self.frame.size);
CGContextSetLineCap(UIGraphicsGetCurrentContext(), kCGLineCapRound);
CGContextSetLineWidth(UIGraphicsGetCurrentContext(), 15.0);
CGContextSetRGBStrokeColor(UIGraphicsGetCurrentContext(), red, green, blue, 1.0);
CGContextBeginPath(UIGraphicsGetCurrentContext());
CGContextMoveToPoint(UIGraphicsGetCurrentContext(), lastPoint.x, lastPoint.y);
CGContextAddLineToPoint(UIGraphicsGetCurrentContext(), currentPoint.x, currentPoint.y);
CGContextStrokePath(UIGraphicsGetCurrentContext());
UIGraphicsEndImageContext();
lastPoint = currentPoint;
moved++;
if (moved == 10) {
moved = 0;
}
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
if ([touch tapCount] == 2) {
[self eraseButtonClicked];
return;
}
}
Your drawRect: is drawing all the paths in the same colour. When you call [currentColor setStroke], you are setting the colour for all the strokes you draw. You'll need to maintain the colours for the strokes as well, and reset the colour before each call to strokeWithBlendMode.
Something like:
- (void)drawRect:(CGRect)rect
{
for( int i=0; i<[pathArray count]; i++) {
[[colorArray objectAtIndex:i] setStroke];
[[pathArray objectAtIndex:i] strokeWithBlendMode:kCGBlendModeNormal alpha:1.0];
}
}
You'll have to make sure you add a UIColor object to the colorArray every time you add a path to pathArray.
You could add [colorArray addObject:currentColor]; after the line [pathArray addObject:myPath];
Hey all, can anyone please explain how I can subclass UIButton and override some method so that when the user drags off a button it comes up right away? The problem is that when I drag out of the button frame it remains active and down. I want it to stop as soon as the finger leaves the button frame. Any ideas?
(Cocoa Touch)
If anyone ever has this problem, the following code allows for extremely accurate edge sensing while dragging. If you drag out of the button, it wont extend past the button's edge like normal.
(I subclassed UIButton and made the following:)
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
touchBlocker = TRUE;
self.highlighted = TRUE;
NSLog(#"Touch Began");
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self];
if (touchBlocker) {
if (!CGRectContainsPoint([self bounds], location)) {
touchBlocker =FALSE;
self.highlighted = FALSE;
NSLog(#"Touch Exit");
}
} else if (CGRectContainsPoint([self bounds], location)) {
touchBlocker = TRUE;
self.highlighted = TRUE;
NSLog(#"Touch Enter");
}
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
touchBlocker = FALSE;
self.highlighted = FALSE;
NSLog(#"Touch Ended");
}