《iOS UI 開發(fā)捷徑 利用 Interface Builder 高效预茄、優(yōu)雅地開發(fā) UI》 讀書筆記

第1章 Interface Bundle 概要


Bundle

一種標準化的層次結(jié)構(gòu)催式,保存了可執(zhí)行代碼及代碼所需要的資源悬而。

nib

Next Interface Builder

Interface Builder 的優(yōu)點

  1. 開發(fā)和維護效率高
  2. 減少大量的 UI 代碼和“膠水代碼”
  3. 適配變得十分簡單
  4. IB 也可以做一些非 UI 的事情
  5. 利用 IB 學(xué)習控件可以達到事半功倍的效果

Interface Builder 的缺點

  1. IB 的執(zhí)行效率沒有純代碼高
  2. 使用 IB 開發(fā)的過程中容易出現(xiàn)一些小問題
  3. 有一定的學(xué)習成本
  4. 文件易沖突
  5. 沒有代碼表達清晰
  6. 不利于代碼的封閉和工程架構(gòu)的組織

Interface Builder 學(xué)習的特點

  1. 簡單呜舒,容易入門
  2. 容易犯錯誤
  3. 有很多的“坑”锭汛,需要積累屬于自己的經(jīng)驗

Interface Builder 的發(fā)展

xib -> sb -> AutoLayout -> LaunchScreen.storyboard

蘋果越來越重視 IB笨奠。

CocoaPods

# 1 最新版本
pod 'AFNetworking'

# 2 最新的2.x版本
pod 'AFNetworking', '~>2.5.3'

# 3 指定版本
pod 'AFNetworking', '2.5.3' 

試用

$ pod try AFNetworking

Podfile文件與CocoaPods的三種依賴方式

  • 遠程依賴
# master
pod 'Alamofile', :git => 'https://github.com/Alamofile/Alamofile.git'

# branch
pod 'Alamofile', :git => 'https://github.com/Alamofile/Alamofile.git', :branch -> 'dev'

# commit
pod 'Alamofile', :git => 'https://github.com/Alamofile/Alamofile.git', :commit => '0f506b1c45'
  • 本地依賴
pod 'AFNetworking', :path => '../externals/libs/AFNetworking'
  • 私有依賴
pod 'AFNetworking', :podspec => '../externals/libs/AFNetworking.podspec'

“:podspec=>”用于指定本地的一個xxx.podspec文件。

podspec文件

$ pod init
$ cat Podfile

第2章 使用 Interface Builder


解決沖突

  1. 解決普通IB文件沖突

Open As -> Source Code

<<<<<<<

=======

>>>>>>>

編輯好唤殴,再刪除這三行就可以了般婆。

  1. 解決 Xcode 8 引起的 IB 文件沖突

如果用 Source Code 不能打開,就用文件編輯器(vim, etc)打開朵逝,把systemVersion等沖突解決蔚袍。

關(guān)聯(lián) xib 文件與源文件

  1. 關(guān)聯(lián) xib 文件與 UIView 子類的源文件
  • 新建一個空的xib文件,拖一個UIView上去
  • 新建一個繼承自UIView的源文件
  • 選中xib文件里的View,把class改為上面

@IBOutlet 與 @IBAction

連線

設(shè)計模式之MVC

mvc

理解 File's Owner

關(guān)聯(lián) xib 文件與 UIViewController 子類的源文件

  • 自定義一個 VC 的 View 的兩種方法
  1. 在 IB 文件中選中 VC 所在的 View配名,在 Show the Identity inspector 中設(shè)置 Class 標簽的值為自定義的 View 的類名啤咽。
  2. 在源文件的 loadView() 方法里設(shè)置該 VC 的 View 屬性為這個自定義的 View。
override func loadView() {
    self.view = CustomView.init(frame: UIScreen.main.bounds)
}
  • File's Owner 指向 VC

  • VC 的 View 連線

xib 既可以與 UIView 關(guān)聯(lián)渠脉,也可以與 UIViewController 關(guān)聯(lián)宇整,也可以同時關(guān)聯(lián) UIView 與 UIViewController

使用 xib

  1. 通過 Bundle 方式加載
  2. 通過 UINib 方式加載

