iOS - 具有多个动态大小的UILabel和UIImage的Autolayout

时间:2015-12-12 16:04:30

标签: ios autolayout

这是我的情况。我有3个不同的数据(最后忽略一个钱,它不会被包括在内),如下所示:

enter image description here

但是第一个数据(音乐类型)可能会更长,最终应该是这样的:

enter image description here

因此,我必须尊重多种限制: 音乐类型应该跟随事件类型数据,在任何需要的行上。必须包含事件类型的徽标。当然,总宽度不应大于它的超视宽度。

我根本不知道从哪里开始使用音乐类型和事件类型。我试过但我不知道如何使用动态宽度的< =宽度约束。

我正在使用Storyboard。

3 个答案:

答案 0 :(得分:6)

如果您尝试使用大量自动布局规则来解决它,那就太难了。如果您能够使用它,则有一个更简单的建议:NSAttributedStringNSTextAttachment。归属字符串是附加格式的字符串(粗体,斜体,对齐,颜色等),但您也可以将图像附加到属性字符串中,它们只是与文本一起绘制。

以下是帮助您入门的示例:

// create an NSMutableAttributedString that we'll append everything to
let fullString = NSMutableAttributedString(string: "Start of text")

// create our NSTextAttachment
let image1Attachment = NSTextAttachment()
image1Attachment.image = UIImage(named: "awesomeIcon.png")

// wrap the attachment in its own attributed string so we can append it
let image1String = NSAttributedString(attachment: image1Attachment)

// add the NSTextAttachment wrapper to our full string, then add some more text.
fullString.appendAttributedString(image1String)
fullString.appendAttributedString(NSAttributedString(string: "End of text"))

// draw the result in a label
yourLabel.attributedText = fullString

答案 1 :(得分:2)

我认为如果您将图标放在自定义字体中并对所有文本和图标使用单个标签,这将是最简单的。这是我采用这种方法的结果:

result

我使用http://fontello.com/创建了一个自定义字体,其中包含record playerpair of champagne glasses和一个时钟。我把它放在一个名为appfont.ttf的文件中。

以下是我加载字体的方式:

let appFontURL = NSBundle.mainBundle().URLForResource("appfont", withExtension: "ttf")!
let appFontData = NSData(contentsOfURL: appFontURL)!
let appFontDescriptor = CTFontManagerCreateFontDescriptorFromData(appFontData)!

iOS有一个默认的“级联列表”,它用于查找不在字体中的代码点的字形,但如果要为纯文本选择自己的后备字体,则很容易覆盖。我用Papyrus字体来演示:

let baseFontDescriptor = CTFontDescriptorCreateWithNameAndSize("Papyrus", 18)
let fontAttributes: [NSString:AnyObject] = [
    kCTFontCascadeListAttribute : [ baseFontDescriptor ]
]
let fontDescriptor = CTFontDescriptorCreateCopyWithAttributes(appFontDescriptor, fontAttributes)
let font = CTFontCreateWithFontDescriptor(fontDescriptor, 18, nil) as UIFont

接下来,我将所有文本组合成一个大字符串。您可以在此处看到替换最终字符串的不同部分是多么容易:

let recordPlayer = "\u{E802}"
let champagneGlasses = "\u{E801}"
let clock = "\u{E800}"
let nonBreakingSpace = "\u{00A0}"

let music1 = "Electro, Disco, 80's"
let music2 = "Jazz, Latino, Rock and roll, Electro, Beat Music"
let occasion = "After Office"
let time = "9:00 PM - 2:00 AM"

let text1 = "\(recordPlayer) \(music1) \(champagneGlasses)\(nonBreakingSpace)\(occasion)\n\(clock) \(time)"
let text2 = "\(recordPlayer) \(music2) \(champagneGlasses)\(nonBreakingSpace)\(occasion)\n\(clock) \(time)"
let text = text1 + "\n\n\n" + text2

我创建了一个段落样式,用于将包裹的行缩进25个点:

let paragraphStyle = NSMutableParagraphStyle()
paragraphStyle.headIndent = 25

现在我可以创建将自定义字体和段落样式应用于纯文本的NSAttributedString

let richText = NSAttributedString(string: text, attributes: [
        NSFontAttributeName: font,
        NSParagraphStyleAttributeName: paragraphStyle
    ])

此时您需要设置label.attributedText = richText,其中label是与故事板中标签相关联的插座。我在操场上做这一切,所以为了看看它的外观,我创建了一个标签,并根据它来调整尺寸:

let label = UILabel(frame: CGRectMake(0, 0, 320, 0))
label.backgroundColor = UIColor.whiteColor()
label.attributedText = richText
label.numberOfLines = 0
label.bounds.size.height = label.sizeThatFits(CGSizeMake(label.bounds.size.width, CGFloat.infinity)).height

最后,我将标签绘制成图像以查看它:

UIGraphicsBeginImageContextWithOptions(label.bounds.size, true, 1)
label.drawViewHierarchyInRect(label.bounds, afterScreenUpdates: true)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
image

您在我的答案顶部看到了结果。我已经发布了所有代码和fontello config in this gist

答案 2 :(得分:0)

这可能是最直接的解决方案,认为它看起来像是黑客......

想法是,很难正确定位两个标签。仅仅制作一个标签并以某种方式覆盖图标不是很好吗?

事实上!因此,假设您在第一个字符串和第二个字符串之间插入10个空格。现在的问题是,图标应该放在哪里?

事实证明,有一种方便的方法可以让您找到屏幕上绘制特定字符的位置。请参阅此SO post

更具体地说,一个好的方法是:

首先格式化字符串。假设您的图标宽度大约为10个空格。让我们将字符串设为[NSString stringWithFormat:@"%@*spaces here*%@", @"1st string", @"2nd string"]。那么我们需要做的是用上面的SO帖子中的方法找到空格的位置,并将图标移动到该位置。

一些极端情况: 当空间位于两条不同的线上时进行处理。 这意味着没有足够的空间来容纳第一行的图标。您可能希望将其移动到新行。要检测此情况,请检查第一个空格的位置以及该中间部分的最后一个位置。如果它们的y值不同,则它们分为两行。然后我们只需修改字符串,在第一个空格之前添加一个新行,我们就完成了!

也许你想要更精细的控制 - 如果theres 只是足够的空间来显示图标,而不是之后的文字,它可能看起来不太好!

在这种情况下,您可以检测最终空间的x值,以查看它是否太靠近超视图的宽度。如上所述插入换行也解决了这个问题。

希望这有帮助!