【IOS】將字型大小不同的文字底部對齊,ios字型大小對齊
從WP轉IOS了,還是放不下......
在項目中,要實現多個不同大小的文字 底部對齊的效果 像下面這樣:
(想要的效果)
以為用三個UIFont不同的UILabel 之後讓他們底部對齊就可以了,但是效果是下面這樣的:
(不想要的效果)
底部完全不對齊呀,為什麼"1314"比兩邊高出了那麼多呀!!!!強迫症不能忍呀!!!
--------------------------------------------------------------------------------
對比:
1.在Windows Phone中 控制項是相對布局
Windows Phone裡面TextBlock需要設定一個固定的 寬度 和 高度 (至少我是這樣做的)
TextBlock不但可以將文字設定為水平置中、偏左、偏右,還可以通過屬性
text.VerticalContentAlignment=Top/Center/Bottom將文字置於頂部/置中/底部。
2.在IOS中 控制項是絕對布局: 對於一個控制項 需要設定它的frame(包括起始位置、高和寬)
可以通過以下方法直接擷取一個字串的自適應的高度和寬度:(這點覺得比WindowsPhone好)
CGSize labelSize = [@"1314" sizeWithAttributes:@{NSFontAttributeName:kLabelFont}];
而原生的UIlabel只能設定textAlignment文字的水平位移屬性,而無法直接更改豎直方向的位移。
WindowsPhone中要實現上面的效果,只需將三個TextBlock置底,TextBlock內容居下,即可對齊。
(這一點我突然的不確定了,好像很多時候我都是直接設定margin來手動對齊的,有空回WindowsPhone看看再修改。)
彎路:
所以在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);