iOS基礎(chǔ):AVPlayer的入門以及應(yīng)用(自定義播放管理器的開發(fā))

一甸饱、閑談

一直用著網(wǎng)易云音樂這個(gè)app,也一直想要模擬著它做一個(gè)卻總是懶得邁出第一步境蜕,最近終于下定決心,打算先做一點(diǎn)最基礎(chǔ)的凌停。一個(gè)音樂播放器最基礎(chǔ)的當(dāng)然就是播放管理器了粱年。

二、AVPlayer的入門

其實(shí)AVPlayer用起來很簡(jiǎn)單苦锨,我也就不說廢話,直接放上代碼逼泣。

第一步:初始化等操作

// 初始化一個(gè)AVPlayer
self.player = [[AVPlayer alloc] init];
// 創(chuàng)建一個(gè)item
AVPlayerItem *item =[AVPlayerItem playerItemWithURL:[NSURL URLWithString:@"http://m2.music.126.net/lpeVipLJshTxA-T7xjFI2g==/1046735069650768.mp3"]];
// 監(jiān)聽status屬性
[item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
// 監(jiān)聽loadedTimeRanges屬性
[item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
// 設(shè)置player的item
[self.player replaceCurrentItemWithPlayerItem:item];

下面再補(bǔ)充一下監(jiān)聽的兩個(gè)屬性趴泌。

1.status

這個(gè)屬性指的是item的狀態(tài),狀態(tài)一共有三種拉庶,如下:

typedef NS_ENUM(NSInteger, AVPlayerItemStatus) {
    AVPlayerItemStatusUnknown,
    AVPlayerItemStatusReadyToPlay,
    AVPlayerItemStatusFailed
};

顯然嗜憔,當(dāng)status為AVPlayerItemStatusReadyToPlay的時(shí)候,就說明可以播放了氏仗。

2.loadedTimeRanges

這個(gè)屬性主要是用在獲取緩沖的進(jìn)度的吉捶,具體的使用在下文會(huì)說到。

第二步:響應(yīng)監(jiān)聽

既然有監(jiān)聽皆尔,那就肯定要響應(yīng)呐舔。先上代碼:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerItemStatus status =[change[@"new"]integerValue];//change為string類型
        switch (status) {
            case AVPlayerItemStatusUnknown:
                NSLog(@"AVPlayerItemStatusUnknown");
                break;          
            case AVPlayerItemStatusReadyToPlay:
                //調(diào)用播放方法
                [self.player play];
                break;
            case AVPlayerItemStatusFailed:{
                NSLog(@"AVPlayerItemStatusFailed");
                break;
            }          
            default:
                break;
        }
    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        // 計(jì)算緩沖的進(jìn)度百分比
        float timeInterval= [self availableDuration];
        NSInteger totalDuration = [self fetchTotalTime];
        // 打印緩沖進(jìn)度的百分比
        NSLog(@"進(jìn)度百分比%f", timeInterval / totalDuration);
    }
}

其中監(jiān)聽item的狀態(tài)的代碼就不需要說了,只需要在AVPlayerItemStatusReadyToPlay后加上

[self.player play];

就可以了慷蠕。
下面講一下計(jì)算緩沖的進(jìn)度百分比的思路珊拼,其實(shí)也很簡(jiǎn)單,先獲取到緩沖的進(jìn)度流炕,再獲取到總的時(shí)間澎现,然后 緩沖的進(jìn)度/總時(shí)間 就是緩沖的百分比。

自己寫一個(gè)獲取總時(shí)間的方法:
// 獲取總時(shí)間每辟,總秒數(shù)
- (NSInteger)fetchTotalTime
{
    //獲取當(dāng)前播放歌曲的總時(shí)間
    CMTime time = self.player.currentItem.duration;
    
    if (time.timescale == 0) {
        return 0;
    }
    //播放秒數(shù) = time.value/time.timescale
    return time.value/time.timescale;
}
自己寫一個(gè)獲取緩沖總進(jìn)度的方法:
- (float)availableDuration
{
    NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 獲取緩沖區(qū)域
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    float result = startSeconds + durationSeconds;// 計(jì)算緩沖總進(jìn)度
    return result;
}

補(bǔ)充一點(diǎn)CMTimeRange的知識(shí):

