TextKit詳解

一敌厘、參與者詳解

1滴须、string:讀入需要繪制的文本內(nèi)容舌狗。

2、NSTextStorage:管理string的內(nèi)容扔水;這個(gè)很容易理解痛侍,NSTextStorage的父類是NSAttributedString繼承屬性文字所有的可設(shè)置屬性,但是他們唯一不同的地方在與:NSTextStorage包含了一個(gè)方法铭污,可以將所有對(duì)其內(nèi)容進(jìn)行的修改以通知的方式發(fā)送出來(這個(gè)方法在后面會(huì)將到)恋日;簡(jiǎn)單的理解就是:NSTextStorage保存并管理這個(gè)string;在使用一個(gè)自定義的 NSTextStorage 就可以讓文本在稍后動(dòng)態(tài)地添加字體或者顏色高亮等文本屬性修飾嘹狞。

3、UITextView:堆棧的另一頭是實(shí)際顯示的視圖誓竿。作用一磅网,就是顯示內(nèi)容,作用二筷屡,就是處理用戶的交互涧偷。唯一,需特別處理的就是毙死,它已遵守了UITextInput的協(xié)議燎潮,來處理鍵盤事件。

4扼倘、NSTextContainer:textView給出了一個(gè)文本的繪制區(qū)域确封;在一般情況下,NSTextContainer精確的描述了這個(gè)可用的區(qū)域再菊,其就是一個(gè)矩形爪喘,在垂直方向上無限大;但是纠拔,在特定的情況下秉剑,例如要是界面文字內(nèi)容固定大小,就像是一本書一樣稠诲,每頁內(nèi)容固定侦鹏,可以翻頁的效果;還有一中情況就是臀叙,圖片在這個(gè)固定大小的頁面中占據(jù)了一塊區(qū)域略水,文字內(nèi)容會(huì),填充圖片意外剩余的區(qū)域匹耕。

5聚请、NSLayoutManager:核心組件,聯(lián)系了以上所有組件;1驶赏、與NSTextStorage的關(guān)系:它監(jiān)聽著NSTextStorage發(fā)出的關(guān)于string屬性改變的通知炸卑,一旦接受到通知就會(huì)觸發(fā)重新布局;2煤傍、從NSTextStorage中獲取string(內(nèi)容)將其轉(zhuǎn)化為字形(與當(dāng)前設(shè)置的字體等內(nèi)容相關(guān))盖文;3、一旦字形完全生成完畢蚯姆,NSLayoutManager(管理者)會(huì)像NSTextContainer查詢文本可用的繪制區(qū)域五续;4、NSTextContainer龄恋,會(huì)將文本的當(dāng)前狀態(tài)改為無效疙驾,然后交給textView去顯示。

注:CoreText,并沒用直接包含在TextKit中郭毕,CoreText是進(jìn)行實(shí)地排版的庫它碎,他詳細(xì)的管理者實(shí)地排版中的每一行,斷句以及從字義到字形的翻譯显押。

二扳肛、Demo
Demo1、基本用法

- (void)viewDidLoad
{
   [super viewDidLoad];

   //1乘碑、獲取文本管理者
   NSTextStorage *sharedTextStorage = self.originalTextView.textStorage;
   //2挖息、讀取本地文件
   [sharedTextStorage replaceCharactersInRange:NSMakeRange(0, 0) withString:[NSString stringWithContentsOfURL:[NSBundle.mainBundle URLForResource:@"lorem" withExtension:@"txt"] usedEncoding:NULL error:NULL]];
   //3、布局與字形的管理
   NSLayoutManager *otherLayoutManager = [NSLayoutManager new];
   [sharedTextStorage addLayoutManager: otherLayoutManager];
   //4兽肤、布局的rect
   NSTextContainer *otherTextContainer = [NSTextContainer new];
   [otherLayoutManager addTextContainer: otherTextContainer];
   //otherTextView與originalTextView使用了同一個(gè)NSTextStorage 但是套腹,使用了新創(chuàng)建的NSLayoutManager與NSTextContainer獨(dú)立管理otherTextView的布局
   UITextView *otherTextView = [[UITextView alloc] initWithFrame:self.otherContainerView.bounds textContainer:otherTextContainer];
   otherTextView.backgroundColor = self.otherContainerView.backgroundColor;
   otherTextView.translatesAutoresizingMaskIntoConstraints = YES;
   otherTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
   //禁止滑動(dòng)
   otherTextView.scrollEnabled = NO;
   
   [self.otherContainerView addSubview: otherTextView];
   self.otherTextView = otherTextView;
   
   //thirdTextView與otherTextView使用了同一個(gè)otherLayoutManager:(分頁的實(shí)現(xiàn))
   NSTextContainer *thirdTextContainer = [NSTextContainer new];
   [otherLayoutManager addTextContainer: thirdTextContainer];
   
   UITextView *thirdTextView = [[UITextView alloc] initWithFrame:self.thirdContainerView.bounds textContainer:thirdTextContainer];
   thirdTextView.backgroundColor = self.thirdContainerView.backgroundColor;
   thirdTextView.translatesAutoresizingMaskIntoConstraints = YES;
   thirdTextView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
   
   [self.thirdContainerView addSubview: thirdTextView];
   self.thirdTextView = thirdTextView;
}

