自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS屏幕適配實(shí)踐淺談

移動(dòng)開(kāi)發(fā)
在 iOS 平臺(tái)上,蘋(píng)果爸爸對(duì)適配的支持個(gè)人感覺(jué)很不人性化,提供了 AutoLayout、sizeClass 等技術(shù),感覺(jué)沒(méi)有前端類似 flexBox 這樣的技術(shù)來(lái)得靈活。像是點(diǎn)歪了技能樹(shù),過(guò)于重視使用 xib 配置 UI,但很多碼農(nóng)還是習(xí)慣純代碼編程。Cocoa 沒(méi)有 css 這樣的純布局文件,導(dǎo)致很多時(shí)候我們將布局、UI 和邏輯寫(xiě)在一起,十分混亂、冗長(zhǎng)。

前端開(kāi)發(fā)的屏幕適配其實(shí)算是基本功,每個(gè)碼農(nóng)在長(zhǎng)期實(shí)踐中都有自己的總結(jié)。

在 iOS 平臺(tái)上,蘋(píng)果爸爸對(duì)適配的支持個(gè)人感覺(jué)很不人性化,提供了 AutoLayout、sizeClass 等技術(shù),感覺(jué)沒(méi)有前端類似 flexBox 這樣的技術(shù)來(lái)得靈活。像是點(diǎn)歪了技能樹(shù),過(guò)于重視使用 xib 配置 UI,但很多碼農(nóng)還是習(xí)慣純代碼編程。Cocoa 沒(méi)有 css 這樣的純布局文件,導(dǎo)致很多時(shí)候我們將布局、UI 和邏輯寫(xiě)在一起,十分混亂、冗長(zhǎng)。

下面簡(jiǎn)單介紹下在實(shí)踐中適配屏幕的方向思路,拋磚引玉。

從設(shè)計(jì)到代碼:溝通與標(biāo)準(zhǔn)

App 的 UI 界面是由設(shè)計(jì)人員(產(chǎn)品,UI)繪制的,然后由開(kāi)發(fā)實(shí)現(xiàn),雙方要有良好的溝通,并且把設(shè)計(jì)內(nèi)容標(biāo)準(zhǔn)化、文檔化。

對(duì)設(shè)計(jì)方來(lái)說(shuō),適配的規(guī)則總是在設(shè)計(jì)師心中的,是按比例的縮放,還是固定的間距,是公用一套規(guī)則,還是在大屏下有特殊的布局,都需要有明確方式傳達(dá)給耿直的碼農(nóng)們。

iOS屏幕適配實(shí)踐淺談

 

一般常見(jiàn)的布局方式有:

  • 固定間距:在不同尺寸下,間距總是固定。
  • 流式布局:文字,圖片等在不同屏幕下流式排布,比如大屏下一行顯示四張圖片,小屏一行三張,圖片尺寸固定。
  • 比例放大:間距,文字大小,圖片大小等比例放大。
  • 保持比值:兩個(gè)UI元素或者圖片的長(zhǎng)寬等屬性保持一定的比值。
  • 對(duì)齊:元素間按某個(gè)方向?qū)R。

設(shè)計(jì)師需要將這些布局規(guī)則標(biāo)注清楚,有利溝通,也方便日后追溯。

對(duì)于一些通用 UI 組件,要進(jìn)行標(biāo)準(zhǔn)化,設(shè)計(jì)上有利于 App 風(fēng)格統(tǒng)一,實(shí)現(xiàn)上也方便開(kāi)發(fā)進(jìn)行封裝。

iOS屏幕適配實(shí)踐淺談

UI 的搭建:xib VS 純代碼

蘋(píng)果一直用 xib 來(lái)標(biāo)榜他們家 App 開(kāi)發(fā)簡(jiǎn)單易上手:將各種你需要的東西往屏幕上一拖一放,一個(gè) UI 界面就搞定了,這很 cool 不是嘛!

