iOS View 編程指導(一)-view和window的底層邏輯和結(jié)構(gòu)詳解

本系列文章參考蘋果官方文檔:View Programming Guide for iOS

本系列文章還包括:

  1. iOS View 編程指導(二)-window
  2. iOS View 編程指導(三)-View
  3. iOS View 編程指導(四)-動畫

窗口(Windows) 和 視圖(Views)


  • 在iOS中,用Windows和Views來展示UI界面
  • Windows是個容器, 本身不可見, 是用來盛放View的
  • Views定義了填充Window的內(nèi)容, 比如image,text,shapes, 或者各種可見UI元素的組合, 等等
  • 另外Window繼承自View

預覽


  • 每個APP至少需要一個window和一個view
  • UIKit提供了一些定義好的view,比如button, text label, table view, scroll view, picker view等,這些view都是可以直接拿來用的
  • 如果有的地方需要的界面, 用UIKit提供的系統(tǒng)view無法滿足, 開發(fā)者可以自定義view

views是用來管理應用中的UI界面

  • app中的view都是類UIView的實例,表示屏幕上的一塊矩形區(qū)域
  • view用來繪制內(nèi)容,響應用戶觸碰事件,管理view自己的subviews.
  • 繪制內(nèi)容用到的繪圖技術(shù)包括Core Graphic, OpenGL ES, UIKit中的畫shape,畫image,畫text
  • View還是touch event的響應者
  • view和它的super view,subviews構(gòu)成了一個樹形結(jié)構(gòu)叫做view hierarchy,本文中我稱它為view的層級樹

可以將視圖看做是構(gòu)建應用UI界面的磚頭,UI界面是使用各種視圖堆砌起來的,這時各種視圖間的聯(lián)系構(gòu)成了view hierarchy.

window用來協(xié)調(diào)View的顯示

  • 一個window是一個UIWindow的實例,它管理view的顯示,處理用戶事件;配合view一起構(gòu)建APP的用戶界面.
  • 每個App至少有個window,大多數(shù)時候App都是只有一個key window(在設備的主屏幕上顯示用戶界面)的,而且該window通常不會變化的, window創(chuàng)建后保持不變只有window內(nèi)的view可能會變化.
  • 當設備連接了外置屏幕時,系統(tǒng)會創(chuàng)建第二個window

動畫給用戶提供了界面變化的視覺反饋

  • iOS提供了豐富的動畫如一組view間的modal,transitioning
  • view的許多屬性變化也提供了動畫,這些屬性有:透明度(alpha),位置大小變化(frame),backgroundColor等
  • view的動畫可以使用底層的layer來做CoreAnimation動畫

Interface Builder的作用

界面的創(chuàng)建除了可以用來代碼直接創(chuàng)建,還可以使用一個xcode工具-InterfaceBuilder來構(gòu)建,這個工具是一個可視化構(gòu)建工具,可以直接拖拽View等UI元素進入界面,可以直接修改UI元素的屬性和位置大小.具體請參考文檔Interface Builder User GuideView Controller Programming Guide for iOS

view和window的結(jié)構(gòu)


  • UIView和UIWindow這個類提供非常厲害的工具來管理布局和view的展示.
  • 理解這兩個類的底層的結(jié)構(gòu)和工作原理對構(gòu)建UI界面有益

view的底層結(jié)構(gòu)


  • 在iOS中view指一塊在屏幕上的可見矩形區(qū)域,view可以在該矩形區(qū)域繪制內(nèi)容,處理用戶的觸摸事件.
  • view同時也可以是其他視圖的父視圖,父視圖管理子view的位置和大小,這些事情UIView這個類默認幫你干了
  • 如果想要定制view可以繼承UIView

在View底層有一個Layer,該layer用來繪制UI內(nèi)容,UIView上的動畫支持也是由底層的layer來實現(xiàn)的.所以說UIView這個類是對CALayer的擴展已提供對用戶屏幕事件的響應能力.
開發(fā)者對view的操作大部分都是通過UIView中開放的接口進行的,然而有時候也會用到CALayer來進行操作.

