Core Animation編程指導(三)-設置Layer對象

layer對象是你進行CoreAnimation操作的核心. layer對象管理著界面中顯示的內容, 并提供機會讓你去修改內容的風格和外觀. 雖然iOS中的view默認有一個layer支持, 但是開發(fā)OS X系統(tǒng)上的APP時需要自己顯示啟用layer來使用它. 當你啟用layer時,你需要了解如何去設置layer, 以便讓layer發(fā)揮應有的功能.

讓你APP使用CoreAnimation


iOS中的App總是開啟了layer支持, 所以CoreAnimation也是開啟的. OS X中的App需要自己通過下面操作來顯示開啟:

  • 鏈接到QuartzCore框架(iOS App要鏈接這個框架需要顯示的調用CoreAnimation中的API)
  • 如果要讓layer支持NSView, 需要完成如下操作:
    • 在nib文件中, 通過View Effects檢測器來開啟layer支持. 在該檢測器中會顯示checkbox來表示是否選擇view或者它的subview. 強烈推薦開啟window中content view的layer支持
    • 如果通過代碼創(chuàng)建的view, 你可以調用setWantsLayer:(傳YES)方法來開啟layer支持.

使用前面方法開啟layer支持, 會創(chuàng)建layer-backed視圖, 對于layer-backed view系統(tǒng)會負責創(chuàng)建底層layer, 并同步view信息. 在OS X中, 你還可以創(chuàng)建layer-hosting view, 這就意味著APP需要自己負責創(chuàng)建底層支持的layer, 并同步view的信心, 另外在iOS中是無法創(chuàng)建layer-hosting view的, 因為iOS中的view都是layer-backed.

修改和view關聯(lián)的layer對象


layer-backed view會默認創(chuàng)建一個CALayer實例, 而且大多數(shù)情況下, 都是使用這個類來創(chuàng)建. 但是CoreAnimation提供了其他類型的Layer, 在某些情況下, 你可以發(fā)現(xiàn)某些類型的layer還是蠻有用的, 比如, 當你的view需要展示一張超大的圖片是, 你可以使用CATiledLayer, 這樣可以提高性能.

修改UIView使用的layer

你可以通過重寫view中的layerClass類方法來修改view背后layer的類型. iOS中大部分view背后的layer都是CALayer類型. 大多數(shù)情況下, 使用默認類型的layer是好的, 但是某些情況下, 你需要使用其他類型的layer, 比如下面列舉的幾種情況:

  • 如果你使用Metal或OpenGL ES技術來繪制view中的內容, 你需要使用CAMetalLayerCAEAGLLayer類型的layer對象.
  • 有幾種layer是用來改善性能的, 比如CATiledLayer
  • 你需要使用某種layer的特性, 比如粒子發(fā)射器和復制器.

修改view的layer類型很簡單, 如代碼2-1所示. 你只需要重寫layerClass類方法, 在方法中返回一個你想要的layer類型即可. 該方法會在view顯示之前調用, 來獲取layer的類型, 然后通過該類創(chuàng)建一個新的layer對象. 當layer創(chuàng)建后, view的layer對象就不能被改變了.
代碼清單2-1 設置iOS中view的layer

+ (Class) layerClass {
   return [CAMetalLayer class];
}

在OS X中通過layer-hosting技術來修改layer對象

如果你的NSView對象是一個layer-hosting view. 那么, 需要App自己管理view底層的layer對象. 在你需要控制與view關聯(lián)的layer對象類型的情況下, 你可以使用hosting layer. 比如, 你創(chuàng)建一個layer-hosting視圖, 以便可以分配除默認CALayer類型外的layer. 你還可能在為了用單個view管理一個獨立的layer樹的情況下使用layer-hosting技術.

當你調用view的setLayer:方法設置一個layer時, AppKit就不會干涉這個layer了. 正常情況下, AppKit會更新view的layer對象, 但是在layer-hosting情況下, AppKit不會更新layer.