使用與UIView子類源文件關(guān)聯(lián)的xib

Bundle

- (NSArray *)loadNibNamed:(NSString *)name 
                    owner:(id)owner 
                  options:(NSDictionary *)options;
func loadNibNamed(_ name: String, 
            owner: Any?, 
          options: [AnyHashable : Any]? = nil) -> [Any]?

Parameters 參數(shù)

  • name
    The name of the nib file, which need not include the .nib extension.
    nib名稱
  • owner
    The object to assign as the nib’s File's Owner object.
    如果xib文件有File's Owner,一定傳其實例對象芋膘,否則傳nil
  • options
    A dictionary containing the options to use when opening the nib file. For a list of available keys for this dictionary, see UIKit Nib Loading Options.
Bundle Demo
let testView = Bundle.main.loadNibNamed("TestView", owner: nil, options: nil)?[0] as! UIView
view.addSubview(testView)

UINib

NS_CLASS_AVAILABLE_IOS(4_0) @interface UINib : NSObject 

// If the bundle parameter is nil, the main bundle is used.
// Releases resources in response to memory pressure (e.g. memory warning), reloading from the bundle when necessary.
+ (UINib *)nibWithNibName:(NSString *)name bundle:(nullable NSBundle *)bundleOrNil;

// If the bundle parameter is nil, the main bundle is used.
+ (UINib *)nibWithData:(NSData *)data bundle:(nullable NSBundle *)bundleOrNil;

// Returns an array containing the top-level objects from the NIB.
// The owner and options parameters may both be nil.
// If the owner parameter is nil, connections to File's Owner are not permitted.
// Options are identical to the options specified with -[NSBundle loadNibNamed:owner:options:]
- (NSArray *)instantiateWithOwner:(nullable id)ownerOrNil options:(nullable NSDictionary *)optionsOrNil;
@end
@available(iOS 4.0, *)
open class UINib : NSObject {

    
    // If the bundle parameter is nil, the main bundle is used.
    // Releases resources in response to memory pressure (e.g. memory warning), reloading from the bundle when necessary.
    public /*not inherited*/ init(nibName name: String, bundle bundleOrNil: Bundle?)

    
    // If the bundle parameter is nil, the main bundle is used.
    public /*not inherited*/ init(data: Data, bundle bundleOrNil: Bundle?)

    
    // Returns an array containing the top-level objects from the NIB.
    // The owner and options parameters may both be nil.
    // If the owner parameter is nil, connections to File's Owner are not permitted.
    // Options are identical to the options specified with -[NSBundle loadNibNamed:owner:options:]
    open func instantiate(withOwner ownerOrNil: Any?, options optionsOrNil: [AnyHashable : Any]? = nil) -> [Any]
}
UINib Demo
let testViewNib = UINib.init(nibName: "TestView", bundle: Bundle.main)
func loadTestView() {
    let testView = UINib.instantiate(withOwner: nil, options: nil)[0] as! UIView
    view.addSubview(testView)
}

使用與 UIViewController 子類源文件關(guān)聯(lián)的 xib