通過下圖可以幫我們理解view和layer之間的關系,圖中顯示的是蘋果的demo-ViewTransitions一個界面的UIView和底層Layer的結(jié)構(gòu).
下圖包括的view: 有window,一個普通的View容器containerView,一個imageView,toolbar(控件control也是集成自UIView),bar button(不是UIView的子類,但它底層是由UIView構(gòu)成的,相當于view的容器).每個UIView都有一個Layer,通過UIView的layer屬性可以訪問.在CALayer的底層又是由Core Animation對象構(gòu)成的,用于硬件加速和屏幕內(nèi)容的繪制.

一個界面中的View結(jié)構(gòu)圖

使用Core Animation對于提高性能有重要意義. 在實際的視圖繪制中,在內(nèi)容繪制代碼(盡量少調(diào)用,因為很耗性能)調(diào)用后,繪制的內(nèi)容會被Core Animation緩存好,以備接下來復用. 復用緩存好的內(nèi)容可以減少視圖更新重繪對性能的消耗,特別是在做動畫時,coreAnimation的復用機制非常重要.

View的層級樹和subview的管理

  • view除了可以顯示內(nèi)容外還可以作為其他view的容器,這時就形成了一種父子關系,作為容器的為superview,容器中的view成為subview,所以這是一種組合設計模式(參考iOS設計模式(二)-21種設計模式),這種設計模式對view層級堆砌有重要的意義
  • 顯然,當subview的內(nèi)容是不透明時會遮住superview的內(nèi)容.如果subview的內(nèi)容部分透明時顯示的內(nèi)容是混合的. superview用一個數(shù)組來管理它的subviews,所以各個subview之間有先后順序,后加入的subview會遮住先加入的.
  • 改變superview的size,隱藏superview,改變superview的alpha值,對superview做transform操作,都會相應的改變或者影響它的subview
  • view的層級樹也會對用戶事件響應產(chǎn)生影響. 事件發(fā)生后一般是把該事件給一個合適view處理,如果該view不處理那么會將事件往它的superview傳遞,如果該superview不處理,事件繼續(xù)向上傳遞給它的superview的superview; 也就說,事件的傳遞是沿著響應鏈(responder chain)往上傳遞的; 直到傳遞給UIApplication對象(一般處理是將事件丟棄掉),就不再傳遞了.

view的繪制

UIView使用以一種按需繪制(on-demand,類似懶加載)方式進行內(nèi)容的繪制. 當view第一次加載時,系統(tǒng)調(diào)用view的繪制代碼開始繪制,然后將繪制的內(nèi)容保存為一種圖片,然后將圖片顯示. 如果view接下來不更新那么系統(tǒng)不會再繪制而是一直顯示那種圖片,當view有了更新系統(tǒng)才會再一次繪制并保存一直新的圖片后顯示.

當view更新重繪時,不是直接調(diào)用繪制代碼再一次繪制,而是調(diào)用UIView的setNeedsDisplay或者setNeedsDisplayInRect:方法來通知系統(tǒng)需要更新view. 系統(tǒng)會等待下次runloop調(diào)用(時間為一幀時間,通常為1/60秒),在等待期間系統(tǒng)可以給你進行view的remove,resize,hide,reposition等操作.

注意:view幾何上(位置,大小)的更新不會導致view的重繪,而是根據(jù)view的contentMode來拉伸或者移動上次繪制的內(nèi)容圖片,不是重新繪制.具體那種contentMode會怎樣影響view的更新,下文會提到.

當開始繪制view的內(nèi)容時,UIKit提供的系統(tǒng)view時直接調(diào)用系統(tǒng)私有方法來進行繪制的. 如果是自定義view的話需要覆蓋(override)drawRect:方法,也可以直接設置底層layer的contents,但不常用.