為了創(chuàng)建一個layer-hosting視圖, 你需要在view顯示之創(chuàng)建一個layer, 并將layer和view關聯(lián)起來, 如代碼2-2所示. 另外, 為了設置layer對象, 你必須調用setWantsLayer:方法, 讓view知道要開啟layer支持了.

代碼清單2-2 創(chuàng)建layer-hosting視圖

// Create myView...
[myView setWantsLayer:YES];
CATiledLayer* hostedLayer = [CATiledLayer layer];
[myView setLayer:hostedLayer];
// Add myView to a view hierarchy.

如果你使用host layer時, 你需要給layer設置好contentScale, 并在高分辨的屏幕上提供高分辨率的內容.

不同類型的layer擁有不同的特性

CoreAnimation定義了好幾種layer類, 每個類都是為了不同需求而定義的. CALayer是這些類的root類, 該類定義了多種layer類的共有的特性, 并支持layer的基本特性. 下面列舉了CALayer幾個子類的特性, 和適用場景, 如表2-1
表2-1 CALayer子類和使用場景

Class 使用
CAEmitterLayer 用于使用CoreAnimation中粒子發(fā)射器系統(tǒng). emitter layer負責創(chuàng)建粒子和控制這些粒子的origin
CAGradientLayer 用于繪制漸變顏色的layer
CAMetalLayer 用于使用Metal技術繪制文本內容的layer
CAEAGLLayer/CAOpenGLLayer 用于使用OpenGL ES(iOS)或OpenGL(OS X)技術繪制內容的layer
CAReplicatorLayer 如果你想自動復制sublayer. replicator為你創(chuàng)建副本,并提供屬性供你修改外觀和其他屬性.
CAScrollLayer 用于管理大片可滾動的由大量sublayer組成的區(qū)域
CAShapeLayer 用于繪制三次bezierpath, shape layer對于繪制基于路徑的圖形是有利的.
CATextLayer 用于渲染純文本, 或者attributed string
CATiledLayer 用于顯示和管理大型圖片, 它會將大圖切割成小圖,然后逐個渲染, 而且支持縮放. 能提高性能
CATransformLayer 用于渲染真正的3D圖形
QCCompositionLayer 用于渲染Quartz Composer中的合成內容(僅OS X)

設置layer中的內容


layer是管理App內容的數(shù)據(jù)對象. layer的內容由一個bitmap組成, bitmap包含了你想顯示的數(shù)據(jù)信息. 你可以通過下面三種方式來為layer提供bitmap:

  • 直接將一個圖像設置到layer的contents屬性中. (這種方式適合當layer的內容不變, 或者很少改變情況)
  • 給layer設置一個delegate, 然后讓delegate去繪制layer中內容. (這種方式適合layer的內容會周期性地改變并且layer的內容可以由外部對象提供, 比如view)
  • 定義一個layer子類, 并重寫layer中的繪制方法來自己提供layer的content. (這種方式適合你需要創(chuàng)建一個自定義的layer, 并且你想改變layer的底層繪制行為)

當你自己創(chuàng)建layer對象時, 你唯一需要操心的是為layer提供內容. 但是如果你的App只包含layer-backed視圖時, 這個操心你也省了, 因為UIView會以最好的方式為view關聯(lián)的layer提供內容.

使用一個image來作為layer的content

因為layer對象是一個管理bitmap圖像的容器, 所以你可以直接將一個image對象賦值給layer的contents屬性. 這種操作比較簡單, 也能讓你直接將image顯示在屏幕上, 而不需要UIImageView來顯示. layer對象會直接使用這個image對象, 而不是創(chuàng)建一個副本image(普通內容話, 最終會創(chuàng)建內容image副本), 這樣也可以節(jié)省內存, 因為App可能在多個地方使用同一個image.

你給layer賦值的image類型必須是CGImageRef類型. (在 OS X v10.6及以后, 你也可以使用NSImage來賦值). 在使用image最為layer的content時, 注意圖像的分辨率要和設備屏幕分辨率相匹配. 如果設備屏幕時retina屏幕, 那么你需要調整image的contentsScale屬性.

使用一個delegate對象來為layer提供內容

如果layer中的內容會經常改變, 那么你可以使用一個delegate對象來提供并且更新layer中的內容. 在準備顯示之前, layer會調用delegate中的方法來獲取所需的內容:

  • 如果你的delegate實現(xiàn)了displayLayer:方法, 該方法就可以layer創(chuàng)建一個bitmap, 然后將其賦值給layer的contents屬性.
  • 如果你的delegate實現(xiàn)了drawLayer:inContext:方法, CoreAnimation會創(chuàng)建一個bitmap繪圖上下文, 你需要在該方法中將你想要的內容繪制到bitmap中.

layer的delegate必須實現(xiàn)上面兩個方法中的一個, 如果兩個都實現(xiàn)了的話, layer只會調用displayLayer:方法.

重寫displayLayer:方法適用于App偏向創(chuàng)建或加載要顯示的的內容的bitmap. 代碼2-3是displayLayer:方法的一個實現(xiàn)例子. 在該例中, delegate會使用一個工具類來幫忙加載并且顯示想要的image. delegate根據(jù)內部的一個狀態(tài)displayYesImage來選擇要展示的image.
代碼清單2-3 直接設置layer的contents

- (void)displayLayer:(CALayer *)theLayer {
    // Check the value of some state property
    if (self.displayYesImage) {
        // Display the Yes image
        theLayer.contents = [someHelperObject loadStateYesImage];
    }
    else {
        // Display the No image
        theLayer.contents = [someHelperObject loadStateNoImage];
    }
}

如果你沒有渲染好的image圖像, 也沒有工具類幫助你創(chuàng)建一個bitmap, 那么delegate可以通過drawLayer:inContext:自己繪制想要的內容. 代碼2-4是一個drawLayer:inContext:實現(xiàn)的一個例子. 在該例子中的delegate使用固定的線寬和描邊顏色來繪制一條曲線.
代碼清單2-4 繪制layer中的內容

- (void)drawLayer:(CALayer *)theLayer inContext:(CGContextRef)theContext {
    CGMutablePathRef thePath = CGPathCreateMutable();
 
    CGPathMoveToPoint(thePath,NULL,15.0f,15.f);
    CGPathAddCurveToPoint(thePath,
                          NULL,
                          15.f,250.0f,
                          295.0f,250.0f,
                          295.0f,15.0f);
 
    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, thePath);
 
    CGContextSetLineWidth(theContext, 5);
    CGContextStrokePath(theContext);
 
    // Release the path
    CFRelease(thePath);
}

對于自定義內容的layer-backed視圖來說, 需要重寫view的方法來完成繪制. layer-backed視圖會自動將自己設置為它的layer的delegate并實現(xiàn)了delegate方法, 而你需要做的, 就是實現(xiàn)drawRect:方法, layer的配置你不能動.

在OS X v10.8及以后, 有一種自己繪制的替代方法, 就是重寫view的wantsUpdateLayerupdateLayer方法. 在wantsUpdateLayer中返回YES, 這回告訴NSView使用替代流程. 然后你再實現(xiàn)updateLayer方法, 在該方法中, 你需要使用bitmap賦值給layer的contents屬性. 這是AppKit希望直接設置視圖的layer內容的一種情況

通過子類來提供layer的內容

如果打算自定義layer, 那么你可以通過實現(xiàn)layer中的繪制方法來繪制任何你需要的內容. layer通常不會自己生產定制的內容, 但是layer可以管理要顯示的內容. 像CATiledLayer類就可以將一個大圖分解許多小圖(tile), 然后單獨將這些小圖渲染出來. 因為只有l(wèi)ayer知道這些小圖的渲染需要的信息, 所以layer直接參與管理繪制的過程.

