抖音的轉(zhuǎn)場動畫—iOS

前言

今天帶來的是抖音的轉(zhuǎn)場動畫實現(xiàn) 廢話不多說上圖

這里需要用到前一篇文章的上下滑實現(xiàn)

學(xué)習(xí)這篇文章之前推薦看下喵神的iOS7中的ViewController轉(zhuǎn)場切換

如果對轉(zhuǎn)場不是很了解的話可能學(xué)習(xí)會有一些難度和疑問.

轉(zhuǎn)場調(diào)用代碼

- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath {
    AwemeListViewController *awemeVC = [[AwemeListViewController alloc] init];
    awemeVC.transitioningDelegate = self; //0

    // 1
    UICollectionViewCell *cell = [collectionView cellForItemAtIndexPath:indexPath];
    // 2
    CGRect cellFrame = cell.frame;
    // 3
    CGRect cellConvertedFrame = [collectionView convertRect:cellFrame toView:collectionView.superview];

    //彈窗轉(zhuǎn)場
    self.presentScaleAnimation.cellConvertFrame = cellConvertedFrame; //4

    //消失轉(zhuǎn)場
    self.dismissScaleAnimation.selectCell = cell; // 5
    self.dismissScaleAnimation.originCellFrame  = cellFrame; //6
    self.dismissScaleAnimation.finalCellFrame = cellConvertedFrame; //7

    awemeVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; //8
    self.modalPresentationStyle = UIModalPresentationCurrentContext; //9

    [self.leftDragInteractiveTransition wireToViewController:awemeVC];
    [self presentViewController:awemeVC animated:YES completion:nil];
}

0 處代碼使我們需要把當(dāng)前的類做為轉(zhuǎn)場的代理
1 這里我們要拿出cell這個view
2 拿出當(dāng)前Cell的frame坐標(biāo)
3 cell的坐標(biāo)轉(zhuǎn)成屏幕坐標(biāo)
4 設(shè)置彈出時候需要cell在屏幕的位置坐標(biāo)
5 設(shè)置消失轉(zhuǎn)場需要的選中cell視圖
6 設(shè)置消失轉(zhuǎn)場原始cell坐標(biāo)位置
7 設(shè)置消失轉(zhuǎn)場最終得cell屏幕坐標(biāo)位置 用于消失完成回到原來位置的動畫
8 設(shè)置彈出得vc彈出樣式 這個用于顯示彈出VC得時候 默認(rèn)底部使blua的高斯模糊
9 設(shè)置當(dāng)前VC的模態(tài)彈出樣式為當(dāng)前的彈出上下文

5~7 步設(shè)置的消失轉(zhuǎn)場動畫 下面會講解

這里我們用的是前面講上下滑的VC對象 大家不必?fù)?dān)心 當(dāng)它是一個普通的UIViewController即可

實現(xiàn)轉(zhuǎn)場所需要的代理

首先在需要實現(xiàn)UIViewControllerTransitioningDelegate這個代理

 #pragma mark -
#pragma mark - UIViewControllerAnimatedTransitioning Delegate
- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {

    return self.presentScaleAnimation; //present VC
}

- (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
    return self.dismissScaleAnimation; //dismiss VC
}

