iOS頁(yè)面動(dòng)態(tài)化胯杭,怎么樣用JSON數(shù)據(jù)的原生頁(yè)面擺脫低效的H5頁(yè)面驯杜,來(lái)動(dòng)態(tài)更新app頁(yè)面樣式

最近花了幾天時(shí)間研究了一下怎么用iOS原生頁(yè)面高效的更新app頁(yè)面樣式,我的思路是使用仿H5樣式的JSON數(shù)據(jù)做个,利用各種布局(流動(dòng)鸽心,線性等布局)來(lái)動(dòng)態(tài)更新頁(yè)面樣式滚局。

頁(yè)面動(dòng)態(tài)化主要的使用場(chǎng)景是app的電商頁(yè)面亮垫,由于電商的業(yè)務(wù)需求較大等限,經(jīng)常會(huì)需要改變各個(gè)banner的樣式來(lái)滿足業(yè)務(wù)的需求弧腥,所以需要客戶端根據(jù)數(shù)據(jù)實(shí)時(shí)更新樣式军浆,下面說(shuō)說(shuō)我對(duì)頁(yè)面動(dòng)態(tài)化的理解跟思路愧旦。先看一下最后demo的效果:

其他app是怎么做的
用Charles抓包左胞,發(fā)現(xiàn)京東跟網(wǎng)易考拉都是用type這個(gè)字段提前定義好各種banner的樣式魏身,通過(guò)后臺(tái)返回的數(shù)據(jù)刀脏,來(lái)實(shí)現(xiàn)頁(yè)面動(dòng)態(tài)化更新蟀淮,這樣做有好的方面也有不好的地方:

好的方面:提前定義好banner的樣式最住,客戶端只需要定義好各個(gè)樣式的UI,根據(jù)type字段來(lái)展現(xiàn)就好
不好的方面:只能根據(jù)定義好的樣式來(lái)進(jìn)行動(dòng)態(tài)化更新怠惶,如果需要加入新的樣式涨缚,需要提交新包

我的做法
客戶端不定義banner樣式,而是定義布局樣式來(lái)實(shí)現(xiàn)高度動(dòng)態(tài)更新頁(yè)面策治,思路來(lái)自于CSS里定義的div+CSS布局脓魏,CSS里可以根據(jù)display的inline跟block值來(lái)進(jìn)行布局,iOS里通惫,我定義了幾種常見(jiàn)的布局:

FlowLayout:流式布局茂翔,根據(jù)display值橫向或者縱向布局,根據(jù)屏幕寬度跟banner寬度換行
LinearLayout:線性布局讽膏,縱向布局
WaterfallLayout:瀑布流布局
OneAndNLayout:左邊一個(gè)大圖檩电,右邊N張小圖的布局
StickyLayout:懸浮布局

整體架構(gòu)
頁(yè)面動(dòng)態(tài)化 整體架構(gòu)如下:



每個(gè)UIViewController都是一個(gè)頁(yè)面,頁(yè)面是由一個(gè)個(gè)卡片組成的府树,卡片其實(shí)就是代表了一個(gè)布局樣式俐末,每個(gè)卡片是由一個(gè)個(gè)元素組成的,元素其實(shí)指的就是卡片布局樣式下的各個(gè)banner奄侠,對(duì)應(yīng)的JSON數(shù)據(jù)結(jié)構(gòu)如下:

{
"cards":
[

{

                  "layout": 1,

               "elements": [

                        {
 
                           },
                         {
                                 
                           },
                         ...
                ]
          },
         {
                  "layout": 1,
               "elements": [
                      {
                                 
                           },
                         {
                                 
                           },
                         ...
                ]
          },
         ...
]

}

具體實(shí)現(xiàn)
由于大部分頁(yè)面內(nèi)容都需要上下滑動(dòng)顯示更多內(nèi)容的卓箫,所以頁(yè)面動(dòng)態(tài)化的實(shí)現(xiàn)是基于UICollectionView來(lái)做的,當(dāng)然也可以使用UIScrollView來(lái)實(shí)現(xiàn)(淘寶天貓都是通過(guò)一個(gè)自定義具有回收復(fù)用機(jī)制的UIScrollView來(lái)展示動(dòng)態(tài)化頁(yè)面內(nèi)容的)垄潮,我的理解是既然UICollectionView可以通過(guò)自定義UICollectionViewLayout來(lái)展現(xiàn)自定義的cell烹卒,為什么不用還需要自己定義一個(gè)具有回收復(fù)用機(jī)制的UIScrollView去展現(xiàn)內(nèi)容,UICollectionView自身就是帶有回收復(fù)用機(jī)制的弯洗。我的具體實(shí)現(xiàn)旅急,先看下整體的UML圖:

每個(gè)KBBaseCard代表了一個(gè)布局的卡片,對(duì)應(yīng)UICollectionView里的一個(gè)section牡整,KBBaseCard里elements的每個(gè)KBBaseElement代表了一個(gè)banner藐吮,對(duì)應(yīng)UICollectionView里的一個(gè)item,KBBaseElement里的KBElementStyle提供banner需要展現(xiàn)的樣式。KBElementStyle里的type字段是用來(lái)定義banner的樣式谣辞,比方說(shuō)type=1代表這個(gè)banner就是一張圖迫摔。實(shí)際展示圖如下:

