您的位置:首页 > 产品设计 > UI/UE

【iOS开发】根据图片透明度自定义UIButton实现

2014-10-20 11:32 495 查看
日常开发过程中,经常会碰到自定义按钮的需求,例如:微信中的图片部分的尖角。本身就是根据聊天的气泡进行“塑形”的,如下图就是微信中图片“气泡化”显示。



要达成目标,我们需要解决的问题有下面几个:

1、点击没有图片的部分,不响应点击操作

2、根据指定的mask图片,进行图片合成&剪切

问题1:根据图片,设定响应区域

我们建立一个UIButton的子类,变量imageMask用来记录图片的形状,UIButton每次点击的时候,都会调用:

- (BOOL)pointInside:(CGPoint)point
withEvent:(UIEvent *)event;

来判断当前点击的按钮是否需要响应,所以,我们在UIButton的子类(KMAutoShapeButton)中响应该函数:

// 判断当前point对应的alpha是否在0.1以内,设置的阀值是0.1
- (BOOL)isAlphaVisibleAtPoint:(CGPoint)point forImage:(UIImage *)image
{
CGSize iSize = image.size;
CGSize bSize = self.bounds.size;
point.x *= (bSize.width != 0) ? (iSize.width / bSize.width) : 1;
point.y *= (bSize.height != 0) ? (iSize.height / bSize.height) : 1;

CGColorRef pixelColor = [[self.imageMask colorAtPixel:point] CGColor];
CGFloat alpha = CGColorGetAlpha(pixelColor);
return alpha >= kAlphaVisibleThreshold;
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
// Return NO if even super returns NO (i.e., if point lies outside our bounds)
BOOL superResult = [super pointInside:point withEvent:event];
if (!superResult) {
return superResult;
}

if (CGPointEqualToPoint(self.previousTouchPoint, point)) {
return self.previousTouchHitTestResponse;
}

self.previousTouchPoint = point;
self.previousTouchHitTestResponse = [self isAlphaVisibleAtPoint:point forImage:self.imageMask];
return self.previousTouchHitTestResponse;
}


在-(BOOL)pointInside:withEvent: 中,先判断父类的结果并返回。

再次判断 当前点击位置是否等于上次的点击位置,如果是,返回上次的结果。在响应过程中一次点击可能会多次调用-(BOOL)pointInside:withEvent:

否则返回当前次判断返回结果。

问题2:根据制定的mask图片,进行图片合成&剪切

解决了问题1,我们只是能根据提供的mask图片检测响应区域,下面讨论怎么在:

- (void)setImage:(UIImage *)image forState:(UIControlState)state;

- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state;

的函数里面对要设置的图片进行剪切。

在图片绘制CGContext系列函数里面,CGContextClipToMask
是根据指定mask图片的alpha值进行剪切,由此,我们可以通过mask图片&CGContextClipToMask 函数,将设置的Image进行剪切然后设置到UIButton中。

UIImage+shape.m剪切部分:

- (UIImage *)imageWithMask:(UIImage*)imageMask
{
// 转换坐标
imageMask = [imageMask flipVertical];

UIGraphicsBeginImageContext(CGSizeMake(self.size.width, self.size.height));

CGContextRef context = UIGraphicsGetCurrentContext();

CGImageRef maskRef = [imageMask fitSize:self.size].CGImage;

CGContextClipToMask(context, CGRectMake(0, 0, self.size.width, self.size.height), maskRef);

[self drawInRect:CGRectMake(0, 0, self.size.width, self.size.height)];
UIImage *reSizeImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return reSizeImage;
}

- (UIImage*)flipVertical
{
UIImage *image = nil;
switch (self.imageOrientation) {
case UIImageOrientationUp:
{
image = [UIImage imageWithCGImage:self.CGImage scale:1 orientation:UIImageOrientationDownMirrored];
break;
}
case UIImageOrientationDown:
{
image = [UIImage imageWithCGImage:self.CGImage scale:1 orientation:UIImageOrientationUpMirrored];
break;
}
case UIImageOrientationLeft:
{
image = [UIImage imageWithCGImage:self.CGImage scale:1 orientation:UIImageOrientationLeftMirrored];
break;
}
case UIImageOrientationRight:
{
image = [UIImage imageWithCGImage:self.CGImage scale:1 orientation:UIImageOrientationRightMirrored];
break;
}
case UIImageOrientationUpMirrored:
{
image = [UIImage imageWithCGImage:self.CGImage scale:1 orientation:UIImageOrientationDown];
break;
}
case UIImageOrientationDownMirrored:
{
image = [UIImage imageWithCGImage:self.CGImage scale:1 orientation:UIImageOrientationUp];
break;
}
case UIImageOrientationLeftMirrored:
{
image = [UIImage imageWithCGImage:self.CGImage scale:1 orientation:UIImageOrientationLeft];
break;
}
case UIImageOrientationRightMirrored:
{
image = [UIImage imageWithCGImage:self.CGImage scale:1 orientation:UIImageOrientationRight];
break;
}
default:
break;
}

return image;
}


KMAutoShapeButton.m重载图片设置部分:

// Reset the Hit Test Cache when a new image is assigned to the button
- (void)setImage:(UIImage *)image forState:(UIControlState)state
{
[super setImage:self.imageMask ? [image imageWithMask:self.imageMask] : image forState:state];

[self resetHitTestCache];
}

- (void)setBackgroundImage:(UIImage *)image forState:(UIControlState)state
{
[super setBackgroundImage:self.imageMask ? [image imageWithMask:self.imageMask] : image forState:state];
[self resetHitTestCache];
}

- (void)resetHitTestCache
{
self.previousTouchPoint = CGPointMake(CGFLOAT_MIN, CGFLOAT_MIN);
self.previousTouchHitTestResponse = NO;
}
通过
按钮点击检测、图片剪切 等步骤,可以得到我们最终需要的图片效果,并且在需要变换形状的时候,仅仅将mask图片替换掉即可。

代码下载:http://download.csdn.net/detail/u013494674/8046173
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: