Cập nhật
Trong Swift, chúng tôi không phải đối phó với những thứ cũ của iOS5 bên cạnh cú pháp ngắn hơn để mọi thứ trở nên thực sự đơn giản:
Swift 5
func attributedString(from string: String, nonBoldRange: NSRange?) -> NSAttributedString {
let fontSize = UIFont.systemFontSize
let attrs = [
NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: fontSize),
NSAttributedString.Key.foregroundColor: UIColor.black
]
let nonBoldAttribute = [
NSAttributedString.Key.font: UIFont.systemFont(ofSize: fontSize),
]
let attrStr = NSMutableAttributedString(string: string, attributes: attrs)
if let range = nonBoldRange {
attrStr.setAttributes(nonBoldAttribute, range: range)
}
return attrStr
}
Swift 3
func attributedString(from string: String, nonBoldRange: NSRange?) -> NSAttributedString {
let fontSize = UIFont.systemFontSize
let attrs = [
NSFontAttributeName: UIFont.boldSystemFont(ofSize: fontSize),
NSForegroundColorAttributeName: UIColor.black
]
let nonBoldAttribute = [
NSFontAttributeName: UIFont.systemFont(ofSize: fontSize),
]
let attrStr = NSMutableAttributedString(string: string, attributes: attrs)
if let range = nonBoldRange {
attrStr.setAttributes(nonBoldAttribute, range: range)
}
return attrStr
}
Sử dụng:
let targetString = "Updated 2012/10/14 21:59 PM"
let range = NSMakeRange(7, 12)
let label = UILabel(frame: CGRect(x:0, y:0, width:350, height:44))
label.backgroundColor = UIColor.white
label.attributedText = attributedString(from: targetString, nonBoldRange: range)
label.sizeToFit()
Tiền thưởng: Quốc tế hóa
Một số người bình luận về quốc tế hóa. Cá nhân tôi nghĩ rằng điều này nằm ngoài phạm vi của câu hỏi này nhưng với mục đích hướng dẫn thì đây là cách tôi sẽ làm
// Date we want to show
let date = Date()
// Create the string.
// I don't set the locale because the default locale of the formatter is `NSLocale.current` so it's good for internationalisation :p
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
let targetString = String(format: NSLocalizedString("Update %@", comment: "Updated string format"),
formatter.string(from: date))
// Find the range of the non-bold part
formatter.timeStyle = .none
let nonBoldRange = targetString.range(of: formatter.string(from: date))
// Convert Range<Int> into NSRange
let nonBoldNSRange: NSRange? = nonBoldRange == nil ?
nil :
NSMakeRange(targetString.distance(from: targetString.startIndex, to: nonBoldRange!.lowerBound),
targetString.distance(from: nonBoldRange!.lowerBound, to: nonBoldRange!.upperBound))
// Now just build the attributed string as before :)
label.attributedText = attributedString(from: targetString,
nonBoldRange: nonBoldNSRange)
Kết quả (Giả sử tiếng Anh và tiếng địa phương tiếng Nhật có sẵn)
Câu trả lời trước cho iOS6 trở lên (Objective-C vẫn hoạt động):
Trong iOS6 UILabel
, UIButton
, UITextView
, UITextField
, hỗ trợ do chuỗi đó có nghĩa là chúng ta không cần phải tạo ra CATextLayer
như là người nhận của chúng tôi cho các chuỗi do. Hơn nữa, để tạo chuỗi được gán, chúng ta không cần phải chơi với CoreText nữa :) Chúng ta có các lớp mới trong obj-c Foundation.framework like NSParagraphStyle
và các hằng số khác sẽ giúp cuộc sống của chúng ta dễ dàng hơn. Yay!
Vì vậy, nếu chúng ta có chuỗi này:
NSString *text = @"Updated: 2012/10/14 21:59"
Chúng ta chỉ cần tạo chuỗi được gán:
if ([_label respondsToSelector:@selector(setAttributedText:)])
{
// iOS6 and above : Use NSAttributedStrings
// Create the attributes
const CGFloat fontSize = 13;
NSDictionary *attrs = @{
NSFontAttributeName:[UIFont boldSystemFontOfSize:fontSize],
NSForegroundColorAttributeName:[UIColor whiteColor]
};
NSDictionary *subAttrs = @{
NSFontAttributeName:[UIFont systemFontOfSize:fontSize]
};
// Range of " 2012/10/14 " is (8,12). Ideally it shouldn't be hardcoded
// This example is about attributed strings in one label
// not about internationalisation, so we keep it simple :)
// For internationalisation example see above code in swift
const NSRange range = NSMakeRange(8,12);
// Create the attributed string (text + attributes)
NSMutableAttributedString *attributedText =
[[NSMutableAttributedString alloc] initWithString:text
attributes:attrs];
[attributedText setAttributes:subAttrs range:range];
// Set it in our UILabel and we are done!
[_label setAttributedText:attributedText];
} else {
// iOS5 and below
// Here we have some options too. The first one is to do something
// less fancy and show it just as plain text without attributes.
// The second is to use CoreText and get similar results with a bit
// more of code. Interested people please look down the old answer.
// Now I am just being lazy so :p
[_label setText:text];
}
Có một vài bài đăng blog giới thiệu hay ở đây từ những người ở invasivecode giải thích với nhiều ví dụ sử dụng hơn NSAttributedString
, hãy tìm "Giới thiệu về NSAttributionString cho iOS 6" và "Chuỗi được gán cho iOS bằng Trình tạo giao diện" :)
PS: Trên mã nó sẽ hoạt động nhưng nó được biên dịch não. Tôi hy vọng nó là đủ :)
Câu trả lời cũ cho iOS5 trở xuống
Sử dụng CATextLayer với NSAttributionString! nhẹ hơn nhiều và đơn giản hơn 2 UILabels. (iOS 3.2 trở lên)
Thí dụ.
Đừng quên thêm khung QuartzCore (cần thiết cho CALayers) và CoreText (cần thiết cho chuỗi được gán.)
#import <QuartzCore/QuartzCore.h>
#import <CoreText/CoreText.h>
Ví dụ dưới đây sẽ thêm một lớp con vào thanh công cụ của bộ điều khiển điều hướng. à la Mail.app trong iPhone. :)
- (void)setRefreshDate:(NSDate *)aDate
{
[aDate retain];
[refreshDate release];
refreshDate = aDate;
if (refreshDate) {
/* Create the text for the text layer*/
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:@"MM/dd/yyyy hh:mm"];
NSString *dateString = [df stringFromDate:refreshDate];
NSString *prefix = NSLocalizedString(@"Updated", nil);
NSString *text = [NSString stringWithFormat:@"%@: %@",prefix, dateString];
[df release];
/* Create the text layer on demand */
if (!_textLayer) {
_textLayer = [[CATextLayer alloc] init];
//_textLayer.font = [UIFont boldSystemFontOfSize:13].fontName; // not needed since `string` property will be an NSAttributedString
_textLayer.backgroundColor = [UIColor clearColor].CGColor;
_textLayer.wrapped = NO;
CALayer *layer = self.navigationController.toolbar.layer; //self is a view controller contained by a navigation controller
_textLayer.frame = CGRectMake((layer.bounds.size.width-180)/2 + 10, (layer.bounds.size.height-30)/2 + 10, 180, 30);
_textLayer.contentsScale = [[UIScreen mainScreen] scale]; // looks nice in retina displays too :)
_textLayer.alignmentMode = kCAAlignmentCenter;
[layer addSublayer:_textLayer];
}
/* Create the attributes (for the attributed string) */
CGFloat fontSize = 13;
UIFont *boldFont = [UIFont boldSystemFontOfSize:fontSize];
CTFontRef ctBoldFont = CTFontCreateWithName((CFStringRef)boldFont.fontName, boldFont.pointSize, NULL);
UIFont *font = [UIFont systemFontOfSize:13];
CTFontRef ctFont = CTFontCreateWithName((CFStringRef)font.fontName, font.pointSize, NULL);
CGColorRef cgColor = [UIColor whiteColor].CGColor;
NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
(id)ctBoldFont, (id)kCTFontAttributeName,
cgColor, (id)kCTForegroundColorAttributeName, nil];
CFRelease(ctBoldFont);
NSDictionary *subAttributes = [NSDictionary dictionaryWithObjectsAndKeys:(id)ctFont, (id)kCTFontAttributeName, nil];
CFRelease(ctFont);
/* Create the attributed string (text + attributes) */
NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:text attributes:attributes];
[attrStr addAttributes:subAttributes range:NSMakeRange(prefix.length, 12)]; //12 is the length of " MM/dd/yyyy/ "
/* Set the attributes string in the text layer :) */
_textLayer.string = attrStr;
[attrStr release];
_textLayer.opacity = 1.0;
} else {
_textLayer.opacity = 0.0;
_textLayer.string = nil;
}
}
Trong ví dụ này tôi chỉ có hai loại phông chữ khác nhau (đậm và bình thường) nhưng bạn cũng có thể có kích thước phông chữ khác nhau, màu sắc khác nhau, chữ nghiêng, gạch chân, v.v. Hãy xem các khóa chuỗi thuộc tính NSAttributionString / NSMutableAttributionString và CoreText .
Hy vọng nó giúp