Content Modes

每個view都一個contentmode用來控制循環(huán)使用view中的內(nèi)容.當一個view第一次繪制時,會保存一個bitmap來表示內(nèi)容,當發(fā)生集合變動時,view直接使用哪個bitmap來根據(jù)view的contentmode來做些改動循環(huán)使用.contentMode會對以下view的變動產(chǎn)生影響:

  • 改變view的寬高或者位置(frame和bounds的改變)
  • 給view加一個變換transform

多數(shù)view的contentMode的默認值是UIViewContentModeScaleToFill,該模式使得view的content縮放后填充frame設置的大小.下圖中顯示不同的contentMode對應view的content填充樣式,從圖中可以看到并不是所有的模式都是充滿view的frame,從而使一些內(nèi)容變形.

contentMode

你可以將view的contentMode設置為UIViewContentModeRedraw,此時view的幾何更新會致使系統(tǒng)調(diào)用drawRect:重繪view的內(nèi)容.所以一般不用這種模式,這種模式對性能影響很大.

view的拉伸

view可以通過設置contentStretch來確定view可以進行拉伸的部分內(nèi)容.contentMode的部分模式(UIViewContentModeScaleToFill, UIViewContentModeScaleAspectFit, UIViewContentModeScaleAspectFill)可以導致view可以拉伸,view的拉伸如下圖所示:

view的拉伸

view內(nèi)置的動畫

view底層的layer帶來一個好處是view改動帶來的動畫. 適當?shù)膭赢嬙O計給APP帶來好的用戶體驗. view的許多屬性是支持動畫的,要創(chuàng)建view的動畫需要干兩件事:

  1. 告訴UIKit你想展示一個動畫

  2. 改變view的屬性
    下面是一些可以做動畫的屬性:

  3. frame-創(chuàng)建移動和大小的動畫變動

  4. bounds-創(chuàng)建大小的動畫變動

  5. center-創(chuàng)建移動動畫

  6. transfrom-創(chuàng)建變換(縮放,旋轉(zhuǎn))動畫

  7. alpha-創(chuàng)建透明度動畫

  8. backgroundColor-創(chuàng)建背景顏色動畫

  9. contentStretch-創(chuàng)建拉伸動畫

還有就是view的過度動畫(transition),比如controller間的modal,navigationController間的視圖切換都是view的transition
另外動畫可以通過UIKit創(chuàng)建也可以通過CoreAnimation創(chuàng)建動畫,core Animation動畫直接操作layer層,這樣可以創(chuàng)建的動畫可以更加豐富(比如控制動畫的timing等),想要更加深入的學習Core Animation可以瀏覽Apple官方文檔Core Animation 編程指導Core Animation指南

視圖幾何表示和坐標系


UIKit中的坐標系規(guī)定原點在屏幕的左上方.另外每一個window和view都自己的坐標系,所以view中的subview的位置相對于該view的坐標系而不是屏幕的坐標系. 下圖展示了UIKit中的坐標系:

iOS中屏幕坐標系

因為每個view或者window都有自己的坐標系,所以在做幾何變動或者繪制圖形時都要考慮到你需要參考的坐標系,比如在view中繪制圖形時,你參考的是該view的坐標系.類UIWindowUIView都提供了一些方法供開發(fā)來切換不同的坐標系操作.

注意:在iOS中不同框架中對坐標系定義(原點,x/y軸的方向)有區(qū)別.比如在Core Graphic和OpenGL ES中使用的坐標系和UIKit中不同,它們定義的坐標系是:原點在屏幕的左下角,x軸向右,y軸向上.所以在用core graphic繪制圖形時,要考慮到此時的坐標系和UIKit中不同(主要是上下顛倒了)

Frame,Bounds和Center這些屬性之間的關系

view通過frame,bounds,center這幾個屬性來記錄它的位置和大小:

  • frame,記錄view在superview中(superview的坐標系)的大小和位置信息
  • bounds,記錄view自己的坐標系原點位置,和大小
  • center,記錄自己在中心點在superview中的位置