typedef struct
{
    CMTime          start;      /*! @field start The start time of the time range. */
    CMTime          duration;   /*! @field duration The duration of the time range. */
} CMTimeRange;

start表示的是開始時(shí)間剑辫,duration表示的是時(shí)間范圍的持續(xù)時(shí)間。所以這邊緩沖的總進(jìn)度就是兩者相加了渠欺。

入門寫到這里盟迟,下面是自定義一個(gè)播放管理器

三赋访、自定義播放管理器

1.創(chuàng)建類并聲明方法

想象一下一個(gè)播放管理器會(huì)有哪些方法罕容,播放萌抵,暫停,開始播放網(wǎng)絡(luò)音樂捐名,開始播放本地音樂旦万,甚至還有拉進(jìn)度條來快進(jìn)快退闹击。代碼如下:

//單例
+ (instancetype)sharedPlayerManager;

//暫停
- (void)pasuseMusic;

//播放
- (void)playMusic;

//準(zhǔn)備去播放
- (void)prepareToPlayMusicWithUrl:(NSString *)url;

//本地播放方法
- (void)prepareToPlayMusicWithFilePath:(NSString *)musicFilePath;

//快進(jìn)快退方法
- (void)playMusicWithSliderValue:(CGFloat)peogress;

2.相關(guān)方法的實(shí)現(xiàn)

趁熱打鐵镶蹋,先寫播放歌曲方法

// 播放網(wǎng)絡(luò)歌曲
- (void)prepareToPlayMusicWithUrl:(NSString *)url
{
    if (!url) {
        return;
    }
    //判斷當(dāng)前有沒有正在播放的item
    if (self.player.currentItem) {
        //移除觀察者
        [self.player.currentItem removeObserver:self forKeyPath:@"status"];
        [self.player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    }
    //創(chuàng)建一個(gè)item
    AVPlayerItem *item =[AVPlayerItem playerItemWithURL:[NSURL URLWithString:url]];
    //觀察item的加載狀態(tài)
    [item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    [item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //替換當(dāng)前item
    [self.player replaceCurrentItemWithPlayerItem:item];
    //播放完成后自動(dòng)跳到下一首
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nextMusic) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];

}

// 播放本地歌曲
- (void)prepareToPlayMusicWithFilePath:(NSString *)musicFilePath
{
    //判斷當(dāng)前有沒有正在播放的item
    if (self.player.currentItem) {
        //移除觀察者
        [self.player.currentItem removeObserver:self forKeyPath:@"status"];
        [self.player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    }
    //創(chuàng)建一個(gè)item
    AVPlayerItem *item =[AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:musicFilePath]];
    
    //觀察item的加載狀態(tài)
    [item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    [item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //替換當(dāng)前item
    [self.player replaceCurrentItemWithPlayerItem:item];
    //播放完成后自動(dòng)跳到下一首
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(nextMusic) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}

再寫相關(guān)私有方法

#pragma mark - 私有方法
// 獲取當(dāng)前時(shí)間
- (NSInteger)fetchCurrentTime
{
    CMTime time = self.player.currentItem.currentTime;
    if (time.timescale == 0) {
        return 0;
    }
    return time.value/time.timescale;
}

// 獲取總時(shí)間時(shí)間
- (NSInteger)fetchTotalTime
{
    CMTime time = self.player.currentItem.duration;
    if (time.timescale == 0) {
        return 0;
    }
    return time.value/time.timescale;
}

// 獲取當(dāng)前播放進(jìn)度
- (CGFloat)fetchProgressValue
{
    return [self fetchCurrentTime]/(CGFloat)[self fetchTotalTime];
}

// 獲取緩沖進(jìn)度
- (float)availableDuration
{
    NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 獲取緩沖區(qū)域
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    float result = startSeconds + durationSeconds;// 計(jì)算緩沖總進(jìn)度
    return result;
}

//將秒數(shù)轉(zhuǎn)化成類似00:00的格式,用于界面顯示
- (NSString *)changeSecondsTime:(NSInteger)time
{
    NSInteger min =time/60;
    NSInteger seconds =time % 60;
    return [NSString stringWithFormat:@"%.2ld:%.2ld",min,seconds];
}

監(jiān)聽響應(yīng)

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerItemStatus status =[change[@"new"]integerValue];//change為string類型
        switch (status) {
            case AVPlayerItemStatusUnknown:
                NSLog(@"未知錯(cuò)誤");
                break;
            case AVPlayerItemStatusReadyToPlay:
                //調(diào)用播放方法
                [self.player play];
                break;
            case AVPlayerItemStatusFailed:{
                NSLog(@"錯(cuò)誤");
                break;
            }
            default:
                break;
        }
    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        float timeInterval= [self availableDuration];
        NSInteger totalDuration = [self fetchTotalTime];
        NSLog(@"==%f", timeInterval / totalDuration);
    }
}

由于始終要刷新界面的進(jìn)度條赏半,所以我們要?jiǎng)?chuàng)建一個(gè)timer來時(shí)刻返回當(dāng)前的時(shí)間贺归。這里我用的是代理模式。同時(shí)加兩個(gè)開關(guān)定時(shí)器的私有方法断箫。

