讀源碼系列(swift2048)-view篇

前言

筆者是swift自學(xué)新手,希望借助閱讀別人開源項目提升自己swift水平耍共。文中將盡量使用文字描述來代替代碼的堆砌烫饼,建議讀者多參考源碼,以便更好理解項目试读。文中難免有錯誤之處杠纵,歡迎各路大牛留言指正。

項目信息

swift-2048 github地址

項目主界面

該項目可以說一個帶有實驗學(xué)習(xí)性質(zhì)的項目钩骇,其中部分功能沒有實現(xiàn)或不完整比藻。但2048游戲的基本功能均完整實現(xiàn)铝量。筆者將分3篇文章,分別按controller银亲、model慢叨、view的進(jìn)行介紹。

本篇是最后一篇群凶,將重點展開介紹view部分插爹。
以往文章:
第1篇-controller篇
第2篇-model篇

正文

本文將從以下2點展開說明:

  1. 文件結(jié)構(gòu)概括
  2. 游戲盤view

1.文件結(jié)構(gòu)概括

筆者喜歡先從文件結(jié)構(gòu)看起哄辣。該項目的view部分请梢,有下面4個文件組成:

views/AccessoryViews.swift //輔助的views.里面含顯示得分ScoreView和用來控制作用的ControlView(未實現(xiàn)也未使用)
views/GameboardView.swift //游戲盤view
views/TileView.swift //棋子view
AppearanceProvider.swift //外觀的提供者,按規(guī)則顯示提供顏色和字體大小

2.游戲盤view(GameboardView)

GameboardView代表游戲盤,TileView代表棋子力穗。


游戲盤和棋子

GameboardView源碼中

class GameboardView : UIView {
   ...
   var tiles: Dictionary<NSIndexPath, TileView>
   ...
}

源碼可見毅弧,GameboardView是以Dictionary結(jié)構(gòu)來存儲TileView。Dictionary中的key当窗,是NSIndexPath够坐,實際運用中將位置坐標(biāo)x y(或raw col)轉(zhuǎn)成NSIndexPath,例如:

tiles[NSIndexPath(forRow: row, inSection: col)] = tile //設(shè)置位置坐標(biāo)為(row崖面,col)上的TileView

各位移步看TileView的內(nèi)部:

class TileView : UIView {
    ...
    let numberLabel : UILabel//顯示數(shù)字的label
    var value : Int = 0 {
    didSet {
        backgroundColor = delegate.tileColor(value)//棋子的背景
        numberLabel.textColor = delegate.numberColor(value)//數(shù)字的顏色
        numberLabel.text = "\(value)"http://值
        }
    }
    unowned let delegate : AppearanceProviderProtocol //顯示信息委托
    ...
}

TileView不復(fù)雜元咙,UIView中是一個UILabel。然后數(shù)字和棋子背景因value不同而不同巫员。顯示的規(guī)則來自AppearanceProviderProtocol庶香。

protocol AppearanceProviderProtocol: class {
  func tileColor(value: Int) -> UIColor //根據(jù)值,返回棋子的背景顏色
  func numberColor(value: Int) -> UIColor//根據(jù)值,返回棋子的數(shù)字顏色
  func fontForNumbers() -> UIFont //返回數(shù)字使用的字體
}

該協(xié)議的的實現(xiàn),按典型的switch-case的結(jié)構(gòu)简识,有多少情況赶掖,只要預(yù)先設(shè)定好,即可:

class AppearanceProvider: AppearanceProviderProtocol {
  func tileColor(value: Int) -> UIColor {
    switch value {
    case 2:
      return UIColor(red: 238.0/255.0, green: 228.0/255.0, blue: 218.0/255.0, alpha: 1.0)
    case 4:
      return UIColor(red: 237.0/255.0, green: 224.0/255.0, blue: 200.0/255.0, alpha: 1.0)
        ...
    }
  }
  ...
}

那開發(fā)者為何使用AppearanceProviderProtocol呢七扰?筆者猜想奢赂,這樣可以將顯示屬性(顏色、字體)相關(guān)的邏輯從TileView的邏輯中獨立出來颈走,便于統(tǒng)一修改和調(diào)試膳灶。


讀過上一篇model篇的讀者,會發(fā)現(xiàn)這里的GameboardView-TileView與model中的SquareGameboard-TileObject比較相似立由,但是2者還是有本質(zhì)上的差別:

  • 相同點:2者都在各自領(lǐng)域(view和model)中袖瞻,表示游戲盤和棋子
  • 不同點:在model中,SquareGameboard組織TileObject的方式是數(shù)組拆吆。
struct SquareGameboard<T> {
    ...
    var boardArray : [T]//實際使用過程中聋迎,泛型使用TileObject代替
    ...
}

在view中,GameboardView組織TileView的方式是Dictionary