Demo HomeViewController.swift <==> HomeController.xib
let homeVC = HomeViewController()
class HomeViewController {
    var aName: String?

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: "HomeController", bundle: nil)
    }

    init(aName: String) {
        name = aName
        super.init(nibName: "HomeController", bundle: nil)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

嵌套 xib

https://github.com/iOSDevLog/iOSDevLog/tree/master/228.%20NestedXib

圖片上傳失敗請鳞青。參考 http://iosdevlog.com/ios/2017/12/19/ios-ui-interface-builder.html

使用 storyboard

@available(iOS 5.0, *)
open class UIStoryboard : NSObject {

    
    public /*not inherited*/ init(name: String, bundle storyboardBundleOrNil: Bundle?)

    
    open func instantiateInitialViewController() -> UIViewController?

    open func instantiateViewController(withIdentifier identifier: String) -> UIViewController
}

storyboard Demo

extension UIViewController {
    class func storyboardID() -> String {
        return String(describing: self)
    }
}

let userStoryBoard = UIStoryboard(name: "User", bundle: nil)
let profileVC = userStoryBoard.instantiateInitialViewController(withIdentifier: ProfileController.storyboardID())

第3章 全面學(xué)習 xib


Autoresizing

Autoresizing

默認選中左,上为朋。

對應(yīng)代碼為:

testView.autoresizingMask = [.flexibleRightMargin, .flexibleBottomMargin]

外框的 上臂拓、下、左习寸、右如果選中胶惰,則UIView的邊框與父View邊框距離保持不變。

中間帶箭頭的選中表示UIView邊框是隨屏幕尺寸變化的霞溪。
否則UIView大小保持不變孵滞。

也可以看右側(cè)的動畫查看顯示效果精钮。

第4章 在 Interface Builder 中使用 Auto Layout


在 IB 中使用 Auto Layout 的優(yōu)缺點

  • 設(shè)置約束十分簡單

  • 如果約束不恰當,IB 提供很好的實時反饋

  • 如果約束不恰當剃斧,IB 可以幫忙改正轨香。改正操作十分簡單、方便幼东、快捷臂容。

  • 難以理解

約束

Auto Layout 的數(shù)學(xué)公式

item1.attribute1 = multiplier * item2.attribute2 + constant

約束屬性

public enum NSLayoutAttribute : Int {
    case left
    case right
    case top
    case bottom
    case leading
    case trailing
    case width
    case height
    case centerX
    case centerY
    case lastBaseline
    @available(iOS 8.0, *)
    case firstBaseline
    @available(iOS 8.0, *)
    case leftMargin
    @available(iOS 8.0, *)
    case rightMargin
    @available(iOS 8.0, *)
    case topMargin
    @available(iOS 8.0, *)
    case bottomMargin
    @available(iOS 8.0, *)
    case leadingMargin
    @available(iOS 8.0, *)
    case trailingMargin
    @available(iOS 8.0, *)
    case centerXWithinMargins
    @available(iOS 8.0, *)
    case centerYWithinMargins
    case notAnAttribute
}

約束關(guān)系

public enum NSLayoutRelation : Int {
    case lessThanOrEqual
    case equal
    case greaterThanOrEqual
}

約束的優(yōu)先級

public struct UILayoutPriority : RawRepresentable, Equatable, Hashable {
    public init(_ rawValue: Float)
    public init(rawValue: Float)
}

extension UILayoutPriority {
    @available(iOS 6.0, *)
    public static let required: UILayoutPriority

    @available(iOS 6.0, *)
    public static let defaultHigh: UILayoutPriority // This is the priority level with which a button resists compressing its content.

    @available(iOS 6.0, *)
    public static let defaultLow: UILayoutPriority // This is the priority level at which a button hugs its contents horizontally.

    @available(iOS 6.0, *)
    public static let fittingSizeLevel: UILayoutPriority // When you send -[UIView systemLayoutSizeFittingSize:], the size fitting most closely to the target size (the argument) is computed.  UILayoutPriorityFittingSizeLevel is the priority level with which the view wants to conform to the target size in that computation.  It's quite low.  It is generally not appropriate to make a constraint at exactly this priority.  You want to be higher or
    lower.
}

Instrinsic Size 固有尺寸

默認設(shè)置了 Width 和 Height

Content Compression Resistance 壓縮阻力

Content Hugging 內(nèi)容吸附

NSLayoutConstraint 與 @IBOutlet 連線

設(shè)置約束的方法

  1. 在 IB 中設(shè)置 - 推薦
  2. 蘋果原生 API - 最復(fù)雜,強烈不推薦
  3. 用 VFL (Visual Format Language) 設(shè)置約束 - 不推薦
  4. 第三方庫(Masonry等)設(shè)置約束 - 代碼設(shè)置最簡單根蟹、最常用 推薦(如果不熟悉 Auto Layout)

UIStackView

Axis

  • Vertical: 豎直布局
  • Horizontal: 水平布局

Alignment

  • Fill
  • Top
  • Leading
  • Center
  • Bottom
  • Trailing
  • First Baseline
  • Last Base Line

Distribution

  • Fill
  • Fill Equal
  • Fill Proportionally
  • Equal Spacing
  • Equal Centering

Space

Baseline Relative

FDStackView

NSUUID https://gist.github.com/OliverLetterer/4643294

Auto Layout 的異類 - UIScrollView

UIScrollView 的子 View 需要設(shè)置 6 個約束

scrollView.contentSize.width = subView.leading + subView.width + subView.trailing;
scrollView.contentSize.height = subView.top + subView.height+ subView.bottom;

設(shè)置 ScrollView 的子 View 約束時一定要讓系統(tǒng)確定 ScrollView 的 contentSize脓杉。

第5章 storyboard 全面學(xué)習


Extra View

segue

Embed Segue

Unwind Segue

Launch Screen

https://github.com/iOSDevLog/iOSDevLog/tree/master/229.%20ScreenLunch

@interface AppDelegate ()
            
@property (nonatomic, strong) UIWindow* launchWindow;

@end

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    self.launchWindow = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
    self.launchWindow.hidden = NO;
    self.launchWindow.windowLevel = UIWindowLevelNormal + 1;
    self.launchWindow.rootViewController = [UIStoryboard storyboardWithName:@"Launch Screen" bundle:nil].instantiateInitialViewController;
    [UIView animateWithDuration:3 delay:0.5 options: UIViewAnimationOptionCurveEaseInOut animations:^{
        self.launchWindow.alpha = 0;
    } completion:^(BOOL finished) {
        self.launchWindow.hidden = YES;
        self.launchWindow.windowLevel = UIWindowLevelNormal - 1;
        self.launchWindow.alpha = 1;
    }];
    
    return YES;
}
@end
var launchWindow: UIWindow?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
    launchWindow = UIWindow(frame: UIScreen.main.bounds)
    launchWindow?.windowLevel = UIWindowLevelNormal + 1
    launchWindow?.isHidden = false
    launchWindow?.rootViewController = UIStoryboard(name: "LaunchScreen", bundle: nil).instantiateInitialViewController()
    UIView.animate(withDuration: 0.5, delay: 3, options: .curveEaseInOut, animations: {
        self.launchWindow?.alpha = 0
    }) { (finish) in
        if finish {
            self.launchWindow?.isHidden = true
            self.launchWindow?.windowLevel = UIWindowLevelNormal - 1
            self.launchWindow?.alpha = 1
        }
    }
    return true
}

