Draggable UIImageView Частично прозрачный и неправильной формы - PullRequest
0 голосов
/ 20 апреля 2011
@interface UIDraggableImageView : UIImageView {

}

.m файл

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
// Retrieve the touch point
CGPoint point = [[touches anyObject] locationInView:self];
startLocation = point;
[[self superview] bringSubviewToFront:self];
}

 - (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
// Move relative to the original touch point
CGPoint point = [[touches anyObject] locationInView:self];
CGRect frame = [self frame];
frame.origin.x += point.x - startLocation.x;
frame.origin.y += point.y - startLocation.y;
[self setFrame:frame];
}

удалил этот код из Интернета для перетаскиваемого изображения,

Проблема: изображение неправильной формы с прозрачными областями, при перетаскивании по прозрачным областямэто также.

Требуемое решение: Как сделать прозрачные области не интерактивными / не перетаскиваемыми?

Любые предложения, я попытаюсь замаскировать изображение как попытку и опубликую результаты, но любые обходные пути / совет.

В дополнение к предложениям MiRAGe: Попытка включить код в один файл класса, так как свойство изображения доступно в UIImageView, и было бы проще подключить и играть с любым UIImageView в интерфейсестроитель, но все еще возникают проблемы, прозрачные области являются подвижными, метод hitTest вызывается несколько раз одним кликом, любой совет?

#import "UIImageViewDraggable.h"

@implementation UIImageViewDraggable

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
// Retrieve the touch point
CGPoint point = [[touches anyObject] locationInView:self];
startLocation = point;
[[self superview] bringSubviewToFront:self];
}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
// Move relative to the original touch point
CGPoint point = [[touches anyObject] locationInView:self];
CGRect frame = [self frame];
frame.origin.x += point.x - startLocation.x;
frame.origin.y += point.y - startLocation.y;
[self setFrame:frame];
}

- (NSData *)alphaData {
CGContextRef    cgctx = NULL;
void *          bitmapData;
int             bitmapByteCount;

size_t pixelsWide = CGImageGetWidth(self.image.CGImage);
size_t pixelsHigh = CGImageGetHeight(self.image.CGImage);

bitmapByteCount     = (pixelsWide * pixelsHigh);

bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL) 
    return nil;

cgctx = CGBitmapContextCreate (bitmapData,
                               pixelsWide,
                               pixelsHigh,
                               8,
                               pixelsWide,
                               NULL,
                               kCGImageAlphaOnly);
if (cgctx == NULL) {
    free (bitmapData);
    fprintf (stderr, "Context not created!");

    return nil;
}

CGRect rect = {{0,0},{pixelsWide,pixelsHigh}}; 
CGContextDrawImage(cgctx, rect, self.image.CGImage); 

unsigned char *data = CGBitmapContextGetData(cgctx);

CGContextRelease(cgctx);

if (!data) {
    free(bitmapData);
    return nil;
}

size_t dataSize = pixelsWide * pixelsHigh;

NSData *alphaData = [NSData dataWithBytes:data length:dataSize];

free(bitmapData);
return alphaData;
}    

- (BOOL)isTransparentLocation:(CGPoint)point withData:(NSData *)data {   
if (data == nil)
    NSLog(@"data was nil");

NSUInteger index = point.x + (point.y * [self.image size].width);
unsigned char *rawDataBytes = (unsigned char *)[data bytes];

return (rawDataBytes[index] == 0);
}

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
NSLog(@"test");
NSAutoreleasePool *pool = [NSAutoreleasePool new];

// view responding to the hit test. note that self may respond too.
UIView *anyViewResponding = [super hitTest:point withEvent:event];  
if( anyViewResponding == nil || anyViewResponding == self ) {
    // convert the point in the image, to a global point.
    CGPoint framePoint = [self.superview convertPoint:point fromView:self];
    // if the point is in the image frame, and there is an image, see if we need to let the touch through or not
    if(self.image != nil && CGRectContainsPoint([self frame], framePoint)) {
        NSData *imageData = [self alphaData];         

        // check if the point touched is transparent in the image
        if( imageData != nil && [self isTransparentLocation:point withData:imageData]) {               
            // return nil, so the touch will not arrive at this view
            anyViewResponding = nil;
        }
    }
}

[pool drain];
return anyViewResponding;
}

Ответы [ 2 ]

1 голос
/ 20 апреля 2011

Вы можете легко обнаружить альфа-области и сделать их не перетаскиваемыми.Вот некоторый код, который позволит вам обнаружить альфа-области.Это может быть для вас непростой задачей, но это лучшее, что я могу сделать.

