Index: ios/chrome/browser/ui/util/CRUILabel+AttributeUtils.mm |
diff --git a/ios/chrome/browser/ui/util/CRUILabel+AttributeUtils.mm b/ios/chrome/browser/ui/util/CRUILabel+AttributeUtils.mm |
new file mode 100644 |
index 0000000000000000000000000000000000000000..dee9ac44434c64255625baba08ca2d6b2e632fa1 |
--- /dev/null |
+++ b/ios/chrome/browser/ui/util/CRUILabel+AttributeUtils.mm |
@@ -0,0 +1,94 @@ |
+// Copyright 2015 The Chromium Authors. All rights reserved. |
+// Use of this source code is governed by a BSD-style license that can be |
+// found in the LICENSE file. |
+ |
+#include "ios/chrome/browser/ui/util/CRUILabel+AttributeUtils.h" |
+ |
+#import <objc/runtime.h> |
+ |
+#import "base/ios/weak_nsobject.h" |
+#include "base/mac/scoped_nsobject.h" |
+#import "ios/chrome/browser/ui/util/label_observer.h" |
+ |
+namespace { |
+// They key under which to associate the line height with the label. |
+const void* const kLineHeightKey = &kLineHeightKey; |
+// Creates an NSNumber from |line_height| and associates it with |label|. |
+void SetAssociatedLineHeight(CGFloat line_height, UILabel* label) { |
+ objc_setAssociatedObject(label, kLineHeightKey, @(line_height), |
+ OBJC_ASSOCIATION_RETAIN_NONATOMIC); |
+} |
+// Returns the line height associated with |label|. |
+CGFloat GetAssociatedLineHeight(UILabel* label) { |
+ return [objc_getAssociatedObject(label, kLineHeightKey) floatValue]; |
+} |
+} |
+ |
+@implementation UILabel (CRUILabelAttributeUtils) |
+ |
+// If there's no text in the label, the line height is whatever is stored in the |
+// associated value. |
+- (CGFloat)cr_lineHeight { |
+ if (!self.text.length || !self.attributedText.string.length) |
+ return GetAssociatedLineHeight(self); |
+ NSParagraphStyle* style = |
+ [self.attributedText attribute:NSParagraphStyleAttributeName |
+ atIndex:0 |
+ effectiveRange:nullptr]; |
+ return style.maximumLineHeight; |
+} |
+ |
+- (void)cr_setLineHeight:(CGFloat)lineHeight { |
+ DCHECK_GT(lineHeight, 0.0); |
+ // If this is the first time the line height is being set, register the |
+ // LabelObserverAction. |
+ if (!GetAssociatedLineHeight(self)) { |
+ LabelObserver* observer = [LabelObserver observerForLabel:self]; |
+ [observer addTextChangedAction:^(UILabel* label) { |
+ label.cr_lineHeight = GetAssociatedLineHeight(label); |
+ }]; |
+ } |
+ |
+ // Store the new line height as an associated object. |
+ SetAssociatedLineHeight(lineHeight, self); |
+ |
+ // If there's no text yet, there's nothing that can be done. The |
+ // LabelObserverAction will call this selector again upon changes to the text. |
+ if (!self.text.length || !self.attributedText.string.length) |
+ return; |
+ |
+ base::scoped_nsobject<NSMutableAttributedString> newString( |
+ [self.attributedText mutableCopy]); |
+ DCHECK([newString length]); |
+ NSParagraphStyle* style = [newString attribute:NSParagraphStyleAttributeName |
+ atIndex:0 |
+ effectiveRange:nullptr]; |
+ if (!style) |
+ style = [NSParagraphStyle defaultParagraphStyle]; |
+ base::scoped_nsobject<NSMutableParagraphStyle> newStyle([style mutableCopy]); |
+ [newStyle setMinimumLineHeight:lineHeight]; |
+ [newStyle setMaximumLineHeight:lineHeight]; |
+ [newString addAttribute:NSParagraphStyleAttributeName |
+ value:newStyle |
+ range:NSMakeRange(0, [newString length])]; |
+ self.attributedText = newString; |
+} |
+ |
+- (void)cr_adjustLineHeightForMaximimumLines:(NSUInteger)maximumLines { |
+ CGSize labelSize = self.bounds.size; |
+ CGFloat lineHeight = self.cr_lineHeight; |
+ CGFloat numberOfLines = floorf(labelSize.height / lineHeight); |
+ CGSize maxSize = CGSizeMake(labelSize.width, CGFLOAT_MAX); |
+ CGSize textSize = [self sizeThatFits:maxSize]; |
+ |
+ // |textSize.height| should be a multiple of |lineHeight|. If this is not the |
+ // case, then it is safer to fit one more line to ensure that the text of the |
+ // label is not cropped. |
+ CGFloat requiredNumberOfLines = ceilf(textSize.height / lineHeight); |
+ if (requiredNumberOfLines > numberOfLines) { |
+ requiredNumberOfLines = MIN(requiredNumberOfLines, maximumLines); |
+ self.cr_lineHeight = floorf(labelSize.height / requiredNumberOfLines); |
+ } |
+} |
+ |
+@end |