在 Swift 2.0 中自定义 UIButton 外观

Posted

技术标签:

【中文标题】在 Swift 2.0 中自定义 UIButton 外观【英文标题】:Customizing UIButton Appearance in Swift 2.0 【发布时间】:2015-11-15 00:54:03 【问题描述】:

我想在 Swift 2.0 中自定义一个 UIButton,如下图所示:

http://i.imgur.com/P8nGdHd.png

渐变从:#b1ffb1(浅绿色)到 #e7e7e7(白色/灰色) 描边:2dp 宽度,颜色为#999999(纯灰色) 20dp 的左上角/右上角半径

按下此按钮会变成灰色渐变

按下渐变:#717171(深灰色)到 #acacac(浅灰色) 笔画相同 半径相同

我的尝试:

我的应用中有很多按钮,几个按钮会有相同的外观。所以我觉得为我的自定义按钮创建单独的类是最佳的。

这是我复制那个按钮的原始尝试:

import Foundation
import UIKit
import QuartzCore

class CustomButtonTopGreen: UIButton 


required init(coder aDecoder: NSCoder) 
    super.init(coder: aDecoder)!
    self.layer.cornerRadius = 20;
    self.layer.borderColor = UIColor.grayColor().CGColor
    self.layer.borderWidth = 2
    self.backgroundColor = UIColor.greenColor()
    self.tintColor = UIColor.whiteColor()   
    

产量: http://i.imgur.com/iUdX81W.png

所以我的问题是:

如何合并十六进制颜色代码? 如何添加渐变? 如何自定义各个角? 如何向此按钮添加“按下时”视图?

我对该主题进行了很多研究,但没有运气。我尝试将代码示例粘贴到我的代码中,尝试对其进行操作以查看它是否适合,但我仍然会遇到错误。

任何帮助将不胜感激!

【问题讨论】:

最简单的方法是对图像进行 Photoshop 处理并将其用作按钮的背景图像!!!! 这实际上是我现在所拥有的,问题是我希望我的按钮看起来尽可能与我的 android 版本中的按钮相同(这都是在代码中完成的)。我不确定,也许我对它有点强迫症。 你不只是在android中截取你的按钮,并将其转换为所需大小的图像吗? 【参考方案1】:

您可以继承 UIButton 并在 drawRect 中创建一个子类,如下所示:

import UIKit