第6章 Interface Builder 進階


Use Trait Variations

設(shè)備 豎屏 橫屏
3.5 iPhone wC hR wC hC
4.0 iPhone wC hR wC hC
4.7 iPhone wC hR wC hC
5.5 iPhone wC hR wR hC
iPad wR hR wR hR

User Define Runtime Attribute

IB 中的類型 Swift Objective-C
Boolean Bool BOOL
Number + +
String String NSString
Localized String String NSString
Point CGPoint CGPoint
Size CGSize CGSize
Rect CGRect CGRect
Range Range NSRange
Color UIColor UIColor
Image UIImage UIImage
Nil Nil Nil

Number 在 Swift 里面可以對應(yīng) Int、Double简逮、Float球散。
在 Objective-C 里面可以對應(yīng) NSInteger、NSNumber 等散庶。

extension UIView {
    var borderColor: UIColor {
        set {
            self.layer.borderColor = newValue.cgColor
        }
        get {
            return UIColor.init(cgColor: self.layer.borderColor!)
        }
    }
}

IB 文件的加載過程

Bundle 和 UINib

  1. 將 nib 加載到內(nèi)存
  2. 解固化并實例化 nib 文件里對應(yīng)的對象
  3. 建立 connections (outlet蕉堰、action)
  4. 調(diào)用 awakeFromNib() 方法
  5. 將 nib 中可見的控件顯示出來

本地化

兩種策略

  1. App 本地化跟隨系統(tǒng)語言
  2. App 內(nèi)部有一個可以設(shè)置語言的選項

本地化介紹

Base

文本的本地化

  1. 利用 NSLocalizedString。 新建 Localizable.strings 文件

Localizable.strings(English)

"test" = "hello world";

Localizable.strings(Chinese(Simplified))

