UIButton基础知识和自定义详解

UIButton是我们经常用的UI控件,继承UIControl。这里将对UIButton的基本使用方法和自定义UIButton进行详细介绍。

一、UIBUtton基本知识介绍

对于我们学习一个新的控件、无外乎两种方法。第一种是在xcode中的.m文件查看该控件的属性和相关方法,第二种直接在storyBoard中拖入该控件,然后在Xcode中的属性检查器面板,查看该控件属性。这里选择第二种,形象生动。

这里写图片描述

无论学习什么控件,都需要把该控件的基本属性熟记于心。

1、Type
主要有以下几种
这里写图片描述

  • Custom
    该属性允许开发者设计按钮外观、而不是系统默认样式,比如要自定义Button样式。

  • System
    该属性使得按钮呈现默认风格。

  • Detail Disclosure
    该属性使得按钮呈现一个详情图标。这里写图片描述

  • InfoLight
    该属性使得按钮呈现一个图标,同Detail Disclosure。

  • InfoDark
    该属性使得按钮呈现一个图标,同Detail Disclosure。
  • ContactAdd
    该属性使得按钮呈现一个图标。这里写图片描述

总结:在我们使用Button过程中,一般直接选用Custom。

2、State Config
该属性用来设置按钮的的状态。按钮总共有4种状态:

默认状态:UIControlStateNormal

高亮状态:UIControlStateHighlighted
对应属性:highlighted

选中状态:UIControlStateSelected
对应属性:selected

禁用状态:UIControlStateDisabled
对应属性:enabled

备注:高亮和选中状态的区别:高亮指的是用户碰触该按钮的时候,按钮显示高亮效果、用户离开时按钮高亮效果消失;选中状态是需要开发者设置selected属性为YES时,才会展示某种效果、设置为NO时,效果消失。

3、Title
标题、默认使用Plain、不过多解释

4、Font
设置文本标题字体大小、不过多解释

5、TextColor
设置文本标题颜色、不过多解释

6、Shadow Color
文本标题阴影颜色、需要设置Shadow Offset

7、Image
如果给按钮设置image,前面设置的Title属性可能会不起作用,该按钮只会显示一张图片。如果还想显示文字,则需要设置titleEdgeInsets和imageEdgeInsets属性<后面的自定义button会详细讲解>。

8、Backgroud
设置按钮的背景图片、不会遮挡标题文字

9、Shadow Offset
设置阴影文本与正常文本的偏移量

这里写图片描述

Width:大于0,阴影文本相对右偏移,反之,左偏移
Height:大于0,阴影文本相对下偏移,反之,上偏移

10、Line Break
对button文本标题的截断、因为标题太长、显示不全。有以下三种模式:
Truncate Head : 对字符串多余对开头部分截断,用…代替截断部分。
Truncate Middle : 对字符串多余的中间部分截断,用…代替截断部分。
Truncate Tail : 对字符串多余的结尾部分截断,用…代替截断部分。

11、Edge和Inset
二者结合在一起使用才有意义、不是孤立存在的。
Edge指的是边界,Inset指的是边界间距。
下面自定义Button会详细介绍到。

二、改变button中图片和文字的位置

默认情况下设置按钮的图片和文字,展示效果是图片在右边、文字在左边。
相关代码如下:

UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
[btn setImage:[UIImage imageNamed:@"qq.jpg"] forState:UIControlStateNormal];
[btn setTitle:@"title" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
btn.layer.borderColor = [UIColor redColor].CGColor;
btn.layer.borderWidth = 1.0;
btn.frame = CGRectMake(100, 100, 200, 200);
[self.view addSubview:btn];

效果图如下:

这里写图片描述

接下来将设置图片上文字下、图片左文字右、图片下文字上三种模式。

我们会通过两种方法进行,第一种方法:通过UIEdgeInsets设置边距;第二种方法通过完全自定义的方法。最后,我们将会对比这两种方法的优缺点。

方法一:通过UIEdgeInsets设置边距

1、UIEdgeInsets设置边距
首先需要介绍UIEdgeInsets

typedef struct UIEdgeInsets {
    CGFloat top, left, bottom, right;  // specify amount to inset (positive) for each of the edges. values can be negative to 'outset'
} UIEdgeInsets;  

这里的四个参数表示距离上边界、左边界、下边界、右边界的距离,默认都是零。此时图片和文字在按钮的正中间。

以前在设置这个参数时,有一个误解,比如说设置按钮图片的上边距为60、即UIEdgeInsetsMake(60, 0, 0, 0)。一直以为是下面这种效果:

这里写图片描述

其实应该是这种效果:top、left、bottom、right是相对于原来的位置而言的。

这里写图片描述

疑问:设置距离上边距60,为什么这里标注30???
解答:其实这个和按钮的contentHorizontalAlignment、contentVerticalAlignment两个属性有关<下面用button的content属性代替>;默认情况下,两个属性都是AlignmentCenter,此时imageView和titleLabel两个子控件实际移动距离是设置距离的一半(60 / 2);下面会详细介绍。

小结:
top :大于0、向下移动;反之向上移动
left:大于0、向右移动;反之向左移动
bottom: 大于0、向上移动;反之向下移动
right: 大于0、向左移动;反之向右移动

2、图片右文字左模式
思路:将imageView向右平移一个自身控件的宽度、将titleLabel向左平移一个自身控件宽度。

代码如下:

//3、获取控件宽度
CGFloat imageViewWidth = btn.imageView.frame.size.width;
CGFloat titleWidth = btn.titleLabel.frame.size.width;

//4、设置内边距
[btn setImageEdgeInsets:UIEdgeInsetsMake(0, imageViewWidth, 0, 0)];
[btn setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, 0, titleWidth)];

