swift - Swift:在视图中水平和垂直居中 NSAttributedString
问题描述
你好呀,
我有一个类 CardButton: UIButton 。在这个 CardButton 的 draw 方法中,我想在其中添加和居中(垂直和水平)NSAttributed String,它基本上只是一个 Emoji。结果看起来像这样:
但是,NSAttributedString 只能对齐到容器内水平维度的中心。
我对解决方案的想法:
- 在 CardButton 内创建一个 containerView
- 在它的容器(即 CardButton)中垂直和水平地居中 containerView
- 在 containerView 中添加 NSAttributedString 并调整 containerView 的大小以适应字符串的字体。
所以结果看起来像这样:
我的尝试是这样的:
class CardButton: UIButton {
override func draw(){
//succesfully drawing the CardButton
let stringToDraw = attributedString(symbol, fontSize: symbolFontSize) //custom method to create attributed string
let containerView = UIView()
containerView.backgroundColor = //green
addSubview(containerView)
containerView.translatesAutoresizingMaskIntoConstraints = false
let centerXConstraint = containerView.centerXAnchor.constraint(equalTo: (self.centerXAnchor)).isActive = true
let centerYConstraint = containerView.centerYAnchor.constraint(equalTo: (self.centerYAnchor)).isActive = true
stringToDraw.draw(in: containerView.bounds)
containerView.sizeToFit()
}
}
长话短说,我非常失败。我首先尝试将 containerView 添加到 cardButton,将背景设为绿色,并为其提供固定的宽度和高度,以确保它被正确添加为子视图。它做了。但是一旦我尝试对其进行主动约束,它就完全消失了。
知道如何解决这个问题吗?
解决方案
实现任何特定 UI 设计目标的方法总是不止一种,但下面的过程相对简单,并且已根据您的问题中提出和理解的要求进行了调整。
UIButton.setImage 方法允许将图像分配给 UIButton 而无需显式创建容器。
UIGraphicsImageRenderer 方法允许使用各种组件制作图像,包括 NSAttributedText 和许多自定义形状。
使用这两个工具为您的项目提供基础的过程将是:
- 使用适当的组件和大小渲染图像
- 将渲染图像分配给按钮
可以为这个功能创建一个类,但这里没有探讨。
此外,您的问题提到应用约束时内容会消失。当图像尺寸对于容器来说太大时,可以观察到这种效果,约束将内容定位在视野之外以及可能存在大量其他条件。
以下代码生成上面的图像:
func drawRectangleWithEmoji() -> UIImage {
let renderer = UIGraphicsImageRenderer(size: CGSize(width: 512, height: 512))
let img = renderer.image { (ctx) in
// Create the outer square:
var rectangle = CGRect(x: 0, y: 0, width: 512, height: 512).insetBy(dx: 7.5, dy: 7.5)
var roundedRect = UIBezierPath(roundedRect: rectangle, cornerRadius: 50).cgPath
// MARK: .cgPath creates a CG representation of the path
ctx.cgContext.setFillColor(UIColor.white.cgColor)
ctx.cgContext.setStrokeColor(UIColor.blue.cgColor)
ctx.cgContext.setLineWidth(15)
ctx.cgContext.addPath(roundedRect)
ctx.cgContext.drawPath(using: .fillStroke)
// Create the inner square:
rectangle = CGRect(x: 0, y: 0, width: 512, height: 512).insetBy(dx: 180, dy: 180)
roundedRect = UIBezierPath(roundedRect: rectangle, cornerRadius: 10).cgPath
ctx.cgContext.setFillColor(UIColor.green.cgColor)
ctx.cgContext.setStrokeColor(UIColor.green.cgColor)
ctx.cgContext.setLineWidth(15)
ctx.cgContext.addPath(roundedRect)
ctx.cgContext.drawPath(using: .fillStroke)
// Add emoji:
var fontSize: CGFloat = 144
var attrs: [NSAttributedString.Key: Any] = [
.font: UIFont.systemFont(ofSize: fontSize)//,
//.backgroundColor: UIColor.gray //uncomment to see emoji background bounds
]
var string = "❤️"
var attributedString = NSAttributedString(string: string, attributes: attrs)
let strWidth = attributedString.size().width
let strHeight = attributedString.size().height
attributedString.draw(at: CGPoint(x: 256 - strWidth / 2, y: 256 - strHeight / 2))
// Add NSAttributedString:
fontSize = 56
attrs = [
.font: UIFont.systemFont(ofSize: fontSize),
.foregroundColor: UIColor.brown
]
string = "NSAttributedString"
attributedString = NSAttributedString(string: string, attributes: attrs)
let textWidth = attributedString.size().width
let textHeight = attributedString.size().height
attributedString.draw(at: CGPoint(x: 256 - textWidth / 2, y: 384 - textHeight / 2))
}
return img
}
激活 NSLayoutContraints 然后可以为按钮设置新图像:
override func viewDidLoad() {
super.viewDidLoad()
view = UIView()
view.backgroundColor = .white
let buttonsView = UIView()
buttonsView.translatesAutoresizingMaskIntoConstraints = false
// buttonsView.backgroundColor = UIColor.gray
view.addSubview(buttonsView)
NSLayoutConstraint.activate([
buttonsView.widthAnchor.constraint(equalToConstant: CGFloat(buttonWidth)),
buttonsView.heightAnchor.constraint(equalToConstant: CGFloat(buttonWidth)),
buttonsView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
buttonsView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
let cardButton = UIButton(type: .custom)
cardButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5)
cardButton.setImage(drawRectangleWithEmoji(), for: .normal)
let frame = CGRect(x: 0, y: 0, width: buttonWidth, height: buttonWidth)
cardButton.frame = frame
buttonsView.addSubview(cardButton)
}
我们将不胜感激您的意见以及对所提供代码的建设性审查。
推荐阅读
- html - 悬停时 - 用于菜单项更改背景和文本颜色
- python - python中5(05、10、15...)的倍数还剩多少分钟
- python - 张量流精度为 0.5
- git - 如何在另一个私有 Go 项目(作为模块)中导入私有 Go 库(作为模块)
- sql - ORA-00971: 缺少 SET 关键字
- swift - 在 Xcode 中创建自定义自动编译错误/警告消息
- javascript - 为基于 Web 的游戏创建到不同数据库的多个 SQL 连接
- python - Cv2所有面部特征检测
- python-2.7 - 删除 aws-sam-cli 的 python2-dev 依赖中断安装
- flutter - 如何将使用graphQL的api响应转换为flutter中的Plain Old Dart Object?