iOS-自定义button详解

在开发中经常会遇到一种情况,就是按钮的UI布局(上图下文、左文右图等)和系统自带的布局(左图右文)不一样 这种情况:一种解决办法是创建一个button并在上面加一个imageView和一个label,但是这样遇到图片的位置会根据文字的长度变化的情况,会相当麻烦;另一种解决办法就是自定义一个button,这种方法更加简洁,同时处理点击事件的逻辑也更方便

  1. 首先创建一个类,继承自UIButton
  2. 初始化方法
+(instancetype)buttonWithType:(UIButtonType)buttonType{
    CCButton *ccButton = [super buttonWithType:buttonType];
    if (ccButton) {
        ccButton.titleLabel.textAlignment = NSTextAlignmentCenter;
        // 开启button的imageView的剪裁属性,根据imageView的contentMode属性选择是否开启
        ccButton.imageView.layer.masksToBounds = YES;
        ccButton.layer.masksToBounds = YES;
    }
    return ccButton;
}
  1. 重写button的几个边界方法,return语句后面的数字,是我打断点得到这几个函数的执行顺序
// 返回背景边界(background)
-(CGRect)backgroundRectForBounds:(CGRect)bounds{
    NSLog(@"背景边界:%@",NSStringFromCGRect(bounds));
    return CGRectMake(0, 0, 200, 10);// 6 7  14
}
// 返回内容边界 标题+图片+标题与图片之间的间隔(title + image + the image and title separately)
-(CGRect)contentRectForBounds:(CGRect)bounds{
    NSLog(@"内容边界:%@",NSStringFromCGRect(bounds));
    return CGRectMake(0, 0, 10, 10); // 1 3 5 8 10 12 15 17 19
}
// 返回标题边界
-(CGRect)titleRectForContentRect:(CGRect)contentRect{
    NSLog(@"标题边界:%@",NSStringFromCGRect(contentRect));
    return CGRectMake(0, 0, 200, 30); // 2 11 18
}
// 返回图片边界
-(CGRect)imageRectForContentRect:(CGRect)contentRect{
    NSLog(@"图片边界:%@",NSStringFromCGRect(contentRect));
    return CGRectMake(0, 0, 100, 60); // 4 9 13 16 20
}

输出如下图:

刚开始对这几个函数不是很明白,经过多次调试,才明白各自的功能:

  • -(CGRect)backgroundRectForBounds:(CGRect)bounds 该函数返回的是背景view的大小,参数bounds是button的大小,即button.frame
-  如果:`return bounds`

此时背景view和button的大小相同,是默认的大小 - 如果:return CGRectMake(0, 0, 50, 50),且button.frame = CGRectMake(0, 0, 100, 100) 此时背景view的大小是{{0,0},{50,50}},而button的大小是{{0,0},{100,100}},在背景view之外的button是透明的且不能改变颜色,它可以响应点击事件 - 如果:return CGRectMake(0, 0, 100, 100),且button.frame = CGRectMake(0, 0, 50, 50) 此时分两种情况,一种是layer.masksToBounds = YES,button的背景view和frame都是{{0,0},{50,50}};另一种layer.masksToBounds = NO,button的背景view的大小是{{0,0},{100,100}},button.frame大小是{{0,0},{50,50}},此时界面显示是一个{{0,0},{100,100}}的button,但是只有button的{{0,0},{50,50}}范围内才会响应点击事件

  • -(CGRect)contentRectForBounds:(CGRect)bounds 该函数返回内容view的大小,内容view包括title view 、image view 和二者之间的间隔,参数bounds是button的大小,即button.frame
    • 如果:return bounds 此时在返回title view边界和image view边界函数中的contentRect参数的值为button.bounds
    • 如果:return CGRectMake(0, 0, 100, 100) 此时在返回title view边界和image view边界函数中的contentRect参数的值为{{0,0},{100,100}}
  • -(CGRect)titleRectForContentRect:(CGRect)contentRect 该函数返回标题view的大小,参数contentRect由函数-(CGRect)contentRectForBounds:(CGRect)bounds确定
  • -(CGRect)imageRectForContentRect:(CGRect)contentRect 该函数返回图片view的大小,参数contentRect由函数-(CGRect)contentRectForBounds:(CGRect)bounds确定
  1. 最后写一个上图下字的示例,这只是一个简单的例子,具体情况可以根据使用场景调整