Xib 的優(yōu)點(diǎn)顯而易見(jiàn):

  • 易上手、可視化,所見(jiàn)即所得
  • 減少代碼量
  • 快,適合小 App 快速開(kāi)發(fā)

但是在我們的實(shí)際項(xiàng)目中,是不推薦使用 xib 的。

首先,xib 本身過(guò)于笨拙,只能搭建一些簡(jiǎn)單的 UI,動(dòng)態(tài)性很差,難以滿足 App 復(fù)雜的 UI 交互需求。

其次,做過(guò)性能優(yōu)化的同學(xué)都知道,xib(or StoryBoard)的性能是很差的,相對(duì)于用純代碼 alloc 的組件來(lái)說(shuō),xib 加載慢,而且會(huì)占用 App 包的體積。不僅僅是 App 的性能,使用老 mac 打開(kāi)較大的 xib 文件,有時(shí)候會(huì)卡的你懷疑人生,嚴(yán)重影響開(kāi)發(fā)效率(心情)。

除此以外,對(duì)于團(tuán)隊(duì)協(xié)作來(lái)說(shuō),xib 也不是一個(gè)好選項(xiàng):閱讀困難,無(wú)法在 git 上查看歷史改動(dòng),容易造成沖突,造成沖突后難以解決,元素通過(guò) outlets 與代碼的鏈接難以維護(hù),容易在改動(dòng)中造成錯(cuò)漏等等。

另外,對(duì)于我這種中途轉(zhuǎn)到前端的工程師來(lái)說(shuō),對(duì)一切在 IDE 界面上配置的東西都有種迷之不信任,感覺(jué)不如一行行黑底白字的代碼來(lái)的靠譜。

當(dāng)然我們不是完全禁用了 xib,用代碼碼 UI 的缺點(diǎn)也很明顯:繁瑣,代碼量大。因此對(duì)一些元素較多,又比較固定的 UI 組件,我們可以用 xib 來(lái)減少代碼量:

iOS屏幕適配實(shí)踐淺談

針對(duì)UI代碼繁瑣,重復(fù)編碼多的情況,我們可以通過(guò)適當(dāng)封裝(UI 工廠類),組織結(jié)構(gòu)(MVC,分離 UI 代碼)等手段,清晰邏輯。

 

  1. // label 工廠方法 
  2. + (UILabel *)labelWithFont:(UIFont *)font 
  3.                      color:(UIColor *) 
  4.                       text:(NSString *)text 
  5.              attributeText:(NSAttributeString *)attributeText 
  6.                  alignment:(NSTextAlignment)alignment; 

布局:返璞歸真

從 iOS7 開(kāi)始蘋(píng)果在 Cocoa 平臺(tái)引入 AutoLayout 進(jìn)行 UI 的基本布局。但是 AutoLayout 非常反人類,不僅代碼繁瑣而且使用不靈活限制很多。

比如我想要把三個(gè)元素等間距地展示在屏幕上,用 AutoLayout 寫(xiě)完基本蛋都碎了,更別說(shuō)動(dòng)態(tài)地在兩套布局間切換這種高級(jí)需求。

后來(lái)蘋(píng)果推出 sizeClass,試圖解決多套布局的問(wèn)題,但是仍然沒(méi)有觸及到碼農(nóng)的痛點(diǎn),而且依賴 xib 使它泛用性不好。

iOS屏幕適配實(shí)踐淺談

一段典型的 AutoLayout 代碼如下所示:

 

  1. _topViewTopPositionConstraint = [NSLayoutConstraint 
  2.                                     constraintWithItem:_topInfoView 
  3.                                     attribute:NSLayoutAttributeTop 
  4.                                     relatedBy:NSLayoutRelationEqual 
  5.                                     toItem:self.view 
  6.                                     attribute:NSLayoutAttributeTop 
  7.                                     multiplier:1.0 
  8.                                     constant:self.navigationController.navigationBar.frame.size.height + self.navigationController.navigationBar.frame.origin.y]; 
  9.     
  10.    [self.view addConstraint:topViewLeftPositionConstraint]; 
  11.     
  12.    (這里省略上述類似結(jié)構(gòu)*4) 

