I'm trying to implement a simple color picker consisting of an image in a UIImageView. When the user drags a finger over it, I want an adjacent view to continuously update with the current pixel color.
I found what looks like something close to the ideal solution in #rdelmar's answer to this question on SO, so I borrowed the code and modified it to send the pickedColor back to a method on the AddCategoryViewController. This method (setColorview), however, is not updating the colorView.
My breakpoints and NSLogs are showing that the color information is being collected from the touch, sent and received, but apparently not applied, as indicated by the fact that the affected UIView colorView does not reflect the color. The most obvious issue is that the property colorView reads null, and I don't understand why.
As a bonus, I would really like for the picker to respond to a sliding finger, not just a tap.
I've included all the relevant code below, with important lines marked with //*******************
Thanks for looking! All help appreciated!
Code starts here, files are separated by ---------------------------:
//
// UIView+UIView_ColorOfPoint.m
// WMDGx
//
//
#import "UIView+UIView_ColorOfPoint.h"
#import <QuartzCore/QuartzCore.h>
#implementation UIView (UIView_ColorOfPoint)
-(UIColor *) colorOfPoint:(CGPoint)point
{
unsigned char pixel[4] = {0};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(pixel,
1, 1, 8, 4, colorSpace, (CGBitmapInfo)kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(context, -point.x, -point.y);
[self.layer renderInContext:context];
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIColor *color = [UIColor colorWithRed:pixel[0]/255.0
green:pixel[1]/255.0 blue:pixel[2]/255.0
alpha:pixel[3]/255.0];
return color;
}
#end
-----------------------------------------
//
// ColorPickerView.m
// WMDGx
//
//
#import "ColorPickerView.h"
AddCategoryViewController *addCatVC;
#implementation ColorPickerView
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [[event allTouches] anyObject];
CGPoint loc = [touch locationInView:self];
self.pickedColor = [self colorOfPoint:loc];
NSLog(#"Touches began");
//******************** For sending color info to setColorView in AddCategoryViewController
addCatVC = [[AddCategoryViewController alloc]init];
addCatVC.colorForColorView = self.pickedColor;
NSLog(#"Picked color is %#",self.pickedColor);
//******************** Call the method in AddCategoryViewController, which should display the color of the current pixel
[addCatVC setColorview];
}
#end
--------------------------------
//
// AddCategoryViewController.m
// WMDGx
//
//
#import "AddCategoryViewController.h"
#interface AddCategoryViewController ()
#end
#implementation AddCategoryViewController
NSMutableArray *array;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.catTextField.delegate = self;
[self.pickerImageView setUserInteractionEnabled:YES];
self.colorView.layer.cornerRadius = 6;
// ********************I put this NSLog here to check the status of the property self.colorView
NSLog(#"Color view is %#",self.colorView);//_colorView UIView * 0x8a63d30 0x08a63d30 (from Variables View)
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[self.catTextField resignFirstResponder];
return YES;
}
-(void)setColorview // ********************This is where the backgroundColor of self.colorView should be set
{
NSLog(#"colorForColorView is %#",self.colorForColorView);
NSLog(#"Color view is %#",self.colorView); //_colorView UIView * nil 0x00000000 (from Variables View)
[self.colorView setBackgroundColor:self.colorForColorView]; //colorView should display the color, but doesn't
NSLog(#"Color view is %#",self.colorView); //_colorView UIView * nil 0x00000000 (from Variables View)
NSLog(#"Color view color is %#",self.colorView.backgroundColor);
}
- (IBAction)saveButton:(UIBarButtonItem *)sender
{
if (self.catTextField.text.length < 1)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No category created"
message:#"Please create a new category"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else if (!self.colorView.backgroundColor)
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No color selected"
message:#"Please select a color for your new category"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
self.thisCategory = [WMDGCategory MR_createInContext:localContext];
self.thisCategory.name = [self.catTextField.text uppercaseString];
self.thisCategory.color = self.colorView.backgroundColor;
[localContext MR_saveToPersistentStoreAndWait];
[self.thisCell setUserInteractionEnabled:NO];
[self.delegate addCatControllerDidSave];
}
}
- (IBAction)cancelButton:(UIBarButtonItem *)sender
{
[self.delegate addCatControllerDidCancel:self.thisCategory];
}
#end
Here is my code that I use for this purpose. In addition to touches began I have the same code for touches moved, and that allows the sliding effect that you also want. My adjacent view has a tag of 200 which I look up and set based on the selected color. It looks like your linked code is a bit cleaner than mine, but perhaps seeing this would be useful.
First, when I get touches:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
NSSet *allTouches = [event allTouches];
if ([allTouches count] != 1)
return;
UIView *picker = [self.view viewWithTag:100];
UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
CGPoint p = [touch locationInView:self.view];
if (CGRectContainsPoint(picker.frame, p))
{
printf("Hit gradient!\n");
p = [touch locationInView:picker];
UIColor *c = [self getPixelColor:[UIImage imageNamed:#"gradient.png"]
xLoc:p.x
yLoc:p.y];
UIView *display = [self.view viewWithTag:200]; // representative color
[display setBackgroundColor:c];
}
}
The code for getting the color (I believe this code was adapted from other code on SO):
- (UIColor*)getPixelColor:(UIImage *)image xLoc:(int)x yLoc:(int)y
{
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
const UInt8* data = CFDataGetBytePtr(pixelData);
if (x < 0 || x >= image.size.width || y < 0 || y >= image.size.height)
{
CFRelease(pixelData);
return [UIColor whiteColor];
}
int pixelInfo = ((image.size.width * y) + x ) * 4;
UInt8 red = data[pixelInfo];
UInt8 green = data[(pixelInfo + 1)];
UInt8 blue = data[pixelInfo + 2];
UInt8 alpha = data[pixelInfo + 3];
CFRelease(pixelData);
UIColor* color = [UIColor colorWithRed:red/255.0f green:green/255.0f blue:blue/255.0f alpha:alpha/255.0f];
return color;
}
Related
this is custom sprite class named BackGround
#import "BackGround.h"
// -----------------------------------------------------------------
id move02;
double roadX;
#implementation BackGround
+ (instancetype)initWithPicture: (NSString *) pic
{
return [[self alloc] init:pic];
}
-(id) init: (NSString *) pic
{
if(self = [super init])
{
CCSpriteFrameCache* spriteFrameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
CCSpriteFrame * bgSpriteFrame = [spriteFrameCache spriteFrameByName:pic];
self = [BackGround spriteWithSpriteFrame:bgSpriteFrame];
self.anchorPoint = ccp(0, 0);
roadX = -(self.contentSize.width-1)*2;
self.position = ccp((-roadX/2), 0);
id move01 = [CCActionMoveBy actionWithDuration:10.0f position:ccp(roadX,0.0)];
move02 = [CCActionRepeatForever actionWithAction:move01];
[self runAction:move02];
}
return self;
}
-(void)bgWhenRun
{
[self stopAllActions];
id move = [CCActionSpeed actionWithAction:move02 speed:2];
[self runAction:move];
}
-(void)bgWhenWalk
{
[self stopAllActions];
[self runAction:move02];
}
// -----------------------------------------------------------------
#end
this is scene class code
#import "_256Deathes.h"
#import "IntroScene.h"
#import "BackGround.h"
#import "cocos2d.h"
#import "Person.h"
// -----------------------------------------------------------------
Person * personA;
#implementation _256Deathes
{
}
- (instancetype)init
{
if ((self = [super init]))
{
NSAssert(self, #"Whoops");
self.userInteractionEnabled = YES;
CCSpriteFrameCache* spriteFrameCache = [CCSpriteFrameCache sharedSpriteFrameCache];
[spriteFrameCache addSpriteFramesWithFile:#"256Deathes.plist"];
BackGround * bgSprite01 = [BackGround initWithPicture:#"earthA.png"];
bgSprite01.position = ccp(0, 0);
[self addChild:bgSprite01 z:0 name:#"bgSpriteA"];
BackGround * bgSprite02 = [BackGround initWithPicture:#"earthA.png"];
[self addChild:bgSprite02 z:1 name:#"bgSpriteB"];
}
return self;
}
- (void)onEnter
{
// always call super onEnter first
[super onEnter];
[self schedule:#selector(updateSprite) interval:0.02];
}
-(void)touchBegan:(CCTouch *)touch withEvent:(CCTouchEvent *)event
{
BackGround *spriteA = (BackGround *)[self getChildByName:#"bgSpriteA" recursively:NO];
BackGround *spriteB = (BackGround *)[self getChildByName:#"bgSpriteB" recursively:NO];
[spriteA bgWhenRun];
[spriteB bgWhenRun];
}
-(void)touchEnded:(CCTouch *)touch withEvent:(CCTouchEvent *)event
{
BackGround *sprite;
for(sprite in [self children])
{
if([sprite.name containsString:#"bgSprite"])
{
[sprite bgWhenWalk];
}
}
}
-(void) updateSprite
{
[self updateBackGround01];
}
-(void) updateBackGround01
{
BackGround *sprite;
for(sprite in [self children])
{
if([sprite.name containsString:#"bgSprite"])
{
double nextX = sprite.contentSize.width-3;
if(sprite.position.x <= (-nextX))
{
sprite.position = ccp(nextX, 0);
}
}
}
}
// -----------------------------------------------------------------
#end
when i touch begin or touch end, spriteA will stop moving, after i tried some times, i found [self stopAllActions] in methods named bgWhenRun and bgWhenWalk can make spriteA and spriteB effect each other.
anyone can find out the mistakes in the code then tell me?i have tried many times,now i really have no idea. thank you!
These two sprites effect each other because both are using same instance of variables id move02 and double roadX as being global ones. Declare them within scope of BackGround class i.e. as member variables of that class.
I have searched a lot for this question, but none of them seem to do exactly what I want.
A lot of tutorials show me how to add lines and polygons in code, but not with freehand drawing.
The question is the following one:
I am building a real estate application. If the user is on the MKMapView it has the ability to draw a rectangle/circle/... around a certain area where he/she wants to buy/rent a house. Then I need to display the results that correspond within the area the user has selected.
Currently I have a UIView on top of my MKMapView where I do some custom drawing, is there a way to translate points to coordinates from that or ..? Or is this completely not the way this is done ? I have also heard about MKMapOverlayView, etc .. but am not exactly sure how to use this.
Can anybody point me in the right direction or does he have some sample code or a tutorial that can help me accomplish what I am in need for?
Thanks
I have an app that basically does this. I have a map view, with a toolbar at the top of the screen. When you press a button on that toolbar, you are now in a mode where you can swipe your finger across the map. The start and end of the swipe will represent the corners of a rectangle. The app will draw a translucent blue rectangle overlay to show the area you've selected. When you lift your finger, the rectangular selection is complete, and the app begins a search for locations in my database.
I do not handle circles, but I think you could do something similar, where you have two selection modes (rectangular, or circular). In the circular selection mode, the swipe start and end points could represent circle center, and edge (radius). Or, the two ends of a diameter line. I'll leave that part to you.
Implementation
First, I define a transparent overlay layer, that handles selection (OverlaySelectionView.h):
#import <QuartzCore/QuartzCore.h>
#import <MapKit/MapKit.h>
#protocol OverlaySelectionViewDelegate
// callback when user finishes selecting map region
- (void) areaSelected: (CGRect)screenArea;
#end
#interface OverlaySelectionView : UIView {
#private
UIView* dragArea;
CGRect dragAreaBounds;
id<OverlaySelectionViewDelegate> delegate;
}
#property (nonatomic, assign) id<OverlaySelectionViewDelegate> delegate;
#end
and OverlaySelectionView.m:
#import "OverlaySelectionView.h"
#interface OverlaySelectionView()
#property (nonatomic, retain) UIView* dragArea;
#end
#implementation OverlaySelectionView
#synthesize dragArea;
#synthesize delegate;
- (void) initialize {
dragAreaBounds = CGRectMake(0, 0, 0, 0);
self.userInteractionEnabled = YES;
self.multipleTouchEnabled = NO;
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
self.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
}
- (id) initWithCoder: (NSCoder*) coder {
self = [super initWithCoder: coder];
if (self != nil) {
[self initialize];
}
return self;
}
- (id) initWithFrame: (CGRect) frame {
self = [super initWithFrame: frame];
if (self != nil) {
[self initialize];
}
return self;
}
- (void)drawRect:(CGRect)rect {
// do nothing
}
#pragma mark - Touch handling
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
UITouch* touch = [[event allTouches] anyObject];
dragAreaBounds.origin = [touch locationInView:self];
}
- (void)handleTouch:(UIEvent *)event {
UITouch* touch = [[event allTouches] anyObject];
CGPoint location = [touch locationInView:self];
dragAreaBounds.size.height = location.y - dragAreaBounds.origin.y;
dragAreaBounds.size.width = location.x - dragAreaBounds.origin.x;
if (self.dragArea == nil) {
UIView* area = [[UIView alloc] initWithFrame: dragAreaBounds];
area.backgroundColor = [UIColor blueColor];
area.opaque = NO;
area.alpha = 0.3f;
area.userInteractionEnabled = NO;
self.dragArea = area;
[self addSubview: self.dragArea];
[dragArea release];
} else {
self.dragArea.frame = dragAreaBounds;
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleTouch: event];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
[self handleTouch: event];
if (self.delegate != nil) {
[delegate areaSelected: dragAreaBounds];
}
[self initialize];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
[self initialize];
[self.dragArea removeFromSuperview];
self.dragArea = nil;
}
#pragma mark -
- (void) dealloc {
[dragArea release];
[super dealloc];
}
#end
Then I have a class that implements the protocol defined above (MapViewController.h):
#import "OverlaySelectionView.h"
typedef struct {
CLLocationDegrees minLatitude;
CLLocationDegrees maxLatitude;
CLLocationDegrees minLongitude;
CLLocationDegrees maxLongitude;
} LocationBounds;
#interface MapViewController : UIViewController<MKMapViewDelegate, OverlaySelectionViewDelegate> {
LocationBounds searchBounds;
UIBarButtonItem* areaButton;
And in my MapViewController.m, the areaSelected method is where I perform the conversion of touch coordinates to geographic coordinates with convertPoint:toCoordinateFromView: :
#pragma mark - OverlaySelectionViewDelegate
- (void) areaSelected: (CGRect)screenArea
{
self.areaButton.style = UIBarButtonItemStyleBordered;
self.areaButton.title = #"Area";
CGPoint point = screenArea.origin;
// we must account for upper nav bar height!
point.y -= 44;
CLLocationCoordinate2D upperLeft = [mapView convertPoint: point toCoordinateFromView: mapView];
point.x += screenArea.size.width;
CLLocationCoordinate2D upperRight = [mapView convertPoint: point toCoordinateFromView: mapView];
point.x -= screenArea.size.width;
point.y += screenArea.size.height;
CLLocationCoordinate2D lowerLeft = [mapView convertPoint: point toCoordinateFromView: mapView];
point.x += screenArea.size.width;
CLLocationCoordinate2D lowerRight = [mapView convertPoint: point toCoordinateFromView: mapView];
searchBounds.minLatitude = MIN(lowerLeft.latitude, lowerRight.latitude);
searchBounds.minLongitude = MIN(upperLeft.longitude, lowerLeft.longitude);
searchBounds.maxLatitude = MAX(upperLeft.latitude, upperRight.latitude);
searchBounds.maxLongitude = MAX(upperRight.longitude, lowerRight.longitude);
// TODO: comment out to keep search rectangle on screen
[[self.view.subviews lastObject] removeFromSuperview];
[self performSelectorInBackground: #selector(lookupHistoryByArea) withObject: nil];
}
// this action is triggered when user selects the Area button to start selecting area
// TODO: connect this to areaButton yourself (I did it in Interface Builder)
- (IBAction) selectArea: (id) sender
{
PoliteAlertView* message = [[PoliteAlertView alloc] initWithTitle: #"Information"
message: #"Select an area to search by dragging your finger across the map"
delegate: self
keyName: #"swipe_msg_read"
cancelButtonTitle: #"Ok"
otherButtonTitles: nil];
[message show];
[message release];
OverlaySelectionView* overlay = [[OverlaySelectionView alloc] initWithFrame: self.view.frame];
overlay.delegate = self;
[self.view addSubview: overlay];
[overlay release];
self.areaButton.style = UIBarButtonItemStyleDone;
self.areaButton.title = #"Swipe";
}
You'll notice that my MapViewController has a property, areaButton. That's a button on my toolbar, which normally says Area. After the user presses it, they are in area selection mode at which point, the button label changes to say Swipe to remind them to swipe (maybe not the best UI, but that's what I have).
Also notice that when the user presses Area to enter area selection mode, I show them an alert that tells them that they need to swipe. Since this is probably only a reminder they need to see once, I have used my own PoliteAlertView, which is a custom UIAlertView that users can suppress (don't show the alert again).
My lookupHistoryByArea is just a method that searches my database for locations, by the saved searchBounds (in the background), and then plots new overlays on the map at the found locations. This will obviously be different for your app.
Limitations
Since this is for letting the user select approximate areas, I did not consider geographic precision to be critical. It doesn't sound like it should be in your app, either. Thus, I just draw rectangles with 90 degree angles, not accounting for earth curvature, etc. For areas of just a few miles, this should be fine.
I had to make some assumptions about your phrase touch based drawing. I decided that both the easiest way to implement the app, and the easiest for a touchscreen user to use, was to simply define the area with one single swipe. Drawing a rectangle with touches would require 4 swipes instead of one, introduce the complexity of non-closed rectangles, yield sloppy shapes, and probably not get the user what they even wanted. So, I tried to keep the UI simple. If you really want the user drawing on the map, see this related answer which does that.
This app was written before ARC, and not changed for ARC.
In my app, I actually do use mutex locking for some variables accessed on the main (UI) thread, and in the background (search) thread. I took that code out for this example. Depending on how your database search works, and how you choose to run the search (GCD, etc.), you should make sure to audit your own thread-safety.
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
#end
ViewController.m
#import "ViewController.h"
#import <MapKit/MapKit.h>
#interface ViewController () <MKMapViewDelegate>
#property (weak, nonatomic) IBOutlet MKMapView *mapView;
#property (nonatomic, weak) MKPolyline *polyLine;
#property (nonatomic, strong) NSMutableArray *coordinates;
#property (weak, nonatomic) IBOutlet UIButton *drawPolygonButton;
#property (nonatomic) BOOL isDrawingPolygon;
#end
#implementation ViewController
#synthesize coordinates = _coordinates;
- (NSMutableArray*)coordinates
{
if(_coordinates == nil) _coordinates = [[NSMutableArray alloc] init];
return _coordinates;
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)didTouchUpInsideDrawButton:(UIButton*)sender
{
if(self.isDrawingPolygon == NO) {
self.isDrawingPolygon = YES;
[self.drawPolygonButton setTitle:#"done" forState:UIControlStateNormal];
[self.coordinates removeAllObjects];
self.mapView.userInteractionEnabled = NO;
} else {
NSInteger numberOfPoints = [self.coordinates count];
if (numberOfPoints > 2)
{
CLLocationCoordinate2D points[numberOfPoints];
for (NSInteger i = 0; i < numberOfPoints; i++)
points[i] = [self.coordinates[i] MKCoordinateValue];
[self.mapView addOverlay:[MKPolygon polygonWithCoordinates:points count:numberOfPoints]];
}
if (self.polyLine)
[self.mapView removeOverlay:self.polyLine];
self.isDrawingPolygon = NO;
[self.drawPolygonButton setTitle:#"draw" forState:UIControlStateNormal];
self.mapView.userInteractionEnabled = YES;
}
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.isDrawingPolygon == NO)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self addCoordinate:coordinate];
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.isDrawingPolygon == NO)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self addCoordinate:coordinate];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
if (self.isDrawingPolygon == NO)
return;
UITouch *touch = [touches anyObject];
CGPoint location = [touch locationInView:self.mapView];
CLLocationCoordinate2D coordinate = [self.mapView convertPoint:location toCoordinateFromView:self.mapView];
[self addCoordinate:coordinate];
[self didTouchUpInsideDrawButton:nil];
}
- (void)addCoordinate:(CLLocationCoordinate2D)coordinate
{
[self.coordinates addObject:[NSValue valueWithMKCoordinate:coordinate]];
NSInteger numberOfPoints = [self.coordinates count];
if (numberOfPoints > 2) {
MKPolyline *oldPolyLine = self.polyLine;
CLLocationCoordinate2D points[numberOfPoints];
for (NSInteger i = 0; i < numberOfPoints; i++) {
points[i] = [self.coordinates[i] MKCoordinateValue];
}
MKPolyline *newPolyLine = [MKPolyline polylineWithCoordinates:points count:numberOfPoints];
[self.mapView addOverlay:newPolyLine];
self.polyLine = newPolyLine;
if (oldPolyLine) {
[self.mapView removeOverlay:oldPolyLine];
}
}
}
#pragma mark - MKMapViewDelegate
- (MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id <MKOverlay>)overlay
{
MKOverlayPathView *overlayPathView;
if ([overlay isKindOfClass:[MKPolygon class]])
{
overlayPathView = [[MKPolygonView alloc] initWithPolygon:(MKPolygon*)overlay];
overlayPathView.fillColor = [[UIColor cyanColor] colorWithAlphaComponent:0.2];
overlayPathView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
overlayPathView.lineWidth = 3;
return overlayPathView;
}
else if ([overlay isKindOfClass:[MKPolyline class]])
{
overlayPathView = [[MKPolylineView alloc] initWithPolyline:(MKPolyline *)overlay];
overlayPathView.strokeColor = [[UIColor blueColor] colorWithAlphaComponent:0.7];
overlayPathView.lineWidth = 3;
return overlayPathView;
}
return nil;
}
- (MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(id<MKAnnotation>)annotation
{
if ([annotation isKindOfClass:[MKUserLocation class]])
return nil;
static NSString * const annotationIdentifier = #"CustomAnnotation";
MKAnnotationView *annotationView = [mapView dequeueReusableAnnotationViewWithIdentifier:annotationIdentifier];
if (annotationView)
{
annotationView.annotation = annotation;
}
else
{
annotationView = [[MKAnnotationView alloc] initWithAnnotation:annotation reuseIdentifier:annotationIdentifier];
annotationView.image = [UIImage imageNamed:#"annotation.png"];
annotationView.alpha = 0.5;
}
annotationView.canShowCallout = NO;
return annotationView;
}
#end
or You can find here the entire project :
https://github.com/tazihosniomar/MapKitDrawing
i hope it will help you.
this is my way how I convert the touches to CLLocation on the MKMapView.
it works with the the Google Maps and the Apple Maps as well:
- (void)viewDidLoad {
// ...
// ... where the _customMapView is a MKMapView object;
// find the gesture recogniser of the map
UIGestureRecognizer *_factoryDoubleTapGesture = nil;
NSArray *_gestureRecognizersArray = [_customMapView gestureRecognizers];
for (UIGestureRecognizer *_tempRecogniser in _gestureRecognizersArray) {
if ([_tempRecogniser isKindOfClass:[UITapGestureRecognizer class]]) {
if ([(UITapGestureRecognizer *)_tempRecogniser numberOfTapsRequired] == 2) {
_factoryDoubleTapGesture = _tempRecogniser;
break;
}
}
}
// my tap gesture recogniser
UITapGestureRecognizer *_locationTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(mapLocationTouchedUpInside:)];
if (_factoryDoubleTapGesture) [_locationTapGesture requireGestureRecognizerToFail:_factoryDoubleTapGesture];
[_customMapView addGestureRecognizer:_locationTapGesture];
// ...
}
and...
- (void)mapLocationTouchedUpInside:(UITapGestureRecognizer *)sender {
CGPoint _tapPoint = [sender locationInView:_customMapView];
CLLocationCoordinate2D _coordinates = [_customMapView convertPoint:_tapPoint toCoordinateFromView:_customMapView];
// ... do whatever you'd like with the coordinates
}
Try MKOverlayPathView. The problem in denoting a region by drawing a path on an MKMapView is, unless you know the zoom scale you don't know much. So you have to track that.
I have 4 elements: greenball, yellowball, orangeball, and redball that fall from the top of the screen
I also have an element, blueball, that follows my touch.
All of these things are working great! :D
However, I want to detect when the greenball intersects with the blueball
my blue ball is placed in the view at viewDidLoad, the 4 balls are placed on the view based on an nstimer that calls onTimer.
All 5 balls are created on the same layer:
[self.view insertSubview:greenImage belowSubview:bottomBar]
I can detect when the redball and greenball collide:
if (CGRectIntersectsRect(greenImage.frame, redImage.frame)) {
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"title" message:#"points" delegate:nil cancelButtonTitle:#"cool" otherButtonTitles:nil];
[message show];
[message release];
}
If I replace "redImage" for "blueball" I don't get the alert. I assume this may be because they aren't declared in the same method.
Any ideas on how to detect this collision?
thanks!
--- EDIT ---
Using the suggestion below I'm doing the following:
greenImage = [[UIImageView alloc] initWithImage:green];
greenImage.frame = CGRectMake(startX,0,43,43);
[self.view insertSubview:greenImage belowSubview:bottomBar];
[UIView beginAnimations:nil context:greenImage];
[UIView setAnimationDuration:5 * speed];
greenImage.frame = CGRectMake(startX, 500.0, 43,43);
CGFloat r1 = greenImage.frame.size.width * .5;
CGFloat r2 = blueBall.frame.size.width * .5;
if(CGPointDistance(greenImage.center, blueBall.center) < (r1 + r2)){
UIAlertView *message = [[UIAlertView alloc] initWithTitle:#"notice" message:#"hit!" delegate:nil cancelButtonTitle:#"cool" otherButtonTitles:nil];
[message show];
[message release];
}
below this method I have:
CGFloat CGPointDistance(CGPoint p1, CGPoint p2)
{
return sqrtf((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));
}
get an error:
conflicting types for 'CGPointDistance'
and a warning:
implicit declaration of function 'CGPointDistance'
To determine if two circles intersect, you simply see if the distance between the centers is less than the sum if their radii. For example...
CGFloat CGPointDistance(CGPoint p1, CGPoint p2)
{
return sqrtf((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y));
}
It looks like your "balls" are views... Assuming the "ball" fills the frame, the radius will be 1/2 the width...
BOOL BallsCollide(UIView *v1, UIView *v2)
{
CGFloat r1 = v1.frame.size.width * .5;
CGFloat r2 = v2.frame.size.width * .5;
return CGPointDistance(v1.center, v2.center) < (r1 + r2);
}
OK -- I have hacked up a quick sample. You can almost drop it into your view controller. Don't use it for production stuff... just as an example of how you can do stuff... You can put this at the top and the rest of your controller below it...
// I do not recommend using this approach for naything non-trivial,
// but it demonstrates the very simple collision detection for circle shapes.
#interface Ball : UIView {
}
#property (nonatomic, strong) UIColor *origColor;
#property (nonatomic, strong) UIColor *color;
+ (id)ballWithRadius:(CGFloat)radius color:(UIColor*)color;
- (BOOL)doesIntersectWith:(Ball*)ball;
#end
#implementation Ball
#synthesize color = _color;
#synthesize origColor = _origColor;
+ (id)ballWithRadius:(CGFloat)radius color:(UIColor*)color
{
CGFloat diameter = radius * 2;
Ball *ball = [[Ball alloc] initWithFrame:CGRectMake(0, 0, diameter, diameter)];
ball.color = ball.origColor = color;
ball.backgroundColor = [UIColor clearColor];
return ball;
}
- (BOOL)doesIntersectWith:(Ball *)ball
{
// Two circles overlap if the sum of their radii
// is less than the distance between the two centers.
CGFloat r1 = self.frame.size.width * .5;
CGFloat r2 = ball.frame.size.width * .5;
CGFloat diffX = self.center.x - ball.center.x;
CGFloat diffY = self.center.y - ball.center.y;
return (diffX*diffX) + (diffY*diffY) < (r1+r2)*(r1+r2);
}
- (BOOL)containsPoint:(CGPoint)point
{
// Contains a point if distance from center is less than radius
CGFloat r = self.frame.size.width *.5;
CGFloat diffX = self.center.x - point.x;
CGFloat diffY = self.center.y - point.y;
return (diffX*diffX) + (diffY*diffY) < r*r;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
[self.color setFill];
[self.color setStroke];
CGContextSetLineWidth(context, 1);
CGContextFillEllipseInRect(context, self.bounds);
}
#end
#interface CollideVC() {
NSMutableDictionary *activeTouches;
NSMutableSet *currentCollisions;
}
#end
#implementation CollideVC
- (void)ball:(Ball*)ball touched:(UITouch*)touch
{
[activeTouches setObject:ball forKey:[NSValue valueWithPointer:(__bridge void*)touch]];
}
- (Ball*)getBallTouchedBy:(UITouch*)touch
{
return [activeTouches objectForKey:[NSValue valueWithPointer:(__bridge void*)touch]];
}
- (void)stopTouch:(UITouch*)touch
{
[activeTouches removeObjectForKey:[NSValue valueWithPointer:(__bridge void*)touch]];
}
- (void)ball:(Ball*)ball1 hasCollidedWith:(Ball*)ball2
{
[currentCollisions addObject:ball1];
[currentCollisions addObject:ball2];
ball1.color = ball2.color = [UIColor yellowColor];
[ball1 setNeedsDisplay];
[ball2 setNeedsDisplay];
}
// NOTE: You should delegate handling of collisions...
- (void)checkForCollisions
{
// Should filter those that don't actually need redisplay...
// For simplicity, all that were or are colliding get it...
[currentCollisions enumerateObjectsUsingBlock:^(Ball *ball, BOOL *stop) {
[ball setNeedsDisplay];
ball.color = ball.origColor;
}];
[currentCollisions removeAllObjects];
NSArray *views = self.view.subviews;
for (size_t i = 0; i < views.count; ++i) {
id v = [views objectAtIndex:i];
if (![v isKindOfClass:[Ball class]]) continue;
Ball *ball1 = v;
for (size_t j = i+1; j < views.count; ++j) {
v = [views objectAtIndex:j];
if (![v isKindOfClass:[Ball class]]) continue;
Ball *ball2 = v;
if ([ball1 doesIntersectWith:ball2]) {
[self ball:ball1 hasCollidedWith:ball2];
}
}
}
}
- (void)addBallWithRadius:(CGFloat)radius point:(CGPoint)point color:(UIColor*)color
{
Ball *ball = [Ball ballWithRadius:radius color:color];
ball.center = point;
[self.view addSubview:ball];
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
CGPoint touchLocation = [touch locationInView:self.view];
for (Ball *ball in self.view.subviews) {
if ([ball containsPoint:touchLocation]) {
[self ball:ball touched:touch];
}
}
}
}
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
// Use relative distance so center does nt jump to tap location.
CGPoint prev = [touch previousLocationInView:self.view];
CGPoint curr = [touch locationInView:self.view];
CGPoint c = [self getBallTouchedBy:touch].center;
[self getBallTouchedBy:touch].center = CGPointMake(c.x+curr.x-prev.x, c.y+curr.y-prev.y);
}
// NOTE: This does not check the path between the moves, only the new point.
// So a fast movement "past" the other object will not get detected.
// If you want to do comple detection, use an existing engine
[self checkForCollisions];
}
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches) {
[self stopTouch:touch];
}
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
[self touchesEnded:touches withEvent:event];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
activeTouches = [NSMutableDictionary dictionary];
currentCollisions = [NSMutableSet set];
[self addBallWithRadius:20 point:CGPointMake(110, 100) color:[UIColor blueColor]];
[self addBallWithRadius:20 point:CGPointMake(200, 200) color:[UIColor redColor]];
[self addBallWithRadius:20 point:CGPointMake(235, 250) color:[UIColor greenColor]];
}
maybe this will help some, just a little modification to the code above.
-(CGFloat)CGPointDistance:(CGPoint)p1 p2:(CGPoint)p2
{
return sqrtf(powf(p1.x - p2.x) + powf(p1.y-p2.y));
}
-(BOOL)DidCollide:(View*)v1 v2:(View*)v2 v1Radius:(CGFloat)v1Radius v2Radius:(CGFloat)v2Radius
{
CGFloat r1 = v1.frame.size.width * v1Radius;
CGFloat r2 = v2.frame.size.width * v2Radius;
return [self PointDistance:v1.center p2:v2.center] < (r1 + r2)
}
and to check for collision your just do
if([self DidCollide:view1 v2:view2 v1Radius:radius v2Radius:radius])
{
//do something
}
i'm a newbie on ios and i'm trying something that it's probably very simple.
i'm making a draw app (it just does circles) and i'm trying to save the draw to the photolibrary but i can't understand how to do that :(
my code so far:
touchdrawview.h
#import <UIKit/UIKit.h>
#interface TouchDrawView : UIView
{
NSMutableDictionary *linesInProcess;
NSMutableArray *completeLines;
}
- (void)clearAll;
- (void)endTouches:(NSSet *)touches;
#end
touchdrawview.m
#import "TouchDrawView.h"
#import "Line.h"
#implementation TouchDrawView
- (id)initWithCoder:(NSCoder *)c
{
self = [super initWithCoder:c];
if (self) {
linesInProcess = [[NSMutableDictionary alloc] init];
// Don't let the autocomplete fool you on the next line,
// make sure you are instantiating an NSMutableArray
// and not an NSMutableDictionary!
completeLines = [[NSMutableArray alloc] init];
[self setMultipleTouchEnabled:YES];
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context, 10.0);
CGContextSetLineCap(context, kCGLineCapRound);
// Draw complete lines in black
[[UIColor blackColor] set];
for (Line *line in completeLines) {
//CGContextMoveToPoint(context, [line begin].x, [line begin].y);
//CGContextAddLineToPoint(context, [line end].x, [line end].y);
CGRect rectangle = CGRectMake([line begin].x, [line begin].y, ([line end].x - [line begin].x), ([line end].y - [line begin].y));
CGContextAddEllipseInRect(context, rectangle);
CGContextStrokePath(context);
}
// Draw lines in process in red
[[UIColor redColor] set];
for (NSValue *v in linesInProcess) {
Line *line = [linesInProcess objectForKey:v];
//CGContextMoveToPoint(context, [line begin].x, [line begin].y);
//CGContextAddLineToPoint(context, [line end].x, [line end].y);
CGRect rectangle = CGRectMake([line begin].x, [line begin].y, ([line end].x - [line begin].x), ([line end].y - [line begin].y));
CGContextAddEllipseInRect(context, rectangle);
CGContextStrokePath(context);
}
}
- (void)clearAll
{
// Clear the collections
[linesInProcess removeAllObjects];
[completeLines removeAllObjects];
// Redraw
[self setNeedsDisplay];
}
- (void)touchesBegan:(NSSet *)touches
withEvent:(UIEvent *)event
{
for (UITouch *t in touches) {
// Is this a double tap?
if ([t tapCount] > 1) {
[self clearAll];
return;
}
// Use the touch object (packed in an NSValue) as the key
NSValue *key = [NSValue valueWithPointer:t];
// Create a line for the value
CGPoint loc = [t locationInView:self];
Line *newLine = [[Line alloc] init];
[newLine setBegin:loc];
[newLine setEnd:loc];
// Put pair in dictionary
[linesInProcess setObject:newLine forKey:key];
// There is a memory leak in this method
// You will find it using Instruments in the next chapter
}
}
- (void)touchesMoved:(NSSet *)touches
withEvent:(UIEvent *)event
{
// Update linesInProcess with moved touches
for (UITouch *t in touches) {
NSValue *key = [NSValue valueWithPointer:t];
// Find the line for this touch
Line *line = [linesInProcess objectForKey:key];
// Update the line
CGPoint loc = [t locationInView:self];
[line setEnd:loc];
}
// Redraw
[self setNeedsDisplay];
}
- (void)endTouches:(NSSet *)touches
{
// Remove ending touches from dictionary
for (UITouch *t in touches) {
NSValue *key = [NSValue valueWithPointer:t];
Line *line = [linesInProcess objectForKey:key];
// If this is a double tap, 'line' will be nil,
// so make sure not to add it to the array
if (line) {
[completeLines addObject:line];
[linesInProcess removeObjectForKey:key];
}
}
// Redraw
[self setNeedsDisplay];
}
- (void)touchesEnded:(NSSet *)touches
withEvent:(UIEvent *)event
{
[self endTouches:touches];
}
- (void)touchesCancelled:(NSSet *)touches
withEvent:(UIEvent *)event
{
[self endTouches:touches];
}
- (void)dealloc
{
[linesInProcess release];
[completeLines release];
[super dealloc];
}
#end
touchdrawappdelegate.h
#import <UIKit/UIKit.h>
#class TouchDrawView;
#interface TouchTrackerAppDelegate : NSObject <UIApplicationDelegate> {
TouchDrawView *view;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
- (IBAction)guardar:(id)sender;
#end
touchdrawappdelegate.m
#import "TouchTrackerAppDelegate.h"
#implementation TouchTrackerAppDelegate
#synthesize window=_window;
-(UIImage *) ChangeViewToImage : (UIView *) view{
UIGraphicsBeginImageContext(view.bounds.size);
[TouchDrawView renderInContext:UIGraphicsGetCurrentContext()];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
- (IBAction)guardar:(id)sender{
NSLog(#"buh");
UIGraphicsBeginImageContext(CGSizeMake(320,480));
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
UIImageWriteToSavedPhotosAlbum(result, self, nil, nil);
}
This action only saw a white image because i can't convert the uiview to a uiimage..
how can this be done?
Regards
CALayer has contents, you can save it like this
CGImageRef imageRef = CGImageCreateWithImageInRect((CGImageRef)penView.layer.contents, cropRect);
UIImage *penImage = [UIImage imageWithCGImage:imageRef];
CGImageRelease(imageRef);
add framework QuartzCore
#import <QuartzCore/QuartzCore.h>
UPDATE
in your code, should be TouchDrawView.layer
UIGraphicsBeginImageContext(view.bounds.size);
[TouchDrawView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
So, I added a popupview to my uisliders. I got the code for the custom sliders with the popup from a guy who had already done that. The popup is showing, but the only problem is that the popup is showing inside the cell in which the slider is at, so it gets cut off at the end of the cell.
How can I bring the popupview in front of the cell ?
(I have multiple sliders each one in a different cell)
#import "MNEValueTrackingSlider.h"
#import "ToothTableViewController.h"
#pragma mark - Private UIView subclass rendering the popup showing slider value
#interface MNESliderValuePopupView : UIView {
MNEValueTrackingSlider *trackingSlider;
ToothTableViewController *toothViewController;
}
#property (nonatomic) float value;
#property (nonatomic, retain) UIFont *font;
#property (nonatomic, retain) NSString *text;
#end
#import "MNEValueTrackingSlider.h"
#import "ToothTableViewController.h"
#implementation MNESliderValuePopupView
#synthesize value=_value;
#synthesize font=_font;
#synthesize text = _text;
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.font = [UIFont boldSystemFontOfSize:18];
}
return self;
}
- (void)dealloc {
self.text = nil;
self.font = nil;
[super dealloc];
}
- (void)drawRect:(CGRect)rect {
// Set the fill color
[[UIColor colorWithWhite:0 alpha:0.8] setFill];
// Create the path for the rounded rectanble
CGRect roundedRect = CGRectMake(self.bounds.origin.x , self.bounds.origin.y, self.bounds.size.width, self.bounds.size.height * 0.8);
UIBezierPath *roundedRectPath = [UIBezierPath bezierPathWithRoundedRect:roundedRect cornerRadius:6.0];
// Create the arrow path
UIBezierPath *arrowPath = [UIBezierPath bezierPath];
CGFloat midX = CGRectGetMidX(self.bounds);
CGPoint p0 = CGPointMake(midX, CGRectGetMaxY(self.bounds));
[arrowPath moveToPoint:p0];
[arrowPath addLineToPoint:CGPointMake((midX - 10.0), CGRectGetMaxY(roundedRect))];
[arrowPath addLineToPoint:CGPointMake((midX + 10.0), CGRectGetMaxY(roundedRect))];
[arrowPath closePath];
// Attach the arrow path to the buble
[roundedRectPath appendPath:arrowPath];
[roundedRectPath fill];
// Draw the text
if (self.text) {
[[UIColor colorWithWhite:1 alpha:0.8] set];
CGSize s = [_text sizeWithFont:self.font];
CGFloat yOffset = (roundedRect.size.height - s.height) / 2;
CGRect textRect = CGRectMake(roundedRect.origin.x, yOffset, roundedRect.size.width, s.height);
[_text drawInRect:textRect
withFont:self.font
lineBreakMode:UILineBreakModeWordWrap
alignment:UITextAlignmentCenter];
}
}
- (void)setValue:(float)aValue {
_value = aValue;
self.text = [NSString stringWithFormat:#"%4.2f", _value];
[self setNeedsDisplay];
}
#end
#pragma mark - MNEValueTrackingSlider implementations
#import "ToothTableViewController.h"
#implementation MNEValueTrackingSlider
#synthesize thumbRect;
#synthesize sliderButtonPoint;
#pragma mark - Private methods
- (void)_constructSlider {
valuePopupView = [[MNESliderValuePopupView alloc] initWithFrame:CGRectZero];
valuePopupView.backgroundColor = [UIColor clearColor];
valuePopupView.alpha = 0.0;
toothViewController = [[ToothTableViewController alloc] init];
[self addSubview:valuePopupView];
}
- (void)_fadePopupViewInAndOut:(BOOL)aFadeIn {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
if (aFadeIn) {
valuePopupView.alpha = 1.0;
} else {
valuePopupView.alpha = 0.0;
}
[UIView commitAnimations];
}
- (void)_positionAndUpdatePopupView {
CGRect _thumbRect = self.thumbRect;
CGRect popupRect = CGRectOffset(_thumbRect, 0, -(_thumbRect.size.height * 1.5));
valuePopupView.frame = CGRectInset(popupRect, -20, -10);
valuePopupView.value = (NSInteger)self.value;
}
#pragma mark - Memory management
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
[self _constructSlider];
}
return self;
}
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
[self _constructSlider];
}
return self;
}
- (void)dealloc {
[valuePopupView release];
[super dealloc];
}
#pragma mark - UIControl touch event tracking
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Fade in and update the popup view
CGPoint touchPoint = [touch locationInView:self];
// Check if the knob is touched. Only in this case show the popup-view
if(CGRectContainsPoint(self.thumbRect, touchPoint)) {
[self _positionAndUpdatePopupView];
[self _fadePopupViewInAndOut:YES];
}
return [super beginTrackingWithTouch:touch withEvent:event];
}
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Update the popup view as slider knob is being moved
[self _positionAndUpdatePopupView];
return [super continueTrackingWithTouch:touch withEvent:event];
}
- (void)cancelTrackingWithEvent:(UIEvent *)event {
[super cancelTrackingWithEvent:event];
}
- (void)endTrackingWithTouch:(UITouch *)touch withEvent:(UIEvent *)event {
// Fade out the popoup view
[self _fadePopupViewInAndOut:NO];
[super endTrackingWithTouch:touch withEvent:event];
}
#pragma mark - Custom property accessors
- (CGRect)thumbRect {
CGRect trackRect = [self trackRectForBounds:self.bounds];
CGRect thumbR = [self thumbRectForBounds:self.bounds
trackRect:trackRect
value:self.value];
return thumbR;
}
#end
Ok so I gave up, I cant figure it out. That is the code for the slider and its popupview. If anyone feels like reading the whole thing I could use the help :P
You could try to add the popupview as a subview of the UITableView.
Then to move it along with the slider, you would have to calculate the point by getting the slider's position relative to your tableview.
This can be achieved by using the UIView's convertPoint:toView: method, for example:
CGPoint sliderButtonRelativePoint = [slider.superview convertPoint:sliderButtonPoint toView:tableView];
where slider.superview would be your UITableViewCell, sliderButtonPoint would be the middle-top point of the slider's round button (for example), and tableView would be, well... your UITableView.
You might have to play around with this a little, and you may find there are strange behaviours when scrolling the tableview, but that's what I would try first.