"test" = "你好悲龟,世界";
override func viewDidLoad() {
    super.viewDidLoad()
    // Localizable.string
    testLabel.text = NSLocalizedString("test", comment: "")
    // Home.strings
    // testLabel.text = NSLocalizedString("test", tableName: "Home", comment: "")
}

Info.plist 的本地化

新建 InfoPlist.strings屋讶,在 Show the File inspector 點擊 Localize...

InfoPlist.strings(English)

CFBundleName = "hello world";
CFBundleDisplayName = "hello world";

InfoPlist.strings(Chinese(Simplified))

CFBundleName = "你好,世界";
CFBundleDisplayName = "你好须教,世界";

圖片資源的本地化

  • 方法1

Localizable.strings(English)

"testImageName" = "1";

Localizable.strings(Chinese(Simplified))

"testImageName" = "2";
testImageView.image = UIImage.init(named: NSLocalizedString("testImageName", comment: "")
  • 方法2

選中圖片皿渗,Show the File inspector 點擊 localize...,替換 zh-Hans.lproj 中的資源文件轻腺。

App 內(nèi)設(shè)置語言的本地化

https://github.com/iOSDevLog/iOSDevLog/tree/master/230.%20Localizations

extension Bundle {
    class func loadLocalizableString(languageBundleName: String, key: String) -> String? {
        let languageBundlePath = Bundle.main.path(forResource: languageBundleName, ofType: "lproj")
        
        guard languageBundlePath != nil else {
            return nil
        }
        
        let languageBundle = Bundle.init(path: languageBundlePath!)
        guard languageBundle != nil else {
            return nil
        }
        
        let value = languageBundle?.localizedString(forKey: key, value: "", table: "")
        
        return value
    }
}

func changeLanguage() {
    let kTestKey = "testKey"
    
    switch selectIndex {
    case 0:
        testLabel.text = Bundle.loadLocalizableString(languageBundleName: Language.simplifiedChinese.rawValue, key: kTestKey)
        break
    case 1:
        testLabel.text = Bundle.loadLocalizableString(languageBundleName: Language.english.rawValue, key: kTestKey)
        break
    case 2:
        testLabel.text = Bundle.loadLocalizableString(languageBundleName: Language.japanese.rawValue, key: kTestKey)
        break
    case 3:
        testLabel.text = Bundle.loadLocalizableString(languageBundleName: Language.korea.rawValue, key: kTestKey)
        break
    default:
        break
    }
}

Storyboard Reference 的使用

使用 RBStoryboardLink https://github.com/rob-brown/RBStoryboardLink

用 Object 重構(gòu) "神VC"

代碼量龐大乐疆、結(jié)構(gòu)臃腫、可維護性差的 VC贬养。

使用 Object

  • 通常 VC 會成為很多對象的 delegate挤土,需要處理很多回調(diào)。用 Object 替 VC 實現(xiàn) delegate煤蚌。
  • 將一些能用需求或交互模塊化在對應(yīng)的 Object 里耕挨。將需求或交互與 VC 解耦。

用 External Object 重構(gòu) VC

只能在于 xib

IB 中的關(guān)鍵字總結(jié)

Swift

  • @IBAction
  • @IBOutlet
  • @IBDesignable
  • @IBInspectable

Objective-C

  • IBAction
  • IBOutlet
  • IB_DESIGNABLE
  • IBInspectable
  • IBOutletCollection(ClassName)

@IBDesignable

可以不運行程序的情況下把源文件中的一些代碼實時渲染到 IB 中尉桩,但是源文件必須是 UIView 或者 NSView 的子類筒占。

prepareForInterfaceBuild()

只需要將實時渲染的代碼放到 prepareForInterfaceBuild() 方法中就可以了,該方法并不會在程序運行時調(diào)用蜘犁。

@IBInspectable

@IBInspectable 修飾的屬性會顯示在 IB 的 Show the Attributes inspector翰苫。

extension UIView {
    private struct AssociatedKeys {
        static var name: String?
    }
    
    // 存儲屬性
    @IBInspectable var name: String {
        get {
            return objc_getAssociatedObject(self, &AssociatedKeys.name) as! String
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKeys.name, newValue, .OBJC_ASSOCIATION_RETAIN)
        }
    }
    
    
    // 計算屬性
    @IBInspectable var borderColor: UIColor {
        set {
            self.layer.borderColor = newValue.cgColor
        }
        get {
            return UIColor.init(cgColor: self.layer.borderColor!)
        }
    }
}