如果你使用繼承的方式, 那么你可以使用技術之一來繪制layer中的內容:

  • 重寫layer的display方法, 然后直接給屬性contents賦值.
  • 重寫layer的drawInContext:方法, 使用該方法在繪圖上下文中繪制內容.

根據(jù)需要控制layer繪制內容的程度來選擇上面的兩個方法. display方法是layer更新內容的主入口, 所以你重寫該方法可以完全控制layer的內容繪制. 另外, 你重寫display方法的話, 你要負責創(chuàng)建CGImageRef對象并負責給contents屬性. 如果你只是向控制layer的內容的繪制操作, 你可以重寫drawInContext:, 這樣可以讓layer為你創(chuàng)建后備緩存.

對你提供的layer內容進行微調

當你給contents屬性賦值時, layer會根據(jù)屬性contentsGravity來控制content來適配layer的bounds的. 默認情況下, 如果圖片大于或小于layer的bounds, layer會縮放圖片來適配當前的bounds. 如果圖片的寬高比和bounds的寬高比不一致的話, 這樣會導致圖片變形. 所以你可以使用contentsGravity來控制contents在layer中顯示適當.

contentsGravity的值可以分為兩類:

  • 基于位置的gravity常量讓你將圖片對齊layer的bounds區(qū)域內的邊或頂角, 不會進行縮放.
  • 基于縮放的gravity常量讓你可以將圖片進行拉伸, 某些配置可以讓拉伸按照寬高比來進行, 也有些配置不會.

圖2-1展示了基于位置的gravity設置圖片的影響. 除了kCAGravityCenter常量外, 其它常量都是讓圖片緊靠bounds的四邊或四角. kCAGravityCenter常量讓圖片處于layer的中心位置, 圖片不會拉伸, 如果圖片的size大于layer的bounds, 那么圖片超出bounds的部分將會被剪切; 如果圖片的size小于bounds, 那么圖片外的layer區(qū)域會顯示背景顏色(如果layer設置了背景顏色).

圖2-1 基于位置的gravity常量

圖2-3展示了縮放gravity設置對layer內容(圖片)的影響. 這些基于縮放的gravity常量會根據(jù)當前圖片是否適配layer的bounds來縮放圖片, 區(qū)別是-這些常量對寬高比的處理方式不一樣, 有些保持原寬高比不變, 有些會改變寬高比. 屬性contentsGravity的默認值為kCAGravityResize常量, 這個常量是唯一不會維持圖片的寬高比不變的.

圖2-3 layer的基于縮放的gravity常量

使用高分辨率圖片

layer并不知道設備屏幕分辨率. layer只是保存了一個指向bitmap的指針然后將其用合適的方式將bitmap顯示出來. 如果你給layer的contents屬性賦值了, 你必須通過layer的屬性contentsScale來告訴CoreAnimation關于image的分辨率的. layer的contentsScale屬性的默認值是1.0, 適用在普通屏幕上顯示圖像. 如果你的圖片是retina版本的, 那么該屬性的值應該設置為2.0.

當且僅當你直接給layer設置一個bitmap時, 你才改變contentsScale的值. 像UIKit和AppKit中的layer-backed視圖, 你是不需要關注contentsScale的, 因為layer-backed視圖會自動更加屏幕分辨率來給layer設置合適的scale. 比如, 在OS X中, 你將一個NSImage對象賦值給layer的contents屬性, AppKit會檢測image的分辨率, 然后使用合適的值來設置layer的contentsScale.

在OS X中, 基于位置的gravity常量會影響賦值給layer的NSImage選擇表現(xiàn)的方式. 因為這些常量都不會對image進行縮放, CoreAnimation根據(jù)contentsScale屬性來選擇合適的像素密度來展示image.

在OS X中, layer的delegate可以通過實現(xiàn)方法layer:shouldInheritContentsScale:fromWindow:來響應scale因子的改變. 當window的分辨率改變(可能因為window的分辨率在普通和高倍之間切換)時, AppKit會調用這個方法, 在方法中, 如果delegate支持image的分辨率的變化, 你應該返回YES, 然后你還應該更新layer的內容以適配新的分辨率.