// timer懶加載
- (NSTimer *)timer {
    if (!_timer) {
        _timer =[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
    }
    return _timer;
}

//定時(shí)器方法
- (void)timerAction {
    if ([self.delegate respondsToSelector:@selector(playManagerDelegateFetchTotalTime:currentTime:progress:)]) {
        //1.總時(shí)間  2.當(dāng)期時(shí)間 3.當(dāng)前進(jìn)度
        NSString *totalTime = [self changeSecondsTime:[self fetchTotalTime]];//總時(shí)間
        NSString *currentTime =[self changeSecondsTime:[self fetchCurrentTime]];//當(dāng)前時(shí)間
        CGFloat progress = [self fetchProgressValue];
        
        [self.delegate playManagerDelegateFetchTotalTime:totalTime  currentTime:currentTime  progress:progress];
    }
}

//開啟定時(shí)器
- (void)startTimer
{
    [self.timer fire];
}

//關(guān)閉定時(shí)器
- (void)closeTimer
{
    [self.timer invalidate];
    self.timer = nil;  //置空
}

最后完成剩下的方法

// 暫停
- (void)pasuseMusic
{
    [self.player pause];
    [self closeTimer];
}

// 播放
- (void)playMusic
{
    [self.player play];
    [self startTimer];
}

//快進(jìn)快退
- (void)playMusicWithSliderValue:(CGFloat)peogress{
    //滑動(dòng)之前 先暫停音樂
    [self pasuseMusic];
    [self.player seekToTime:CMTimeMake([self fetchTotalTime] * peogress, 1) completionHandler:^(BOOL finished) {
        if (finished) {
            //活動(dòng)結(jié)束繼續(xù)播放
            [self playMusic];
        }
    }];
}

好了拂酣,到這邊所有的方法都完成了。我把代碼全部再貼上仲义。
.h文件

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

@protocol YQPlayerManagerDelegate <NSObject>
// 傳遞播放時(shí)間總時(shí)間等信息
-(void)playManagerDelegateFetchTotalTime:(NSString *)totalTime currentTime:(NSString *)currentTime progress:(CGFloat)progress;
// 傳遞播放的進(jìn)度百分比
- (void)playManagerDelegateFetchLoadedTimeRanges:(CGFloat)loadPercent;
// 下一首歌
- (void)playNextMusic;
@end

@interface YQPlayerManager : NSObject

@property (nonatomic, weak) id <YQPlayerManagerDelegate> delegate;

//單例
+ (instancetype)sharedPlayerManager;

//暫停
- (void)pasuseMusic;

//播放
- (void)playMusic;

//準(zhǔn)備去播放
- (void)prepareToPlayMusicWithUrl:(NSString *)url;

//本地播放方法
- (void)prepareToPlayMusicWithFilePath:(NSString *)musicFilePath;

//快進(jìn)快退方法
- (void)playMusicWithSliderValue:(CGFloat)peogress;
@end

.m文件

#import "YQPlayerManager.h"

@interface YQPlayerManager()
@property (nonatomic, strong) AVPlayer *player;
@property (nonatomic, strong) NSTimer *timer;
@end

@implementation YQPlayerManager

// timer懶加載
- (NSTimer *)timer {
    if (!_timer) {
        _timer =[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(timerAction) userInfo:nil repeats:YES];
    }
    return _timer;
}

//定時(shí)器方法
- (void)timerAction {
    if ([self.delegate respondsToSelector:@selector(playManagerDelegateFetchTotalTime:currentTime:progress:)]) {
        //1.總時(shí)間  2.當(dāng)期時(shí)間 3.當(dāng)前進(jìn)度
        NSString *totalTime = [self changeSecondsTime:[self fetchTotalTime]];//總時(shí)間
        NSString *currentTime =[self changeSecondsTime:[self fetchCurrentTime]];//當(dāng)前時(shí)間
        CGFloat progress = [self fetchProgressValue];
        [self.delegate playManagerDelegateFetchTotalTime:totalTime  currentTime:currentTime  progress:progress];
    }
}

//開啟定時(shí)器
- (void)startTimer
{
    [self.timer fire];
}

//關(guān)閉定時(shí)器
- (void)closeTimer
{
    [self.timer invalidate];
    self.timer = nil;  //置空
}


//player懶加載
- (AVPlayer *)player
{
    if (_player == nil) {
        _player = [[AVPlayer alloc] init];
    }
    return _player;
}


//單例
+ (instancetype)sharedPlayerManager {
    static YQPlayerManager *handle = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        handle = [[YQPlayerManager alloc] init];
    });
    return handle;
}