framecenter主要用來操作view的幾何改變(位置,大小).你使用這兩個屬性來構(gòu)建你層級樹或更新位置和大小.如果你只是單單改變位置,center是你的首先,因為center一直有效,而frame在view做了transform變換后,frame就會失效,而center不會.

而屬性bounds的使用場景是在view中進行圖形繪制. 因為bounds表示view自己的坐標系,原點默認為(0,0),大小為指view的size.
如下圖所示圖片在父視圖中的位置是(40,40),大小是(240,380),所以圖片的frame是(40,40,240,380),而bounds是(0,0,240,380)

view的frame和bounds

改變frame,bounds,center中任意一個會影響其他屬性:

  • 當你設置frame時,bounds中的size會和frame中一致,center也會相應的改變
  • 當你設置center時,frame中origin會改變,但bounds不變
  • 當你設置bounds的size時,frame中的size會變,center不變
  • 當你設置bounds的origin時,frame,center都不變,但view中的subview受到影響(可以寫個demo自測一下,subview在屏幕上的位置會移動)

默認子view超出父view的邊界不會被裁剪. 當superview的屬性clipsToBounds設置為YES時,view超出superview的frame部分會被裁剪掉.但是touch event不會傳遞給邊界外的子view.

坐標系的變換

坐標系變換可以使view(和里面的內(nèi)容)更快地的變換. affine transform(仿射變換,旋轉(zhuǎn),縮放,位移)是一個矩陣. 在內(nèi)容繪制時,可以使用仿射變換來快速修改畫好的內(nèi)容:

  • 如果想給整個view進行變換那么直接給屬性transform設置一個CGAffineTransform的值
  • 如果自定義view時,在drawRect:中使用仿射變換對圖形進行修改

通常通過仿射變換給view進行選擇的動畫,如果想對view進行永久性位移和大小的改變則可以通過view的frame和center

當進行仿射變換時,是基于view的center,也就是說進行放射變換center是不變的,bounds也不會變

在方法drawRect:中,使用放射變換來移動和改變方向繪畫操作,而不是固定繪畫對象在一個位置; 在開始繪制前,通常是先將繪制的對象固定到一個點(通常為(0,0)),然后給對象做一次相應的位移變換;通過這種方式,如果改變繪制對象在view中,那么只需要通過再做一次放射變換,這樣比再創(chuàng)建一個新的繪圖對象更快更節(jié)省系統(tǒng)資源. 通過方法CGContextGetCTM來獲取繪圖上下文(graphic context)中的當前transform,通過core graphic中方法來設置和修改繪畫對象的transform.

給view進行幾何變換時,此時的current transform存放在view的屬性transform中,而在drawRect:中,transform是和繪畫上下文graphic context綁定在一起的.

每個subview在創(chuàng)建時是根據(jù)它們的superview的坐標系.如果給superview加上一個仿射變換后,那么subviews相對于屏幕來說也變動了,但相對于superview來說它們是沒有變化的,因為做放射變換時bounds不會變.

下圖展示了分別給superview和subview做旋轉(zhuǎn)變換的效果.在view的drawRect:方法中,給view中矩形旋轉(zhuǎn)45°,然后再給view旋轉(zhuǎn)45°,結(jié)果是view中的矩形好像旋轉(zhuǎn)了90°,其實相對于view來說矩形只旋轉(zhuǎn)了45°.

放射變換對view中內(nèi)容產(chǎn)生的影響

注意:如果view的transform不是identity transform的話,view的frame是無效的你需要忽略掉它.如果你對一個view做了放射變換那么你可以用bounds或者center來獲取view的位置和大小. view中的subview的frame是有效的

如果想學習更多關于放射變換的知識可以參考Apple文檔Drawing and Printing Guide for iOS

點和像素