調整layer視覺風格和外觀


layer對象內置了許多視覺上的修飾, 比如邊界(border)/背景顏色, 通過修改這些來裝飾layer中的主體內容. 因為這些視覺裝飾部分由layer自己控制, 所以這些效果都是通過layer的屬性來設置的, 你不需要你自己進行繪制, 包括部分動畫. 關于如何使用這些視覺裝飾來影響layer的外觀的詳細知識, 請看后續(xù)系列文章-補充中的Layer Style Property Animations

layer有自己的背景和邊界

layer除了可以展示基于圖像的內容外, 還可以顯示背景和描邊. layer中, 背景在主體內容后面, 但描邊顯示在主體內容前面, 如圖2-3所示. 如果layer包含子layer, 它們也會出現(xiàn)在描邊的下面. 因為背景是在內容的下面, 如果內容有透明部分, 將會透過內容看到背景.


圖2-3 往layer中添加描邊和背景

代碼2-5展示如何設置layer的背景和描邊, 下面涉及的屬性都是可動畫的.
代碼清單2-5 設置layer的背景顏色和描邊顏色

myLayer.backgroundColor = [NSColor greenColor].CGColor;
myLayer.borderColor = [NSColor blackColor].CGColor;
myLayer.borderWidth = 3.0;

注意:layer的背景可使用任何類型的顏色, 比如漸變, 圖案等都可以, 在使用圖案最為背景時, 記得CoreAnimation能使用硬件加速能很好的處理背景圖案, 但是要記得CoreAnimation中的坐標系和iOS中默認坐標系不一樣, 可能需要翻轉坐標系.

如果你的layer的背景是透明的顏色, 考慮可以將layer的opaque屬性設置為YES, 這樣做免去layer內容和layer背后的圖片進行合成, 也可以省去layer開啟后備存儲來處理alpha通道(alpha channel). 但是你layer有個非零的圓角,那么layer不能設置為opaque.

layer支持圓角

你可以給layer叫上圓角(corner radius)來創(chuàng)建圓角矩形. 一個圓角是通過在layer的bounds矩形的四個角上加一個一個圓形遮罩(mask), 讓layer四角上的內容透過遮罩顯示, 如圖2-4所示. 因為涉及使用的是透明遮罩, 所以corner radius對layer中的contents不會影響, 除非你將屬性masksToBounds設置為YES. 但一定會影響layer的背景和border的繪制.

圖2-4 layer上的corner radius

layer提供cornerRadius屬性讓你來設置圓角, 該屬性值為圓角半徑, 單位是點.

layer的內置陰影

CALayer包含好幾個屬性用來設置layer的陰影效果. 陰影效果使的layer中的內容好像懸浮界面上其他內容之上, 讓界面看起來又具有深度. 這種效果在某些場景比較有用. 通過layer, 你可以控制陰影的顏色, 便宜位置, 透明度, 和形狀.

默認情況下, 陰影的opacity為0, 完全隱藏的, 所以你需要將印象的opacity設置為非零值. 另外, 陰影是直接位于內容的正下方, 如果想看到陰影, 你需要設置陰影的offset, 這樣才能看到陰影. 你在設置陰影時, 需要記得這兩點. 在設置陰影的offset時, iOS和OS X是有區(qū)別的, 因為坐標系不一樣. 如圖2-5, 同樣的效果, 在iOS中y的值為正, 而在OSX中為負.


圖2-5 設置layer的陰影

當你給layer加上陰影后, 陰影也屬于內容的一部分, 但是陰影的區(qū)域實際上是超出layer的bounds區(qū)域的. 如果masksToBuounds設置為YES的話, 陰影會被bounds裁剪. 如果你即想要陰影, 又想要bounds masking的話, 你可以使用兩個相同內容的layer疊加在一起, 上面那個開啟masksToBounds, 下面那個設置陰影. 也可以將第一層添加到第二層中.

