從WP轉IOS了,還是放不下......
在項目中,要實現如圖多個不同大小的文字 底部對齊的效果 像下面這樣:
(想要的效果)
以為用三個UIFont不同的UILabel 之后讓他們底部對齊就可以了,但是效果是下面這樣的:
(不想要的效果)
底部完全不對齊呀,為什么"1314"比兩邊高出了那么多呀!!!!強迫症不能忍呀!!!
--------------------------------------------------------------------------------
對比:
1.在Windows Phone中 控件是相對布局
Windows Phone里面TextBlock需要設置一個固定的 寬度 和 高度 (至少我是這樣做的)
TextBlock不但可以將文字設置為水平居中、偏左、偏右,還能通過屬性
text.VerticalContentAlignment=Top/Center/Bottom將文字置於頂部/居中/底部。(WP中發現也只能水平方向的)
2.在IOS中 控件是絕對布局: 對於一個控件 需要設置它的frame(包括起始位置、高和寬)
可以通過以下方法直接獲取一個字符串的自適應的高度和寬度:(這點覺得比WindowsPhone好)
CGSize labelSize = [@"1314" sizeWithAttributes:@{NSFontAttributeName:kLabelFont}];
而原生的UIlabel只能設置textAlignment文字的水平偏移屬性,而無法直接更改豎直方向的偏移。
WindowsPhone中要實現上面的效果,只需將三個TextBlock置底,TextBlock內容居下,即可對齊。
(這一點我突然的不確定了,好像很多時候我都是直接設置margin來手動對齊的,有空回WindowsPhone看看再修改。)
[2016.5.25修改] WP中TextBlock也沒有VerticalContentAlignment屬性...
彎路:
所以在IOS處理這個問題的時候,我想着既然三個控件的底部都是對齊了的,只是高度不一樣,能否仿照着WindowsPhone那樣,
將較高UILabel的內容("1314")豎直偏移到最底下呢?
經過查閱 UILabel找到了這些:
不能直接調用 只能通過繼承來重寫
// override points. can adjust rect before calling super. (在調用父類前 可以調整文本內容的位置TextRect)
// label has default content mode of UIViewContentModeRedraw
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines; //重寫來重繪文字區域
- (void)drawTextInRect:(CGRect)rect; //重寫來重繪文本 重寫時調用super可以按默認圖形屬性繪制
所以為了改變text的位置, 我們只需要改變textRectForBounds的返回值rect,並且根據這個rect重繪文本就可以了
1、關於contentMode,該模式為視圖提供了多種模式用以適用框架矩形。如果對除UIVewContentModeRedraw之外的模式(如UIViewContentModeScaleToFill)都不滿足需求,或者說有特定需要自定義繪制視圖,可以設置為此值。那么將在視圖適應框架矩形變化時缺省自動調用setNeedsDispllay或setNeedsDisplayInRect:,從而重繪視圖。
2、而向視圖發送setNeedsDisplay(或setNeedsDisplayInRect:)消息時,無論此時contentMode為何種模式,都將強制調用drawRect:
主要代碼:(這個代碼網上一大把,自己找去)
- (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines { //方法里的形參bounds指的是UILabel的bounds CGRect rc = [super textRectForBounds:bounds limitedToNumberOfLines:numberOfLines]; //text的bounds switch (_verticalAlignment) { case VerticalAlignmentTop: rc.origin.y = bounds.origin.y; break; case VerticalAlignmentBottom: rc.origin.y = bounds.origin.y + bounds.size.height - rc.size.height; break; case VerticalAlignmentMiddle: default: rc.origin.y = bounds.origin.y + (bounds.size.height - rc.size.height) / 2; break; } return rc; } - (void)drawTextInRect:(CGRect)rect { CGRect rc = [self textRectForBounds:rect limitedToNumberOfLines:self.numberOfLines]; [super drawTextInRect:rc]; }
然而發現:對於自適應寬高(CGSize)的Label, 設置了verticalAlignment屬性基本上沒多大區別
origin.x origin.y 均為零 並且SIZE區別幾乎沒有 所有也不會有多大區別。
這里我進行了一個對比:對於字符串@"1314",設置不同的UIFont 觀察UILabel和內部的textRect的大小差別
UIFont 1 50 100
rc(text) 1.000000,2.333333 105.666667,61.000000 208.666667,120.666667
bounds(label) 1.000000,2.193359 105.541992,60.667969 208.349609,120.335938
相差 0,0.139974 0.124675,0.332031 0.317058, 0.330729
rc居然還要比bounds大那么一點點,我認為為了文字不被截取,文字大小還是比其文字邊框還要小的,
並且針對不同大小的UIFont或字體類型,這種小的程度還是不一樣的。
所以就算設置verticalAlignment屬性也發現不了什么區別。
如果只將文字大小設置更大,導致rc比bounds大,那么文字部分就可能會被截取;
如果只增加UILabel的大小,導致rc比bounds小,那么就會看到除了文字外多余的空白區域;
對於后兩者,設置verticalAlignment屬性,就能夠明顯的看到上下偏移了。
所以這種方案對於實現所需效果無效。
終點:
找呀找呀 又找到了另外一種方法,可以通過attributedText屬性讓UILabel顯示富文本
實現一個字符串中包含不同顏色、字號等。
我封裝了一個方法:
// 獲取帶有不同樣式的文字內容 //stringArray 字符串數組 //attributeAttay 樣式數組 - (NSAttributedString *)attributedText:(NSArray*)stringArray attributeAttay:(NSArray *)attributeAttay{ // 定義要顯示的文字內容 NSString * string = [stringArray componentsJoinedByString:@""]; //拼接傳入的字符串數組 // 通過要顯示的文字內容來創建一個帶屬性樣式的字符串對象 NSMutableAttributedString * result = [[NSMutableAttributedString alloc] initWithString:string]; for(NSInteger i = 0; i < stringArray.count; i++){
// 將某一范圍內的字符串設置樣式 [result setAttributes:attributeAttay[i] range:[string rangeOfString:stringArray[i]]]; } // 返回已經設置好了的帶有樣式的文字 return [[NSAttributedString alloc] initWithAttributedString:result]; }
以及其使用
NSDictionary *attributesExtra = @{NSFontAttributeName:kLabelFont,//字號12 NSForegroundColorAttributeName: [UIColor orangeColor]}; NSDictionary *attributesPrice = @{NSFontAttributeName:kPriceFont,//字號18 NSForegroundColorAttributeName: [UIColor orangeColor]}; NSAttributedString *attributedString = [self attributedText:@[@"¥", @"1314", @"起"] attributeAttay:@[attributesExtra,attributesPrice,attributesExtra]]; UILabel *price = [[UILabel alloc]init];
price.attributedText = attributedString; CGRect rect = [attributedString boundingRectWithSize:CGSizeMake(self.width / 2, 100) options:NSStringDrawingUsesLineFragme ntOrigin context:nil]; //此方法獲取到的是自適應的Rect,而不是CGSize 最大Size值為CGSizeMake(self.width / 2, 100)
price.frame = CGRectMake(0,0,rect.size.width, rect.size.height);