[Swift]iOS开发:在视图上绘制文字的3种高效方法以及如何自适应文本高度
来源:互联网 发布:阿里云备案电话 编辑:程序博客网 时间:2024/05/18 07:27
在开始之前我想先着重介绍下 NSAttributedString
NSAttributedString叫做富文本,是一种带有属性的字符串,通过它可以轻松的在一个字符串中表现出多种字体、字号、字体大小等各不相同的风格,还可以对段落进行格式化。
通过 NSAttributedString 我们可以很方便的实现文字排版,得到我们想要的文字效果。具体的属性介绍参考:iOS之文本属性Attributes的使用
接下来我简单介绍下使用方法顺便附上 UILabel 自适应高度的正确写法:
override func viewDidLoad() { super.viewDidLoad() let string = "要显示的长长长长长长长长长长长文字" let paragraph = NSMutableParagraphStyle()//设置文本的段落样式 paragraph.lineBreakMode = .byCharWrapping//换行方式 paragraph.lineSpacing = 10//行距 let font = UIFont.systemFont(ofSize: 15)//设置字体大小 let color = UIColor.yellow//设置字体颜色 let dict:[String:Any] = [ NSFontAttributeName:font, NSForegroundColorAttributeName:color, NSParagraphStyleAttributeName:paragraph ]//属性键值对,这里的属性名称可在我上边给出的文章里找到,一般是以NS开头 let stringSize = string.boundingRect(with: CGSize(width:100,height:CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: dict, context: nil).size//获取字段显示区域的大小(给定宽100,高度无上限) let attribute = NSAttributedString(string: string, attributes: dict) let label = UILabel(frame: CGRect(origin: CGPoint(x:100,y:100), size: stringSize))//这里UILabel的大小一定是上边算好的字段大小 label.backgroundColor = UIColor.brown label.attributedText = attribute//设置UILabel的文本属性 label.numberOfLines = 0//设置多行,必须 view.addSubview(label) }
显示效果:
NSAttributedString结合boundingRect能够完美解决控件自适应文本高度,而且完全不需要自己去算显示区域的大小,方便快捷,推荐使用。
以下正文:
第一种方法:重写 View 的 drawRect 方法,自己画文字
class TextView: UIView { private var _text:String! init(frame: CGRect,text:String) { super.init(frame: frame) _text = text } override func draw(_ rect: CGRect) { _text.draw(in: rect, withAttributes: [NSForegroundColorAttributeName:UIColor.black,NSFontAttributeName:UIFont.systemFont(ofSize: 14)])//给定文字绘制区域为视图大小 } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }}//////////////////////////////////////// override func viewDidLoad() { super.viewDidLoad() let textView = TextView(frame: CGRect(x:100,y:100,width:100,height:100), text: "测试文字测试文字测试文字测试文字测试文字") textView.backgroundColor = UIColor.brown view.addSubview(textView) }
这个方法有很多妙用,比如 iOS 的 UITextView 没有占位符,那么我们就可以重写 UITextView 的 drawRect 方法,自己绘制占位符。具体可参考我的另一篇文章给 UITextView 添加占位符的方法
第二种方法:使用CATextLayer
override func viewDidLoad() { super.viewDidLoad() let string = "要显示的长长长长长长长长长长长长长长长长文本" let stringSize = string.boundingRect(with: CGSize(width:100,height:CGFloat.greatestFiniteMagnitude), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName:UIFont.systemFont(ofSize: 14)], context: nil).size let textLayer = CATextLayer() textLayer.frame = CGRect(x: 100, y: 100, width: stringSize.width, height: stringSize.height*1.03)//这里高度有大约0.03的偏差 textLayer.string = NSAttributedString(string: string, attributes: [NSForegroundColorAttributeName : UIColor.black,NSFontAttributeName:UIFont.systemFont(ofSize: 14)]) textLayer.backgroundColor = UIColor.brown.cgColor textLayer.isWrapped = true//设置是否自动换行 textLayer.contentsScale = UIScreen.main.scale//寄宿图的像素尺寸和视图大小的比例,不设置为屏幕比例文字就会像素化 view.layer.addSublayer(textLayer) }
这里要注意的是计算出的高度和CATextLayer实际显示的高度有偏差,原因不详。
第三种方法:用 CoreText 进行文本布局,因为 CoreText 是基于 CoreGraphics 的,所以需要获取当前的上下文
class TextView:UIView{ override init(frame: CGRect) { super.init(frame: frame) } //一旦你重写drawRect方法,系统会自动创建一个上下文 override func draw(_ rect: CGRect) { super.draw(rect) let ctx = UIGraphicsGetCurrentContext()//获取当前上下文 let size = "我是长长长长长长长长长长长长长长长文字".boundingRect(with: CGSize(width:bounds.width,height:CGFloat(MAXFLOAT)), options: .usesLineFragmentOrigin, attributes: [NSFontAttributeName : UIFont.systemFont(ofSize: 18)], context: nil).size //计算文本显示区域大小 ctx?.translateBy(x: 0, y: size.height) ctx?.scaleBy(x: 1, y: -1) //翻转坐标系,iOS 底层绘制引擎的原点都在左下角 ctx?.setFillColor(UIColor.brown.cgColor) ctx?.fill(CGRect(x: 0, y: 0, width: size.width, height: size.height))//设置显示区域的颜色 let attrstr = NSAttributedString(string: "我是长长长长长长长长长长长长长长长文字", attributes: [NSFontAttributeName : UIFont.systemFont(ofSize: 18),NSForegroundColorAttributeName:UIColor.yellow]) let frameSetter = CTFramesetterCreateWithAttributedString(attrstr)//根据NSAttributedString生成CTFramesetter let path = UIBezierPath(rect: CGRect(x: 0, y: 0, width: size.width, height: size.height)).cgPath//设置文本显示区域大小 let frame = CTFramesetterCreateFrame(frameSetter, CFRangeMake(0, attrstr.length), path, nil)//根据以上两个参数以及文本宽度获取CTFrame CTFrameDraw(frame, ctx!)//绘制文本 } required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") }}//////////////////////////////////////// override func viewDidLoad() { super.viewDidLoad() let textView = TextView(frame: CGRect(x: 100, y: 100, width: 100, height: 100)) view.addSubview(textView) }
另外,无论我们想要绘制什么内容,首要任务就是先获取上下文,你可以把上下文理解成一块画布,有了画布才能画东西;iOS 有三种获取上下文的方式:重写 UIView 的drawRect 和 drawRect inContext 方法会自动生成一个上下文,我们直接在这两个方法里绘制内容,UIView 就能自动渲染出来了,还有一种方法是使用UIGraphicsBeginImageContextWithOptions方法自己创建一个 UIImage 类型的上下文
UIGraphicsBeginImageContextWithOptions(size, true, UIScreen.main.scale)//创建一个基于位图的上下文(context),并将其设置为当前上下文(context),参数:size位图大小,opaque是否为不透明(设置为true能提升性能,scale缩放因子) //这里复制上段代码就行了 let img = UIGraphicsGetImageFromCurrentImageContext()//生成UIImage UIGraphicsEndImageContext()//使用完后一定要记得释放 let imgview = UIImageView(frame: rect) imgview.image = img view.addSubview(imgview)
这种方法应该是三种方法里最高效的,也是最复杂了,想具体深入研究可参考【iOS】使用CoreText实现图文混排
如果你还有其他方法请一定告诉我
- [Swift]iOS开发:在视图上绘制文字的3种高效方法以及如何自适应文本高度
- IOS Swift语言开发 tableView的重用以及自cell的自适应高度
- 如何使用Core Text计算一段文本绘制在屏幕上之后的高度
- 如何使用Core Text计算一段文本绘制在屏幕上之后的高度
- 如何使用Core Text计算一段文本绘制在屏幕上之后的高度
- 简便方法IOS中自适应文字高度
- IOS文本自适应高度
- swift 高度自适应方法
- 【iOS界面开发】iOS下,UILabel自适应高度的方法
- Label文本的自适应高度方法...
- iOS TextView自适应文字高度
- iOS 根据文字自适应高度
- Ios UILabel 自适应 文本高度
- iOS Label文本自适应高度
- iOS开发(OC)——文字的自适应高度和行间距的设置
- 如何在iOS地图上高效的显示大量数据 分类: iOS开发
- iOS开发笔记--UILabel和UITextView自适应文本高度代码
- iOS开发笔记--UILabel和UITextView自适应文本高度代码
- 《linux命令行与shell脚本编程大全》第三版
- SpringMvc的校验框架
- 2017 计蒜之道 复赛 B. Windows 画图(暴力)
- C语言文件权限控制fstat
- Linux网络基础——CRC校验
- [Swift]iOS开发:在视图上绘制文字的3种高效方法以及如何自适应文本高度
- C程序设计进阶week3
- golang: 类型转换和类型断言
- c# 数据文件操作的用法
- CI学习之路
- android studio编译好的apk文件位置
- 中文乱码
- swing中对panel的切换
- 微信预约 乐享其约 会议室预约