關于如何設置shadow的列子, 可以看補充中的Shadow Properties

使用過濾器(filters)向OS X視圖中添加視覺效果

在OS X應用程序中, 你可以直接向layer中的content上應用一個Core Image過濾器. 這樣你可以進行模糊或者銳化layer中的內容, 修改顏色, 扭曲內容等一些操作. 比如, 一個圖片處理進程可能使用過濾器來無損地修改圖像, 而視頻編輯程序可以使用它來實現(xiàn)不同類型視頻切換小姑. 并且由于過濾器會使用硬件加速, 所以渲染時快速且平滑的.

注意:你不能往iOS中的layer對象中添加過濾器

對于給定的layer, 你可以將過濾添加到layer的foreground content和background content中. foreground content包括layer本身所包含的所有內容, 包括屬性contents中的image, 背景顏色, border, 和sublayer中的內容. background content是直接在layer的下面, 實際上并不是layer本身的一部分. 大多數(shù)layer的background content是其直接super layer的內容, 這些內容部分或者全部地被遮住. 例如, 當你希望用戶應該關注layer的foreground部分時, 你可以將模糊過濾器加入background content中.

你可以通過下面的一些屬性來設置一個CIFilter過濾器:

  • 屬性filters包含一組過濾器, 加入的是layer的foreground content.
  • 屬性backgroundFilters包含的一組過濾器, 加入是layer的background content中.
  • 屬性compositingFilter中的過濾器定義如何將foreground content和background content組合在一起.

為了往layer中添加過濾, 第一步是創(chuàng)建一個CIFilter對象, 之后配置該對象. CIFilter類提供了好幾個類方法用來配置CIFilter對象, 比如filterWithName:. 所以創(chuàng)建過濾器對象只是第一步, 好多過濾器需要許多參數(shù)來定義如何修改一個圖像. 比如, 一個box blur過濾器與一個輸入半徑的參數(shù), 定義了模糊的程度. 所以, 添加過濾器之前你總是要配置好這些參數(shù). 而且這些過濾器的有一個共同的參數(shù)不需要你設置, 那就是輸入的image, 這個參數(shù)由layer自己來設置.

所以在添加過濾器之前, 你需要配置好過濾器, 因為, 一旦過濾器添加到layer后, 你是不能通過CIFilter提供的API來修改過濾器的. 但是, 你可以通過layer的setValue:forkeyPath:方法來改變過濾器的值.
代碼2-6展示了如何創(chuàng)建一個pinch distortion過濾器并添加到layer對象中. 該過濾可以通過向內捏合使中心點像素失真. 注意, 在這個示例中, 不需要為過濾器指定輸入圖像, 因為layer中的圖像會被自動使用.
代碼清單2-6 往layer中添加過濾器

CIFilter* aFilter = [CIFilter filterWithName:@"CIPinchDistortion"];
[aFilter setValue:[NSNumber numberWithFloat:500.0] forKey:@"inputRadius"];
[aFilter setValue:[NSNumber numberWithFloat:1.25] forKey:@"inputScale"];
[aFilter setValue:[CIVector vectorWithX:250.0 Y:150.0] forKey:@"inputCenter"];
 
myLayer.filters = [NSArray arrayWithObject:aFilter];

關于更多過濾的使用方法, 請見Core Image Filter Reference

OS X中view的重繪策略會影響性能


在OS X中,layer-backed視圖支持幾個不同的策略來確定何時更新底層layer的內容闸度。因為原生AppKit繪圖模型和CoreAnimation引入的模型之間存在差異莺禁,所以這些策略使得將舊代碼遷移到CoreAnimation上來更加容易哟冬。您可以在逐個視圖的基礎上配置這些策略浩峡,以確保每個視圖的最佳性能。

