UIImageView scope. Accessing from another class - iphone

Here's part of the code I'm working with: http://pastie.org/2472364
I've figured out how to access the UIImageView from another method within the same class file in which it was programmatically created.
However, I was wondering how I'd access that same UIImageView from within the LetterTiles.m file, specifically within the touchesMoved method. The way I wrote the code in the sample, it will only show if the frames intersect if they're on top of each other when the otherMethod is called. Of course, I need to be able to check if the views intersect within the actual touchesMoved method. I'm sure it's something super easy, but I'm just not sure how to do it.
Thanks in advance for any help you can give me.

From your comment, and using the code you already have, I would go down this route. This isn't what I would do personally, just FYI. The structure is a bit shakey with the way it sounds like you want this.
Create the place holder UIImageView in the touchesBegan function, then check to see if they intersect when the user stops moving the image.
#import "LetterTiles.h"
#implementation LetterTiles
#synthesize placeHolder;
- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
// Retrieve the touch point (I consider this useful info to have, so I left it in)
CGPoint pt = [[touches anyObject] locationInView:self];
startLocation = pt;
// Create a place holder image wherever you want
[self setPlaceHolder:[[[UIImageView alloc] initWithFrame:CGRectMake(39, 104, 70, 70)] autorelease]];
[newImage setImage[UIImage imageNamed:#"placeHolder.png"]] autorelease];
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
CGPoint pt = [[touches anyObject] locationInView:[self superview]];
[self setCenterPoint:pt];
}
-(void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
LetterTiles *movingTile = self;
if (CGRectIntersectsRect([movingTile frame], [placeHolder frame])) {
NSLog(#"Touched");
[self setFrame:[placeHolder frame]];
}
}

Make a protocol called ViewMoved which will contain one method otherMethod.
implement that in myMainViewController
take a delegate property of type ViewMoved in LetterTiles.
Assign self when you make new object of type LetterTiles in myMainViewController.
On every movement of touch call oherMethod of delegate and check whether any views of type LetterTiles are intersecting or not.
This will catch any intersection when any of the view is moved.....
If above is not matching with your question then write here......

Related

How to pass touch event to another object?

I referenced the apps called "Comic Strip" and "Balloon Stickies Free"
When i add a speech balloon and touch s.b or s.b's tail, it works. But when i touch tail's around or between s.b and s.b's tail, it doesn't work. And Photo gets touch and works below the s.b.
So i tried to use hitTest:withEvent.
It works when i touch rectangle or tailRect first time. But when i touch other place in the object, and i touch rectangle or tailRect again, it doesn't work.
So how to modify this code ? i don't know .. help me please
- (id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
UIView *hitView = [super hitTest:point withEvent:event];
if(CGRectContainsPoint(rectangle, currentPt)==YES || CGRectContainsPoint(tailRect, currentPt)==YES)
return hitView;
else
return nil;
}
Try overriding - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event instead.
Or take a look at Ole Begemann's OBShapedButton. Code can easily be modified
to work with UIView instead of UIButton.
See this post horizontal scrolling. Using this code you can get all touch events in a single UIWindow class. You have to write some code to pass control appropriately.

Putting UIButton and other UIControl objects inside an MKAnnotationView and allowing user interaction

I have a custom annotation view on the map, which has a UIButton in it, but the UIButton is not responsive when pressed. I have two main problems with user interaction on the annotation view:
Buttons and other controls are not responsive.
I want the annotation to block touches according to my implementation of - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent*)event - that is if I return YES then I don't want the touches to get sent through to the MKMapView (potentially selecting other annotations that are BEHIND my annotation view), I want to handle the touch myself in this case.
I have made sure userInteractionEnabled is set to YES and I have investigated how touches are sent to the custom annotation view (my subclass of MKAnnotationView) by overriding touchesBegan etc. - but it appears that the touches are usually cancelled (thought I've managed to get touchesEnded a few times) - so it seems like it will even be difficult to manually implement any user-interaction with the custom annotation view.
Does anyone have any insights into allowing more user interaction with MKAnnotationView objects?
I managed to resolve this with the help of a colleague. The solution is to override - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event. Our assumption is that MKAnnotationView (which your annotation view must inherit from) overrides this to do the 'wrong' thing (presumably so that annotation selection doesn't get blocked between overlapping annotations). So you have to re-override it to do the right thing and return the appropriate UIView, the system will then send the events to it and the user will be able to interact with it :). This has the beneficial (in this case) side-effect that the interactive annotation blocks the selection of annotations that are behind it.
I found that rather than overriding hitTest:withEvent: I could just override pointInside:withEvent: instead and just get it to return YES. I guess that officially I should be doing a point-rect intersect check to ensure the place I'm tapping is within the control element, but in practise, just putting return YES appears to work perfectly well, still allowing you to dismiss the MKAnnotationView by tapping away from it.
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// for testing purposes
BOOL result = [super pointInside:point withEvent:event];
NSLog(#"pointInside:RESULT = %i", result);
return YES;
}
Adding up to the answer of jhabbott, this is what worked for me. I have a custom annotation view MKCustomAnnotationView that holds a custom annotation CustomPin as annotation. That 'pin' holds a UIButton as accessory button replacement which I wanted to get touch events.
My hitTest method would look like this:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
UIView *result = [super hitTest:point withEvent:event];
//NSLog(#"ht: %f:%f %d %#", point.x, point.y, [[event touchesForView:self] count], result);
if ([result isKindOfClass:[MKCustomAnnotationView class]])
{
MKCustomAnnotationView *av = (MKCustomAnnotationView *)result;
CustomPin *p = av.annotation;
UIButton *ab = p.accessoryButton;
if (p.calloutActive && point.x >= ab.frame.origin.x)
return ab;
}
return result;
}
The calloutActive bool is probably not necessary in most cases.
For anyone looking to add a tapGesture to an AnnotationView subview then the answer at the bottom of this:
MKannotationView with UIButton as subview, button don't respond
Worked for me:
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
if (CGRectContainsPoint(_button.frame, point)) {
return _button;
}
return [super hitTest:point withEvent:event];
}

Why is xcode giving me a "method not found" error?

I have an object called Shot which is a subclass of UIIMageView.
// Shot.h
#import <Foundation/Foundation.h>
#interface Shot : UIImageView {
CGPoint position;
}
- (void)SetShot:(CGPoint *)point;
#end
// Shot.m
#import "Shot.h"
#implementation Shot
- (void)SetShot:(CGPoint *)point;
{
position.x = point->x;
position.y = point->y;
}
#end
When I try to call the SetShot method, xcode gives me this warning:
method -SetShot not found(return type defaults to id)
Here is the call:
//CustomImageView.m
#import "CustomImageView.h"
#class Shot;
#implementation CustomImageView
-(id) initWithCoder:(NSCoder *)aDecoder
{
self.userInteractionEnabled = YES;
return self;
}
-(void) setInteraction
{
self.userInteractionEnabled = YES;
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
CGPoint point = [touch locationInView:self];
Shot *shot;
[shot SetShot:point];
}
- (void)dealloc
{
[super dealloc];
}
#end
When I run the program, I get a fatal error when the method is called. Why is that?
There are three problems in your code. Firstly, you need to import Shot.h in your CustomImageView.m implementation file:
#import "Shot.h"
instead of simply forward-declaring the Shot class:
#class Shot;
When the compiler sees a forward declaration, it becomes aware of the existence of that class but doesn’t yet know its attributes, declared properties, or methods — in particular, it doesn’t know that Shot has a -SetPoint: instance method.
Secondly, you’re not creating an instance of Shot:
Shot *shot;
[shot SetShot:point];
This only declares that shot is a pointer to Shot but there’s no allocation/initialisation. You should create an object, i.e.:
Shot *shot = [[Shot alloc] init];
then use it:
[shot SetShot:point];
and, when you don’t need it any longer, release it:
[shot release];
Although it’s not clear what’s the benefit of creating a shot, setting its point, and then releasing it. Unless your code is a contrived example, you might want to rethink this behaviour.
Also, your -SetPoint: method has a pointer to CGPoint parameter but you’re passing a CGPoint value (i.e., not a pointer) argument:
// point is not a pointer!
CGPoint point = [touch locationInView:self];
Shot *shot;
[shot SetShot:point];
I suggest you drop the pointer altogether, i.e.:
- (void)SetShot:(CGPoint)point;
{
position = point;
}
and maybe use a declared property instead of a manually implemented setter method.
Do
#import "Shot.h"
instead of:
#class Shot;
You have not created an instance of Shot; you have only created a pointer with:
Shot *shot;
You must allocate and initialize it:
Shot *shot = [[Shot alloc] init];
At some point you must import the header file Shot.h as well.