Я подклассифицировал UIImage и поместил этот код в файл реализации.

#import <CoreGraphics/CoreGraphics.h>

- (NSData *)alphaData
{
    CGContextRef    cgctx = NULL;
    void *          bitmapData;
    int             bitmapByteCount;

    size_t pixelsWide = CGImageGetWidth(self.CGImage);
    size_t pixelsHigh = CGImageGetHeight(self.CGImage);

    bitmapByteCount     = (pixelsWide * pixelsHigh);

    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL) 
        return nil;

    cgctx = CGBitmapContextCreate (bitmapData,
                                   pixelsWide,
                                   pixelsHigh,
                                   8,
                                   pixelsWide,
                                   NULL,
                                   kCGImageAlphaOnly);
    if (cgctx == NULL)
    {
        free (bitmapData);
        fprintf (stderr, "Context not created!");

        return nil;
    }

    CGRect rect = {{0,0},{pixelsWide,pixelsHigh}}; 
    CGContextDrawImage(cgctx, rect, self.CGImage); 

    unsigned char *data = CGBitmapContextGetData(cgctx);

    CGContextRelease(cgctx);

    if (!data)
    {
        free(bitmapData);
        return nil;
    }

    size_t dataSize = pixelsWide * pixelsHigh;

    NSData *alphaData = [NSData dataWithBytes:data length:dataSize];

    free(bitmapData);
    return alphaData;
}    

- (BOOL)isTransparentLocation:(CGPoint)point withData:(NSData *)data
{   
    if (data == nil)
        NSLog(@"data was nil");

    NSUInteger index = point.x + (point.y * [self size].width);
    unsigned char *rawDataBytes = (unsigned char *)[data bytes];

    return (rawDataBytes[index] == 0);
}

Теперь в подклассе UIImageView(Я использую функцию hitTest, чтобы разрешить обнаружение, но вы можете легко изменить это на что-то, что работает для вас, это всего лишь пример) Я поместил этот код, чтобы обнаружить, было ли попадание точки прозрачным или нет.Если оно прозрачное, мы передаем касание представлению ниже, в противном случае мы сохраняем прикосновение к себе.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    NSAutoreleasePool *pool = [NSAutoreleasePool new];

    // view responding to the hit test. note that self may respond too.
    UIView *anyViewResponding = [super hitTest:point withEvent:event];  
    if( anyViewResponding == nil || anyViewResponding == self )
    {
        // convert the point in the image, to a global point.
        CGPoint framePoint = [self.superview convertPoint:point fromView:self];
        // if the point is in the image frame, and there is an image, see if we need to let the touch through or not
        if( self.image != nil && CGRectContainsPoint([self frame], framePoint) )
        {
            NSData *imageData = [self.image alphaData];         

            // check if the point touched is transparent in the image
            if( imageData != nil && [self.image isTransparentLocation:point imageData] )
            {               
                // return nil, so the touch will not arrive at this view
                anyViewResponding = nil;
            }
        }
    }

    [pool drain];
    return anyViewResponding;
}
0 голосов
/ 20 апреля 2011

Вы можете выполнить обнаружение попадания, чтобы определить, находится ли CGPoint, который представляет жест касания, внутри фигуры, определенной CGPath .

- (id)initWithFrame:(CGRect)frame {
    ...
    CGPathRef outline = CGPathCreateMutable();
    CGPathMoveToPoint(outline, NULL, 20, 20);
    // Build up path
    ...
}

- (void) touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
    CGPoint point = [[touches anyObject] locationInView:self];
    if (CGPathContainsPoint(outline, NULL, point, false) {
        ...
        dragIsRespected = YES;
    }
}

- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
    if (dragIsRespected) {
        ...
    }
}

- (void)dealloc {
    CGPathRelease(outline);
    ...
}

Плохо то, что зданиепуть для сложных форм утомителен.Хорошая вещь заключается в том, что, поскольку вы имеете дело с прикосновениями пальцев, грубых контуров, вероятно, должно быть достаточно.Кроме того, это позволяет вашей сенсорной цели отклоняться от непрозрачных частей изображения на случай, если вам потребуется дополнительное пространство для удобства использования.Это также обеспечивает прозрачность внутри сенсорной цели, что позволяет вам при необходимости иметь более сложные изображения.

Вы можете довольно легко получить желаемые граничные точки, если просто отобразите их в редакторе изображений.

...