上面省略了很多代碼,實(shí)際上一頁(yè)都放不下。它干了什么呢,只是將一個(gè)元素緊貼屏幕上邊緣放置。項(xiàng)目中我們會(huì)使用三方 AutoLayout 的封裝:PureLayout ,簡(jiǎn)化代碼,也有其它實(shí)用功能。

AutoLayout 比較適合:

  • 基本的對(duì)齊(上下左右對(duì)齊,居中對(duì)齊等)
  • 固定的布局,固定的間距,動(dòng)態(tài)性不高的頁(yè)面
  • 簡(jiǎn)單且數(shù)量較少的 UI 元素

不擅長(zhǎng):

  • 比例布局
  • 動(dòng)態(tài)性較強(qiáng)的頁(yè)面局部
  • 不同屏幕大小比例的適配
  • 復(fù)雜的 UI

另外有一點(diǎn),AutoLayout 對(duì)性能是有損耗的,所以對(duì)性能有要求的場(chǎng)景,比如列表中的 cell,我們會(huì)用代碼計(jì)算 frame,提高滑動(dòng)幀率。

所以在實(shí)際工程中,需要來(lái)選擇布局方式。

下面是 App 中首頁(yè)新聞 Feeds 的布局代碼片段:

 

  1. - (void)layoutSubviews { 
  2.      
  3.     [super layoutSubviews]; 
  4.      
  5.     CGFloat cellWidth = CGRectGetWidth(self.bounds); 
  6.     CGFloat currentY = 0.f; 
  7.      
  8.     // 0.content 
  9.     CGFloat cellHeight = CGRectGetHeight(self.bounds); 
  10.     CGFloat contentHeigth = cellHeight - kCellPaddingHeight; 
  11.     _mainContentView.frame = CGRectMake(0, 0, cellWidth, contentHeigth); 
  12.      
  13.     // 1. topic 
  14.     CGFloat topicLabelWidth = [_topicLabel.text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:_topicLabel.font} context:nil].size.width; 
  15.      
  16.     CGFloat topicLabelHeight = [@"測(cè)高度" boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:_topicLabel.font} context:nil].size.height; 
  17.      
  18.     CGFloat topicLogoLeftPadding = 3.f; 
  19.     CGFloat topicLogoWidth = 10.f; 
  20.     CGFloat topicLeftPadding = 13.f; 
  21.      
  22.     _topicView.frame = CGRectMake(topicLeftPadding, currentY + kTopicUpPadding, topicLogoWidth + topicLogoLeftPadding + topicLabelWidth, topicLabelHeight); 
  23.     _topicLogo.frame = CGRectMake(topicLabelWidth + topicLogoLeftPadding, CGRectGetHeight(_topicView.frame) / 2.0 - topicLogoWidth / 2.0, topicLogoWidth, topicLogoWidth); 
  24.     _topicLabel.frame = CGRectMake(0, 0, topicLabelWidth, topicLabelHeight); 
  25.      
  26.     (省略大量代碼……) 
  27.      
  28.     // 10._sourceLabel 
  29.     CGSize sourceSize = [_sourceLabel.text boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName:_sourceLabel.font} context:nil].size
  30.      
  31.     _sourceLabel.frame = CGRectMake(kEdgeHorizontalPadding, currentY + kLeadingUpPading, sourceSize.width, sourceSize.height); 

可以看到,為了確定每個(gè)元素的位置,我們需要進(jìn)行大量的計(jì)算,代碼可讀性也不好,繁瑣難讀。如果引入動(dòng)態(tài)性,比如不同屏幕字體大小改變,元素大小按比例擴(kuò)大等,則計(jì)算量又要上一個(gè)數(shù)量級(jí)。

動(dòng)態(tài)布局:清晰獨(dú)立

