SwiftUI之AlignmentGuides

本質(zhì)上会前,Alignment Guides屬于SwiftUI中布局的知識點特碳,在某些特殊場景下话浇,使用Alignment Guides能起到事半功倍的效果,比如我們平時經(jīng)常用的下邊的這樣的效果:

1

上圖顯示了疚颊,當切換背景容器的最大寬度時狈孔,使用Alignment Guides能夠自動執(zhí)行動畫效果,這正是我們想要的材义,核心代碼如下:

struct TestWrappedLayout: View {
    let w: CGFloat
    var texts: [String]

    var body: some View {
        self.generateContent(in: w)
    }

    private func generateContent(in w: CGFloat) -> some View {
        var width = CGFloat.zero
        var height = CGFloat.zero

        return ZStack(alignment: .topLeading) {
            ForEach(self.texts, id: \.self) { t in
                self.item(for: t)
                    .padding([.trailing, .bottom], 4)
                    .alignmentGuide(.leading, computeValue: { d in
                     
                        if (abs(width - d.width) > w)
                        {
                            width = 0
                            height -= d.height
                        }
                        let result = width
                        if t == self.texts.last! {
                            width = 0 //last item
                        } else {
                            width -= d.width
                        }
                        return result
                    })
                    .alignmentGuide(.top, computeValue: {d in
                        let result = height
                        if t == self.texts.last! {
                            height = 0 // last item
                        }
                        return result
                    })
            }
        }
    }

    func item(for text: String) -> some View {
        Text(text)
            .padding([.leading, .trailing], 8)
            .frame(height: 30)
            .font(.subheadline)
            .background(Color.orange)
            .foregroundColor(.white)
            .cornerRadius(15)
            .onTapGesture {
                print("你好啊")
        }
    }
}

在本篇文章中均抽,最核心的思想就是容器container中的每個View都有它的alignment guide。

Alignment Guide是什么母截?

說到對齊到忽,大家頭腦中一定要有一個組的概念,也就是group清寇,如果只有一個view喘漏,那對齊就失去了意義,我們在設計對齊相關的ui的時候华烟,是對一組中的多個view進行考慮的翩迈,這也恰恰和容器的概念對應上了,我這里說的容器指的是VStack,HStack,ZStack盔夜。

換句話說负饲,我們對容器內(nèi)的Views使用Alignment guide。

對齊共分為兩種:水平對齊(horizontal),垂直對齊(vertical)

我們先以水平對齊為例喂链,先看下圖:

align-horizontal-1.png