在iOS中,坐標值和距離的單位是點(points),在代碼中用float表示. 但每一的物理表示(一點含有多個少個像素)和設備有關.點points確定了內(nèi)容繪制的結(jié)構(gòu)(屏幕大小).
下表中列舉了不同的設備的點數(shù):

設備 屏幕大小(點)
Iphone 5s,4英寸 320 x 568
iPhone 4s,3.5英寸 320 x 480
ipad 768 x 1024

points都是用來給view的坐標系做單位的,用與繪制內(nèi)容. 像素是屏幕的分辨率的單位,有的設備一個點等于一個像素,但有的高清屏幕上一個點等于多個像素, 所以你要牢記:點不一定和屏幕像素一一對應. 在繪制內(nèi)容時,不管是UIKit還是CoreGraphic都是用點為單位的,雖然底層系統(tǒng)會將點轉(zhuǎn)換為屏幕像素來顯示內(nèi)容,但我們在繪制代碼中不需要考慮,也就是說繪圖是不需要考慮當前設備屏幕分辨率.

在iOS中像OpenGL ES這種繪圖技術(shù)就是基于屏幕像素的,這是在繪圖代碼中就需要考慮屏幕像素. 還有像iOS中的圖片顯示就需要考慮屏幕的分辨率,在資源文件中iOS根據(jù)圖片的后綴(@2x,@3x)來自動轉(zhuǎn)換圖片來適配不同的分辨率的屏幕. UIView也提供了scale信息來基于像素繪圖技術(shù)的使用,如果想進一步學習該技術(shù)可以參考蘋果文檔Drawing and Printing Guide for iOS.中一節(jié)內(nèi)容:Supporting High-Resolution Screens In Views

View的runtime交互模型


任意時刻屏幕交互和代碼產(chǎn)生view的變化,在底層UIKit一系列復雜的操作來響應改變或者更新,在該系列操作過程中,UIKit暴露了一些點供開發(fā)者加入個性代碼.理解這些暴露點可以幫助理解view的底層邏輯.下圖展示了屏幕產(chǎn)生的touch事件后,view處理該事件將流程圖(代碼產(chǎn)生的view事件也是同樣的流程):

UIKit和view交互的流程圖

通過上圖的展示,我們可以看到在個狀態(tài)下發(fā)生了什么和開發(fā)者需要如何參與該交互流程以開發(fā)自己的應用:

  1. 用戶觸摸屏幕

  2. 硬件將觸摸事件報告給UIKit框架

  3. UIKit將觸摸事件封裝成UIEvent對象,然后將該對象派送到合適的view.(如果想進一步了解事件的傳遞和響應,請看Apple文檔: Event Handling Guide for iOS)

  4. 你需要在view中處理event,你的事件處理代碼可以如下:

    • 改變view或者view的subview的屬性(frame,bounds,alpha,等)
    • 調(diào)用view或者view的subview的setNeedsLayout來標記該view需要更新布局
    • 調(diào)用view或者view的subview的setNeedsDisplay或者setNeedsDisplayInRect:來標記該view需要重繪
    • 通知controller更新部分數(shù)據(jù)
      上面的動作根據(jù)個人需求來進行實施
  5. 如果view的在幾何上有更新,UIKit將會根據(jù)下面規(guī)則來更新view的subviews:

    1. 如果view使用了autoresizing, UIKit根據(jù)自動布局的規(guī)則來調(diào)整subviews.如果你想學習自動布局的工作原理請看Apple的文檔Handling Layout Changes Automatically Using Autoresizing Rules
    2. 如果你的view重寫了layoutSubViews方法,UIKit將會調(diào)用它
      • 自定義view時,在layoutSubViews中可以對該view中的subviews進行調(diào)整(比如,大小,位置). 舉個列子,有個這樣的view,該view很大需要滾動顯示. 那么我們可以創(chuàng)建幾個subview作為可復用的"磚頭"(tiles)來部分顯示內(nèi)容,而不是一下創(chuàng)建整個要顯示的內(nèi)容,不管怎么樣,這樣做不利于內(nèi)存的利用. 這時重寫layoutSubViews時,需要隱藏屏幕外的磚頭或?qū)⑺麄円苿有碌奈恢糜盟麄儊碇乩L將要顯示的內(nèi)容,需要重繪的磚頭的布局代碼此時也就失效了,需要重新設置布局.
  6. 如果view標記了需要重繪,那么UIKit會要求view重繪.

    • 自定義view重寫drawRect:,UIKit會自動調(diào)用該方法.需要注意的是在方法中只能做跟視覺更新有關的事情,不能干其他事情,比如更新數(shù)據(jù),更新布局等,需要快速的完成視覺上的更新. 系統(tǒng)提供的view通常不會實現(xiàn)drawRect:方法,但會在drawRect調(diào)用時來管理他們的內(nèi)容繪制.
  7. 任何需要更新的view會一起和應用中的其他視覺內(nèi)容打包壓縮給設備硬件

  8. 然后繪圖硬件將渲染好的內(nèi)容顯示到屏幕上