- (IBAction)endEditing:(UIBarButtonItem *)sender
{
   [self.view endEditing: YES];
}

Demo2、高亮文字
如果轿衔,不明白每個(gè)參與者的責(zé)任沉迹,你很難理解像textKit這樣的框架;例如害驹,唐巧也很早寫過一篇博文鞭呕,并在github配有Demo來講解textKit,但是宛官,你看完要不是一臉懵逼葫松,就是自己寫的話還是沒有邏輯;
廢話不多說底洗,看代碼:在前面已經(jīng)介紹了腋么,各個(gè)參與者的責(zé)任,想要實(shí)現(xiàn)高亮文字亥揖,其實(shí)就是由NSTextStorage負(fù)責(zé)的珊擂,因?yàn)樗^承自NSMutableAttributedString圣勒;

NSTextStorage ---
NSTextStorage是NSMutableAttributedString的子類,根據(jù)蘋果官方文檔描述
是semiconcrete子類摧扇,因?yàn)镹STextStorage沒有實(shí)現(xiàn)
NSMutableAttributedString中的方法圣贸,所以說NSTextStorage應(yīng)該是
NSMutableAttributedString的類簇。 
所要我們深入使用NSTextStorage不僅要繼承NSTextStorage類還要實(shí)現(xiàn)
NSMutableAttributedString的下面方法
- (NSString *)string
- (void)replaceCharactersInRange:(NSRange)range    withString:(NSString *)str
- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range
- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range  

因?yàn)檫@些方法實(shí)際上NSTextStorage并沒有實(shí)現(xiàn)然而我們斷然不知道NSMutableAttributedString是如何實(shí)現(xiàn)這些方法扛稽,所以我們繼承NSTextStorage并實(shí)現(xiàn)這些方法最簡(jiǎn)單的莫過于在NSTextStorage類中實(shí)例化一個(gè)NSMutableAttributedString對(duì)象然后調(diào)用NSMutableAttributedString對(duì)象的這些方法來實(shí)現(xiàn)NSTextStorage類中的這些方法

還值得注意的是:每次編輯都會(huì)調(diào)用-(void)processEditing的方法

-(void)processEditing;

完整的實(shí)現(xiàn)代碼如下:
.h文件

#import <UIKit/UIKit.h>

@interface TKDHighlightingTextStorage : NSTextStorage

@end

.m文件

#import "TKDHighlightingTextStorage.h"


@implementation TKDHighlightingTextStorage
{
    NSMutableAttributedString *_imp;
}

//實(shí)例化 NSMutableAttributedString對(duì)象
- (id)init
{
    self = [super init];
    
    if (self) {
        _imp = [NSMutableAttributedString new];
    }
    
    return self;
}


#pragma mark - Reading Text - get方法

- (NSString *)string
{
    return _imp.string;
}

- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range
{
    return [_imp attributesAtIndex:location effectiveRange:range];
}


#pragma mark - Text Editing

- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str
{
    [_imp replaceCharactersInRange:range withString:str];
    [self edited:NSTextStorageEditedCharacters range:range changeInLength:(NSInteger)str.length - (NSInteger)range.length];
}

- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range
{
    [_imp setAttributes:attrs range:range];
    [self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
}


#pragma mark - Syntax highlighting

- (void)processEditing
{
    //正則表達(dá)式來查找單詞以i開頭連接W的單詞
    static NSRegularExpression *iExpression;
    iExpression = iExpression ?: [NSRegularExpression regularExpressionWithPattern:@"i[\\p{Alphabetic}&&\\p{Uppercase}][\\p{Alphabetic}]+" options:0 error:NULL];
    
    
    // 首先清除之前的所有高亮
    NSRange paragaphRange = [self.string paragraphRangeForRange: self.editedRange];
    [self removeAttribute:NSForegroundColorAttributeName range:paragaphRange];
    
    // 其次遍歷所有的樣式匹配項(xiàng)并高亮它們
    [iExpression enumerateMatchesInString:self.string options:0 range:paragaphRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
        // Add red highlight color
        [self addAttribute:NSForegroundColorAttributeName value:[UIColor redColor] range:result.range];
    }];
  
  /*
   請(qǐng)注意僅僅使用 edited range 是不夠的吁峻。例如,當(dāng)手動(dòng)鍵入 iWords在张,只有一個(gè)單詞的第三個(gè)字符被鍵入后用含,正則表達(dá)式才開始匹配。但那時(shí) editedRange 僅包含第三個(gè)字符帮匾,因此所有的處理只會(huì)影響這一個(gè)字符啄骇。通過重新處理整個(gè)段落可以解決這個(gè)問題,這樣既完成高亮功能辟狈,又不會(huì)太過影響性能
   
   */
  [super processEditing];
}

@end

Demo3肠缔、布局演示
需求:文本中的網(wǎng)址不斷行
1.NSTextStorage負(fù)責(zé)監(jiān)聽文本中出現(xiàn)的網(wǎng)址string

#import "TKDLinkDetectingTextStorage.h"


@implementation TKDLinkDetectingTextStorage
{
    NSTextStorage *_imp;
}

- (id)init
{
    self = [super init];
    
    if (self) {
        _imp = [NSTextStorage new];
    }
    
    return self;
}


#pragma mark - Reading Text

- (NSString *)string
{
    return _imp.string;
}

- (NSDictionary *)attributesAtIndex:(NSUInteger)location effectiveRange:(NSRangePointer)range
{
    return [_imp attributesAtIndex:location effectiveRange:range];
}


#pragma mark - Text Editing

//NSString 替換字符串中某一位置的文字
- (void)replaceCharactersInRange:(NSRange)range withString:(NSString *)str
{
    // Normal replace
    [_imp replaceCharactersInRange:range withString:str];
    [self edited:NSTextStorageEditedCharacters range:range changeInLength:(NSInteger)str.length - (NSInteger)range.length];
    
    
    
    // Regular expression matching all iWords -- first character i, followed by an uppercase alphabetic character, followed by at least one other character. Matches words like iPod, iPhone, etc.
    static NSDataDetector *linkDetector;
    linkDetector = linkDetector ?: [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypeLink error:NULL];
    
    // Clear text color of edited range
    NSRange paragaphRange = [self.string paragraphRangeForRange: NSMakeRange(range.location, str.length)];
    [self removeAttribute:NSLinkAttributeName range:paragaphRange];
    [self removeAttribute:NSBackgroundColorAttributeName range:paragaphRange];
    [self removeAttribute:NSUnderlineStyleAttributeName range:paragaphRange];
    
    // Find all iWords in range
    [linkDetector enumerateMatchesInString:self.string options:0 range:paragaphRange usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
        // Add red highlight color
        [self addAttribute:NSLinkAttributeName value:result.URL range:result.range];
        [self addAttribute:NSBackgroundColorAttributeName value:[UIColor yellowColor] range:result.range];
        [self addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:result.range];
    }];
}

- (void)setAttributes:(NSDictionary *)attrs range:(NSRange)range
{
    [_imp setAttributes:attrs range:range];
    [self edited:NSTextStorageEditedAttributes range:range changeInLength:0];
}

@end

2.重寫NSLayoutManager“對(duì)應(yīng)的”drawGlyphsForGlyphRange方法
這里我們重寫這個(gè)方法

#import "TKDOutliningLayoutManager.h"