How to call a method only once during -(void)touchesMoved?

I am using - (void) touchesMoved to do stuff when ever I enter a specific frame, in this case the area of a button.
My problem is, I only want it to do stuff when I enter the frame - not when I am moving my finger inside the frame.
Does anyone know how I can call my methods only once while I am inside the frame, and still allow me to call it once again if I re-enter it in the same touchMove.
Thank you.
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event touchesForView:self.view] anyObject];
CGPoint location = [touch locationInView:touch.view];
if(CGRectContainsPoint(p1.frame, location))
{
//I only want the below to me called
// once while I am inside this frame
[self pP01];
[p1 setHighlighted:YES];
}else {
[p1 setHighlighted:NO];
}
}
You can use some attribute to check if the code was already called when you were entering specific area. It looks like highlighted state of p1 object (not sure what it is) may be appropriate for that:
if(CGRectContainsPoint(p1.frame, location))
{
if (!p1.isHighlighted){ // We entered the area but have not run highlighting code yet
//I only want the below to me called
// once while I am inside this frame
[self pP01];
[p1 setHighlighted:YES];
}
}else { // We left the area - so we'll call highlighting code when we enter next time
[p1 setHighlighted:NO];
}
Simply add a BOOL that you check in touchesMoved and reset in touchesEnded
if( CGRectContainsPoint([p1 frame],[touch locationInView:self.view])) {
NSLog (#"Touch Moved over p1");
if (!p14.isHighlighted) {
[self action: p1];
p1.highlighted = YES;
}
}else {
p1.highlighted = NO;
}
try using a UIButton and use the 'touch drag enter' connection in Interface Builder.

Implementing iphone's copy/paste controls on a custom view / uiview subclass

I will admit that there is already a question exactly along these lines here on S.O., but it lacks implementation details, a working answer, and I would like to be more specific, so I think a new question is in order. Obviously, let me know if I'm wrong and we can try to restart the thread over there.
Basically, I want to copy the text in a UILabel to the pasteboard when a user holds down on the label. Not hard to do, honestly. However, I think the best way to provide visual feedback is to prompt the user with the Copy menu option from UIMenuController.
According to the Event Handling section of the iPhone Application Programming Guide, specifically the section on Copy, Cut, and Paste Operations, it should be possible to provide copy, cut, and/or paste operations from a custom view.
So, I've sub-classed UILabel with the following implementation as described by the guide, but the UIMenuController won't show up. There's no indication in the guide that there's anything else required to do this, and the NSLog statement does print out to the console, indicating that the selector is being performed when I hold down on the label:
//
// CopyLabel.m
// HoldEm
//
// Created by Billy Gray on 1/20/10.
// Copyright 2010 Zetetic LLC. All rights reserved.
//
#import "CopyLabel.h"
#implementation CopyLabel
- (void)showCopyMenu {
NSLog(#"I'm tryin' Ringo, I'm tryin' reeeeal hard.");
// bring up editing menu.
UIMenuController *theMenu = [UIMenuController sharedMenuController];
// do i even need to show a selection? There's really no point for my implementation...
// doing it any way to see if it helps the "not showing up" problem...
CGRect selectionRect = [self frame];
[theMenu setTargetRect:selectionRect inView:self];
[theMenu setMenuVisible:YES animated:YES]; // <-- doesn't show up...
}
// obviously, important to provide this, but whether it's here or not doesn't seem
// to change the fact that the UIMenuController view is not showing up
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
BOOL answer = NO;
if (action == #selector(copy:))
answer = YES;
return answer;
}
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
[self performSelector:#selector(showCopyMenu) withObject:nil afterDelay:0.8f];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showCopyMenu) object:nil];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showCopyMenu) object:nil];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(showCopyMenu) object:nil];
}
#end
So, what else does one have to do to make this happen?
For those following along and trying to do this, too, you'll also need to set 'User Interaction Enabled' for the label
Edit:
For clarity, let me add that this should be similar to the little [Copy] menu item that appears over an image in certain iphone views when you hold down on it. -B
I'll say upfront I don't have an aswer, but I did some poking around and found more out. I'm sure you've looked at this already: CopyPasteTile
That code does work on my simulator and goes like this:
CGRect drawRect = [self rectFromOrigin:currentSelection inset:TILE_INSET];
[self setNeedsDisplayInRect:drawRect];
UIMenuController *theMenu = [UIMenuController sharedMenuController];
[theMenu setTargetRect:drawRect inView:self];
[theMenu setMenuVisible:YES animated:YES];
There are a few differences here:
drawRect is calculated from a giant view tile and tap point calculations
setNeedsDisplayInRect is being called
self is a large screen sized view, you may need screen coords instead of local coords (you can probably get that from self.superview)
I'd try making these adjustments to match the example first and see what kind of progress it gets me.