在Swift中绘制带有尾巴的消息气泡
消息传递应用程序中的一个常见主题是使消息气泡带有尾巴,这比将一堆块彼此叠放更好,并且这是区分谁发送了特定消息的简便方法。 尽管在您现在的iOS开发经验中,您可能会想知道如何创建这些自定义视图,所以在这篇文章中,我将向您展示如何制作自己的视图!
注意:对于本教程,我已经准备了一个在Github上可用的项目,该项目具有动态调整UITableViewCell
设置的大小。 这是使用Xcode 8.3.3在Swift 3中编写的。
贝济耶救援之路
创建一个方形的消息单元并不难,即使是圆角的消息单元也不错,但是您必须改变通常创建单元的方式,以便在消息底部添加一条尾巴。 在下面,我将指导您完成一些步骤,不仅在消息单元下方绘制一条尾巴,还根据发送消息的人将其向左或向右绘制,类似于iMessage。
为了获得最终结果,我们需要使用UIBezierPath
绘制消息气泡的形状,然后用所需的颜色填充它。 乍一看似乎令人望而生畏,但想起来就像在纸上画一个正方形一样。 您从给定点开始,思考(0,0),然后开始将第一条线绘制到下一个点(1,0)。 再过三边,您又回到起点,准备关闭形状并填充它。现在,我们只需要在代码中执行相同的操作即可!
绘制邮件正文
跳至MessageBubbleView
类,让我们开始在draw(_ rect)
编写代码。 (删除调用super.drawRect
因为我们将提供自己的绘图代码。)现在,我们可以使用以下代码开始路径:
让bezierPath = UIBezierPath()
bezierPath.move(收件人:CGPoint(x:rect.minX,y:rect.minY))
move
视为拿起铅笔并将其放置在给定点的代码。 这将是我们信息泡沫的起点。 现在我们要画顶线。
bezierPath.addLine(至:CGPoint(x:rect.maxX,y:rect.minY))
这将在rect的最右边绘制一条线,即maxX
。 现在,我们可以遵循相同的逻辑来绘制其他三个边缘。
bezierPath.addLine(至:CGPoint(x:rect.maxX,y:rect.maxY-10.0))
bezierPath.addLine(至:CGPoint(x:rect.minX,y:rect.maxY-10.0))
bezierPath.addLine(至:CGPoint(x:rect.minX,y:rect.minY))
现在您可能想知道为什么我没有一直画线一直到rect或maxY
的底部边缘。 这是因为我为绘制尾巴留了10.0点的空间。 我鼓励调整这些值,并查看您自己的代码中的不同结果!
画尾巴
现在添加尾巴。 我们将在这里再次使用move
功能。 就像您从rect的左上边缘(我们刚刚结束最后一行的地方)拿起铅笔并将其移动到尾巴的起点一样。 在此示例中,我将绘制一条指向右下方的尾巴,然后绘制一条平坦的边缘,该边缘再次向上并与我们的邮件正文相遇。
bezierPath.move(至:CGPoint(x:rect.maxX-25.0,y:rect.maxY-10.0))
bezierPath.addLine(至:CGPoint(x:rect.maxX-10.0,y:rect.maxY))
bezierPath.addLine(至:CGPoint(x:rect.maxX-10.0,y:rect.maxY-10.0))
我们有自己的形状! 但是,如果您运行该代码,则会发现看不到它。 这是因为我们需要关闭路径并填写。
UIColor.lightGray.setFill()
bezierPath.fill()
bezierPath.close()
大! 我们将路径封闭并用浅灰色填充。 现在,我们的draw
方法应如下所示:
覆盖func draw(_ rect:CGRect){
让bezierPath = UIBezierPath()
//绘制主体
bezierPath.move(收件人:CGPoint(x:rect.minX,y:rect.minY))
bezierPath.addLine(至:CGPoint(x:rect.maxX,y:rect.minY))
bezierPath.addLine(至:CGPoint(x:rect.maxX,y:rect.maxY-10.0))
bezierPath.addLine(至:CGPoint(x:rect.minX,y:rect.maxY-10.0))
bezierPath.addLine(至:CGPoint(x:rect.minX,y:rect.minY))
//画尾巴
bezierPath.move(至:CGPoint(x:rect.maxX-25.0,y:rect.maxY-10.0))
bezierPath.addLine(至:CGPoint(x:rect.maxX-10.0,y:rect.maxY))
bezierPath.addLine(至:CGPoint(x:rect.maxX-10.0,y:rect.maxY-10.0))
UIColor.lightGray.setFill()
bezierPath.fill()
bezierPath.close()
}
生成并运行项目,您应该得到以下结果:
移尾
看起来不错! 现在,如果尾巴根据发送消息的人而移动,那就太好了。 为此,我们将在MessageBubbleView
上设置一个变量,该变量用作确定尾部位置的标志。
var currentUserIsSender = true {
didSet {
setNeedsDisplay()
}
}
现在,我们有一个名为currentUserIsSender
的公共属性,默认为true
。 使用Swift的didSet
可以让我们通过调用setNeedsDisplay
通知该视图,该属性更改后需要重绘自身。 现在,在我们的draw
方法中,我们可以基于此值调整尾部。
如果currentUserIsSender {
bezierPath.move(至:CGPoint(x:rect.maxX-25.0,y:rect.maxY-10.0))
bezierPath.addLine(至:CGPoint(x:rect.maxX-10.0,y:rect.maxY))
bezierPath.addLine(至:CGPoint(x:rect.maxX-10.0,y:rect.maxY-10.0))
}其他{
//在左边画尾巴
}
在这里,我只是根据设置的标志将当前的尾部绘制代码移动到了if/else
语句中。 现在,我们只需要添加代码以在左侧绘制尾巴即可。 所有需要做的是,而不是从maxX
开始,我们从minX
开始, minX
所示:
bezierPath.move(至:CGPoint(x:rect.minX + 25.0,y:rect.maxY-10.0))
bezierPath.addLine(至:CGPoint(x:rect.minX + 10.0,y:rect.maxY))
bezierPath.addLine(至:CGPoint(x:rect.minX + 10.0,y:rect.maxY-10.0))
现在,让我们添加一种更新currentUserIsSender
标志的方法。 在MessageTableViewCell
的configure
方法中添加一个新属性:
func configure(withMessage消息:字符串,currentUserIsSender:布尔){
messageLabel.text =消息
messageContainerView.currentUserIsSender = currentUserIsSender
}
然后,我们可以添加一些逻辑来切换我们的cellForRow
方法中的所有其他消息的标志:
让currentUserIsSender = indexPath.row%2 == 0
cell.configure(withMessage:消息,currentUserIsSender:currentUserIsSender)
好了,现在我们有了一条尾巴,可以根据发送消息的人来选择! 继续构建并运行项目以查看结果。
太棒了! 🎉
现在,您正在使用UIBezierPath
运行! 您现在可以做的事情还很多,我鼓励您进一步尝试该项目! 将您的想法写在纸上,然后将其转换为代码,甚至更容易。
您可以尝试的一些想法是:
- 根据发送者的不同来改变消息的颜色
- 调整尾巴的形状和位置
- 根据发送消息的人调整文本对齐方式
将来,我计划通过更多示例来扩展该项目。 在此之前,请试用当前项目,还可以通过从我的Github存储库中检出finished-project
分支来找到完工项目。
如果您有任何疑问,请随时发表评论,我会尽力与您联系! 如果您喜欢这篇文章和/或觉得它很有用,请👏并分享!