第7章 在 Interface Builder 開發(fā)中的技巧和 Bug


調(diào)整 View 的尺寸,使它與顯示內(nèi)容的尺寸相適應(yīng)

comment + =

查看各個 View 之間的距離

選中 View, 按住 option奏窑,懸停在其它 View 上导披。

在 IB 中添加參考線

Editor -> Guides -> Add Horizontal Line

command + -

Editor -> Guides -> Add Vertical Line

command + ctrl + |

快速調(diào)整底層被擋住的 View 的位置

快速查看 View 的 UI 層次關(guān)系

command + shift + right click

連線小技巧

兩個窗口

使用吸管快速設(shè)置顏色

IB 中的復(fù)制與粘貼

command + c

command + v

利用 Media Library 快速設(shè)置圖片

IB 開發(fā)中遇到的一些小 bug

最好的做法就是重啟 Xcode。

  • 無法連線

IB 文件是否與源文件關(guān)聯(lián)

  • @IBAction 紅色提示

先在源文件中定義好方法埃唯,再從源文件 到 IB 文件進行 連線

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末撩匕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子墨叛,更是在濱河造成了極大的恐慌止毕,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,383評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件漠趁,死亡現(xiàn)場離奇詭異扁凛,居然都是意外死亡,警方通過查閱死者的電腦和手機闯传,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,522評論 3 385
  • 文/潘曉璐 我一進店門谨朝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人甥绿,你說我怎么就攤上這事字币。” “怎么了妹窖?”我有些...
    開封第一講書人閱讀 157,852評論 0 348
  • 文/不壞的土叔 我叫張陵纬朝,是天一觀的道長。 經(jīng)常有香客問我骄呼,道長,這世上最難降的妖魔是什么判没? 我笑而不...
    開封第一講書人閱讀 56,621評論 1 284
  • 正文 為了忘掉前任蜓萄,我火速辦了婚禮,結(jié)果婚禮上澄峰,老公的妹妹穿的比我還像新娘嫉沽。我一直安慰自己,他們只是感情好俏竞,可當我...
    茶點故事閱讀 65,741評論 6 386
  • 文/花漫 我一把揭開白布绸硕。 她就那樣靜靜地躺著,像睡著了一般魂毁。 火紅的嫁衣襯著肌膚如雪玻佩。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,929評論 1 290
  • 那天席楚,我揣著相機與錄音咬崔,去河邊找鬼。 笑死,一個胖子當著我的面吹牛垮斯,可吹牛的內(nèi)容都是我干的郎仆。 我是一名探鬼主播,決...
    沈念sama閱讀 39,076評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼兜蠕,長吁一口氣:“原來是場噩夢啊……” “哼扰肌!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起熊杨,我...
    開封第一講書人閱讀 37,803評論 0 268
  • 序言:老撾萬榮一對情侶失蹤狡耻,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后猴凹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體夷狰,經(jīng)...
    沈念sama閱讀 44,265評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,582評論 2 327
  • 正文 我和宋清朗相戀三年郊霎,在試婚紗的時候發(fā)現(xiàn)自己被綠了沼头。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,716評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡书劝,死狀恐怖进倍,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情购对,我是刑警寧澤猾昆,帶...
    沈念sama閱讀 34,395評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站骡苞,受9級特大地震影響垂蜗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜解幽,卻給世界環(huán)境...
    茶點故事閱讀 40,039評論 3 316
  • 文/蒙蒙 一贴见、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧躲株,春花似錦措译、人聲如沸详囤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,798評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至望浩,卻和暖如春辖所,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背曾雕。 一陣腳步聲響...
    開封第一講書人閱讀 32,027評論 1 266
  • 我被黑心中介騙來泰國打工奴烙, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 46,488評論 2 361
  • 正文 我出身青樓切诀,卻偏偏與公主長得像揩环,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子幅虑,可洞房花燭夜當晚...
    茶點故事閱讀 43,612評論 2 350

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