- (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator {
    return self.leftDragInteractiveTransition.isInteracting? self.leftDragInteractiveTransition: nil;
}

這里面我們看到我們分別返回了

  • 彈出動畫實例self.presentScaleAnimation

  • dismiss動畫實例self.dismissScaleAnimation

  • 以及self.leftDragInteractiveTransition實例用于負(fù)責(zé)轉(zhuǎn)場切換的具體實現(xiàn)

    所以我們需要在 當(dāng)前的VC中聲明3個成員變量 并初始化

    @property (nonatomic, strong) PresentScaleAnimation *presentScaleAnimation;
    @property (nonatomic, strong) DismissScaleAnimation *dismissScaleAnimation;
    @property (nonatomic, strong) DragLeftInteractiveTransition *leftDragInteractiveTransition;

并在viewDidLoad:方法中初始化一下

 //轉(zhuǎn)場的兩個動畫
self.presentScaleAnimation = [[PresentScaleAnimation alloc] init];
self.dismissScaleAnimation = [[DismissScaleAnimation alloc] init];
self.leftDragInteractiveTransition = [DragLeftInteractiveTransition new];

這里我說一下這三個成員都負(fù)責(zé)啥事

首先DragLeftInteractiveTransition類負(fù)責(zé)轉(zhuǎn)場的 手勢 過程,就是pan手勢在這個類里面實現(xiàn),并繼承自UIPercentDrivenInteractiveTransition類,這是iOS7以后系統(tǒng)提供的轉(zhuǎn)場基類必須在interactionControllerForDismissal:代理協(xié)議中返回這個類或者子類的實例對象,所以我們生成一個成員變量self.leftDragInteractiveTransition

其次是彈出present和消失dismiss的動畫類,這倆類其實是負(fù)責(zé)簡單的手勢完成之后的動畫.

這兩個類都是繼承自NSObject并實現(xiàn)UIViewControllerAnimatedTransitioning協(xié)議的類,這個協(xié)議里面有 需要你復(fù)寫某些方法返回具體的動畫執(zhí)行時間,和中間過程中我們需要的相關(guān)的容器視圖以及控制器的視圖實例,當(dāng)我們自己執(zhí)行完成之后調(diào)用相關(guān)的block回答告知轉(zhuǎn)場是否完成就行了.

 @implementation PresentScaleAnimation
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext{
    return 0.3f;
}

- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
    UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];    
    if (CGRectEqualToRect(self.cellConvertFrame, CGRectZero)) {
        [transitionContext completeTransition:YES];
        return;
    }
    CGRect initialFrame = self.cellConvertFrame;
    UIView *containerView = [transitionContext containerView];
    [containerView addSubview:toVC.view];
    CGRect finalFrame = [transitionContext finalFrameForViewController:toVC];
    NSTimeInterval duration = [self transitionDuration:transitionContext];
    toVC.view.center = CGPointMake(initialFrame.origin.x + initialFrame.size.width/2, initialFrame.origin.y + initialFrame.size.height/2);
    toVC.view.transform = CGAffineTransformMakeScale(initialFrame.size.width/finalFrame.size.width, initialFrame.size.height/finalFrame.size.height);
    [UIView animateWithDuration:duration
                          delay:0
         usingSpringWithDamping:0.8
          initialSpringVelocity:1
                       options:UIViewAnimationOptionLayoutSubviews
                     animations:^{
                         toVC.view.center = CGPointMake(finalFrame.origin.x + finalFrame.size.width/2, finalFrame.origin.y + finalFrame.size.height/2);
                         toVC.view.transform = CGAffineTransformMakeScale(1, 1);
                     } completion:^(BOOL finished) {
                         [transitionContext completeTransition:YES];
                     }];
}
@end

很簡單.

消失的動畫 同上邊差不多


