2014年3月11日 星期二

IOS Non Rectangle Button Implement 實現不規格按鈕

Non Rectangle Button Implement

UIButton 在使用有透明的 png 圖檔時

即使點到透明的部份依然會觸發 touch 事件

為了達到更準確的點擊效果

需要繼承 UIButton 類別

修改 -(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 的觸發條件

並擴展 UIImage 類別的功能

以便根據 UIButton 所造成的圖片縮放取得點擊位置 pixel 資料

建立 UIImage+GetPixelRGBA



























UIImage+GetPixelRGBA.h

@interface UIImage (GetPixelRGBA)

    -(UIColor *)colorAtPoint:(CGPoint)point WithImageSize:(CGSize)size;
    -(UIImage *)reSizeImage:(UIImage *)image toSize:(CGSize)reSize;

@end


UIImage+GetPixelRGBA.m

@implementation UIImage (GetPixelRGBA)

//取得 pixel UIColor
-(UIColor*)colorAtPoint:(CGPoint)point WithImageSize:(CGSize)size{
    
    UIImage *resizeimage = [self reSizeImage:self toSize:size];
    
    CGRect rect = CGRectMake(0.0f, 0.0f, resizeimage.size.width, resizeimage.size.height);
    if (CGRectContainsPoint(rect, point) == NO)  {return nil;}
    
    CGImageRef image = resizeimage.CGImage;
    size_t width = CGImageGetWidth(image);
    size_t height = CGImageGetHeight(image);
    int bytesPerPixel = 4;
    int bytesPerRow = (bytesPerPixel*1);        // 8bpp
    unsigned char pixelData[4] = {0, 0, 0, 0};
    
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pixelData, 1, 1, 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast|kCGBitmapByteOrder32Big);
    CGColorSpaceRelease(colorSpace);
    
    if (context == NULL)  {
        NSLog(@"[colorAtPixel] Unable to create context!");
        return nil;
    }
    
    CGContextSetBlendMode(context, kCGBlendModeCopy);
    
    CGFloat pointX = point.x;
    CGFloat pointY = height-point.y;
    CGContextTranslateCTM(context, -pointX, -pointY);
    CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, (CGFloat)width, (CGFloat)height), image);
    CGContextRelease(context);
    
    //Convert color values [0..255] to floats [0.0..1.0]
    CGFloat red = (CGFloat)pixelData[0]/255.0f;
    CGFloat green = (CGFloat)pixelData[1]/255.0f;
    CGFloat blue = (CGFloat)pixelData[2]/255.0f;
    CGFloat alpha = (CGFloat)pixelData[3]/255.0f;
    return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];

}

//改變 UIIamge 圖片大小
-(UIImage *)reSizeImage:(UIImage *)image toSize:(CGSize)reSize
{
    UIGraphicsBeginImageContext(CGSizeMake(reSize.width, reSize.height));
    [image drawInRect:CGRectMake(0, 0, reSize.width, reSize.height)];
    UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return reSizeImage;
}

@end


建立 NonRectButton 
















直接覆寫 UIButton 原有方法

另外記得要 import 剛剛擴展的 UIImage 方法

NonRectButton.m

#import "NonRectButton.h"
#import "UIImage+GetPixelRGBA.h"

@implementation NonRectButton

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event  {
    
    //  We can't test the image's alpha channel if the button has no image. Fall back to super.
    UIImage *image = [self backgroundImageForState:UIControlStateNormal];
    if (image == nil)  {return YES;}
    //NSLog(@"b %@", NSStringFromCGPoint(point));
    CGColorRef color = [[image colorAtPoint:point WithImageSize:self.frame.size] CGColor];
    CGFloat alphaValue = CGColorGetAlpha(color);
    return (alphaValue >= 0.1f);
}

@end

最後在 ViewController 上實作 NonRectButton

記得要 import NonRectButton.h

MainViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
// Do any additional setup after loading the view.
    [self.view setBackgroundColor:[UIColor whiteColor]];
    NonRectButton *button = [NonRectButton buttonWithType:UIButtonTypeCustom];
    [button setFrame:CGRectMake(60, 60, 200, 200)];
    [button setBackgroundImage:[UIImage imageNamed:@"star.png"] forState:UIControlStateNormal];
    [self.view addSubview:button];
}

出來的結果
























若成功的話

將只會在 touch 到有顏色的部分時觸發點擊事件
























End ~