UICollectionViewLayout的自定義
UICollectionView提供的UICollectionViewFlowLayout并不能滿足我的對(duì)樣式展現(xiàn)的需求,所以這里我們必須自己寫一套UICollectionViewLayout來(lái)提供對(duì)KBBaseElement里style字段里的樣式支持泥从,核心方法如下句占,具體實(shí)現(xiàn)在本文中不做過(guò)多詳解,大家可以自己查詢一下相關(guān)的知識(shí):

  • (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath
    {
    UICollectionViewLayoutAttributes *layoutAttributes = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];

    NSInteger sectionLayout = 1; // CardFlowLayout is the default layout

    if (self.delegate && [self.delegate respondsToSelector:@selector(collectionView:layout:layoutForSection:)]) {
    sectionLayout = [self.delegate collectionView:self.collectionView layout:self layoutForSection:indexPath.section];
    }

    // CardFlowLayout 流式布局
    if (sectionLayout == 1) {
    [self handleLayoutAttributesForFlowLayout:layoutAttributes atIndexPath:indexPath];
    }
    // CardLinearLayout 線性布局
    if (sectionLayout == 2) {
    [self handleLayoutAttributesForLinearLayout:layoutAttributes atIndexPath:indexPath];
    }
    // CardOneAndNLayout 左邊一張大圖右邊N張小圖布局
    if (sectionLayout == 3) {
    [self handleLayoutAttributesForOneAndNLayout:layoutAttributes atIndexPath:indexPath];
    }
    // CardWaterfallLayout 瀑布流布局
    if (sectionLayout == 4) {
    [self handleLayoutAttributesForWaterfallLayout:layoutAttributes atIndexPath:indexPath];
    }

    return layoutAttributes;
    }

JSON數(shù)據(jù)
這里提供一個(gè)我自己創(chuàng)建的JSON mock數(shù)據(jù)躯嫉,還有根據(jù)這個(gè)JSON數(shù)據(jù)最終展現(xiàn)出來(lái)的頁(yè)面圖