每個視圖定義了一個layerContentsRedrawPolicy方法青柄,該方法返回視圖layer的重繪策略致开。使用setLayerContentsRedrawPolicy:方法設置策略双戳。為了保持與傳統(tǒng)繪圖模型的兼容性飒货,AppKit默認將重繪策略設置為NSViewLayerContentsRedrawDuringViewResize塘辅。但是扣墩,可以將策略更改為表2-2中的任何值呻惕。請注意亚脆,推薦的重繪策略不是默認策略濒持。
表2-2 layer的重繪策略

策略 使用
NSViewLayerContentsRedrawOnSetNeedsDisplay 推薦使用,具體見The Layer Redraw Policy for OS X Views Affects Performance
NSViewLayerContentsRedrawDuringViewResize 默認,見The Layer Redraw Policy for OS X Views Affects Performance
NSViewLayerContentsRedrawBeforeViewResize 見The Layer Redraw Policy for OS X Views Affects Performance
NSViewLayerContentsRedrawNever 見The Layer Redraw Policy for OS X Views Affects Performance

給layer添加自定義屬性


CAAnimationCALayer這兩個類擴展了KVC(key-value coding)方便支持自定義屬性. 你使用這種特性往layer中添加數(shù)據(jù)并用你定義的key來獲取該數(shù)據(jù). 你也可以將一個動作和自定義屬性關聯(lián)起來, 以便在更改屬性時執(zhí)行相應的動畫. 有關如何設置和獲取自定義屬性的知識, 請參考Key-Value Coding Compliant Container Classes, 有關如何向layer對象添加action的知識, 請參考Changing a Layer’s Default Behavior

打印layer-backed視圖中的內容


在打印期間郁竟,layer根據(jù)需要重新繪制其內容以適應打印環(huán)境棚亩。雖然CoreAnimation通常依賴于緩存的位圖,當渲染到屏幕上時纺阔,它會重畫打印時的內容笛钝。特別地玻靡,如果layer-backed視圖使用drawRect:方法提供層內容囤捻,那么CoreAnimation在打印期間會再次調用drawRect:來生成打印的layer內容蝎土。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市蒜撮,隨后出現(xiàn)的幾起案子淀弹,更是在濱河造成了極大的恐慌菌赖,老刑警劉巖琉用,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異晶丘,居然都是意外死亡沫浆,警方通過查閱死者的電腦和手機滚秩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門本股,熙熙樓的掌柜王于貴愁眉苦臉地迎上來痊末,“玉大人,你說我怎么就攤上這事盒件〕吹螅” “怎么了翔始?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長狼电。 經常有香客問我蜒灰,道長,這世上最難降的妖魔是什么肩碟? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任强窖,我火速辦了婚禮,結果婚禮上削祈,老公的妹妹穿的比我還像新娘翅溺。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布未巫。 她就那樣靜靜地躺著窿撬,像睡著了一般叙凡。 火紅的嫁衣襯著肌膚如雪严里。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天冠胯,我揣著相機與錄音悉盆,去河邊找鬼耗美。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼打洼!你這毒婦竟也來了酝锅?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤苛聘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后拣宰,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晌该,經...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡舟茶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年针余,在試婚紗的時候發(fā)現(xiàn)自己被綠了伪朽。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坚洽。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡援所,死狀恐怖谱煤,靈堂內的尸體忽然破棺而出硫惕,到底是詐尸還是另有隱情秋忙,我是刑警寧澤苦蒿,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布,位于F島的核電站甲喝,受9級特大地震影響,放射性物質發(fā)生泄漏悄雅。R本人自食惡果不足惜览徒,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一稿湿、第九天 我趴在偏房一處隱蔽的房頂上張望神帅。 院中可真熱鬧元镀,春花似錦遇革、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽员淫。三九已至,卻和暖如春击敌,著一層夾襖步出監(jiān)牢的瞬間介返,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工沃斤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留圣蝎,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓衡瓶,卻偏偏與公主長得像徘公,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鞍陨,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內容