效果如下:

这里写图片描述

此时效果图并不是我们想要的,就像上面提到的,这里是由于button的两个特殊属性引起的,此时需要将设置距离=自身宽度 * 2。

//4、设置内边距
[btn setImageEdgeInsets:UIEdgeInsetsMake(0, imageViewWidth * 2, 0, 0)];
[btn setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, 0, titleWidth * 2)];

实际效果如下:
这里写图片描述

疑问:如果设置button中的两个属性为其它模式,移动距离是否还是设置距离的2倍???

解答:经过一翻实验发现:
a、如果将contentHorizontalAlignment设置为UIControlContentHorizontalAlignmentCenter

左右移动距离 = 设定距离 / 2;
其它模式下左右移动距离 = 设定距离。

b、如果将contentVerticalAlignment设置为UIControlContentVerticalAlignmentCenter

上下移动距离 = 设定距离 / 2;
其它模式下上下移动距离 = 设定距离。

另外,如果将imageView和titleLabel设置为以下四种情况,则在当前位置,二者无法进行左右互换:

这里写图片描述

下面写的代码默认button的content属性为center。

为了方便理解,可以下载代码,详情地址见文章最后。

3、图片上文字下模式
思路:将imageView向上移动(自身高度/2)、向右移动(自身宽度/2);将titleLabel向下移动(自身高度/2)、向左移动(自身宽度/2)。

//3、获取控件宽度
CGFloat imageViewWidth = btn.imageView.frame.size.width;
CGFloat imageViewHeight = btn.imageView.frame.size.height;

CGFloat titleWidth = btn.titleLabel.frame.size.width;
CGFloat titleHeight = btn.titleLabel.frame.size.height;

//4、设置内边距
[btn setImageEdgeInsets:UIEdgeInsetsMake(0, imageViewWidth, imageViewHeight, 0)];
[btn setTitleEdgeInsets:UIEdgeInsetsMake(titleHeight, 0, 0, titleWidth)];

效果如下图:
这里写图片描述

4、图片下文字上模式
思路:将imageView向下移动(自身高度/2)、向右移动(自身宽度/2);将titleLabel向上移动(自身高度/2)、向左移动(自身宽度/2)。

//3、获取控件宽度
CGFloat imageViewWidth = btn.imageView.frame.size.width;
CGFloat imageViewHeight = btn.imageView.frame.size.height;

CGFloat titleWidth = btn.titleLabel.frame.size.width;
CGFloat titleHeight = btn.titleLabel.frame.size.height;

//4、设置内边距
[btn setImageEdgeInsets:UIEdgeInsetsMake(imageViewHeight, imageViewWidth, 0, 0)];
[btn setTitleEdgeInsets:UIEdgeInsetsMake(0, 0, titleHeight, titleWidth)];

效果图如下:

这里写图片描述

补充:默认情况下,imageView和titleLabel控件二者中心点与UIButton的中心点重合。

5、此方法使用局限性
当图片过大的时候,当前按钮只会显示一张图片;因为我们开发人员无法控制按钮内部的imageView和titleLabel两个子控件大小、只能移动位置。
这里写图片描述

解释:
1.当button.width < image.width时,只显示被压缩后的图片,图片是按fillXY的方式压缩。

2.当button.width > image.width,且 button.width < (image.width + text.width)时,图片正常显示,文本被压缩。

3.当button.width > (image.width + text.width),两者并列默认居中显示,可通过button的属性contentHorizontalAlignment改变对齐方式。

方法二、自定义Button
这个也可以分为以下两种方式:

a、重写系统Rect方法

思路:设置内部imageView子控件的高度=宽度=当前按钮的高度;设置内部titleLabel的高度=当前按钮的高度、宽度=(当前按钮的宽度 - 当前按钮的高度)。

备注:这里可以随意设置imageView和titleLabel的frame,这里只是提供一种思路。这个方法不是本文重点,重点是第二种方式。

重写系统的两个方法
-(CGRect)titleRectForContentRect:(CGRect)contentRect
-(CGRect)imageRectForContentRect:(CGRect)contentRect

代码如下:

//返回标题的区域
- (CGRect)titleRectForContentRect:(CGRect)contentRect
{
    CGFloat titleWidth = contentRect.size.width - contentRect.size.height;
    return CGRectMake(0, 0, titleWidth, contentRect.size.height);
}

//返回图片等区域
- (CGRect)imageRectForContentRect:(CGRect)contentRect
{
    CGFloat imageHeight = contentRect.size.height;
    CGFloat imageWidth = imageHeight;

    return CGRectMake(contentRect.size.width - imageWidth, 0, imageWidth, imageHeight);
}

b、重写系统layoutSubviews方法

思路:这个方法主要是重写系统的layoutSubviews、重新设置imageView、titleLabel、button自身宽高。

这里对按钮重新进行了封装,方便使用,详情见demo。

三、扩大Button的响应区域
项目中遇到一个需求,那就是不改变按钮的大小,但是响应区域要变大。经过一翻查找,终于找到了解决办法,特此记录一下。

主要利用ios的事件响应链,重写系统方法、拦截事件,扩大响应区域。

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if(UIEdgeInsetsEqualToEdgeInsets(self.hitTestEdgeInsets, UIEdgeInsetsZero) || !self.enabled || self.hidden)
    {
        return [super pointInside:point withEvent:event];
    }

    CGRect relativeFrame = self.bounds;
    CGRect hitFrame = UIEdgeInsetsInsetRect(relativeFrame, self.hitTestEdgeInsets);

    return CGRectContainsPoint(hitFrame, point);
}

详细见gitHub代码:
https://github.com/yscMichael/CustomizeButton

参考文献:
https://www.jianshu.com/p/0fc2bc2a034c

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值