注意:上面的更新模型一般只適用于使用標準的系統(tǒng)view和標準的繪圖技術(shù)的應用. 如果你的應用中使用的OpenGL技術(shù)來繪圖話,情況就不一樣了,具體請看文檔OpenGL ES Programming Guide

在前面的步驟中,自定義view中的需要關注的幾個點有:

  • event-handing事件處理方法:
    • touchesBegan:withEvent:
    • touchesMoved:withEvent:
    • touchesEnded:withEvent:
    • touchesCancelled:withEvent:
  • layoutSubViews方法
  • drawRect:方法

上面那些方法是view提供給我們重寫的,你可以根據(jù)特定業(yè)務需求來重寫部分方法.比如你使用手勢時,event-handing方法就不需要重寫了,同樣view中不含subview,或者它size不變,那么就不需要重寫layoutSubviews方法,像drawRect:方法都是用來用重繪view中的內(nèi)容的,當view的內(nèi)容不需要更新時就不需要重寫該方法.
除了上述幾個主要的重寫方法,UIView還提供了其他方法供用戶重寫,具體請看UIView這個類.

關于view性能方面的幾個建議


再使用自定義view時,需要關注view的性能問題,在優(yōu)化view性能之前應該先收集數(shù)據(jù),然后在確定問題點之后才是優(yōu)化.

不是所有的view都有一個controller與之對應

controller管理view的層級樹,通常controller由很多個view組成.在iPhone中一個view層級樹通常充滿整個屏幕,iPad中有部分view的層級樹只是占屏幕的一部分.
你需要明確你應用中controller的作用. controller提供了許多功能,比如調(diào)整view的顯示,view移除和添加,切換,低內(nèi)存警告時,controller會釋放無用的view和對象,當設備旋轉(zhuǎn)時controller會旋轉(zhuǎn)view的方向以便顯示正常. 了解更多關于controller的信息請看Apple文檔View Controller Programming Guide for iOS

盡量少地繪制內(nèi)容

view的內(nèi)容繪制非常耗性能,所以不要繪制多余的東西,繪制算法要足夠好. 如果許多不同view中的內(nèi)容可以結(jié)合在一個view繪制,那么最好將其結(jié)合繪制.如果系統(tǒng)的view能解決問題,那么久沒必要集成UIView后重寫drawRect:方法.

充分利用view的Content Modes

content mode能夠減少view繪制的時間. 默認情況下view的contentMode是UIViewContentModeScaleToFill,避免使用UIViewContentModeRedraw

盡量將view設為不透明(Opaque設置NO)

view的屬性opaque控制了view的透明度.如果將它設置YES的話,UIKit需要花資源去將幾個不同view內(nèi)容混合渲染來顯示最終結(jié)構(gòu),這樣很性能.所以能使view不透明就不透明.