JSON
{
"cards": [
{
"layout": 1,
"style": {
"backgroundColor": "#ffffff"
},
"elements": [
{
"type": 1,
"image": "http://haitao.nos.netease.com/lqdbpar1xWZw5NuOB9ezf80UDm75Ei%2BZyMo%2BMgvE%2Bdunea_02T1704271119_480_240.jpg",
"style": {
"display": "inline",
"margin": [
"0",
"0",
"0.75",
"0.75"
],
"width_ratio": 0.5,
"width_height_ratio": 2.0
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/i11BQFE2dWpzplHNBV1Tr8Hafa5zTz%2BCoxF%2BwIBS%2BKF2Vx_03T1704261946_480_240.jpg",
"style": {
"display": "inline",
"margin": [
"0",
"0.75",
"0.75",
"0"
],
"width_ratio": 0.5,
"width_height_ratio": 2.0
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/KwaBThC4mguSnQCGBXVtfK4RmTTSeQ%2BZ5Ql%2BTNvQ%2BKNWzP_05T1704251128_480_240.jpg",
"style": {
"display": "inline",
"margin": [
"0.75",
"0",
"0",
"0.75"
],
"width_ratio": 0.5,
"width_height_ratio": 2.0
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/G4LGkdg7si4p5ZzVBZUKmkTq7EeTKt%2BRRaE%2BfQyx%2B6JlfC_06T1704251128_480_240.jpg",
"style": {
"display": "inline",
"margin": [
"0.75",
"0.75",
"0",
"0"
],
"width_ratio": 0.5,
"width_height_ratio": 2.0
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/HNkdnuFcFey5Om5GpNpO-C2LLgTrO3WtFT1704201935_960_210.jpg",
"style": {
"display": "block",
"margin": [
"0.75",
"0",
"0",
"0"
],
"width_height_ratio": 4.57
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/mrui23TlZJcRAocRWB70T1704262151_600_375.jpg",
"style": {
"display": "inline",
"margin": [
"0.75",
"0",
"0",
"0.75"
],
"width_ratio": 0.7,
"width_height_ratio": 1.6
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/ppiV8ODszIZciIZbmQih-A6HUakFq6g6oLTNhT1704201914_474_555.jpg",
"style": {
"display": "inline",
"margin": [
"0.75",
"0.75",
"0",
"0"
],
"width_ratio": 0.3,
"width_height_ratio": 0.685
}
}
]
},
{
"layout": 3,
"style": {
"backgroundColor": "#ffffff"
},
"elements": [
{
"type": 1,
"image": "http://haitao.nos.netease.com/KHASB80nO5JMsX1e2iChshdRT1704262150_480_480.jpg",
"style": {
"margin": [
"0",
"0",
"0",
"0.75"
],
"width_ratio": 0.5,
"width_height_ratio": 1.0
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/ygMuXb96hrtGtT6Wc9vZ2T17040101959_480_240.jpg",
"style": {
"margin": [
"0",
"0.75",
"0.75",
"0"
],
"width_ratio": 0.5,
"width_height_ratio": 2.0
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/ADB5IaeoJWP9pIzVmwzkfGKhT1704262151_480_240.jpg",
"style": {
"margin": [
"0.75",
"0.75",
"0",
"0"
],
"width_ratio": 0.5,
"width_height_ratio": 2.0
}
}
]
},
{
"layout": 1,
"style": {
"backgroundColor": "#ffffff"
},
"elements": [
{
"type": 1,
"image": "http://haitao.nos.netease.com/ppiV8ODszIZciIZbmQih-A6HUakFq6g6oLTNhT1704201914_474_555.jpg",
"style": {
"display": "inline",
"margin": [
"0",
"0",
"0",
"0.75"
],
"width_ratio": 0.5,
"width_height_ratio": 0.856
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/mbO7ln3VxpAWxKkw84Ay-ys6BLHmk9LLRvwa4T1704201914_474_555.jpg",
"style": {
"display": "inline",
"margin": [
"0",
"0.75",
"0",
"0"
],
"width_ratio": 0.5,
"width_height_ratio": 0.856
}
}
]
},
{
"layout": 2,
"style": {
"backgroundColor": "#ffffff"
},
"elements": [
{
"type": 1,
"image": "http://haitao.nos.netease.com/hwCkTs9AoDThXhv5k38dr2M0T1704242204_960_480.jpg",
"style": {
"margin": [
"0",
"0",
"10",
"0"
],
"width_height_ratio": 2.0
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/Tt9TfxyDTSSirP27lXEiIsKPriT1704241519_960_480.jpg",
"style": {
"margin": [
"0",
"0",
"10",
"0"
],
"width_height_ratio": 2.0
}
},
{
"type": 1,
"image": "http://haitao.nos.netease.com/uey1sJ03lEOglRm626Th6dKrT1704242203_960_480.jpg",
"style": {
"margin": [
"0",
"0",
"10",
"0"
],
"width_height_ratio": 2.0
}
}
]
}
]
}

頁(yè)面圖

本文轉(zhuǎn)載自:http://kobedai.me/2017/04/28/iOS%E9%A1%B5%E9%9D%A2%E5%8A%A8%E6%80%81%E5%8C%96%EF%BC%8C%E6%80%8E%E4%B9%88%E6%A0%B7%E7%94%A8JSON%E6%95%B0%E6%8D%AE%E7%9A%84%E5%8E%9F%E7%94%9F%E9%A1%B5%E9%9D%A2%E6%91%86%E8%84%B1%E4%BD%8E%E6%95%88%E7%9A%84H5%E9%A1%B5%E9%9D%A2%EF%BC%8C%E6%9D%A5%E5%8A%A8%E6%80%81%E6%9B%B4%E6%96%B0app%E9%A1%B5%E9%9D%A2%E6%A0%B7%E5%BC%8F/

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末纱烘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子祈餐,更是在濱河造成了極大的恐慌凹炸,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,406評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昼弟,死亡現(xiàn)場(chǎng)離奇詭異啤它,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)舱痘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門变骡,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人芭逝,你說(shuō)我怎么就攤上這事塌碌。” “怎么了旬盯?”我有些...
    開封第一講書人閱讀 167,815評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵台妆,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我胖翰,道長(zhǎng)接剩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,537評(píng)論 1 296
  • 正文 為了忘掉前任萨咳,我火速辦了婚禮懊缺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘培他。我一直安慰自己鹃两,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評(píng)論 6 397
  • 文/花漫 我一把揭開白布舀凛。 她就那樣靜靜地躺著俊扳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪猛遍。 梳的紋絲不亂的頭發(fā)上馋记,一...
    開封第一講書人閱讀 52,184評(píng)論 1 308
  • 那天碎绎,我揣著相機(jī)與錄音,去河邊找鬼抗果。 笑死,一個(gè)胖子當(dāng)著我的面吹牛奸晴,可吹牛的內(nèi)容都是我干的冤馏。 我是一名探鬼主播,決...
    沈念sama閱讀 40,776評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼寄啼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼逮光!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起墩划,我...
    開封第一講書人閱讀 39,668評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤涕刚,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后乙帮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體杜漠,經(jīng)...
    沈念sama閱讀 46,212評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評(píng)論 3 340
  • 正文 我和宋清朗相戀三年察净,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了驾茴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,438評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡氢卡,死狀恐怖锈至,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情译秦,我是刑警寧澤峡捡,帶...
    沈念sama閱讀 36,128評(píng)論 5 349
  • 正文 年R本政府宣布,位于F島的核電站筑悴,受9級(jí)特大地震影響们拙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜阁吝,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評(píng)論 3 333
  • 文/蒙蒙 一睛竣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧求摇,春花似錦射沟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至摔刁,卻和暖如春挥转,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工绑谣, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留党窜,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,827評(píng)論 3 376
  • 正文 我出身青樓借宵,卻偏偏與公主長(zhǎng)得像幌衣,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子壤玫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容