// 暫停
- (void)pasuseMusic
{
    [self.player pause];
    [self closeTimer];
}

// 播放
- (void)playMusic
{
    [self.player play];
    [self startTimer];
}

// 播放網(wǎng)絡(luò)歌曲
- (void)prepareToPlayMusicWithUrl:(NSString *)url
{
    if (!url) {
        return;
    }
    //判斷當(dāng)前有沒有正在播放的item
    if (self.player.currentItem) {
        //移除觀察者
        [self.player.currentItem removeObserver:self forKeyPath:@"status"];
        [self.player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    }
    //創(chuàng)建一個(gè)item
    AVPlayerItem *item =[AVPlayerItem playerItemWithURL:[NSURL URLWithString:url]];
    //觀察item的加載狀態(tài)
    [item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    [item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //替換當(dāng)前item
    [self.player replaceCurrentItemWithPlayerItem:item];
    //播放完成后自動(dòng)跳到下一首
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(nextMusic) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];

}

// 播放本地歌曲
- (void)prepareToPlayMusicWithFilePath:(NSString *)musicFilePath
{
    //判斷當(dāng)前有沒有正在播放的item
    if (self.player.currentItem) {
        //移除觀察者
        [self.player.currentItem removeObserver:self forKeyPath:@"status"];
        [self.player.currentItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    }
    //創(chuàng)建一個(gè)item
    AVPlayerItem *item =[AVPlayerItem playerItemWithURL:[NSURL fileURLWithPath:musicFilePath]];
    
    //觀察item的加載狀態(tài)
    [item addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    [item addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //替換當(dāng)前item
    [self.player replaceCurrentItemWithPlayerItem:item];
    //播放完成后自動(dòng)跳到下一首
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(nextMusic) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
}

//快進(jìn)快退
- (void)playMusicWithSliderValue:(CGFloat)peogress{
    //滑動(dòng)之前 先暫停音樂
    [self pasuseMusic];
    [self.player seekToTime:CMTimeMake([self fetchTotalTime] * peogress, 1) completionHandler:^(BOOL finished) {
        if (finished) {
            //活動(dòng)結(jié)束繼續(xù)播放
            [self playMusic];
        }
    }];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerItemStatus status =[change[@"new"]integerValue];//change為string類型
        switch (status) {
            case AVPlayerItemStatusUnknown:
                NSLog(@"未知錯(cuò)誤");
                break;
            case AVPlayerItemStatusReadyToPlay:
                // 調(diào)用播放方法 
                // 注意這里要改成[self playMusic];而不是還是原來的[self.player play]婶熬,否則無法開啟定時(shí)器=9础!赵颅!
                [self playMusic];
                break;
            case AVPlayerItemStatusFailed:{
                NSLog(@"錯(cuò)誤");
                break;
            }
            default:
                break;
        }
    } else if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        float timeInterval= [self availableDuration];
        NSInteger totalDuration = [self fetchTotalTime];
        float percent = timeInterval /totalDuration;
        if (percent > 1) {
            percent = 1;
        }
        if ([self.delegate respondsToSelector:@selector(playManagerDelegateFetchLoadedTimeRanges:)]) {
            [self.delegate playManagerDelegateFetchLoadedTimeRanges:percent];
        }
    }
}

#pragma mark - 私有方法
- (void)nextMusic
{
    if ([self.delegate respondsToSelector:@selector(playNextMusic)]) {
        [self.delegate playNextMusic];
    }
}

// 獲取當(dāng)前時(shí)間
- (NSInteger)fetchCurrentTime
{
    CMTime time = self.player.currentItem.currentTime;
    if (time.timescale == 0) {
        return 0;
    }
    return time.value/time.timescale;
}

// 獲取總時(shí)間時(shí)間
- (NSInteger)fetchTotalTime
{
    CMTime time = self.player.currentItem.duration;
    if (time.timescale == 0) {
        return 0;
    }
    return time.value/time.timescale;
}

// 獲取當(dāng)前播放進(jìn)度
- (CGFloat)fetchProgressValue
{
    return [self fetchCurrentTime]/(CGFloat)[self fetchTotalTime];
}

// 獲取緩沖進(jìn)度
- (float)availableDuration
{
    NSArray *loadedTimeRanges = [[self.player currentItem] loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];// 獲取緩沖區(qū)域
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSeconds = CMTimeGetSeconds(timeRange.duration);
    float result = startSeconds + durationSeconds;// 計(jì)算緩沖總進(jìn)度
    return result;
}

//將秒數(shù)轉(zhuǎn)化成類似00:00的格式虽另,用于界面顯示
- (NSString *)changeSecondsTime:(NSInteger)time
{
    NSInteger min =time/60;
    NSInteger seconds =time % 60;
    return [NSString stringWithFormat:@"%.2ld:%.2ld",min,seconds];
}

3.使用管理器

在視圖控制器中使用,上代碼:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    YQPlayerManager *manager = [YQPlayerManager sharedPlayerManager];
    [manager prepareToPlayMusicWithUrl:@"http://m2.music.126.net/lpeVipLJshTxA-T7xjFI2g==/1046735069650768.mp3"];
    manager.delegate = self;
}

-  (void)playManagerDelegateFetchTotalTime:(NSString *)totalTime currentTime:(NSString *)currentTime progress:(CGFloat)progress
{
    NSLog(@"%@---%@---%f", totalTime, currentTime, progress);
}

- (void)playManagerDelegateFetchLoadedTimeRanges:(CGFloat)loadPercent
{
    NSLog(@"%f", loadPercent);
}

- (void)playNextMusic
{
    NSLog(@"playNextMusic");
}

結(jié)果:

結(jié)果展示.gif

最后

到這里就全部搞定了饺谬,喜歡的點(diǎn)個(gè)贊唄~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末捂刺,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子募寨,更是在濱河造成了極大的恐慌族展,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拔鹰,死亡現(xiàn)場(chǎng)離奇詭異仪缸,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)列肢,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門腹殿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人例书,你說我怎么就攤上這事锣尉。” “怎么了决采?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵自沧,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我树瞭,道長(zhǎng)拇厢,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任晒喷,我火速辦了婚禮孝偎,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘凉敲。我一直安慰自己衣盾,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布爷抓。 她就那樣靜靜地躺著势决,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蓝撇。 梳的紋絲不亂的頭發(fā)上果复,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音渤昌,去河邊找鬼虽抄。 笑死走搁,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的迈窟。 我是一名探鬼主播朱盐,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼菠隆!你這毒婦竟也來了兵琳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤骇径,失蹤者是張志新(化名)和其女友劉穎躯肌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體破衔,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡清女,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了晰筛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嫡丙。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖读第,靈堂內(nèi)的尸體忽然破棺而出曙博,到底是詐尸還是另有隱情,我是刑警寧澤怜瞒,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布父泳,位于F島的核電站,受9級(jí)特大地震影響吴汪,放射性物質(zhì)發(fā)生泄漏惠窄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一漾橙、第九天 我趴在偏房一處隱蔽的房頂上張望杆融。 院中可真熱鬧,春花似錦霜运、人聲如沸脾歇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽介劫。三九已至徽惋,卻和暖如春案淋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背险绘。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來泰國(guó)打工踢京, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留誉碴,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓瓣距,卻偏偏與公主長(zhǎng)得像黔帕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蹈丸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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