當你view在滾動時,view的繪圖策略需要調(diào)整

view在滾動時在短時間內(nèi)會導致view大量重繪.所以如果你的重繪代碼的算法不好的,就會產(chǎn)生性能問題. 舉個列子:在滾動時你可以占時將內(nèi)容的繪制的質(zhì)量降低或者改變content mode,當滾動結(jié)束后,將view更新到之前的狀態(tài)并且更新內(nèi)容.

不要在自定義控件中內(nèi)嵌subviews

雖然理論上可以自定義控件,但蘋果建議你不要這樣干. 控件的自定義可以通過控件本身提供的接口來實現(xiàn),這些接口是經(jīng)過了良好的設計的; 就像UIButton,你想改變它的背景圖片,你可以通過UIButton中方法setBackgroundImage: forState:來實現(xiàn).使用UIKit定義好的接口能保證代碼運行正確,如果你自己添加一個imageView進去控件中的話,可能會導致一些錯誤(可以看蘋果本文檔的英文原文).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子阴孟,更是在濱河造成了極大的恐慌,老刑警劉巖剂癌,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異翰绊,居然都是意外死亡佩谷,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門监嗜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谐檀,“玉大人,你說我怎么就攤上這事裁奇⊥┾” “怎么了?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵刽肠,是天一觀的道長溃肪。 經(jīng)常有香客問我,道長音五,這世上最難降的妖魔是什么惫撰? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮躺涝,結(jié)果婚禮上厨钻,老公的妹妹穿的比我還像新娘。我一直安慰自己坚嗜,他們只是感情好夯膀,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著苍蔬,像睡著了一般诱建。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上碟绑,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天涂佃,我揣著相機與錄音,去河邊找鬼蜈敢。 笑死,一個胖子當著我的面吹牛汽抚,可吹牛的內(nèi)容都是我干的抓狭。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼造烁,長吁一口氣:“原來是場噩夢啊……” “哼否过!你這毒婦竟也來了午笛?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤苗桂,失蹤者是張志新(化名)和其女友劉穎药磺,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體煤伟,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡癌佩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了便锨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片围辙。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖放案,靈堂內(nèi)的尸體忽然破棺而出姚建,到底是詐尸還是另有隱情,我是刑警寧澤吱殉,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布掸冤,位于F島的核電站,受9級特大地震影響友雳,放射性物質(zhì)發(fā)生泄漏稿湿。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一沥阱、第九天 我趴在偏房一處隱蔽的房頂上張望缎罢。 院中可真熱鬧,春花似錦考杉、人聲如沸策精。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽咽袜。三九已至,卻和暖如春枕稀,著一層夾襖步出監(jiān)牢的瞬間询刹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工萎坷, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凹联,地道東北人。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓哆档,卻偏偏與公主長得像蔽挠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子瓜浸,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

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

  • 重點參考鏈接: View Programming Guide for iOS https://developer....
    Kevin_Junbaozi閱讀 4,430評論 0 15
  • 1澳淑、通過CocoaPods安裝項目名稱項目信息 AFNetworking網(wǎng)絡請求組件 FMDB本地數(shù)據(jù)庫組件 SD...
    陽明先生_X自主閱讀 15,979評論 3 119
  • 周末難得有出去玩的機會了比原,玩點這些幼稚的充氣堡孩子也覺得特別開心。 今天收獲還可以杠巡,釣了幾條了量窘。
    joyful悅閱讀 211評論 0 0
  • 果然男人是很現(xiàn)實的動物,如果女性在交往的過程中也算清楚了利弊氢拥,就像文中這樣蚌铜,還會有這么多怨女么?但是人人如果連感情...
    靜心看人生閱讀 155評論 0 0
  • 沒有嘗試過,永遠不會知道自己能有多優(yōu)秀 2018我開啟了學習hard模式出革。學習有三種模式: 1造壮、有人手把手的教; ...
    三丘的世界閱讀 543評論 0 0