iOS swift 自定義頁面的切換動畫與交互動畫

參照:iOS 自定義頁面的切換動畫與交互動畫 By Swift
oc 版切換動畫

一酱讶、自定義導(dǎo)航欄的Push/Pop動畫

為了在基于UINavigationController下做自定義的動畫切換句惯,
1秕衙、先建立一個簡單的工程搀玖,建一個UINavigationController的子類LSNavigationController藏斩,另外兩個VC viewControllersecondViewController,注意:viewController是一個UINavigationController。在這兩個頁面中先做一些準(zhǔn)備工作就是各有一個按鈕栅干,一個做push操作,一個做pop操作捐祠。
2非驮、LSNavigationController ,用來實現(xiàn)UINavigationControllerDelegate```協(xié)議雏赦。在類中實現(xiàn)代理函數(shù)

func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        if operation == UINavigationControllerOperation.push {
            return LSPushAnimation.init()
        }else if operation == UINavigationControllerOperation.pop {
            return LSPopAnimation.init()
        }
        return nil
    }

上面的協(xié)議函數(shù)會在push和pop時返回已經(jīng)實現(xiàn)了動畫方法的類LSPushAnimationLSPopAnimation
viewControllerviewDidLoadself.navigationController?.delegate = self芙扎,因為導(dǎo)航器的第一個頁面一直存在星岗,所以只需要在這里設(shè)置就可。
3戒洼、編寫動畫類俏橘,由于pop和push實現(xiàn)方式類似,只拿push為例:
LSPushAnimation中實現(xiàn)UIViewControllerAnimatedTransitioning協(xié)議圈浇。 UIViewControllerAnimatedTransitioning是蘋果新增加的一個協(xié)議寥掐,其目的是在需要使用自定義動畫的同時,又不影響視圖的其他屬性磷蜀,讓你把焦點集中在動畫實現(xiàn)的本身上召耘,然后通過在這個協(xié)議的回調(diào)里編寫自定義的動畫代碼,即“切換中應(yīng)該會發(fā)生什么”褐隆,負(fù)責(zé)切換的具體內(nèi)容污它,任何實現(xiàn)了這一協(xié)議的對象被稱之為動畫控制器。
實現(xiàn)兩個協(xié)議函數(shù)

//UIViewControllerAnimatedTransitioning
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.4
    }
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        
        var destView: UIView!
        var destTransform: CGAffineTransform!
        containerView.insertSubview((toViewController?.view)!, aboveSubview: (fromViewController?.view)!)
        destView = toViewController?.view
        destView.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        destTransform = CGAffineTransform(scaleX: 1, y: 1)
        
        UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
            destView.transform = destTransform
        }, completion: ({completed in
            transitionContext.completeTransition(true)
        }))
    }

上面第一個方法返回動畫持續(xù)的時間庶弃,而下面這個方法才是具體需要實現(xiàn)動畫的地方衫贬。UIViewControllerAnimatedTransitioning的協(xié)議都包含一個對象:transitionContext,通過這個對象能獲取到切換時的上下文信息歇攻,比如從哪個VC切換到哪個VC等固惯。我們從transitionContext獲取containerView,這是一個特殊的容器缴守,切換時的動畫將在這個容器中進(jìn)行葬毫;UITransitionContextFromViewControllerKeyUITransitionContextToViewControllerKey就是從哪個VC切換到哪個VC,容易理解屡穗;除此之外供常,還有直接獲取view的UITransitionContextFromViewKeyUITransitionContextToViewKey等。
我按Push和Pop把動畫簡單的區(qū)分了一下鸡捐,Push時scale由小變大栈暇,Pop時scale由大變小,不同的操作箍镜,toViewController的視圖層次也不一樣源祈。最后煎源,在動畫完成的時候調(diào)用completeTransition,告訴transitionContext你的動畫已經(jīng)結(jié)束香缺,這是非常重要的方法手销,必須調(diào)用。在動畫結(jié)束時沒有對containerView的子視圖進(jìn)行清理(比如把fromViewController的view移除掉)是因為transitionContext會自動清理图张,所以我們無須在額外處理锋拖。

4、這樣祸轮,只需在

注意一點兽埃,這樣一來會發(fā)現(xiàn)原來導(dǎo)航欄的交互式返回效果沒有了,如果你想用原來的交互式返回效果的話适袜,在返回動畫控制器的delegate方法里返回nil柄错,如:

if operation == UINavigationControllerOperation.Push {
    navigationOperation = operation
    return self
}
return nil

然后在LSNavigationControllerviewDidLoad里,Objective-C直接self.navigationController.interactivePopGestureRecognizer.delegat = self就行了苦酱,Swift除了要navigationController.interactivePopGestureRecognizer.delegate = self之外售貌,還要在self上聲明實現(xiàn)了UIGestureRecognizerDelegate這個協(xié)議,雖然實際上你并沒有實現(xiàn)疫萤。
一個簡單的自定義導(dǎo)航欄Push/Pop動畫就完成了颂跨。

二、自定義Modal的Present/Dismiss動畫

自定義Modal的Present與Dismiss動畫與之前類似扯饶,都需要提供一個動畫管理器毫捣,我們用詳情頁面來展示一個Modal頁面,詳情頁面就作為動畫管理器:
為了方便帝际,我依然在LSViewController操作(實際開發(fā)中蔓同,只需要在有特殊需要的頁面中實現(xiàn)即可),
1蹲诀、 LSViewController實現(xiàn)協(xié)議UIViewControllerTransitioningDelegate,這個協(xié)議與之前的UINavigationControllerDelegate協(xié)議具有相似性斑粱,都是返回一個動畫管理器,

func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return LSPresentAnimation.init()
    }
    
    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return LSDismissAnimation.init()
    }

其中LSPresentAnimationLSDismissAnimation也是實現(xiàn)了UIViewControllerAnimatedTransitioning協(xié)議的用來實現(xiàn)具體的動畫脯爪。直接上代碼则北。

//UIViewControllerAnimatedTransitioning
    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return 0.6
    }
    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        let containerView = transitionContext.containerView
        
        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        
        var destView: UIView!
        var destTransfrom = CGAffineTransform()
        let screenHeight = UIScreen.main
            .bounds.size.height
        
        
        destView = toViewController?.view
        destView.transform = CGAffineTransform(translationX: 0, y: screenHeight)
        containerView.addSubview((toViewController?.view)!)
        
        UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0, usingSpringWithDamping: 0.6, initialSpringVelocity: 0,
                       options: UIViewAnimationOptions.curveLinear, animations: {
                        destView.transform = destTransfrom
        }, completion: {completed in
            transitionContext.completeTransition(true)
        })
        
    
    }
3、在 LSViewControllerself.transitioningDelegate = self(之所以讓viewControllersecondViewcontroller繼承LSViewController是因為懶痕慢,都寫在一起了尚揣,不然需要在兩個VC中實現(xiàn))

這樣present就會有動畫,想要dismiss也實現(xiàn)我們自己的動畫需要在viewControllerpresent按鈕中將 secondViewController定位動畫管理器掖举。

以上簡單demo可以點擊下載

三快骗、自定義導(dǎo)航欄的交互式動畫

與動畫控制器類似,我們把實現(xiàn)了*** UIViewControllerInteractiveTransitioning 協(xié)議的對象稱之為交互控制器***,最常用的就是把交互控制器應(yīng)用到導(dǎo)航欄的Back手勢返回上方篮,而如果要實現(xiàn)一個自定義的交互式動畫名秀,我們有兩種方式來完成:實現(xiàn)一個交互控制器,或者使用iOS提供的UIPercentDrivenInteractiveTransition類作交互控制器藕溅。

使用UIPercentDrivenInteractiveTransition

我們這里就用UIPercentDrivenInteractiveTransition來完成導(dǎo)航欄的交互式動畫匕得。先看下UIPercentDrivenInteractiveTransition的定義:

open class UIPercentDrivenInteractiveTransition : NSObject, UIViewControllerInteractiveTransitioning {

    
    /// This is the non-interactive duration that was returned when the
    /// animators transitionDuration: method was called when the transition started.
    open var duration: CGFloat { get }

    
    /// The last percentComplete value specified by updateInteractiveTransition:
    open var percentComplete: CGFloat { get }

    
    /// completionSpeed defaults to 1.0 which corresponds to a completion duration of
    /// (1 - percentComplete)*duration.  It must be greater than 0.0. The actual
    /// completion is inversely proportional to the completionSpeed.  This can be set
    /// before cancelInteractiveTransition or finishInteractiveTransition is called
    /// in order to speed up or slow down the non interactive part of the
    /// transition.
    open var completionSpeed: CGFloat

    
    /// When the interactive part of the transition has completed, this property can
    /// be set to indicate a different animation curve. It defaults to UIViewAnimationCurveEaseInOut.
    /// Note that during the interactive portion of the animation the timing curve is linear. 
    open var completionCurve: UIViewAnimationCurve

    
    /// For an interruptible animator, one can specify a different timing curve provider to use when the
    /// transition is continued. This property is ignored if the animated transitioning object does not
    /// vend an interruptible animator.
    @available(iOS 10.0, *)
    open var timingCurve: UITimingCurveProvider?

    
    /// Set this to NO in order to start an interruptible transition non
    /// interactively. By default this is YES, which is consistent with the behavior
    /// before 10.0.
    @available(iOS 10.0, *)
    open var wantsInteractiveStart: Bool

    
    /// Use this method to pause a running interruptible animator. This will ensure that all blocks
    /// provided by a transition coordinator's notifyWhenInteractionChangesUsingBlock: method
    /// are executed when a transition moves in and out of an interactive mode.
    @available(iOS 10.0, *)
    open func pause()

    
    // These methods should be called by the gesture recognizer or some other logic
    // to drive the interaction. This style of interaction controller should only be
    // used with an animator that implements a CA style transition in the animator's
    // animateTransition: method. If this type of interaction controller is
    // specified, the animateTransition: method must ensure to call the
    // UIViewControllerTransitionParameters completeTransition: method. The other
    // interactive methods on UIViewControllerContextTransitioning should NOT be
    // called. If there is an interruptible animator, these methods will either scrub or continue 
    // the transition in the forward or reverse directions.
    open func update(_ percentComplete: CGFloat)

    open func cancel()

    open func finish()
}

實際上這個類就是實現(xiàn)了UIViewControllerInteractiveTransitioning協(xié)議的交互控制器,我們使用它就能夠輕松地為動畫控制器添加一個交互動畫巾表。調(diào)用update更新進(jìn)度汁掠;調(diào)用cancel取消交互,返回到切換前的狀態(tài)集币;調(diào)用finish通知上下文交互已完成考阱,同completeTransition一樣。我們把交互動畫應(yīng)用到詳情頁面Back回主頁面的地方惠猿,由于之前的動畫管理器的角色是主頁面擔(dān)任的,Navigation Controllerdelegate同一時間只能有一個负间。

首先我們需要創(chuàng)建一個交互控制器偶妖。新建一個Cocoa Touch Class文件,命名為LSPercentDrivenInteractiveTransition政溃,讓它繼承自UIPercentDrivenInteractiveTransition趾访。

打開LSNavigationController.swift,在類定義的最開始添加下面這些屬性:

var interactionInProgress = false //用于指示交互是否在進(jìn)行中董虱。
    
    ///交互控制器
    private var interactivePopTransition : LSPercentDrivenInteractiveTransition!

在viewDidLoad:中添加

self.delegate = self
        let gesture = UIScreenEdgePanGestureRecognizer(target:self,action:#selector(handleGesture(gestureRecognizer:)))
        gesture.edges = .left
        self.view.addGestureRecognizer(gesture)

并實現(xiàn)手勢的方法:

 // 以下----使用UIPercentDrivenInteractiveTransition交互控制器
        func handleGesture(gestureRecognizer: UIScreenEdgePanGestureRecognizer) {
            var progress = gestureRecognizer.translation(in: gestureRecognizer.view?.superview).x / self.view.bounds.size.width
            progress = min(1.0, max(0.0, progress))
    //        let translation = gestureRecognizer.translation(in: gestureRecognizer.view?.superview)
    //        var progress = Float(translation.x / 200)
    //        progress = fminf(fmaxf(progress, 0.0), 1.0)
    
            print("\(progress)")
            if gestureRecognizer.state == UIGestureRecognizerState.began {
                print("Began")
                self.interactivePopTransition = LSPercentDrivenInteractiveTransition()
                interactionInProgress = true
                self.popViewController(animated: true)
            } else if gestureRecognizer.state == UIGestureRecognizerState.changed {
                self.interactivePopTransition.update(CGFloat(progress))
                print("Changed")
            } else if gestureRecognizer.state == UIGestureRecognizerState.ended || gestureRecognizer.state == UIGestureRecognizerState.cancelled {
                if progress > 0.5 {
                    self.interactivePopTransition.finish()
                    print("finished")
                } else {
                    self.interactivePopTransition.cancel()
                    print("canceled")
                }
                interactionInProgress = false
                self.interactivePopTransition = nil
            }
        }
  1. 手勢開始后扼鞋,我們初始化交互控制器self.interactivePopTransition,調(diào)整interactionInProgress的值并觸發(fā)關(guān)閉視圖控制器的操作愤诱。
  1. 手勢進(jìn)行時云头,我們不斷調(diào)用update方法更新進(jìn)度。它是UIPercentDrivenInteractiveTransition的一個方法淫半,根據(jù)你傳入的百分比值更新過渡動畫溃槐。
  2. 如果手勢被取消,更新interactionInProgress的值科吭,并回滾過渡動畫昏滴。
  3. 手勢完成后,根據(jù)當(dāng)前進(jìn)度判斷是取消還是完成過渡動畫对人。

LSNavigationController中實現(xiàn)UINavigationControllerDelegate協(xié)議谣殊,

/// UINavigationControllerDelegate 以下兩個協(xié)議均實現(xiàn)時,以第二個為準(zhǔn)牺弄,
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationControllerOperation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        if operation == UINavigationControllerOperation.push {
            return LSPushAnimation.init()
        }else if operation == UINavigationControllerOperation.pop {
            return LSPopAnimation.init()
        }
        return nil
    }
    
    /// 當(dāng)返回值為nil時姻几,上面的協(xié)議返回的push和pop動畫才會有作用
    func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        if interactivePopTransition != nil {
            return interactivePopTransition
        }
        return nil
    }

這里的第一個方法前面已經(jīng)用過,第二個是返回交互控制器,因為如果交互控制器不為空的話鲜棠,就會調(diào)用控制器來控制交互肌厨,這樣就使上面的push和pop失去的效果,所以只有在需要自定義交互控制器時才會返回豁陆,不然則返回nil即可(就像自定義滑動返回手勢)柑爸。所以在上面的手勢處理中才會在開始時初始化控制器,在結(jié)束后制為nil盒音。

使用UIPercentDrivenInteractiveTransition的Demo

自定義交互控制器

在上面的demo基礎(chǔ)上修改表鳍。

LSPercentDrivenInteractiveTransition需要自己實現(xiàn)UIViewControllerInteractiveTransitioning協(xié)議。
UIViewControllerInteractiveTransitioning協(xié)議總共有三個方法祥诽,其中startInteractiveTransition:是必須實現(xiàn)的方法譬圣,我們在里面初始化動畫的狀態(tài):

///以下是自定義交互控制器 
///先初始化需要的變量
    var transitionContext : UIViewControllerContextTransitioning!
    var transitingView : UIView!
/// 以下----自定義交互控制器
    override func startInteractiveTransition(_ transitionContext: UIViewControllerContextTransitioning) {
        self.transitionContext = transitionContext
        
        let containerView = transitionContext.containerView
        let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
        let fromViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)
        
        containerView.insertSubview((toViewController?.view)!, belowSubview: (fromViewController?.view)!)
        
        self.transitingView = fromViewController?.view

    }
    override func update(_ percentComplete: CGFloat) {
        let scale = CGFloat(fabsf(Float(percentComplete - CGFloat(1.0))))
        transitingView?.transform = CGAffineTransform(scaleX: scale, y: scale)
        transitionContext?.updateInteractiveTransition(percentComplete)
    }
    
    
    
    func finishBy(cancelled: Bool) {
        if cancelled {
            UIView.animate(withDuration: 0.4, animations: {
                self.transitingView!.transform = CGAffineTransform(scaleX: 1, y: 1)
            }, completion: {completed in
                self.transitionContext!.cancelInteractiveTransition()
                self.transitionContext!.completeTransition(false)
            })
        } else {
            UIView.animate(withDuration: 0.4, animations: {
                print(self.transitingView)
                self.transitingView!.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
                print(self.transitingView)
            }, completion: {completed in
                self.transitionContext!.finishInteractiveTransition()
                self.transitionContext!.completeTransition(true)
            })
        }
    }

update:方法用來更新view的transform屬性,finishBy:方法主要用來判斷是進(jìn)入下一個頁面還是返回到之前的頁面雄坪,并告知transitionContext目前的狀態(tài)厘熟,以及對當(dāng)前正在scale的view做最后的動畫。這里的transitionContext和transitingView可以在前面的處理手勢識別代碼中取得维哈,因此手勢的處理中變成了:

///以下是自定義交互器
    func handleGesture(gestureRecognizer: UIScreenEdgePanGestureRecognizer) {
        var progress = gestureRecognizer.translation(in: gestureRecognizer.view?.superview).x / self.view.bounds.size.width
        progress = min(1.0, max(0.0, progress))
        //        let translation = gestureRecognizer.translation(in: gestureRecognizer.view?.superview)
        //        var progress = Float(translation.x / 200)
        //        progress = fminf(fmaxf(progress, 0.0), 1.0)
        
        print("\(progress)")
        if gestureRecognizer.state == UIGestureRecognizerState.began {
            print("Began")
            self.interactivePopTransition = LSPercentDrivenInteractiveTransition()
            interactionInProgress = true
            self.popViewController(animated: true)
        } else if gestureRecognizer.state == UIGestureRecognizerState.changed {
            interactivePopTransition.update(progress)
            print("Changed")
        } else if gestureRecognizer.state == UIGestureRecognizerState.ended || gestureRecognizer.state == UIGestureRecognizerState.cancelled {
            interactivePopTransition.finishBy(cancelled: progress < 0.5)
            interactionInProgress = false
            self.interactivePopTransition = nil
        }
    }

這樣就完成了自定義交互控制器的全部內(nèi)容绳姨。

自定義控制器的demo

注意,視圖控制器的這些同樣適用于model視圖的動畫(連接中包括三個工程阔挠,其中一個是圖片瀏覽飘庄,swift代碼還不太熟悉,需要改善)购撼。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末跪削,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子迂求,更是在濱河造成了極大的恐慌碾盐,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件揩局,死亡現(xiàn)場離奇詭異廓旬,居然都是意外死亡,警方通過查閱死者的電腦和手機谐腰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門孕豹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人十气,你說我怎么就攤上這事励背。” “怎么了砸西?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵叶眉,是天一觀的道長址儒。 經(jīng)常有香客問我,道長衅疙,這世上最難降的妖魔是什么莲趣? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮饱溢,結(jié)果婚禮上喧伞,老公的妹妹穿的比我還像新娘。我一直安慰自己绩郎,他們只是感情好潘鲫,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著肋杖,像睡著了一般溉仑。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上状植,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天浊竟,我揣著相機與錄音,去河邊找鬼津畸。 笑死振定,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的洼畅。 我是一名探鬼主播吩案,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼棚赔,長吁一口氣:“原來是場噩夢啊……” “哼帝簇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起靠益,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤丧肴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后胧后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體芋浮,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年壳快,在試婚紗的時候發(fā)現(xiàn)自己被綠了纸巷。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡眶痰,死狀恐怖瘤旨,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情竖伯,我是刑警寧澤存哲,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布因宇,位于F島的核電站,受9級特大地震影響祟偷,放射性物質(zhì)發(fā)生泄漏察滑。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一修肠、第九天 我趴在偏房一處隱蔽的房頂上張望贺辰。 院中可真熱鬧,春花似錦氛赐、人聲如沸魂爪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽滓侍。三九已至,卻和暖如春牲芋,著一層夾襖步出監(jiān)牢的瞬間撩笆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工缸浦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留夕冲,地道東北人。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓裂逐,卻偏偏與公主長得像歹鱼,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子卜高,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

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