@implementation TKDOutliningLayoutManager
//下面重寫NSLayoutManager的drawGlyphsForGlyphRange方法
- (void)drawUnderlineForGlyphRange:(NSRange)glyphRange underlineType:(NSUnderlineStyle)underlineVal baselineOffset:(CGFloat)baselineOffset lineFragmentRect:(CGRect)lineRect lineFragmentGlyphRange:(NSRange)lineGlyphRange containerOrigin:(CGPoint)containerOrigin
{
    // Left border (== position) of first underlined glyph
    CGFloat firstPosition = [self locationForGlyphAtIndex: glyphRange.location].x;
    
    // Right border (== position + width) of last underlined glyph
    CGFloat lastPosition;
    
    // When link is not the last text in line, just use the location of the next glyph
    if (NSMaxRange(glyphRange) < NSMaxRange(lineGlyphRange)) {
        lastPosition = [self locationForGlyphAtIndex: NSMaxRange(glyphRange)].x;
    }
    // Otherwise get the end of the actually used rect
    else {
        lastPosition = [self lineFragmentUsedRectForGlyphAtIndex:NSMaxRange(glyphRange)-1 effectiveRange:NULL].size.width;
    }
    
    // Inset line fragment to underlined area
    lineRect.origin.x += firstPosition;
    lineRect.size.width = lastPosition - firstPosition;
    
    // Offset line by container origin
    lineRect.origin.x += containerOrigin.x;
    lineRect.origin.y += containerOrigin.y;
    
    // Align line to pixel boundaries, passed rects may be
    lineRect = CGRectInset(CGRectIntegral(lineRect), .5, .5);
    
    [[UIColor greenColor] set];
    [[UIBezierPath bezierPathWithRect: lineRect] stroke];
}


3.在textView所在頁面,使用NSLayoutManager的代理做具體的實(shí)現(xiàn)

#import "TKDLayoutingViewController.h"

#import "TKDLinkDetectingTextStorage.h"
#import "TKDOutliningLayoutManager.h"


@interface TKDLayoutingViewController () <NSLayoutManagerDelegate>
{
    // Text storage must be held strongly, only the default storage is retained by the text view.
    TKDLinkDetectingTextStorage *_textStorage;
}
@end

@implementation TKDLayoutingViewController

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    // Create componentes
    _textStorage = [TKDLinkDetectingTextStorage new];
    
    NSLayoutManager *layoutManager = [TKDOutliningLayoutManager new];
    [_textStorage addLayoutManager: layoutManager];
    
    NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize: CGSizeZero];
    [layoutManager addTextContainer: textContainer];
    
    UITextView *textView = [[UITextView alloc] initWithFrame:CGRectInset(self.view.bounds, 5, 20) textContainer: textContainer];
    textView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    textView.translatesAutoresizingMaskIntoConstraints = YES;
    textView.keyboardDismissMode = UIScrollViewKeyboardDismissModeInteractive;
    [self.view addSubview: textView];
    
    
    // Set delegate
    layoutManager.delegate = self;
    
    // Load layout text
    [_textStorage replaceCharactersInRange:NSMakeRange(0, 0) withString:[NSString stringWithContentsOfURL:[NSBundle.mainBundle URLForResource:@"layout" withExtension:@"txt"] usedEncoding:NULL error:NULL]];
}


#pragma mark - Layout

- (BOOL)layoutManager:(NSLayoutManager *)layoutManager shouldBreakLineByWordBeforeCharacterAtIndex:(NSUInteger)charIndex
{
    NSRange range;
    NSURL *linkURL = [layoutManager.textStorage attribute:NSLinkAttributeName atIndex:charIndex effectiveRange:&range];
    
    // Do not break lines in links unless absolutely required
    if (linkURL && charIndex > range.location && charIndex <= NSMaxRange(range))
        return NO;
    else
        return YES;
}

- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager lineSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect
{
    return floorf(glyphIndex / 100);
}

- (CGFloat)layoutManager:(NSLayoutManager *)layoutManager paragraphSpacingAfterGlyphAtIndex:(NSUInteger)glyphIndex withProposedLineFragmentRect:(CGRect)rect
{
    return 10;
}

@end

Demo4哼转、綜合實(shí)例
NSTextContainer 和NSBezierPath的使用

#import "TKDInteractionViewController.h"

#import "TKDCircleView.h"http://只是為橢圓添加一個(gè)空白邊距

@interface TKDInteractionViewController () <UITextViewDelegate>
{
   CGPoint _panOffset;
}
@end

@implementation TKDInteractionViewController

- (void)viewDidLoad
{
   [super viewDidLoad];
   
   // Load text
   [self.textView.textStorage replaceCharactersInRange:NSMakeRange(0, 0) withString:[NSString stringWithContentsOfURL:[NSBundle.mainBundle URLForResource:@"lorem" withExtension:@"txt"] usedEncoding:NULL error:NULL]];
   
   // Delegate
   self.textView.delegate = self;
   self.clippyView.hidden = YES;
   
   // Set up circle pan
   [self.circleView addGestureRecognizer: [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(circlePan:)]];
   [self updateExclusionPaths];
   
   // Enable hyphenation
   self.textView.layoutManager.hyphenationFactor = 1.0;
}


#pragma mark - Exclusion