// 该自定义button的背景和内容view都和它的frame一样大,所以可以不用重写-(CGRect)backgroundRectForBounds:(CGRect)bounds和-(CGRect)contentRectForBounds:(CGRect)bounds这两个函数
// 返回标题边界
-(CGRect)titleRectForContentRect:(CGRect)contentRect{
      // 这contentRect就是button的frame,我们返回标题view宽和button相同,高为20,在button的底部
      return CGRectMake(0, contentRect.size.height-20, contentRect.size.width, 20);
}
// 返回图片边界
-(CGRect)imageRectForContentRect:(CGRect)contentRect{
      // button的image view 是正方形,由于title占了20的高了,所以取height - 20和width中最小的值作为image view的边长
      // 如果图片的位置是根据文字来布局的,这里可以通过self.titleLabel.text拿到title,再计算出图片的位置
      CGFloat imageWidth = MIN(contentRect.size.height - 20, contentRect.size.width);  
      return CGRectMake(contentRect.size.width/2 - imageWidth/2, 0, imageWidth, imageWidth);
}
  1. demo地址:https://github.com/cdcyd/CommonControlsCollection

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏進无尽的文章

绘图-几种基本统计图的实现分析

在开发中我们会遇到各种统计图,或者各种绘图,本文通过对基本三大统计图:折线图、柱状图、扇形图的实现来掌握基本统计图的绘制,在下一篇文中会带来复杂一些的绘图案例分...

1651
来自专栏flutter开发者

[Flutter Widget]ExpansionTile

在前面的文章红我们学习了Chip的用法,使用Chip可以很方便的完成对想要的东西打上想要的标签。在文章的最后让大家实现如下的效果

5522
来自专栏算法channel

Python-GUI|Tk类,属性文档使用指南

这是一篇tkinter相关API的介绍性地帮助文档,包括常用的包,类结构图,属性取值等,可以作为一个工具文档,供大家查阅。 01Tk中的包 __main...

3177
来自专栏老司机的简书

老司机带你走进Core Animation 之图层的透视、渐变及复制

老司机的想法就是要把CoreAnimation头文件中的类大概都说一遍,毕竟一开始把系列名定成了《老司机带你走进CoreAnimation》(深切的觉得自己给自...

1544
来自专栏小灰灰

Java 实现图片合成

图片合成 利用Java的绘图方法,实现图片合成 在开始之前,先定一个小目标,我们希望通过图片合成的方式,创建一个类似下面样式的图片 ? I. 设计思路 首先...

1.1K10
来自专栏非典型技术宅

OC绘制饼状图、柱状图和扇形图1. 绘制柱状图bar chart2. 绘制饼图Pie Chart3. 绘制进度条和进度扇形4. 神秘感增强器:IB_DESIGNABLE和IBInspectable5.

1294
来自专栏進无尽的文章

动画| 金币抛入红包动画详解

这个动画效果很早就出来了,也是一个比较经典的关键帧动画和组合动画的运用,通过剖析源码,可以发现实际上这个酷炫的动画实现起来很简单。

2765
来自专栏王金龙的专栏

svg.js教程及使用手册详解(二)

上篇简要介绍了svg.js的基本信息和基本用法,这篇开始详细讲解svg.js的用法。

1474
来自专栏非典型技术宅

iOS动画系列之八:使用CAShapeLayer绘画动态流量图1. CAShapeLayer2. 实战:绘制一个镂空图层动画3. 使用CAShapeLayer绘画动态流量图

2043
来自专栏陈满iOS

iOS动画专题·UIView二维形变动画与CAAnimation核心动画(transform动画,基础,关键帧,组动画,路径动画,贝塞尔曲线)

总的来说,从涉及类的形式来看,iOS动画有:基于UIView的仿射形变动画,基于CAAnimation及其子类的动画,基于CG的动画。这篇文章着重总结前两种动画...

3471

扫码关注云+社区