Multiple buttons on UIImageView - iphone

I have an UIImageView on my view. Certain parts of that image, I want to use as UIButtons. But the problem is, Those image parts are not of in a regular shape. I haven't really tried anything. The immediate solution which came to my mind was to recognize small frames of image and put custom button over that frame. But since the image portion (button area) is not of regular shape, this concept failed.
How can I place buttons on that UIImageView so that particular portion(not of regular shape) of image responds to some action.
Consider the following image :
I want to place one button at the center circle which is dark. I want to place buttons in between two perpendicular lines so that a quarter of button is clickable each with different action. So, in all I have 5 buttons.

I can think of 2 options:
first one
-(CGFloat)percentFromHeight:(CGFloat)percent{
return (CGRectGetHeight(self.bounds)/100)*percent;
}
-(CGFloat)percentFromWidth:(CGFloat)percent{
return (CGRectGetWidth(self.bounds)/100)*percent;
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint currentTouchPosition = [touch locationInView:self];
//first check if the tup is in the center
if(currentTouchPosition.x > [view percentFromWidth:45] && currentTouchPosition.x < [view percentFromWidth:55] && currentTouchPosition.y > [view percentFromWidth:45] && currentTouchPosition.y < [view percentFromWidth:55]){
//the tup is in the center
//Do your thing
return;
}
//if this is not in the center, check other options
if(currentTouchPosition.x > [view percentFromWidth:50]){
if(currentTouchPosition.y > [view percentFromHeight:50]{
//this is the bottom left side
else{
//this is the top left side
}
}else if(currentTouchPosition.x < [view percentFromWidth:50]{
if(currentTouchPosition.y > [view percentFromHeight:50]{
//this is the bottom right side
else{
//this is the top right side
}
}
second -
subclass UIButton / UIImage as you prefer and use UIBezierPath to draw custom shapes in drawRect:, then use [UIBezierPath containsPoint] to check if the those is inside the path of the view/button.

Read this topic - even the same image.

My opinion is you should use touches method to find which portion is touched(using the image frame and touchable portions' frame) and make appropriate action than adding a button.

Related

Restrict image movement to grid

I'm trying to make the boxes move only in horizontal and vertical lines following the touchesMoved event.
I could easily check on every touch event if the center of the box is in the center of the current grid block and then allow a direction change. But that will require the touches to be very precise, and could also lead to bugs because of speedy fingers etc. and then miss the touch event.
What I essential would like to do is make the box move correctly in the grid, even though your touch path is not "perfect". See image below, blue lines indicates box movement, green line is the path of the touch. The box needs to follow the grid closest to the touch path, so it looks like your moving it.
How can i accomplish this?
Edit: Forgot to mention that the movement of the box should be smooth, not jump from grid to grid.
Video
Bonus info: I will also need to flicks boxes left/right up/down with touch momentum, and of course have some sort of collision detection, so boxes can't move through other boxes on the grid. Am I better off with a 2d physics engine?
Smooth animation based on hacker2007 answer:
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *aTouch = [touches anyObject];
CGPoint location = [aTouch locationInView:gridContainerView];
for (UIView *subView in gridContainerView.subviews) {
if (conditionForBeingAGridBlock && CGRectContainsPoint(subview.frame, touchPoint))
{
[UIView beginAnimations:#"Dragging A DraggableView" context:nil];
self.frame = CGRectMake(0, location.y, subview.frame.size.width, subview.frame.size.height);
[UIView commitAnimations];
}
}
}
This will move the view you are dragging under your finger, you can add checks yourself to make sure that it doesn't go where it can't. But this will get your a smooth dragging animation.
Seems the problem is what you're setting the frame to in your anitamion:
Currently every time you move the square a little bit you get a new rect here:
CGRect rect = [self.grid getCellRect:self.grid.gridView x:cell.x y:cell.y];
Then in your animation you do this:
self.frame = rect;
Then you animate the box to that rect. So if you move your finger really quickly then you will get that 'skip' effect. If you change it to this:
self.frame = CGRectMake(location.x - self.bounds.size.width / 2, location.y - self.bounds.size.height / 2, self.bounds.size.width, self.bounds.size.height);
try this approach assuming your grid blocks are located in gridContainerView
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint touchPoint = [touch locationInView: gridContainerView];
for (UIView *subView in gridContainerView.subviews) {
if (conditionForBeingAGridBlock &&
CGRectContainsPoint(subview.frame, touchPoint)) {
box.frame = subview.frame;
}
}
}
}

Zooming a background image without zooming the overlay

I'm a beginner to the iOS development, and I'm trying to display an image (a map in fact) which need to be zoomable and pannable. My problem is that I don't know how to add an overlay which will follow the pan to always represent the same location, but won't be scaled by the zoom. There will be several overlays, and each one must be clickable.
To zoom and pan the image (map), I added my UIImageView in a UIScrollView and it works great, but I have no idea how to add this feature.
I found this thread but it is not really the same problem since his overlay is static :
UIScrollview with two images - Keeping 1 image zoomable and 1 image static (fixed size)
I've developped the same application in android, and to make this work I was converting a pixel of the map in screen coordinates thanks to the transformation matrix, and I overrode the onDraw method to display it, but I don't know how to do the same on iOS, and I don't know if this is the better solution.
Thanks for any help.
Ok so I found a way to do it, if it can helps anybody :
I added my overlay in the scrollView, with the background image (the map).
+CustomScrollView
----> UIImageView (map)
----> OverlayImageView (overlay)
In order to zoom, the custom scrollview need a delegate with the following methods :
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
//The background image with the map
return mapView;
}
//When a zoom occurs, move the overlay
- (void)scrollViewDidZoom:(UIScrollView *)scrollView {
UIImageView* overlayView = [scroll.subviews objectAtIndex:1];
float x;
float y;
float width;
float height;
//keep the width and height of the overlay
width = overlayView.frame.size.width;
height = overlayView.frame.size.height;
//Move it to stay over the same pixel of the map, and centers it
x = (self.overlay.point.x * scroll.zoomScale - width/2);
y = (self.overlay.point.y * scroll.zoomScale - height/2);
overlayView.frame = CGRectMake(x,y,width,height);
}
With this, we are saying that the zoom only occurs on the background image, but as the overlay is in the UIScrollView, it pans with it. So the only thing we need to care is to move the Overlay when the zoom change, and we know it with the scrollViewDidZoom method.
To handle the touch events, we override the touchEnded:withEvent: of CustomScrollView and we forward it to the overlay if there is only one tap. I don't show the OverlayImageView since it only override this same method (toucheEnded:withEvent:) to handle a touch on it.
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [touches anyObject];
// Coordinates in map view
CGPoint point = [touch locationInView:[self.subviews objectAtIndex:0]];
//forward
if(touch.tapCount == 1){
OverlayImageView* overlayView = [self.subviews objectAtIndex:1];
CGPoint newPoint = [touch locationInView:overlayView];
BOOL isInside = [overlayView pointInside:newPoint withEvent:event];
if(isInside){
[overlayView touchesEnded:touches withEvent:event];
}
}
// zoom
else if(touch.tapCount == 2){
if(self.zoomScale == self.maximumZoomScale){
[self setZoomScale:[self minimumZoomScale] animated:YES];
} else {
CGRect zoomRect = [self zoomRectForScrollView:self withScale:self.maximumZoomScale withCenter:point];
[self zoomToRect:zoomRect animated:YES];
//[self setZoomScale:[self maximumZoomScale] animated:YES];
}
[self setNeedsDisplay];
}
}
Hope this will help.
You can put an imageView on top as an overLay and set its userInteractionEnabled property to NO. Then you have to pan it programmatically.

Xcode Button Click Alpha

Basically I am trying to make a button shaped as a circle and add an image to it. The image is a png with transparency representing a sphere. Adding it to a custom button does it, but it has one problem. The transparent content around the sphere is also clickable. How Do I make so that the nontransparent area of the image is clickable?
You can check out GKTank sample for how to register and use touches.
You have to have to register to get the touch events, then inside the event, check the location, and decide if it is hitting your graphic. To do that, you would have to know the dimmentions and shape of the round button, and then decide if the touch is inside or outside of it.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (myButtonIsActive) {
CGPoint tPoint;
UITouch *thumb = [[event allTouches] anyObject];
tPoint = [thumb locationInView:thumb.view];
// check here if tPoint is inside of the button shape/circle

how to exchange one imageview with another imageview

i am displaying 3 images on image views.
i am getting image position by using the fallowing code.
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
// get touch event
UITouch *touch = [[event allTouches] anyObject];
CGPoint touchLocation = [touch locationInView:self.view];
NSLog(#"%f %f",touchLocation.x,touchLocation.y);
here in console i got the image positions.
Now what i need is when ever imageview is dragged over the imageview2 i need to exchange imageview2 in the place of image view and imageview in the place of imageview2.
can any one please help me.
Thank u in advance.
I wouldn't be replacing the entire imageView2, I would just change the image in imageView2 to the image in imageView.
First, establish that imageView2 is on top of imageView. Second, create an animation block and remove the image from imageView2, change the image in the imageView to the old image from imageView2, and possibly add a nice smooth transition. I would highly recommend a transition animation, it makes the action much more fluid. Use the positions of the imageViews, it wouldn't matter where the image was placed, it would animate as long as it was over top of imageView2.
Remember, there's nothing wrong with faking it. As long as it looks and acts like you want it to, then it works.

iOS - Drag and drop collision detection How to detect when your selected item drags over another subview?

We are adding drag and drop functionality to what is to become a sports field with positions for players.
The positions are mapped out using Interface Builder with each being a separate UIImageView.
We want to be able to drag player images from bench positions from the side of the screen onto positions on the field.
How best can we detect when the selected player which is being moved around collides with an existing gamePosition imageView?
We are looking for a way to detect if there is a view or ImageView under the current location.
-(void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch *touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:touch.view];
tile1.center = location;
if gamePositionExistsAtCurrentLocation(location) { //want something like this
[tile1 setBackgroundColor:[UIColor blueColor]];
} else {
[tile1 setBackgroundColor:[UIColor yellowColor]];
}
}
check if the frame of the item you are moving intersects with the frame from on of your subviews
for (UIView *anotherView in self.subviews) {
if (movingView == anotherView)
continue;
if (CGRectIntersectsRect(movingView.frame, anotherView.frame)) {
// Do something
}
}
If I were you, I would add all game relevant items to an NSArray and for-loop through this. So you don't detect collisions with subviews that have nothing to do with your game like labels and so on.
Also might want to consider view.center with CGRectContainsPoint()