- (void)circlePan:(UIPanGestureRecognizer *)pan
{
   // Capute offset in view on begin
   if (pan.state == UIGestureRecognizerStateBegan)
       _panOffset = [pan locationInView: self.circleView];
   
   // Update view location
   CGPoint location = [pan locationInView: self.view];
   CGPoint circleCenter = self.circleView.center;
   
   circleCenter.x = location.x - _panOffset.x + self.circleView.frame.size.width / 2;
   circleCenter.y = location.y - _panOffset.y + self.circleView.frame.size.width / 2;
   self.circleView.center = circleCenter;
   
   // Update exclusion path
   [self updateExclusionPaths];
}

- (void)updateExclusionPaths
{
   CGRect ovalFrame = [self.textView convertRect:self.circleView.bounds fromView:self.circleView];
   
   // Since text container does not know about the inset, we must shift the frame to container coordinates
   ovalFrame.origin.x -= self.textView.textContainerInset.left;
   ovalFrame.origin.y -= self.textView.textContainerInset.top;
   
   // Simply set the exclusion path
   UIBezierPath *ovalPath = [UIBezierPath bezierPathWithOvalInRect: ovalFrame];
   self.textView.textContainer.exclusionPaths = @[ovalPath];
   
   // And don't forget clippy
   [self updateClippy];
}


#pragma mark - Selection tracking

- (void)textViewDidChangeSelection:(UITextView *)textView
{
   [self updateClippy];
}

- (void)updateClippy
{
   // Zero length selection hide clippy
   NSRange selectedRange = self.textView.selectedRange;
   if (!selectedRange.length) {
       self.clippyView.hidden = YES;
       return;
   }
   
   // Find last rect of selection
   NSRange glyphRange = [self.textView.layoutManager glyphRangeForCharacterRange:selectedRange actualCharacterRange:NULL];
   __block CGRect lastRect;
   [self.textView.layoutManager enumerateEnclosingRectsForGlyphRange:glyphRange withinSelectedGlyphRange:glyphRange inTextContainer:self.textView.textContainer usingBlock:^(CGRect rect, BOOL *stop) {
       lastRect = rect;
   }];
   
   
   // Position clippy at bottom-right of selection
   CGPoint clippyCenter;
   clippyCenter.x = CGRectGetMaxX(lastRect) + self.textView.textContainerInset.left;
   clippyCenter.y = CGRectGetMaxY(lastRect) + self.textView.textContainerInset.top;
   
   clippyCenter = [self.textView convertPoint:clippyCenter toView:self.view];
   clippyCenter.x += self.clippyView.bounds.size.width / 2;
   clippyCenter.y += self.clippyView.bounds.size.height / 2;
   
   self.clippyView.hidden = NO;
   self.clippyView.center = clippyCenter;
}

@end

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市槽华,隨后出現(xiàn)的幾起案子壹蔓,更是在濱河造成了極大的恐慌,老刑警劉巖猫态,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件佣蓉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡亲雪,警方通過查閱死者的電腦和手機(jī)勇凭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來义辕,“玉大人虾标,你說我怎么就攤上這事」嘧” “怎么了璧函?”我有些...
    開封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)基显。 經(jīng)常有香客問我蘸吓,道長(zhǎng),這世上最難降的妖魔是什么撩幽? 我笑而不...
    開封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任库继,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘宪萄。我一直安慰自己艺谆,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開白布雨膨。 她就那樣靜靜地躺著擂涛,像睡著了一般。 火紅的嫁衣襯著肌膚如雪聊记。 梳的紋絲不亂的頭發(fā)上撒妈,一...
    開封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音排监,去河邊找鬼狰右。 笑死,一個(gè)胖子當(dāng)著我的面吹牛舆床,可吹牛的內(nèi)容都是我干的棋蚌。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼挨队,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼谷暮!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起盛垦,我...
    開封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤湿弦,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后腾夯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體颊埃,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年蝶俱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了班利。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡榨呆,死狀恐怖罗标,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情愕提,我是刑警寧澤馒稍,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站浅侨,受9級(jí)特大地震影響纽谒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜如输,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一鼓黔、第九天 我趴在偏房一處隱蔽的房頂上張望央勒。 院中可真熱鬧,春花似錦澳化、人聲如沸崔步。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽井濒。三九已至,卻和暖如春列林,著一層夾襖步出監(jiān)牢的瞬間瑞你,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來泰國打工希痴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留者甲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓砌创,卻偏偏與公主長(zhǎng)得像虏缸,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嫩实,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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