UI 界面是動(dòng)態(tài)的,在不同狀態(tài),不同尺寸或者手機(jī)的橫豎屏情況下,我們往往需要在多套布局方案中切換,或者對(duì)布局進(jìn)行微調(diào)。如果使用 xib 布局的話,可以使用 SizeClass + AutoLayout 的方案;如果是代碼實(shí)現(xiàn)的頁(yè)面,則沒(méi)有官方提供的工具,只能用邏輯去判斷。

一般來(lái)說(shuō),我們寫(xiě)復(fù)雜的 UI 頁(yè)面,需要遵循兩個(gè)原則:

  1. UI 布局代碼要清晰:這是最重要的,要一眼就知道在調(diào)整那一塊,怎么調(diào)整,如果不能,適當(dāng)拆分,優(yōu)化命名。
  2. 布局代碼要和業(yè)務(wù)邏輯獨(dú)立:在一些常用設(shè)計(jì)模式下,我們會(huì)將 UI 和數(shù)據(jù)模型解耦,在 UI 內(nèi)部,同樣要將交互,配置這些邏輯和布局解耦,獨(dú)立出類似前端 css 這樣的純布局文件。

將布局代碼提煉出來(lái),在不同尺寸下調(diào)用不同的實(shí)現(xiàn):

 

  1. if (IS_IPHONE_6){   
  2.     self.layout = [MyLayout iPhone6Layout]; 
  3. }else if (IS_IPHONE_6_PLUS){   
  4.     self.layout = [MyLayout iPhone6PlusLayout];  
  5.  
  6. // 實(shí)現(xiàn)小屏幕布局 
  7. + (MyLayout *)iPhone6Layout {...} 
  8. // 實(shí)現(xiàn)大屏幕布局 
  9. + (MyLayout *)iPhone6PlusLayout {...} 

字體適配:字體集

在開(kāi)發(fā)中我們經(jīng)常會(huì)遇到需要?jiǎng)討B(tài)設(shè)置字體的情況:

  • 不同屏幕尺寸,或者橫豎屏,需要展示不同的字體大小。
  • 為用戶提供了文章調(diào)節(jié)字體選項(xiàng)。
  • App 的不同語(yǔ)言版本,需要顯示的字體不一樣。

iOS屏幕適配實(shí)踐淺談

較為簡(jiǎn)單的做法是用宏或者枚舉定義字體參數(shù),針對(duì)不同尺寸的屏幕,我們拿到不同的值:

 

  1. #ifdef IPHONE6 
  2. #define kChatFontSize 16.f 
  3. #else IPHONE6Plus 
  4. #define kChatFontSize 18.f 
  5. #endif 

在對(duì)一些舊代碼做字體適配擴(kuò)展的時(shí)候,直接修改源碼改動(dòng)太多,容易混亂,可以采用 runTime 方法 hack Label 等控件的展示,替換原有的 setFont 方法:

 

  1. + (void)load{   
  2.      
  3.     Method newMethod = class_getClassMethod([self class], @selector(mySystemFontOfSize:));   
  4.     Method method = class_getClassMethod([self class], @selector(systemFontOfSize:));   
  5.     method_exchangeImplementations(newMethod, method);   
  6. }   
  7.    
  8. + (UIFont *)mySystemFontOfSize:(CGFloat)fontSize{   
  9.     UIFont *newFont=nil;   
  10.     if (IS_IPHONE_6){   
  11.         newFont = [UIFont adjustFont:fontSize * IPHONE6_INCREMENT];   
  12.     }else if (IS_IPHONE_6_PLUS){   
  13.         newFont = [UIFont adjustFont:fontSize * IPHONE6PLUS_INCREMENT];   
  14.     }else{   
  15.         newFont = [UIFont adjustFont:fontSize];   
  16.     }   
  17.     return newFont;   
  18. }  

以上套路缺點(diǎn)顯而易見(jiàn):不夠靈活,將邏輯分散,不便于維護(hù),擴(kuò)展性也不好。

一種比較好的實(shí)踐是引入字體集(Font Collection)的概念,什么是字體集呢,我們?cè)谟?Keynote 或者 Office 的時(shí)候,軟件會(huì)提供一些段落樣式,定義了段落、標(biāo)題、說(shuō)明等文字的字體,我們可以在不同的段落樣式中切換,來(lái)直接改變整個(gè)文章的字體風(fēng)格。