class GameboardView : UIView {
    ...
    var tiles: Dictionary<NSIndexPath, TileView>
    ...
}

為何是這樣?筆者認(rèn)為是model和view關(guān)注點不同

  • model關(guān)注整個游戲的邏輯枣耀,即游戲盤中的每一個有效的位置都要被管理起來霉晕。TileObject不僅代表有數(shù)字的棋子庭再,也代表空棋子。所以牺堰,游戲盤中所有棋子(位置)是連續(xù)的拄轻,可以用數(shù)組表示。
  • view關(guān)注顯示伟葫,即只關(guān)心游戲盤中有數(shù)字的棋子(移動恨搓、插入等)。TileView只表示有數(shù)字的格子筏养,不表示空棋子(空位置)斧抱。在游戲過程中,有數(shù)字的棋子數(shù)量小于游戲盤中棋子位置的總數(shù)量渐溶,而且棋子與棋子之間沒有連續(xù)的關(guān)系辉浦。故而使用數(shù)組就不適合了,而采用Dictionary茎辐,并用位置坐標(biāo)(NSIndexPath)做key就比較合理宪郊。

查看GameboardView的代碼,你會發(fā)現(xiàn)GameboardView沒有配套的委托協(xié)議拖陆。
沒有委托協(xié)議意味著:只存在viewController主動調(diào)用(通知)GameboardView弛槐,反過來GameboardView不需要通知viewController。進(jìn)一步講依啰,GameboardView只負(fù)責(zé)顯示乎串,不負(fù)責(zé)與用戶交互。(看過前面文章的讀者應(yīng)該會記得孔飒,該項目的用戶交互是由滑動手勢發(fā)起的)


筆者統(tǒng)計灌闺,GameboardView被controller調(diào)用的方法是以下4個:

b.reset()
b.moveOneTile(from, to: to, value: value)
b.moveTwoTiles(from, to: to, value: value)
b.insertTile(location, value: value)

除了reset之外,其他3個方法坏瞄,基本和model的協(xié)議是一樣的桂对。因為controller就只負(fù)責(zé)以簡單方式通知view(代碼上,就是直接調(diào)用view的方法)鸠匀。以移動一個棋子的委托方法為例(model委托的分析蕉斜,請參見model部分的文章)

  func moveOneTile(from: (Int, Int), to: (Int, Int), value: Int) {//controller實現(xiàn)的model的委托
    assert(board != nil)//board就是GameboardView
    let b = board!
    b.moveOneTile(from, to: to, value: value)// 直接調(diào)用view的方法
  }

下面是moveOneTile方法:

  func moveOneTile(from: (Int, Int), to: (Int, Int), value: Int) {
    ...(略,檢查參數(shù)代碼)
    let (fromRow, fromCol) = from
    let (toRow, toCol) = to
    let fromKey = NSIndexPath(forRow: fromRow, inSection: fromCol)
    let toKey = NSIndexPath(forRow: toRow, inSection: toCol)
    //上面是得到棋子view的key

    guard let tile = tiles[fromKey] else {
      assert(false, "placeholder error")
    }//得到舊位置的棋子(舊位置上一定會有棋子)
    let endTile = tiles[toKey]//得到新位置的棋子缀棍,可能不存在(單棋子移動分成移動和合并2種情況宅此。只有合并情況才有新位置上的棋子。具體見model篇)

    var finalFrame = tile.frame
    finalFrame.origin.x = tilePadding + CGFloat(toCol)*(tileWidth + tilePadding)
    finalFrame.origin.y = tilePadding + CGFloat(toRow)*(tileWidth + tilePadding)
    //舊位置的frame爬范,計算成新位置的frame

    tiles.removeValueForKey(fromKey)
    tiles[toKey] = tile
    //然后在字典中更新父腕,刪除舊的,在放進(jìn)新的

    ...(略青瀑,移動動畫和pop動畫璧亮,有興趣可查閱源碼)
  }

用文字說明流程:

1》參數(shù)是坐標(biāo)萧诫,轉(zhuǎn)成NSIndexPath,在字典中找到棋子view
2》tiles字典更新枝嘶,將原來位置的棋子從字典原來位置刪除帘饶,覆蓋到新位置
3》原來位置的棋子view,計算新位置的frame群扶,使用動畫移動到新位置及刻。新位子原來的view刪除。如果是合并(新位置原來有格子)竞阐,需要pop動畫

另外2個方法也是差不多的套路:
moveTwoTiles 移動2個格子,過程與前面基本一致:

1》參數(shù)是坐標(biāo)缴饭,轉(zhuǎn)成NSIndexPath,找到棋子view(2個原來位置的棋子)
2》tiles字典更新:將一個原始棋子view從字典原來位置刪除馁菜,覆蓋到新位置茴扁。另外一個原始位置的棋子view從字典中刪除
3》計算新位置棋子的frame铃岔。然后2個原來位置的棋子汪疮,動畫移動到新的位置,然后刪除一個毁习,只保留一個智嚷。并顯示pop動畫

