iOS开发之UIButton的图片显示解惑

作者: 简人Lmy | 来源:发表于2018-11-07 10:53 被阅读31次

    前言:

    写这篇文章来给大家分享一下我了解的关于UIButton的图片显示知识点和我遇到的坑及解决方案,帮助遇到同样问题和相关知识点不清晰的同学,如有错误,欢迎指正,共同进步🤝,本文在解析的时候可能较为啰嗦,是为了将思路完整呈现,对于初学者作用可能较大,老手可忽略,直接看结论。

    需求:

    相信大家都遇到过这种日常需求:一张图片上面有点击事件,同时这个控件的长宽比例固定或者干脆是个正方形,然而显示的图片则是长宽比例不固定的长方形,并且根据产品的需求,这张图片必须要覆盖整个控件,那么这图片势必要进行缩放;还有图片必须不能变形(都知道,产品和UI的日常需求,变形了确实太丑),也就是说显示出来的时候原始图片长宽比例不能变。

    分析:

    涉及到图片缩放,那就不得不提UIViewcontentMode属性,既然要缩放并且图片长宽比例不能变,解决方案应该就是放大或缩小图片,但长宽比例不变,然后将图片居中显示,再裁减掉多余的部分,只显示控件大小的图片,当然是在clipToBoundsYES的情况下。很显然,只有UIViewContentModeScaleAspectFill符合条件,这个枚举的作用大概是以下几种情况:
    这里为了方便,假设横向长度为x,纵向高度为y,
    1. 当目标控件和原始图片都为正方形时,只需要xy同比例缩放即可;
    2. 当原始图片xy比例不为1:1时,根据目标控件的xy比来适当的缩放:
    1)当原始图片的x:y >目标控件的x:y,缩放原始图片的y值等于目标控件的y值,然后根据原始图片的xy比缩放x,得到的图片肯定会在x方向大于目标控件,接着横向居中放置缩放后的原始图片,再裁掉多余部分。
    2)当原始图片的x:y <目标控件的x:y,缩放原始图片的x值等于目标控件的x值,然后根据原始图片的xy比缩放y,得到的图片肯定会在y方向大于目标控件,接着纵向居中放置缩放后的原始图片,再裁掉多余部分。
    好了,这个枚举的作用介绍到这里,很清晰了(其他枚举的用法相信大家都知道,不知道的自行查资料,相信很容易找到)。

    实验:

    知道了这些知识点,要搞定这个需求就很容易了。
    我先在这里准备了两张具有代表性的图片,模拟容易出错的情况。

    • 第一张,这张图非常小,是模拟加载比控件小的图时的情况: 55x53.jpeg
    • 第二张,这张图是长方形,正中间有一轮明月,主要模拟长宽比例不一样时的情况,明月用来便于判断图片是否变形: 525x350.jpeg

    一、UIButton

    我们写一个button,为了方便,长宽一样,设定为100,距离底部100,左右居中,然后clipToBounds属性为YES,为了便于分析,给个背景颜色,就用亮油油的火红火红的绿色,如图:

    绿色的Button

    开始设置图片

    1) 先放一张长方形的图,来测试长宽比例不一样的情况,我这里用的是setImage:forState:(以下省去forState):

    效果1 可以看到月亮已经扁了,明显变形,哦,知道,是因为contentMode的问题,设置一下 代码1 但是没有任何作用,就不上图了,运行后跟图效果1一模一样,怎么回事呢,经过查阅资料,我还是不知道🤓,总之就是UIButton.contentMode就像个摆设,而要设置button图片的contentMode只有用button.imageView.contentMode,我们来试试 代码2 效果2
    好了,这样就对了,应该是满足我们刚才说的原始图片x:y > 目标控件x:y,于是y缩放到目标控件的y值大小,x等比例缩放,再居中显示,x方向两边多余的部分就被裁切了,好了,这种情况已经达到产品的需求。

    2)刚才的情况测试了长方形且不比目标控件小的情况,另一种情况就比较烦了,也是这次我写这篇文章遇到的坑点,比目标控件小的图片,我们放上去试试,代码不变,contentMode还是scaleAspectFill:

    效果3

    😂此时我的心情跟效果3中那个小人的心情一模一样,还记得我们刚才设置的按钮绿色背景,现在起作用了,不然就只能看到很小的一个小人在中间。为什么图片没有缩放呢,不是设置好了contentMode吗?这么坑的吗?呵呵,就是这么坑,这就是button的神奇之处,我想可能是因为是设置的是button的图标的原因吧(就是setImage这个方法)。好,那我们试试setBackgoundImage,呵呵,算了,这样影响我排版了,先把setImage说完,因为我知道setBackgroundImage也没用,等会儿我们再完整地试试。
    emmmm......怎么解决呢?经过查阅资料🌝,这次我找到了解决方案,原来UIControlcontentHorizontalAlignmentcontentVerticalAlignment两个属性

    系统Api中ContentHorizontalAlignment 系统Api中ContentVerticalAlignment 我们这里显而易见是用fill了,试下效果: 代码4(就是没有代码3,要一一对应 🙂,下同) 效果4 代码5
    效果5(1)
    懵逼中......这跟说好的不一样啊,然后我点击了一下button, 效果5(2)
    继续懵逼......不过效果总算符合预期了,这里究竟是怎么回事,经过查阅资料,我猜应该是我在storyboard里面没有做设置,默认的是center,而我写成fill是在代码里写的,点击的时候才重新刷新了布局,如果直接在storyboard里面调整应该不会出现这种情况,不过到这里,应该知道要怎么设置了 storyboard中,如果用storyboard的可以直接选右边红框框出的选项
    代码6
    效果6
    果然,小图也被放大了,并且没有变形,那就是裁去了多余的部分,总算搞定!至此,button设置图片的所有情况应该都涵盖了,正方形的情况是自然没问题的。

    setBackgrounImage

    好了,刚才我们说到的setBackgroundImage方法,试一下

    代码7
    这里因为我的小图准备的是一张近似正方形的图片,所以我把button改成100x200的长方形(之前一直是200x200),效果会更明显,如图 效果7(1) 效果7(2)
    很明显,setBackgroundImage是将图片直接强行缩放到跟目标控件的大小一样,且任由图片变形,不会保持其长宽比例缩放后裁剪,完全不适合本文所提需求。

    二、UIImageView

    接下来尝试imageView,同样的,创建一个imageView,距离顶部100,长宽200,左右居中,clipToBoundsYES

    代码 放长方形图 放小图
    完美满足需求,此时imageView只需要再添加一个点击手势即可。

    结论:

    1. UIButtonsetBackgroundImage方法不适合用此类目标控件为非正方形或原始图片为正方形的需求,因为这个方法会无脑将原始图片生拉硬拽成目标控件的大小,即使原始图片各种变形。
    2. UIButtoncontentMode没有任何作用,设置了也没有效果,只有设置UIButtonimageViewcontentMode才有用,并且只有是调用的setImage时才有用。
    3. 由于UIButton继承自UIControl,UIControl有两个属性,contentHorizontalAlignmentcontentVerticalAlignment,这两个属性类似contentMode,是单独分别针对横向和竖向的,且默认都为center,猜测优先级上应该是这两个属性大于buttonimageViewcontentMode,所以如果imageViewcontentMode和这两个属性矛盾,优先遵循这两个属性,即本文button用小图时所遇到的情况。
    4. 实现此需求的两个最佳解决方案:
      • UIButtonsetImage:forState:方法,设置UIButton.imageView.contentModeUIViewContentModeScaleAspectFill,同时设置contentHorizontalAlignmentcontentVerticalAlignment均为fill
      • UIImageView,设置contentModeUIViewContentModeScaleAspectFill,同时添加点击事件。

    相关文章

      网友评论

        本文标题:iOS开发之UIButton的图片显示解惑

        本文链接:https://www.haomeiwen.com/subject/wvlsxqtx.html