`
mrjeye
  • 浏览: 178096 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

不规则形状的uibutton

 
阅读更多

有的时候,我们需要使用非规则形状的按钮。UIButton允许你选择带有alpha通道的图像。比如,我使用下面四个图像:


image


然后用Interface Builder创建用户定义按钮,你可以透过图像的透明部分看到后面的按钮(假定按钮未定义为opaque)。.然而 UIButton 的点击测试(hit-testing)并未考虑图像的透明性,所以当你将图像重叠放置时,如图所示:


image


如果你点击此处:


image



默认的点击测试的结果是绿色菱形按钮被按下,而不是蓝色按钮。当然这可能就是你需要的效果,但大部分情况下并非如你所愿。那么怎样才能让你的程序正常工作?实际上很简单,你只需要一个UIButton的子类并重写点击测试方法。

 

然而,首先你需要一个方法能确定图像上指定点是透明的。遗憾的是UIImage无法像Cocoa为NSImage提供的 NSBitmapRepresentation 那样方便地访问位图数据。但是每个UIImage都具有一个称为CGImage的属性可以访问内部图像数据,Apple发布了一篇技术文章介绍了怎样通过CGImageRef访问内部位图数据


根据这篇文章的介绍,我们很容易就写出一个方法,它以CGPoint为参数,根据该点是否透明(0)与否返回YES或NO。


UIImage-Alpha.h

1
2
3
4
5
6
7
8
#import <UIKit/UIKit.h>

@interface UIImage( Alpha)

- ( NSData * ) ARGBData;
- ( BOOL ) isPointTransparent: ( CGPoint) point;

@end


UIImage-Alpha.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
CGContextRef CreateARGBBitmapContext ( CGImageRef inImage)
{
    CGContextRef    context = NULL ;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

    size_t pixelsWide = CGImageGetWidth( inImage) ;
    size_t pixelsHigh = CGImageGetHeight( inImage) ;
    bitmapBytesPerRow   = ( pixelsWide * 4) ;
    bitmapByteCount     = ( bitmapBytesPerRow * pixelsHigh) ;

    colorSpace = CGColorSpaceCreateDeviceRGB( ) ;
    if ( colorSpace == NULL )
        return nil ;

    bitmapData = malloc ( bitmapByteCount ) ;
    if ( bitmapData == NULL )
    {
       CGColorSpaceRelease( colorSpace ) ;
       return nil ;
    }

    context = CGBitmapContextCreate ( bitmapData,
                                     pixelsWide,
                                     pixelsHigh,
                                     8,
                                     bitmapBytesPerRow,
                                     colorSpace,
                                     kCGImageAlphaPremultipliedFirst) ;

    if ( context == NULL )
    {
       free ( bitmapData) ;
       fprintf ( stderr , "Context not created!" ) ;
    }

    CGColorSpaceRelease( colorSpace ) ;

    return context;
}

@implementation UIImage( Alpha)

- ( NSData * ) ARGBData
{
    CGContextRef cgctx = CreateARGBBitmapContext( self.CGImage) ;
    if ( cgctx == NULL )        
        return nil ;

    size_t w = CGImageGetWidth( self.CGImage) ;
    size_t h = CGImageGetHeight( self.CGImage) ;
    CGRect rect = { { 0,0} ,{ w,h} } ;
    CGContextDrawImage( cgctx, rect, self.CGImage) ;

    void * data = CGBitmapContextGetData ( cgctx) ;
    CGContextRelease( cgctx) ;    

    if ( ! data)      
        return nil ;

    size_t dataSize = 4 * w * h; // ARGB = 4 8-bit components
    return [ NSData dataWithBytes: data length: dataSize] ;
}    

- ( BOOL ) isPointTransparent: ( CGPoint) point
{
    NSData * rawData = [ self ARGBData] ;  // See about caching this
    if ( rawData == nil )
       return NO ;

    size_t bpp = 4 ;
    size_t bpr = self.size.width * 4 ;

    NSUInteger index = point.x * bpp + ( point.y * bpr) ;
    char * rawDataBytes = ( char * ) [ rawData bytes] ;

    return rawDataBytes[ index] == 0 ;

}

@end

一旦我们有能力确定图像中的某点是否透明,我们就可以编写UIButton的子类,重写hitTest:withEvent: 方法。它将返回一个UIView的实例。如果该点在此视图或其子视图中未被点击,那么将返回nil。如果点击在其子视图,那么将返回点击中的子视图,如果 点击中视图,那么返回视图本身。


然而,我们可以进行一些简化,这是因为尽管UIButton继承了UIView,技术上可能具有子视图,但这非常的少见,而且Interface Builder并不支持这样做。所以在本文的实现中并不考虑子视图。


IrregularShapedButton.h

1
2
3
4
5
6
7
#import <UIKit/UIKit.h>

@interface IrregularShapedButton : UIButton {

}

@end

IrregularShapedButton.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#import "IrregularShapedButton.h"
#import "UIImage-Alpha.h"

@implementation IrregularShapedButton

- ( UIView * ) hitTest: ( CGPoint) point withEvent: ( UIEvent * ) event
{
    if ( ! CGRectContainsPoint( [ self bounds] , point) )
        return nil ;
    else
    {
        UIImage * displayedImage = [ self imageForState: [ self state] ] ;
        if ( displayedImage == nil ) // No image found, try for background image
        displayedImage = [ self backgroundImageForState: [ self state] ] ;
        if ( displayedImage == nil ) // No image could be found, fall back to
            return self;        

        BOOL isTransparent = [ displayedImage isPointTransparent: point] ;
        if ( isTransparent)
            return nil ;

    }

    return self;
}

@end
将Interface Builder中的四个图像按钮改为IrregularShapedButton,它们将正常工作了。
原文见:Irregularly Shaped UIButton
分享到:
评论

相关推荐

    IOS 不规则按钮实现方法

    在iOS开发中,创建不规则形状的按钮是一种常见的需求,比如设计特殊形状的按钮来提升用户界面的美观度和交互性。"IOS 不规则按钮实现方法"主要涉及到自定义按钮和图形绘制技术,通过给定的文件名可以推测出这是一种...

    ios不规则按钮

    在iOS开发中,创建不规则形状的按钮是一种高级技巧,它可以为用户界面带来独特的视觉效果和交互体验。本文将深入探讨如何在iPhone和iPad上利用图片实现不规则形状的按钮,以及相关的技术要点。 首先,iOS系统默认的...

    HZAnomalousButtonDemo:不规则形状的按钮

    `HZAnomalousButtonDemo`项目就是一个很好的例子,它展示了如何用Objective-C编程语言实现一个不规则形状的按钮。这个项目的目标是提供一种方法,让开发者能够突破标准矩形按钮的限制,创造出更具创意的用户界面。 ...

    iOS开发 不规则图形点击

    在iOS开发中,有时我们可能需要为用户界面中的不规则图形添加点击事件,例如一个复杂的形状或者自定义的图标。这种需求通常出现在我们希望用户能够交互的特定区域内,而这个区域不是一个标准的矩形或圆形。本文将...

    iOS 自定义简单不规则TabbarController

    本篇文章将深入探讨如何实现一个自定义的、不规则的TabbarController,特别是利用Xib(Interface Builder)来设计,并且方便地更换图片。 首先,我们需要理解TabBarController的基本工作原理。它是...

    不规则按钮

    首先,你需要创建一个新的UIView子类,比如命名为`OBSShapedButton`,这个类将承载不规则形状的按钮逻辑。在`OBSShapedButton`中,你需要覆盖`hitTest:withEvent:`方法,使用Core Graphics框架来定义按钮的形状。你...

    ios-不规则按钮的实现.zip

    在iOS开发中,创建不规则形状的按钮是一个挑战,因为标准的UIButton类只提供矩形或椭圆形的形状。然而,通过使用自定义视图和绘图技术,开发者可以实现各种复杂的按钮形状。这里我们将深入探讨如何实现不规则按钮,...

    ios-利用OBShapedButton实现不规则按钮的方法.zip

    在iOS开发中,有时我们需要创建形状不规则的按钮,以满足特定界面设计或功能需求,如地图选择区域、智能导诊等。在这种情况下,利用第三方库OBShapedButton可以非常方便地实现这样的效果。OBShapedButton是一个强大...

    Iphone 无规则按钮

    你可以根据需求绘制任意复杂的路径,例如不规则的多边形、曲线等。 2. **设置层属性**:将定义好的UIBezierPath设置为按钮的CAShapeLayer的path属性。这将使按钮的边界跟随自定义路径。 ```swift let shapeLayer...

    iOS实现不规则Button点击效果实例代码

    在iOS开发中,创建自定义不规则Button的点击效果是一个常见的需求,特别是在界面设计需要特殊形状的交互元素时。本文将深入探讨如何实现这一功能,包括理解事件传递机制以及自定义视图的处理。 首先,我们需要了解...

    绘画九宫格跳转

    2. **不规则九宫格**:九宫格通常用于展示图片或内容,但“不规则”意味着每个格子的形状、大小或位置可能不同。这可能涉及到自定义UICollectionViewCell,通过 UICollectionViewFlowLayout 实现复杂的布局计算,每...

    IOS应用源码——ios按钮样式制作大全(20种不同风格的按钮制作方法).zip

    19. **自定义形状**:利用CAShapeLayer和UIBezierPath,可以创建不规则形状的按钮。 20. **触摸反馈**:利用UIImpactFeedbackGenerator提供物理反馈,使用户在触摸按钮时有更直观的感知。 以上知识点覆盖了从基础...

    ios-小小的绘图.zip

    然而,如果需要进行更复杂的定制,例如自定义动画效果或不规则形状,那么直接使用Core Graphics会更加灵活。 在压缩包中的"EmbedText"可能是一个示例,演示了如何在图形上下文中绘制文本。在Core Graphics中,我们...

    威信的聊天气泡效果2.zipIOS应用例子源码下载

    在这个示例中,我们可以学习如何创建自定义气泡视图,通过`CALayer`来绘制不规则形状的气泡,以实现发送方和接收方消息的视觉区别。这包括了利用`CGPath`来定义气泡的边框路径,以及设置`CAShapeLayer`的填充和描边...

    iOS 设计模式 工厂模式

    3. **工厂(Factory)**: 负责创建产品,它可以根据输入参数或者某种规则来决定创建哪种具体产品。 在iOS中,可以使用Objective-C的Category或者Swift的Protocol来实现抽象产品。具体产品则是遵循这些协议的类。...

    uiview源码使用

    7. **遮罩和背景**:`UIView`的`backgroundColor`属性可以设置背景颜色,`maskLayer`属性则可以添加遮罩层,实现不规则形状的视图。 8. **视图控制器**:`UIViewController`通常与`UIView`配合使用,负责管理视图的...

    生成漂浮气泡的按钮

    2. **图形渲染**:实现气泡形状可能需要用到`CGPath`或`CAShapeLayer`,通过定义路径来绘制不规则的气泡形状,并应用填充和边框样式。 3. **动画编程**:要实现“漂浮”效果,可以使用`UIView`的动画方法,如`...

    在iOS开发的Quartz2D使用中实现图片剪切和截屏功能

    不规则形状剪切 除了圆形,还可以剪切成其他形状,例如三角形。同样,先画出三角形路径,然后调用`CGContextClip(ctx);`。以下是一个三角形剪切的例子: - `CGContextMoveToPoint(ctx, 100, 100);` 定义路径起点 ...

    iOS常用菜单

    "又添加了一个path效果的菜单"这句话表明,项目中包含了一种利用CGPath或UIBezierPath实现的特殊效果,这可能是通过绘制不规则形状或动画轨迹来实现独特的视觉效果,增加用户的交互体验。 在实际应用中,菜单可能...

Global site tag (gtag.js) - Google Analytics