class CustomButtonTopGreen: UIButton 
    let cornerRadius:CGFloat = 20.0
    let borderLineWidth:CGFloat = 2.0
    var bezierPath:UIBezierPath = UIBezierPath()
    var gradientLayer:CAGradientLayer = CAGradientLayer()
    var bottomLayer:UInt32 = 0

    override func drawRect(rect: CGRect) 
        if self.state != UIControlState.Highlighted
        
            self.drawBorder()

            let gradient: CAGradientLayer = CAGradientLayer()
            gradient.frame = self.bounds
            gradient.colors = [self.UIColorFromRGB(0xb1ffb1).CGColor, self.UIColorFromRGB(0xe7e7e7).CGColor]
            self.gradientLayer = gradient

            let mask = CAShapeLayer();
            mask.frame = self.bounds;

            mask.path = self.bezierPath.CGPath;
            mask.fillColor = UIColor.blackColor().CGColor;
            mask.strokeColor = UIColor.blackColor().CGColor;
            gradient.mask = mask;

            let shape = CAShapeLayer();
            shape.path = self.bezierPath.CGPath
            shape.lineWidth = borderLineWidth
            shape.strokeColor = UIColor.lightGrayColor().CGColor
            shape.fillColor = UIColor.clearColor().CGColor

            self.gradientLayer.removeFromSuperlayer()
            self.layer.insertSublayer(gradient, atIndex: bottomLayer)
            self.layer.addSublayer(shape)
            self.bottomLayer++

        else
            self.drawBorder()
            let gradient: CAGradientLayer = CAGradientLayer()
            gradient.frame = self.bounds
            gradient.colors = [self.UIColorFromRGB(0x717171).CGColor, self.UIColorFromRGB(0xacacac).CGColor]
            self.gradientLayer = gradient
            let mask = CAShapeLayer();
            mask.frame = self.bounds;

            self.bezierPath.lineWidth = 4.0
            mask.path = self.bezierPath.CGPath;
            mask.fillColor = UIColor.blackColor().CGColor;
            mask.strokeColor = UIColor.blackColor().CGColor;
            gradient.mask = mask;

            let shape = CAShapeLayer();
            shape.path = self.bezierPath.CGPath
            shape.lineWidth = borderLineWidth
            shape.strokeColor = UIColor.lightGrayColor().CGColor
            shape.fillColor = UIColor.clearColor().CGColor

            self.gradientLayer.removeFromSuperlayer()
            self.layer.insertSublayer(gradient, atIndex: bottomLayer)
            self.layer.addSublayer(shape)
            self.bottomLayer++
        
    

    func drawBorder()
    let path: UIBezierPath = UIBezierPath()
    path.moveToPoint(CGPoint(x: borderLineWidth, y: self.bounds.size.height-borderLineWidth))
    path.addLineToPoint(CGPoint(x: borderLineWidth, y: cornerRadius+borderLineWidth))
    path.addQuadCurveToPoint(CGPoint(x: cornerRadius+borderLineWidth, y: borderLineWidth), controlPoint:CGPoint(x:borderLineWidth, y:borderLineWidth))
    path.addLineToPoint(CGPoint(x: self.bounds.size.width-cornerRadius-borderLineWidth, y: borderLineWidth))
    path.addQuadCurveToPoint(CGPoint(x: self.bounds.size.width-borderLineWidth, y: cornerRadius+borderLineWidth), controlPoint: CGPointMake(self.bounds.size.width-borderLineWidth, borderLineWidth))
    path.addLineToPoint(CGPoint(x: self.bounds.size.width-borderLineWidth, y: self.bounds.size.height-borderLineWidth))
    path.closePath()
    path.lineWidth = borderLineWidth
    self.bezierPath = path


    func UIColorFromRGB(rgbValue: UInt) -> UIColor 
        return UIColor(
            red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
            alpha: CGFloat(1.0)
        )
    

    override var highlighted: Bool 
        didSet 

            self.setNeedsDisplay()

        
    



您应该想出一个更好的方法来用突出显示的渐变层替换普通的渐变层,但它可以按原样工作。

【讨论】:

这很好用!虽然我有一个小问题:当我运行代码时,按钮两侧的笔画看起来有点不稳定。我不知道它是否只是 Xcode 模拟器(我尝试了一堆,但给了我相同的结果)。这对我来说是这样的:i.imgur.com/Z2T8ppl.png我觉得侧击应该被抛光 1 px 或 2 hmmm 很奇怪,代码中出现了一些“分隔符”错误i.imgur.com/gi5QiAd.png 我尝试在建议的逗号中折腾,但 Swift 似乎不喜欢它 我想我没有正确粘贴它。它缺少一个“)”并且该方法的下半部分没有更新。我已经更新了。请考虑接受我的回答。 现在看起来不错!我接受了答案!出于好奇,如果我要制作带有底角的按钮,我应该如何操作您的代码? 你只需要改变drawBorder函数。查看路径的绘制方式。在 ios 中,y 值越大,屏幕下方的点越多。它从bottomLeftCorner开始,在左上角Radius开始的地方添加一条线,绘制角,将顶线绘制到下一个cornerRadius,绘制那个角等等。在底部有cornerRadiuses。从左上角 path.moveToPoint(CGPoint(x:borderLineWidth,y:borderLineWidth)) 开始,在右上角添加一条直线 path.addLineToPoint(....) 然后在圆角处用四边形曲线跟踪其余部分。

以上是关于在 Swift 2.0 中自定义 UIButton 外观的主要内容,如果未能解决你的问题,请参考以下文章

通过 UIButton 选择一个单元格 - CollectionViewCell - Swift

使用 Swift 2.0 更新 UIButton 图像

iOS 应用中自定义 UIButton 旁边出现“蓝框”

UITableViewRowAction 在 Swift 中自定义标题字体大小

使用 swift 在 xcode 6 中自定义 NSValueTransformer

在 Swift 4 中自定义 UISearchBar