有3個view返十,分別為A,B椭微,C洞坑,他們alignment guide返回的值分別為0, 20蝇率, 10迟杂,從上圖可以看出,他們的偏移關系正好和值對應上了本慕,當值為正的時候排拷,往左偏移,為負的時候锅尘,往右偏移监氢。這里有下邊幾個概念,大家一定要理解鉴象,如果不理解這幾個概念忙菠,就無法真正明白對齊的奧義:

  • 我們把A,B纺弊,C放到了VStack中牛欢,VStack中使用的對齊方式是水平對齊,比如VStack(alignment: .center)`
  • alignment guide返回的值表達的是這3個view的位置關系淆游,并不是說A的返回值為0傍睹,A就不偏移隔盛,我們需要把他們作為一個整體來看,通過偏移量來描述他們之間的位置關系拾稳,然后讓他們3個view在VStack中整體居中

上邊的重點是吮炕,alignment guide描述的是views之間的位置關系,系統(tǒng)在布局的時候访得,會把他們看成一個整體龙亲,然后在使用frame alignment guide對整體進行布局。

同樣的道理悍抑,下邊圖片展示的是垂直對齊鳄炉,我們就不再多做解釋了:

align-vertical.png

通過上邊這兩個例子,我們得出一個結論:VStack需要水平對齊搜骡,HStack需要垂直對齊拂盯,雖然這聽上去有點怪,但只需在頭腦中想一想他們中view的排列方式记靡,就不難理解谈竿。至于ZStack,即需要水平對齊摸吠,也需要垂直對齊空凸,這個我們在下邊的小節(jié)中,詳細解釋寸痢。

Alignment Guide中的疑惑

相信大家在代碼中的很多地方會用到.leading劫恒,在SwiftUI中,用到對齊的地方一共有下邊幾種:

alignment-confusion.png

這張圖片覆蓋了對齊所有的使用方式轿腺,現(xiàn)在大家可能是一臉茫然,但讀完剩下的文章后丛楚,再回過頭來看這張圖片族壳,就會發(fā)現(xiàn),這張圖片實在是太經(jīng)典了趣些,毫不夸張的說仿荆,你以后在SwiftUI中使用alignment guide的時候,頭腦中一定會浮現(xiàn)出這張圖片坏平。

我們對上邊的幾個概念做個簡單的介紹:

  • Container Alignment: 容器的對齊方式主要有2個目的拢操,首先它定義了其內(nèi)部views的隱式對齊方式,沒有使用alignmentGuides()modifier的view都使用隱式對齊舶替,然后定義了內(nèi)部views中使用了alignmentGuides()的view令境,只有參數(shù)與容器對齊參數(shù)相同,容器才會根據(jù)返回值計算布局
  • Alignment Guide:如果該值和Container Alignment的參數(shù)不匹配顾瞪,則不會生效
  • Implicit Alignment Value:通常來說舔庶,隱式對齊采用的值都是默認的值抛蚁,系統(tǒng)通常會使用和對齊參數(shù)相匹配的值
  • Explicit Alignment Value:顯式對齊跟隱式對齊相反,是我們自己用程序明確給出的返回值
  • Frame Alignment:表示容器中views的對齊方式惕橙,把views看作一個整體瞧甩,整體偏左,居中弥鹦,或居右
  • Text Alignment:控制多行文本的對齊方式

隱式和顯式對齊的區(qū)別

每個view都有一個alignment肚逸,記住這一點非常重要,當我們使用.alignmentGuide()設置對齊方式時彬坏,我們稱之為顯式朦促,相反則稱之為隱式。隱式的情況下苍鲜,.alignmentGuide()的返回值和它父類容器的對齊參數(shù)有關思灰。

如果我們沒有為VStack, HStackZStack提供alignment參數(shù),默認值為center混滔。

ViewDimensions

func alignmentGuide(_ g: HorizontalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat) -> some View
func alignmentGuide(_ g: VerticalAlignment, computeValue: @escaping (ViewDimensions) -> CGFloat) -> some View

我們已經(jīng)知道了computeValue函數(shù)的返回值是一個CGFloat類型洒疚,但我們不太清楚ViewDimensions是個什么東西?很簡單坯屿,我們可以直接查看它的系統(tǒng)定義:

public struct ViewDimensions {
    public var width: CGFloat { get } // The view's width
    public var height: CGFloat { get } // The view's height

    public subscript(guide: HorizontalAlignment) -> CGFloat { get }
    public subscript(guide: VerticalAlignment) -> CGFloat { get }
    public subscript(explicit guide: HorizontalAlignment) -> CGFloat? { get }
    public subscript(explicit guide: VerticalAlignment) -> CGFloat? { get }
}

很容易發(fā)現(xiàn)油湖,通過widthheight,我們很容易獲得該view的寬和高,這在我們返回對齊值的時候非常有用领跛,我們不做過多解釋乏德,我們往下看,subscript表明我們可以像這樣訪問:d[HorizontalAlignment.leading]吠昭。

那么這有什么用呢喊括? 我們先看段代碼:

struct Example6: View {
    var body: some View {
        ZStack(alignment: .topLeading) {
            Text("Hello")
                .alignmentGuide(HorizontalAlignment.leading, computeValue: { d in return 0 })
                .alignmentGuide(.top, computeValue: { d in return 0 })
                .background(Color.green)
            
            Text("World")
                .alignmentGuide(.top, computeValue: { d in return 100 })
                .alignmentGuide(HorizontalAlignment.leading, computeValue: { d in return 0 })
                .background(Color.purple)
            
        }
        .background(Color.orange)
    }
}

這段代碼運行后的效果

1

由于我們給Text("World")設置了.alignmentGuide(.top, computeValue: { d in return 100 }),因此矢棚,它出現(xiàn)在hello的上邊沒什么問題郑什,那么我如果把.alignmentGuide(HorizontalAlignment.leading, computeValue: { d in return 0 })改成.alignmentGuide(HorizontalAlignment.leading, computeValue: { d in return d[.top] })呢?

在設置leading對齊的時候使用了top對齊的數(shù)據(jù)蒲肋,運行效果:

2

可以看出蘑拯,完全符合我們的預期,world又向左偏移了100的距離兜粘,這就是我們上邊說的用法申窘,不過,通常情況下我們基本不需要這樣操作孔轴。

類似d[HorizontalAlignment.leading]這樣的參數(shù)剃法,我們都可簡寫成d[.leading],Swift能夠非常智能的識別這些類型,但是center除外路鹰,原因是HorizontalAlignmentVerticalAlignment都有center玄窝。

對齊類型

對于HorizontalAlignment來說牵寺,有下邊幾個參數(shù):

extension HorizontalAlignment {
    public static let leading: HorizontalAlignment
    public static let center: HorizontalAlignment
    public static let trailing: HorizontalAlignment
}

當我們使用下標訪問數(shù)據(jù)的時候,有兩種方式:

d[.trailing]
d[explicit: .trailing]

d[.trailing]表示獲取d的隱式leading恩脂,也就是默認值帽氓,通常情況下,.leading的值為0俩块,.center的值為width的一半黎休,.trailing的值為width。

d[explicit: .trailing]表示獲取d的顯式的trailing玉凯,當沒有通過.alignmentGuide()指定值的時候势腮,它返回nil,就像上一小節(jié)講的一樣漫仆,在ZStack中捎拯,我們可以獲取顯式的對齊值

對于VerticalAlignment來說,基本用法跟HorizontalAlignment差不多盲厌,但它多了幾個參數(shù):

extension VerticalAlignment {
    public static let top: VerticalAlignment
    public static let center: VerticalAlignment
    public static let bottom: VerticalAlignment
    public static let firstTextBaseline: VerticalAlignment
    public static let lastTextBaseline: VerticalAlignment
}

firstTextBaseline表示所有text的以各自最上邊的那一行的base line對齊署照,lastTextBaseline表示所有text的以最下邊的那一行的base line對齊。對于某個view而言吗浩,如果它不是多行文本建芙,則firstTextBaselinelastTextBaseline是一樣的。

我們可以通過print(d[.lastTextBaseline])打印出這些值懂扼,他們都為正值禁荸。

我們先看個firstTextBaseline的例子:

        HStack(alignment: .firstTextBaseline) {
            Text("床前明月光")
                .font(.caption)
                .frame(width: 50)
                .background(Color.orange)
               
            Text("疑是地上霜")
                .font(.body)
                .frame(width: 50)
                .background(Color.green)
            
            Text("舉頭望明月")
                .font(.largeTitle)
                .frame(width: 50)
                .background(Color.blue)
             
        }
企業(yè)微信截圖_b87e6bd8-84b4-4e49-9f44-3a88d13c64dc.png

可以看出來,這3個text都以他們各自的第一行的base line 對齊了阀湿,我們稍微改下代碼:

        HStack(alignment: .lastTextBaseline) {
            ...
    }
企業(yè)微信截圖_b92bc7fa-3042-4e7c-9026-7c0322ac19e7.png

他們以各自的最后一行的的base line對齊了赶熟,針對這3個text,上邊的代碼都使用了隱式的alignment guide陷嘴,那么我們再進一步嘗試钧大,我們給第3個text一個顯式的alignment guide會是怎么樣的?

        HStack(alignment: .lastTextBaseline) {
            Text("床前明月光")
                .font(.caption)
                .frame(width: 50)
                .background(Color.orange)
               
            Text("疑是地上霜")
                .font(.body)
                .frame(width: 50)
                .background(Color.green)
            
            Text("舉頭望明月")
                .font(.largeTitle)
                .alignmentGuide(.lastTextBaseline, computeValue: { (d) -> CGFloat in
                    d[.firstTextBaseline]
                })
                .frame(width: 50)
                .background(Color.blue)
             
        }
企業(yè)微信截圖_3aa000af-94ee-4224-9926-c6e220d4527a.png

重點來了罩旋,對齊描述的是容器內(nèi)view之間的布局關系,由于computeValue函數(shù)的返回值都是CGFloat眶诈,因此不管是哪種對齊方式涨醋,最終都是得到一個CGFloat。

那么如果我們在text中間加入一個其他的view呢逝撬?

        HStack(alignment: .firstTextBaseline) {
            Text("床前明月光")
                .font(.caption)
                .frame(width: 50)
                .background(Color.orange)
            
            RoundedRectangle(cornerRadius: 3)
                .foregroundColor(.green)
                .frame(width: 50, height: 40)
               
            Text("疑是地上霜")
                .font(.body)
                .frame(width: 50)
                .background(Color.green)
            
            Text("舉頭望明月")
                .font(.largeTitle)
                .alignmentGuide(.firstTextBaseline, computeValue: { (d) -> CGFloat in
                    return 0
                })
                .frame(width: 50)
                .background(Color.blue)
             
        }
企業(yè)微信截圖_afa2d94f-7faf-4f70-bfe4-1f5ed7c41e2c_副本.png
  • 除了text之外的其他view浴骂,都使用bottom對齊方式
  • 不管是lastTextBaseline還是firstTextBaseline,布局的算法都是.top + computeValue ,也就是說以它的頂部為布局的基線
  • alignment 描述的是view之間的關系,把他們作為一個整體或者一組來看待

這一塊可能有點繞宪潮,但并不難理解溯警,如果大家有問題趣苏,可以留言。

我們知道HStack使用VerticalAlignment梯轻,VStack使用HorizontalAlignment食磕,他們只需要一種就行了,但是ZStack同時需要兩種對齊方式喳挑,該如何呢彬伦?

這里引入Alignment類型,用法如下:

ZStack(alignment: Alignment(horizontal: .leading, vertical: .top)) { ... }

本質(zhì)上伊诵,它把horizontal和vertical封裝在了一起单绑,我們平時經(jīng)常用的是下邊這個寫法,只是寫法不同而已:

ZStack(alignment: .topLeading) { ... }

Container Alignment

所謂的容器的對齊方式指的是下邊這里:

VStack(alignment: .leading)
HStack(alignment: .top)
ZStack(alignment: .topLeading)

那么它主要有什么作用呢曹宴?

  • 我們知道搂橙,容器中的view都能夠用.alignmentGuides()modifier來顯式的返回對齊值,.alignmentGuides()的第一個參數(shù)如果與Container Alignment不一樣笛坦,容器在布局的時候就會忽略這個view的.alignmentGuides()
  • 它提供了容器中view的隱式alignment guide

大家看這段代碼:

struct Example3: View {
    @State private var alignment: HorizontalAlignment = .leading
    
    var body: some View {
        VStack {
            Spacer()
            
             VStack(alignment: alignment) {
               LabelView(title: "Athos", color: .green)
                .alignmentGuide(.leading, computeValue: { _ in 30 } )
                   .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 30 } )
                   .alignmentGuide(.trailing, computeValue: { _ in 90 } )
                 
               LabelView(title: "Porthos", color: .red)
                   .alignmentGuide(.leading, computeValue: { _ in 90 } )
                   .alignmentGuide(HorizontalAlignment.center, computeValue: { _ in 30 } )
                   .alignmentGuide(.trailing, computeValue: { _ in 30 } )
                 
                LabelView(title: "Aramis", color: .blue) // use implicit guide
                
             }

            Spacer()
            HStack {
                Button("leading") { withAnimation(.easeInOut(duration: 2)) { self.alignment = .leading }}
                Button("center") { withAnimation(.easeInOut(duration: 2)) { self.alignment = .center }}
                Button("trailing") { withAnimation(.easeInOut(duration: 2)) { self.alignment = .trailing }}
            }
        }
    }
}

它的運行效果如下圖所示:

Kapture 2020-06-01 at 17.11.25.gif

可以很明顯的看出當我們切換container alignment的參數(shù)時区转,它內(nèi)部的view的alignment那些被忽略,那些被使用弯屈。

Frame Alignment

我一直在不斷的強調(diào)蜗帜,我們上邊看到的對齊方式,都應該把容器中的所有view看作一個整體资厉,alignment描述的是view之間的一種位置關系厅缺。

大家思考一下押框,即使.alignmentGuide中的computeValue返回值為0鳖粟,也不能說明該view保持不動困食。

如果我們把容器內(nèi)部的view看成一組厢破,那么Frame Alignment就非常容易理解了:

VStack(alignment: .leading)
VStack(alignment: .center)
VStack(alignment: .trailing)

上邊3張圖片分別展示了VStack(alignment: .leading),VStack(alignment: .center)VStack(alignment: .trailing)的情況姑躲,可以看出棉钧,他們內(nèi)部圖形的布局發(fā)生了變化恨统,但是他們3個整體都是居中對齊的怪蔑。

原因就是我們上一小節(jié)講的娩践,container alignment只影響容器內(nèi)的布局活翩,要讓容器內(nèi)的views整體左對齊或者居中,需要使用Frame Alignment.

.frame(maxWidth: .infinity, alignment: .leading)
Frame Alignment

關于Frame Alignment有一點需要特別注意翻伺,有時候看上去我們的設置沒有生效材泄,只要原因就是,在SwiftUI中吨岭,大多數(shù)情況下View的布局政策基于收緊策略拉宗,也就是View的寬度只是自己需要的寬度,這種情況下設置frame對齊當然就沒有意義了。

Multiline Text Alignment()

多行文本對齊就比較簡單了旦事,大家直接看圖就行了魁巩。

Multiline Text Alignment()

Interacting with the Alignment Guides

如果大家對上邊講的這些對齊方式還有疑惑,可以下載這里的代碼https://gist.github.com/swiftui-lab/793ca53ad1f2f0d7eb07aa23b54d9cbf,自己動手做一些交互姐浮,就應該能夠明白這些原理和用法了谷遂,放一張界面的截圖:

交互

Custom Alignments

大多數(shù)情況,我們是不要自定義對齊的单料,使用系統(tǒng)提供的.leading埋凯,.center等等幾乎可以實現(xiàn)所有的UI效果,在本小節(jié)中扫尖,大家應該重點關注第二個例子白对,基本上只有這種情況,我們優(yōu)先考慮自定義對齊换怖。

自定義對齊的基本寫法如下:

extension HorizontalAlignment {
    private enum WeirdAlignment: AlignmentID {
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            return d.height
        }
    }
    
    static let weirdAlignment = HorizontalAlignment(WeirdAlignment.self)
}
  • 決定是horizontal還是vertical
  • 提供一個隱式對齊的默認值

我們小試牛刀甩恼,在上邊代碼中,我們自定義一個alignment沉颂,默認值返回view的高度条摸,這樣產(chǎn)生的效果如下:

weird-alignment.png

可以看出,每個view的偏移都是它自身的高度铸屉,這樣的效果看上去還挺有意思钉蒲。完整代碼如下:

struct Example4: View {
    var body: some View {
        VStack(alignment: .weirdAlignment, spacing: 10) {
            
            Rectangle()
                .fill(Color.primary)
                .frame(width: 1)
                .alignmentGuide(.weirdAlignment, computeValue: { d in 0 })
            
            ColorLabel(label: "Monday", color: .red, height: 50)
            ColorLabel(label: "Tuesday", color: .orange, height: 70)
            ColorLabel(label: "Wednesday", color: .yellow, height: 90)
            ColorLabel(label: "Thursday", color: .green, height: 40)
            ColorLabel(label: "Friday", color: .blue, height: 70)
            ColorLabel(label: "Saturday", color: .purple, height: 40)
            ColorLabel(label: "Sunday", color: .pink, height: 40)
            
            Rectangle()
                .fill(Color.primary)
                .frame(width: 1)
                .alignmentGuide(.weirdAlignment, computeValue: { d in 0 })
        }
    }
}

struct ColorLabel: View {
    let label: String
    let color: Color
    let height: CGFloat
    
    var body: some View {
        Text(label).font(.title).foregroundColor(.primary).frame(height: height).padding(.horizontal, 20)
            .background(RoundedRectangle(cornerRadius: 8).fill(color))
    }
}

重點來了,我要說彻坛,使用自定義對齊最大的優(yōu)勢是:當在不同的view繼承分支上使用自定義對齊顷啼,會產(chǎn)生理想的效果。

custom-alignment.gif

大家看上圖昌屉,一個HStack包裹這一個Image和VStack钙蒙,VStack中有一組Text,當點擊某個Text的時候间驮,Image可以和點擊的Text對齊躬厌。

這就是我們上邊說的,對于屬于不同層次的view進行對齊竞帽,SwiftUI非常智能的知道我們想要這樣的效果扛施。完整代碼如下:

extension VerticalAlignment {
    private enum MyAlignment : AlignmentID {
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            return d[.bottom]
        }
    }
    static let myAlignment = VerticalAlignment(MyAlignment.self)
}

struct CustomView: View {
    @State private var selectedIdx = 1
    
    let days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
    
    var body: some View {
            HStack(alignment: .myAlignment) {
                Image(systemName: "arrow.right.circle.fill")
                    .alignmentGuide(.myAlignment, computeValue: { d in d[VerticalAlignment.center] })
                    .foregroundColor(.green)

                VStack(alignment: .leading) {
                    ForEach(days.indices, id: \.self) { idx in
                        Group {
                            if idx == self.selectedIdx {
                                Text(self.days[idx])
                                    .transition(AnyTransition.identity)
                                    .alignmentGuide(.myAlignment, computeValue: { d in d[VerticalAlignment.center] })
                            } else {
                                Text(self.days[idx])
                                    .transition(AnyTransition.identity)
                                    .onTapGesture {
                                        withAnimation {
                                            self.selectedIdx = idx
                                        }
                                }
                            }
                        }
                    }
                }
            }
            .padding(20)
            .font(.largeTitle)
    }
}

如果要自定義ZStack的alignment,稍微麻煩一點屹篓,但原理都是一樣的相信大家都能夠理解疙渣,就直接上代碼了:

extension VerticalAlignment {
    private enum MyVerticalAlignment : AlignmentID {
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            return d[.bottom]
        }
    }
    
    static let myVerticalAlignment = VerticalAlignment(MyVerticalAlignment.self)
}

extension HorizontalAlignment {
    private enum MyHorizontalAlignment : AlignmentID {
        static func defaultValue(in d: ViewDimensions) -> CGFloat {
            return d[.leading]
        }
    }
    
    static let myHorizontalAlignment = HorizontalAlignment(MyHorizontalAlignment.self)
}

extension Alignment {
    static let myAlignment = Alignment(horizontal: .myHorizontalAlignment, vertical: .myVerticalAlignment)
}

struct CustomView: View {
    var body: some View {
        ZStack(alignment: .myAlignment) {
            ...
        }
    }
}

總結

通過這篇文章,大家應該對Alignment Guide有了一個全面的了解抱虐,它應該成為我們?nèi)粘i_發(fā)進行布局的強大工具,現(xiàn)在回過頭來再看看這張圖片饥脑,是不是有那么一點感覺了呢恳邀?

alignment-confusion.png

注:上邊的內(nèi)容參考了網(wǎng)站https://swiftui-lab.com/alignment-guides/懦冰,如有侵權,立即刪除谣沸。

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末刷钢,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子乳附,更是在濱河造成了極大的恐慌内地,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赋除,死亡現(xiàn)場離奇詭異阱缓,居然都是意外死亡,警方通過查閱死者的電腦和手機举农,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門荆针,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人颁糟,你說我怎么就攤上這事航背。” “怎么了棱貌?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵玖媚,是天一觀的道長。 經(jīng)常有香客問我婚脱,道長今魔,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任起惕,我火速辦了婚禮涡贱,結果婚禮上,老公的妹妹穿的比我還像新娘惹想。我一直安慰自己问词,他們只是感情好,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布嘀粱。 她就那樣靜靜地躺著激挪,像睡著了一般。 火紅的嫁衣襯著肌膚如雪锋叨。 梳的紋絲不亂的頭發(fā)上垄分,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天,我揣著相機與錄音娃磺,去河邊找鬼薄湿。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的豺瘤。 我是一名探鬼主播吆倦,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼坐求!你這毒婦竟也來了蚕泽?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤桥嗤,失蹤者是張志新(化名)和其女友劉穎须妻,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泛领,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡荒吏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了师逸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片司倚。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖篓像,靈堂內(nèi)的尸體忽然破棺而出动知,到底是詐尸還是另有隱情,我是刑警寧澤员辩,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布盒粮,位于F島的核電站,受9級特大地震影響奠滑,放射性物質(zhì)發(fā)生泄漏丹皱。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一宋税、第九天 我趴在偏房一處隱蔽的房頂上張望摊崭。 院中可真熱鬧,春花似錦杰赛、人聲如沸呢簸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽根时。三九已至,卻和暖如春辰晕,著一層夾襖步出監(jiān)牢的瞬間蛤迎,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工含友, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留替裆,地道東北人校辩。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像辆童,于是被迫代替她去往敵國和親召川。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354