@interface DismissScaleAnimation ()
@end
@implementation DismissScaleAnimation
- (instancetype)init {
    self = [super init];
    if (self) {
        _centerFrame = CGRectMake((ScreenWidth - 5)/2, (ScreenHeight - 5)/2, 5, 5);
    }
    return self;
}
- (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext{
    return 0.25f;
}
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext{
    UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
//    UINavigationController *toNavigation = (UINavigationController *)[transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
//    UIViewController *toVC = [toNavigation viewControllers].firstObject;

    UIView *snapshotView;
    CGFloat scaleRatio;
    CGRect finalFrame = self.finalCellFrame;
    if(self.selectCell && !CGRectEqualToRect(finalFrame, CGRectZero)) {
        snapshotView = [self.selectCell snapshotViewAfterScreenUpdates:NO];
        scaleRatio = fromVC.view.frame.size.width/self.selectCell.frame.size.width;
        snapshotView.layer.zPosition = 20;
    }else {
        snapshotView = [fromVC.view snapshotViewAfterScreenUpdates:NO];
        scaleRatio = fromVC.view.frame.size.width/ScreenWidth;
        finalFrame = _centerFrame;
    }

    UIView *containerView = [transitionContext containerView];
    [containerView addSubview:snapshotView];

    NSTimeInterval duration = [self transitionDuration:transitionContext];

    fromVC.view.alpha = 0.0f;
    snapshotView.center = fromVC.view.center;
    snapshotView.transform = CGAffineTransformMakeScale(scaleRatio, scaleRatio);
    [UIView animateWithDuration:duration
                          delay:0
         usingSpringWithDamping:0.8
          initialSpringVelocity:0.2
                       options:UIViewAnimationOptionCurveEaseInOut
                     animations:^{
                         snapshotView.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
                         snapshotView.frame = finalFrame;
                     } completion:^(BOOL finished) {
                         [transitionContext finishInteractiveTransition];
                         [transitionContext completeTransition:YES];
                         [snapshotView removeFromSuperview];
                     }];
}
@end

我們重點需要說一下 轉(zhuǎn)場過渡的類DragLeftInteractiveTransition繼承自UIPercentDrivenInteractiveTransition負(fù)責(zé)轉(zhuǎn)場過程,

頭文件的聲明

@interface DragLeftInteractiveTransition : UIPercentDrivenInteractiveTransition
/** 是否正在拖動返回 標(biāo)識是否正在使用轉(zhuǎn)場的交互中 */
@property (nonatomic, assign) BOOL isInteracting;
/**
 設(shè)置需要返回的VC

 @param viewController 控制器實例
 */
-(void)wireToViewController:(UIViewController *)viewController;
@end

實現(xiàn)

@interface DragLeftInteractiveTransition ()
@property (nonatomic, strong) UIViewController *presentingVC;
@property (nonatomic, assign) CGPoint viewControllerCenter;
@property (nonatomic, strong) CALayer *transitionMaskLayer;
@end
@implementation DragLeftInteractiveTransition
#pragma mark -
#pragma mark - override methods 復(fù)寫方法
-(CGFloat)completionSpeed{
    return 1 - self.percentComplete;
}
- (void)updateInteractiveTransition:(CGFloat)percentComplete {
    NSLog(@"%.2f",percentComplete);

}
- (void)cancelInteractiveTransition {
    NSLog(@"轉(zhuǎn)場取消");
}
- (void)finishInteractiveTransition {
    NSLog(@"轉(zhuǎn)場完成");
}
- (CALayer *)transitionMaskLayer {
    if (_transitionMaskLayer == nil) {
        _transitionMaskLayer = [CALayer layer];
    }
    return _transitionMaskLayer;
}
#pragma mark -
#pragma mark - private methods 私有方法
- (void)prepareGestureRecognizerInView:(UIView*)view {
    UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
    [view addGestureRecognizer:gesture];
}
#pragma mark -
#pragma mark - event response 所有觸發(fā)的事件響應(yīng) 按鈕、通知、分段控件等
- (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer {
    UIView *vcView = gestureRecognizer.view;
    CGPoint translation = [gestureRecognizer translationInView:vcView.superview];
    if(!self.isInteracting &&
       (translation.x < 0 ||
        translation.y < 0 ||
        translation.x < translation.y)) {
        return;
    }
    switch (gestureRecognizer.state) {
        case UIGestureRecognizerStateBegan:{
            //修復(fù)當(dāng)從右側(cè)向左滑動的時候的bug 避免開始的時候從又向左滑動 當(dāng)未開始的時候
            CGPoint vel = [gestureRecognizer velocityInView:gestureRecognizer.view];
            if (!self.isInteracting && vel.x < 0) {
                self.isInteracting = NO;
                return;
            }
            self.transitionMaskLayer.frame = vcView.frame;
            self.transitionMaskLayer.opaque = NO;
            self.transitionMaskLayer.opacity = 1;
            self.transitionMaskLayer.backgroundColor = [UIColor whiteColor].CGColor; //必須有顏色不能透明
            [self.transitionMaskLayer setNeedsDisplay];
            [self.transitionMaskLayer displayIfNeeded];
            self.transitionMaskLayer.anchorPoint = CGPointMake(0.5, 0.5);
            self.transitionMaskLayer.position = CGPointMake(vcView.frame.size.width/2.0f, vcView.frame.size.height/2.0f);
            vcView.layer.mask = self.transitionMaskLayer;
            vcView.layer.masksToBounds = YES;

            self.isInteracting = YES;
        }

            break;
        case UIGestureRecognizerStateChanged: {
            CGFloat progress = translation.x / [UIScreen mainScreen].bounds.size.width;
            progress = fminf(fmaxf(progress, 0.0), 1.0);

            CGFloat ratio = 1.0f - progress*0.5f;
            [_presentingVC.view setCenter:CGPointMake(_viewControllerCenter.x + translation.x * ratio, _viewControllerCenter.y + translation.y * ratio)];
            _presentingVC.view.transform = CGAffineTransformMakeScale(ratio, ratio);
            [self updateInteractiveTransition:progress];
            break;
        }
        case UIGestureRecognizerStateCancelled:
        case UIGestureRecognizerStateEnded:{
            CGFloat progress = translation.x / [UIScreen mainScreen].bounds.size.width;
            progress = fminf(fmaxf(progress, 0.0), 1.0);
            if (progress < 0.2){
                [UIView animateWithDuration:progress
                                      delay:0
                          options:UIViewAnimationOptionCurveEaseOut
                                 animations:^{
                                     CGFloat w = [UIScreen mainScreen].bounds.size.width;
                                     CGFloat h = [UIScreen mainScreen].bounds.size.height;
                                     [self.presentingVC.view setCenter:CGPointMake(w/2, h/2)];
                                     self.presentingVC.view.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
                                 } completion:^(BOOL finished) {
                                     self.isInteracting = NO;
                                     [self cancelInteractiveTransition];
                                 }];
            }else {
                _isInteracting = NO;
                [self finishInteractiveTransition];
                [_presentingVC dismissViewControllerAnimated:YES completion:nil];
            }
            //移除 遮罩
            [self.transitionMaskLayer removeFromSuperlayer];
            self.transitionMaskLayer = nil;
        }
            break;
        default:
            break;
    }
}
#pragma mark -
#pragma mark - public methods 公有方法
-(void)wireToViewController:(UIViewController *)viewController {
    self.presentingVC = viewController;
    self.viewControllerCenter = viewController.view.center;
    [self prepareGestureRecognizerInView:viewController.view];
}
@end

我們對外提供了一個wireToViewController:方法用于外部需要創(chuàng)建轉(zhuǎn)場使用.

前面的代碼我們發(fā)現(xiàn)有一處

[self.leftDragInteractiveTransition wireToViewController:awemeVC];
[self presentViewController:awemeVC animated:YES completion:nil];

這里就是需要把我們要彈出的上下滑VC實例傳進來,進來之后為VC的self.view加個pan手勢,

復(fù)寫方法中我們可以看到相關(guān)開始結(jié)束 完成過程的百分比相關(guān)方法復(fù)寫

#pragma mark -
#pragma mark - override methods 復(fù)寫方法
-(CGFloat)completionSpeed{
    return 1 - self.percentComplete;
}
- (void)updateInteractiveTransition:(CGFloat)percentComplete {
    NSLog(@"%.2f",percentComplete);
}
- (void)cancelInteractiveTransition {
    NSLog(@"轉(zhuǎn)場取消");
}
- (void)finishInteractiveTransition {
    NSLog(@"轉(zhuǎn)場完成");
}

看是手勢 出發(fā)前 先檢查一下是否如下條件

UIView *vcView = gestureRecognizer.view;
CGPoint translation = [gestureRecognizer translationInView:vcView.superview];
if(!self.isInteracting &&
   (translation.x < 0 ||
    translation.y < 0 ||
    translation.x < translation.y)) {
    return;
}

拿出手勢作用的視圖,然后坐標(biāo)轉(zhuǎn)換,判斷當(dāng)前是否已經(jīng)開始了動畫,如果沒開始 或者x坐標(biāo) < y坐標(biāo)是判斷當(dāng)前是否是超過邊界范圍等等異常case處理.

開始的時候需要注意下

//修復(fù)當(dāng)從右側(cè)向左滑動的時候的bug 避免開始的時候從又向左滑動 當(dāng)未開始的時候
CGPoint vel = [gestureRecognizer velocityInView:gestureRecognizer.view];
if (!self.isInteracting && vel.x < 0) {
    self.isInteracting = NO;
    return;
}

然后 開始的時候加個蒙版做為view.mask 這樣是為了解決tableView 超出contentSize的范圍要隱藏

剩下的就是中間過程

關(guān)鍵的核心代碼

[self updateInteractiveTransition:progress];

更新轉(zhuǎn)場的進度 這是這個類的自帶方法,調(diào)用就行了

最后 手勢結(jié)束

CGFloat progress = translation.x / [UIScreen mainScreen].bounds.size.width;
progress = fminf(fmaxf(progress, 0.0), 1.0);
if (progress < 0.2){
    [UIView animateWithDuration:progress
                          delay:0
                        options:UIViewAnimationOptionCurveEaseOut
                     animations:^{
                         CGFloat w = [UIScreen mainScreen].bounds.size.width;
                         CGFloat h = [UIScreen mainScreen].bounds.size.height;
                         [self.presentingVC.view setCenter:CGPointMake(w/2, h/2)];
                         self.presentingVC.view.transform = CGAffineTransformMakeScale(1.0f, 1.0f);
                     } completion:^(BOOL finished) {
                         self.isInteracting = NO;
                         [self cancelInteractiveTransition];
                     }];
}else {
    _isInteracting = NO;
    [self finishInteractiveTransition];
    [_presentingVC dismissViewControllerAnimated:YES completion:nil];
}
//移除 遮罩
[self.transitionMaskLayer removeFromSuperlayer];
self.transitionMaskLayer = nil;

這里設(shè)置0.2的容差 如果你覺得這個應(yīng)該開放接口設(shè)置可自行封裝.

當(dāng)用戶取消的話記得調(diào)用cancelInteractiveTransition方法取消

完成的話調(diào)用finishInteractiveTransition完成轉(zhuǎn)場

總結(jié)

整個過程還是比較簡單的 如果看過喵神的文章將會更加清晰的了解轉(zhuǎn)場的三個過程
就是 彈出和消失動畫 以及一個中間轉(zhuǎn)場過程需要我們熟悉.

優(yōu)化點: 在原開源工程中的demo轉(zhuǎn)場右滑是有bug的,我做了一下如下判斷

//修復(fù)當(dāng)從右側(cè)向左滑動的時候的bug 避免開始的時候從又向左滑動 當(dāng)未開始的時候
CGPoint vel = [gestureRecognizer velocityInView:gestureRecognizer.view];
if (!self.isInteracting && vel.x < 0) {
    self.isInteracting = NO;
    return;
}

vel這個變量 其實是判斷當(dāng)我們從右側(cè)劃入返回.修復(fù)了原來開源的一個bug

還有 原來開源中tableViewcontentSize以外 區(qū)域露在外部,我用了一個mask的蒙版遮住了顯示在外的區(qū)域.

唯一有些許遺憾的地方是抖音的左滑返回時候,有背景遮蓋透明的漸變.

如果需要抖音的轉(zhuǎn)場動畫Demo,可以加iOS高級技術(shù)交流群:937194184,獲取Demo,以及更多iOS學(xué)習(xí)資料

轉(zhuǎn)載:原文地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,461評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,538評論 3 417
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,423評論 0 375
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,991評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,761評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,207評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,268評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,419評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,959評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,782評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,983評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,528評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,222評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,653評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,901評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,678評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,978評論 2 374

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

  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 12,151評論 4 61
  • 前言的前言 唐巧前輩在微信公眾號「iOSDevTips」以及其博客上推送了我的文章后,我的 Github 各項指標(biāo)...
    VincentHK閱讀 5,399評論 3 44
  • 文/陌霏 我的網(wǎng)名叫“茜茜笑笑”,前兩個字音同我的名字,以前也叫過許多非主流和洗剪吹的名字,可是只有最后這一個,我...
    realChelsea閱讀 501評論 4 3
  • 2018年12月16日星期天天氣晴 今早我和兒子又是睡到了自然醒,差十分七點才醒來,兒子躺在床上背了學(xué)過的課...
    宋胤鋆媽媽閱讀 364評論 6 5
  • 阿貓租房,杭州第一家青年公寓信息導(dǎo)航平臺,2016年由杭州刃戟信息科技有限公司創(chuàng)辦。 阿貓租房定位是杭州青年公寓信...
    阿貓生活閱讀 385評論 0 0