iOS屏幕適配實(shí)踐淺談

聽(tīng)上去和我們的需求是不是很像呢,我們?cè)诖a中也是做類似的事情,將不同場(chǎng)景下的字體定義到一個(gè) Font Collection 中:

 

  1. @protocol XRFontCollectionProtocol <NSObject> 
  2.  
  3. - (UIFont *)bodyFont; // 文章 
  4. - (UIFont *)chatFont; // 聊天 
  5. - (UIFont *)titleFont; // 標(biāo)題 
  6. - (UIFont *)noteFont; // 說(shuō)明 
  7. ...... 
  8. @end 

不同的場(chǎng)景,靈活選擇不同的字體集:

 

  1. + (id<XRFontCollectionProtocol>)currentFontCollection {  
  2. #ifdef IS_IPhone6 
  3.     return [self collectionForIPhone6]; 
  4. #elif IS_IPhone6p 
  5.     return [self collectionForIPhone6Plus]; 
  6. #endif 
  7.     return nil; 
  8.  
  9. // set font 
  10. titleLabel.font = [[XRFontManager currentFontCollection] titleFont]; 

適配新的屏幕或者場(chǎng)景,我們只需要簡(jiǎn)單地增加一套字體集就好了,可以很方便的管理 App 中的字體樣式,做動(dòng)態(tài)切換也很簡(jiǎn)單。

總結(jié)來(lái)說(shuō),用代碼在一個(gè)尺寸實(shí)現(xiàn)設(shè)計(jì)稿是比較簡(jiǎn)單的,但是要在各種尺寸下忠實(shí)反應(yīng)設(shè)計(jì)的想法需要合理的代碼設(shè)計(jì)以及一定的代碼量。

UI 的還原其實(shí)也是大前端開(kāi)發(fā)非常重要的部分,作為程序員,往往重視代碼的穩(wěn)定,業(yè)務(wù)的正常使用而忽略軟件界面這個(gè)同樣重要的用戶體驗(yàn)因素。設(shè)身處地地想,如果設(shè)計(jì)看到自己精心調(diào)配的比例、字體、色號(hào)在不同尺寸手機(jī)上顯示得歪七倒八,一定會(huì)氣的要死吧。

作者是杏仁移動(dòng)開(kāi)發(fā)工程師,前嵌入式工程師,關(guān)注大前端技術(shù)新潮流。

責(zé)任編輯:未麗燕 來(lái)源: 杏仁技術(shù)站
相關(guān)推薦

2023-11-02 09:42:21

iOS屏幕旋轉(zhuǎn)

2013-05-22 09:49:36

2021-09-07 10:17:35

iOS多語(yǔ)言適配設(shè)計(jì)

2022-05-17 09:56:09

Voice Over西瓜視頻開(kāi)發(fā)者

2016-11-30 18:19:22

REM

2011-04-15 14:37:45

JavaCsv

2011-04-02 09:30:46

JavaIO

2015-02-05 14:31:45

iPhone適配

2017-07-21 14:00:00

iOSCrashMach異常

2017-07-25 12:40:42

iOSCrash僵尸對(duì)象

2016-08-31 09:58:55

JavascriptFlux架構(gòu)

2015-11-02 09:49:04

Android屏幕適配官方指導(dǎo)

2011-07-07 11:03:07

iOS MVC Objective-

2018-10-16 15:08:20

屏幕圖像對(duì)象

2011-07-28 10:01:19

IOS 內(nèi)存優(yōu)化

2010-11-09 10:10:15

移動(dòng)開(kāi)發(fā)屏幕適配UI設(shè)計(jì)

2023-06-12 15:43:44

鴻蒙智能家居開(kāi)發(fā)

2009-08-20 09:41:36

2011-07-28 17:20:55

2018-08-29 13:57:40

前端性能測(cè)試Html5
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)