insertTile 新增格子

1》參數(shù)是坐標(biāo),轉(zhuǎn)成NSIndexPath纺且。
2》計算frame盏道,創(chuàng)建新的TileView。加入游戲盤view载碌,然后插入字典中
3》動畫顯示猜嘱。


總結(jié)

筆者經(jīng)過分析model時的邏輯洗禮,再分析view部分時嫁艇,頭腦就清晰多了朗伶。
處理model的委托時,基本就是2步:1》修改保存棋子view的字典步咪。2》移動棋子view

(該項目的view部分還有一些處理邏輯文中沒有提到(例如游戲盤背景的顯示论皆、棋子動畫,得分view等)猾漫,有興趣的讀者可自行查看源碼了解点晴。

非常感謝您的閱讀!您的留言悯周、打賞粒督、點贊、關(guān)注禽翼、分享屠橄,對筆者最大的鼓勵:P

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末萨惑,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仇矾,更是在濱河造成了極大的恐慌庸蔼,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贮匕,死亡現(xiàn)場離奇詭異姐仅,居然都是意外死亡,警方通過查閱死者的電腦和手機刻盐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評論 3 395
  • 文/潘曉璐 我一進(jìn)店門掏膏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人敦锌,你說我怎么就攤上這事馒疹。” “怎么了乙墙?”我有些...
    開封第一講書人閱讀 164,614評論 0 354
  • 文/不壞的土叔 我叫張陵颖变,是天一觀的道長。 經(jīng)常有香客問我听想,道長腥刹,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,671評論 1 293
  • 正文 為了忘掉前任汉买,我火速辦了婚禮衔峰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘蛙粘。我一直安慰自己垫卤,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,699評論 6 392
  • 文/花漫 我一把揭開白布出牧。 她就那樣靜靜地躺著穴肘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪崔列。 梳的紋絲不亂的頭發(fā)上梢褐,一...
    開封第一講書人閱讀 51,562評論 1 305
  • 那天,我揣著相機與錄音赵讯,去河邊找鬼盈咳。 笑死,一個胖子當(dāng)著我的面吹牛边翼,可吹牛的內(nèi)容都是我干的鱼响。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼组底,長吁一口氣:“原來是場噩夢啊……” “哼丈积!你這毒婦竟也來了筐骇?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,223評論 0 276
  • 序言:老撾萬榮一對情侶失蹤江滨,失蹤者是張志新(化名)和其女友劉穎铛纬,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唬滑,經(jīng)...
    沈念sama閱讀 45,668評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡告唆,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,859評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了晶密。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片擒悬。...
    茶點故事閱讀 39,981評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖稻艰,靈堂內(nèi)的尸體忽然破棺而出懂牧,到底是詐尸還是另有隱情,我是刑警寧澤尊勿,帶...
    沈念sama閱讀 35,705評論 5 347
  • 正文 年R本政府宣布僧凤,位于F島的核電站,受9級特大地震影響运怖,放射性物質(zhì)發(fā)生泄漏拼弃。R本人自食惡果不足惜夏伊,卻給世界環(huán)境...
    茶點故事閱讀 41,310評論 3 330
  • 文/蒙蒙 一摇展、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧溺忧,春花似錦咏连、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,904評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至歌溉,卻和暖如春垄懂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背痛垛。 一陣腳步聲響...
    開封第一講書人閱讀 33,023評論 1 270
  • 我被黑心中介騙來泰國打工草慧, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人匙头。 一個月前我還...
    沈念sama閱讀 48,146評論 3 370
  • 正文 我出身青樓漫谷,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蹂析。 傳聞我的和親對象是個殘疾皇子舔示,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,933評論 2 355

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫碟婆、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,103評論 4 62
  • 前言 筆者是swift自學(xué)新手惕稻,希望借助閱讀別人開源項目提升自己swift水平竖共。文中將盡量使用文字描述來代替代碼的...
    安靜的貓咪先生閱讀 1,032評論 3 4
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,139評論 25 707
  • 今年國慶對于我來說卻有不同! 前天女兒過了周歲生日俺祠,哺乳期間多一個小時的哺乳假結(jié)束了肘迎!從今天開始我中午...
    芝芝1981閱讀 184評論 4 2
  • 小學(xué)二年級的時候,我就離開了老家的安樂窩——村校锻煌,轉(zhuǎn)到鄉(xiāng)鎮(zhèn)的小學(xué)去讀書了妓布,同時也寫下了我學(xué)生生涯的唯一光環(huán)—...
    alexader狗閱讀 269評論 0 0