Swift 3.0 iOS 如何绘制 1px 宽的描边

本文介绍如何在iOS应用中使用Swift自定义UIView来绘制精确的1px圆角矩形边框,并解决了边框超出界限及背景颜色不一致等问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

自定义 UIView 绘制 1px 边框描边

我也是初学者,在研究如何制作 1px 的圆角矩形边框时整了半天,也查了半天,终于整出来了,分享下给新手们。
推荐教程 斯坦福大学 和 iOS 10 swift 教程 ,可以直接在 iTunes U 中下载,国内下载的话,需要代理才会快, 不然特别慢 每个视频在 1.2G左右 90分钟(https://itunes.apple.com/cn/course/developing-ios-10-apps-with-swift/id1198467120)
这个讲的特别系统

1, 原理 pt 与 px

苹果手机的原始尺寸是 375 x 667, 也是最初手机的屏幕尺寸,后来的手机都是以这个为原始值缩放的。
比如 iphone 6/7 屏幕是 750 x 1334 正好是这个长宽的 2 倍 iPhone 6/7 和 iPhone 6/7 Plus 都是它的 3
在 UI 中,我们是以 pt (point 即 ) 为单位的,要获取当前手机 1pt 是多少 px 用下面的方法获得

  • 1pt = 1px ( iPhone 5s 之前 )
  • 1pt = 2px ( iPhone 6/7 )
  • 1pt = 3px ( iPhone 6/7 Plus )
let screenScale = UIScreen.main.scale
// 如上所说 iPhone 6/7 上该值是 2.0

知道了这个之后,我们就可以计算出1px 在屏幕上所占的距离是多少,也就是

let 1pxWidth = 1 / UIScreen.main.scale

1pt = 2px

2,自定义 UIView 圆角矩形+描边

下面是基础知识了,不知道的可以再百度搜搜别的教程,这里只是讲1px的事,我只注释一些地方
这里假设你已经知道如何自己绘制东西了

// 因为我们要做一个能在 `StoryBoard` 中使用的 `UIView`

var radius: CGFloat = 10    // 圆角
var lineWidth: CGFloat = 1   // 描边宽度
var lineColor: UIColor = UIColor.orange    // 描边颜色
var fillColor: UIColor = UIColor.white      // 填充颜色


let contentRect = self.bounds       //绘制圆角矩形的「面板」大小
let path = UIBezierPath(roundedRect: contentRect, cornerRadius: radius)     //创建圆角矩形路径
path.lineWidth = lineWidth      //设置描边颜色

lineColor.setStroke()   //设置描边颜色
fillColor.setFill()     //设置填充颜色

path.fill()             //填充
path.stroke()           //描边

这样得出的结果是这样的,有没有发现有点问题,继续看下面

1

3,解决描边问题

2

其实代码都是对的,只是描边的时候它会以路径为中心向两边描边,如图: 黑线是 Bounds, 它只会显示Bounds 内的东西。所以描边被裁掉了外面的问题

那么如何解决呢?
答案: 在绘制的时候定义 圆角矩形的绘制边界小于现在的 Bounds

let contentRect = self.bounds
let path = UIBezierPath(roundedRect: contentRect, cornerRadius: radius) 
// 也就是定义 该方法中的参数  roundedRect 小一些

// 幸运的是 CGRect 里有一个方法可以实现向内部偏移 insetBy(dx: CGFloat, dy: CGFloat)
// 左右收缩 dx 大小, 上下收缩 dy 大小

let contentRect = self.bounds.insetBy(dx: lineWidth/2, dy: lineWidth/2)
// 如上,向内收缩描边的一半大小,这样可以在占满两个 Bounds 的同时描边正常。

现在是这样的: (黑边只是为了标明 Bounds,那个是没有的,不要在意)

3

4, 背景问题

是不是感觉到这了就没什么问题了? 其实还是有问题的,在使用中就会发现
问题是这样的:
如果你在一个非纯白背景中使用这个自定义的 UIView,你就会发现会出现下面这样的情况

4

我们设置了自己的 填充色描边色, 那么为什么四角还是白色的呢?
其实我们还需要设置一个地方,就是设置初始背景色是透明,然后再在上面绘制东西
也就是 UIColor.clear //透明色

这个需要写在 init() 方法中
说几点先: 因为我们是自定义的 UIView 我们需要重写 init(frame: CGRect)init(coder: NSCoder) 两个方法,我们的背景设置就写在这两个方法中。

override init(frame: CGRect) {
    super.init(frame: frame)
    self.backgroundColor = UIColor.clear    // 设置背景透明
}

required init?(coder: NSCoder) {      // 注意,这个init 方法是 required 而且是 Optional 值
    super.init(coder: coder)
    self.backgroundColor = UIColor.clear    // 设置背景透明
}

然后我们得到我们需要的结果了

5

总结:完整代码

说了这么多希望你能有自己思路了,现在可以在 StoryBoard 中嵌套这个 UIView 得到你想要的结果了。
这里还说一下,现在这个代码是可以在 StoryBoard 中设置参数的, 如果不了解,百度 @IBDesinable

效果如图

StoryBoard Design

import UIKit

@IBDesignable // 让该UIView 可以显示在 StoryBoardclass RoundedRectView: UIView {

    // MARK: - 设置参数
    @IBInspectable // 该关键字让该参数可以显示在 StoryBoard 的右边设置面板中
    var radius: CGFloat = 10 { didSet{ setNeedsDisplay() } }

    @IBInspectable
    var lineWidth: CGFloat = 1 / UIScreen.main.scale { //初始值也设为 1px
        didSet{
            lineWidth = lineWidth / UIScreen.main.scale
            setNeedsDisplay() // 我们如果想调用 Draw() 方法的时候使用这个方法,!!!不能直接调用draw()方法!!!
        }
    }

    @IBInspectable
    var lineColor: UIColor = UIColor.lightGray { didSet{ setNeedsDisplay() } }

    @IBInspectable
    var fillColor: UIColor = UIColor.white { didSet{ setNeedsDisplay() } }



    //MARK: - Draw()

    override func draw(_ rect: CGRect) {
        let contentRect = self.bounds.insetBy(dx: lineWidth/2, dy: lineWidth/2)
        let path = UIBezierPath(roundedRect: contentRect, cornerRadius: radius)
        path.lineWidth = lineWidth
        lineColor.setStroke()
        fillColor.setFill()
        path.fill()
        path.stroke()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.backgroundColor = UIColor.clear
    }

    required init?(coder: NSCoder) {
        super.init(coder: coder)
        self.backgroundColor = UIColor.clear
    }
}

使用效果图: 1px 描边

Dis

其它用处

效果图

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

十月ooOO

许个愿,我帮你实现

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值