可切換顏色的tab(仿今日頭條tablayout)

前段時(shí)間看見了今日頭條的tablayout,感覺相當(dāng)新鮮,也比較感興趣,效果就是下邊這個(gè)


gif5新文件.gif

像這種效果應(yīng)該是需要自定義的View來實(shí)現(xiàn)的鸵贬,可以看到在滑動(dòng)過程中,兩個(gè)相鄰的tab是有局部顏色的變換的,前一個(gè)tab部分恢復(fù)成黑色,后一個(gè)tab會(huì)部分變?yōu)榧t色,這取決于滑動(dòng)的距離.

首先每一個(gè)tab應(yīng)該都是自定義的View,因?yàn)檫@涉及到了局部文字變色,所以應(yīng)該先定制一個(gè)能夠局部文字變色的View,普通的View當(dāng)然不支持啦~

先來說下思路~主要用的方法是canvas的clipRect方法,先來看下這個(gè)方法啥子意思喲..

/**
     * Intersect the current clip with the specified rectangle, which is
     * expressed in local coordinates.
     *
     * @param left   The left side of the rectangle to intersect with the
     *               current clip
     * @param top    The top of the rectangle to intersect with the current clip
     * @param right  The right side of the rectangle to intersect with the
     *               current clip
     * @param bottom The bottom of the rectangle to intersect with the current
     *               clip
     * @return       true if the resulting clip is non-empty
     */
    public boolean clipRect(int left, int top, int right, int bottom) {
        return nClipRect(mNativeCanvasWrapper, left, top, right, bottom,
                Region.Op.INTERSECT.nativeInt);
    }

解釋一下俗他,里邊的四個(gè)參數(shù)裁剪范圍的左上右下的位置,比較好理解,需要注意的是,使用完這個(gè)方法后需要及時(shí)的恢復(fù)繪制范圍,所以完整代碼如下

canvas.save();  
canvas.clipRect(left, top, right, bottom);  
//再做繪制操作例如本片要用到的drawText()
canvas.restore(); 

知道了這個(gè)方法,那么就想想怎么繪制出兩種顏色的文本了,先上個(gè)圖



圖中的1部分為黑色,2部分為紅色,那么再繪制過程中我們只需要利用clipRect這個(gè)方法,分別裁剪出1部分的范圍以及2部分的范圍,分別使用不同顏色繪制就OK啦~但是總體的繪制起點(diǎn)以及文本都是一樣的,這樣就看起來是一個(gè)文本兩種顏色,其實(shí)我們是繪制了兩邊,還是比較好理解的

話不多說,直接上代碼

public class ColorClipView extends View {

    private Paint paint;//畫筆
    private String text = "我是不哦車網(wǎng)";//繪制的文本
    private int textSize = sp2px(18);//文本字體大小

    private int textWidth;//文本的寬度
    private int textHeight;//文本的高度

    private int textUnselectColor = R.color.colorPrimary;//文本未選中字體顏色
    private int textSelectedColor = R.color.colorAccent;//文本選中顏色

    private static final int DIRECTION_LEFT = 0;
    private static final int DIRECTION_RIGHT = 1;
    private static final int DIRECTION_TOP = 2;
    private static final int DIRECTION_BOTTOM = 3;

    private int mDirection = DIRECTION_LEFT;

    private Rect textRect = new Rect();//文本顯示區(qū)域

    private int startX;//X軸開始繪制的坐標(biāo)

    private int startY;//y軸開始繪制的坐標(biāo)

    private int baseLineY;//基線的位置

    private float progress;


    public ColorClipView(Context context) {
        this(context, null);
    }

    public ColorClipView(Context context, AttributeSet attrs) {
        super(context, attrs);

        //初始化各個(gè)屬性包括畫筆

        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.ColorClipView);
        text = ta.getString(R.styleable.ColorClipView_text);
        textSize = ta.getDimensionPixelSize(R.styleable.ColorClipView_text_size, textSize);
//        textUnselectColor = ta.getColor(R.styleable.ColorClipView_text_unselected_color, textUnselectColor);
//        textSelectedColor = ta.getColor(R.styleable.ColorClipView_text_selected_color, textSelectedColor);
        mDirection = ta.getInt(R.styleable.ColorClipView_direction, mDirection);
        progress = ta.getFloat(R.styleable.ColorClipView_progress, 0);
        ta.recycle();//用完就得收阔逼!
        paint.setTextSize(textSize);
    }

    private int sp2px(float dpVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,
                dpVal, getResources().getDisplayMetrics());
    }

    public void setProgress(float progress) {
        this.progress = progress;
        invalidate();
    }

    public void setTextSize(int mTextSize) {
        this.textHeight = mTextSize;
        paint.setTextSize(mTextSize);
        requestLayout();
        invalidate();
    }

    public void setText(String text) {
        this.text = text;
        requestLayout();
        invalidate();
    }

    public void setDirection(int direction) {
        this.mDirection = direction;
        invalidate();
    }

    public void setTextUnselectColor(int unselectColor) {
        this.textUnselectColor = unselectColor;
        invalidate();
    }

    public void setTextSelectedColor(int selectedColor) {
        this.textSelectedColor = selectedColor;
        invalidate();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        measureText();//測量文本的長寬

        int width = measureWidth(widthMeasureSpec);//通過模式的不同來測量出實(shí)際的寬度
        int height = measureHeight(heightMeasureSpec);//通過模式的不同來測量出實(shí)際的高度
        setMeasuredDimension(width, height);
        startX = (getMeasuredWidth() - getPaddingRight() - getPaddingLeft()) / 2 - textWidth / 2;
        startY = (textHeight - getPaddingBottom() - getPaddingTop());
    }

    private int measureHeight(int heightMeasureSpec) {
        int mode = MeasureSpec.getMode(heightMeasureSpec);
        int size = MeasureSpec.getSize(heightMeasureSpec);
        int realSize = 0;
        switch (mode) {
            case MeasureSpec.EXACTLY:
                realSize = size;
                break;
            case MeasureSpec.AT_MOST:
            case MeasureSpec.UNSPECIFIED:
                realSize = textHeight;
                realSize += getPaddingTop() + getPaddingBottom();
                break;
        }
        realSize = mode == MeasureSpec.AT_MOST ? Math.min(realSize, size) : realSize;
        return realSize;
    }

    private int measureWidth(int widthMeasureSpec) {
        int mode = MeasureSpec.getMode(widthMeasureSpec);//通過widthMeasureSpec拿到Mode
        int size = MeasureSpec.getSize(widthMeasureSpec);//同理
        int realSize = 0;//最后返回的值
        switch (mode) {
            case MeasureSpec.EXACTLY://精確模式下直接用給出的寬度
                realSize = size;
                break;
            case MeasureSpec.AT_MOST://最大模式
            case MeasureSpec.UNSPECIFIED://未指定模式
                //這兩種情況下,用測量出的寬度加上左右padding
                realSize = textWidth;
                realSize = realSize + getPaddingLeft() + getPaddingRight();
                break;
        }
        //如果mode為最大模式,不應(yīng)該大于父類傳入的值,所以取最小
        realSize = mode == MeasureSpec.AT_MOST ? Math.min(realSize, size) : realSize;
        return realSize;
    }

    private void measureText() {
        textWidth = (int) paint.measureText(text);//測量文本寬度
        Log.d("tag", "measureText=" + paint.measureText(text));


        //直接通過獲得文本顯示范圍,再獲得高度
        //參數(shù)里兆衅,text 是要測量的文字
        //start 和 end 分別是文字的起始和結(jié)束位置,textRect 是存儲(chǔ)文字顯示范圍的對(duì)象嗜浮,方法在測算完成之后會(huì)把結(jié)果寫進(jìn) textRect羡亩。
        paint.getTextBounds(text, 0, text.length(), textRect);
        textHeight = textRect.height();

        //通過文本的descent線與top線的距離來測量文本高度,這是其中一種測量方法
        Paint.FontMetrics fm = paint.getFontMetrics();
        textHeight = (int) Math.ceil(fm.descent - fm.top);

        baseLineY = (int) (textHeight / 2 - (fm.bottom - fm.top) / 2 - fm.top);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //OK~開始繪制咯~
        //首先先判斷方向是左還是右呢?  是上還是下呢? 真期待....
        Log.e("tag", "OnDraw");
        if (mDirection == DIRECTION_LEFT) {
            //繪制朝左的選中文字
            drawHorizontalText(canvas, textSelectedColor, startX,
                    (int) (startX + progress * textWidth));
            //繪制朝左的未選中文字
            drawHorizontalText(canvas, textUnselectColor, (int) (startX + progress
                    * textWidth), startX + textWidth);
        } else if (mDirection == DIRECTION_RIGHT) {
            //繪制朝右的選中文字
            drawHorizontalText(canvas, textSelectedColor,
                    (int) (startX + (1 - progress) * textWidth), startX
                            + textWidth);
            //繪制朝右的未選中文字
            drawHorizontalText(canvas, textUnselectColor, startX,
                    (int) (startX + (1 - progress) * textWidth));
        } else if (mDirection == DIRECTION_TOP) {
            //繪制朝上的選中文字
            drawVerticalText(canvas, textSelectedColor, startY,
                    (int) (startY + progress * textHeight));
            //繪制朝上的未選中文字
            drawVerticalText(canvas, textUnselectColor, (int) (startY + progress
                    * textHeight), startY + textHeight);
        } else {
            //繪制朝下的選中文字
            drawVerticalText(canvas, textSelectedColor,
                    (int) (startY + (1 - progress) * textHeight),
                    startY + textHeight);
            //繪制朝下的未選中文字
            drawVerticalText(canvas, textUnselectColor, startY,
                    (int) (startY + (1 - progress) * textHeight));
        }

    }

    private void drawHorizontalText(Canvas canvas, int color, int startX, int endX) {
        paint.setColor(color);
        canvas.save();
        Log.e("tag", "getMeasuredHeight" + getMeasuredHeight());
        canvas.clipRect(startX, 0, endX, getMeasuredHeight());
        canvas.drawText(text, this.startX, baseLineY, paint);
        canvas.restore();
    }

    private void drawVerticalText(Canvas canvas, int color, int startY, int endY) {
        paint.setColor(color);
        canvas.save();
        canvas.clipRect(0, startY, getMeasuredWidth(), endY);
        canvas.drawText(text, this.startX,
                this.startY, paint);
        canvas.restore();
    }
}

上邊代碼我自己重寫了onMeasure方法,自己測量了高度與寬度,其實(shí)我么你可以直接繼承TextView,這樣可以不用重寫onMeasure方法,直接交給TextView去測量...

還有關(guān)于繪制文字這一點(diǎn),也就是drawText這個(gè)方法需要說一下

/**
     * Draw the text, with origin at (x,y), using the specified paint. The origin is interpreted
     * based on the Align setting in the paint.
     *
     * @param text The text to be drawn
     * @param x The x-coordinate of the origin of the text being drawn
     * @param y The y-coordinate of the baseline of the text being drawn
     * @param paint The paint used for the text (e.g. color, size, style)
     */
    public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
        super.drawText(text, x, y, paint);
    }

上邊的四個(gè)參數(shù)意思分別是,繪制文本,繪制起點(diǎn)X坐標(biāo),繪制起點(diǎn)Y坐標(biāo),用來繪制的畫筆
這里的需要上一張圖



如圖所示,在繪制文本的時(shí)候繪制起點(diǎn)在左下角而不是左上角,這個(gè)需要特殊說明一下...
然后再上一張圖來看下效果,這里我加了手勢操作來改變文本顏色


xixi.gif

然后每個(gè)tab我們制作完了,需要把tab放到tablayout中,并且會(huì)隨著滑動(dòng)距離而改變相鄰兩個(gè)的tab的不分顏色,OK~我們有需要自定義一個(gè)繼承于tablayout的View,重寫addtab方法,將我們剛才的自定義View加入進(jìn)去,并且加入滑動(dòng)監(jiān)聽,從而改變顏色,直接上代碼

public class ColorClipTabLayout extends TabLayout {

    private int tabTextSize;//每個(gè)tab字體大小
    private int tabSelectedTextColor;//每個(gè)tab選中字體顏色
    private int tabTextColor;//每個(gè)tab未選中顏色
    private static final int INVALID_TAB_POS = -1;

    //最后的選中位置
    private int lastSelectedTabPosition = INVALID_TAB_POS;

    private ViewPager viewPager;//所綁定的viewpager

    private ColorClipTabLayoutOnPageChangeListener colorClipTabLayoutOnPageChangeListener;


    public ColorClipTabLayout(Context context) {
        this(context, null);
    }

    public ColorClipTabLayout(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public ColorClipTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        if (attrs != null) {
            // Text colors/sizes come from the text appearance first
            final TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.ColorClipTabLayout);
            //Tab字體大小
            tabTextSize = ta.getDimensionPixelSize(R.styleable.ColorClipTabLayout_text_size, 72);
            //Tab文字顏色
            tabTextColor = ta.getColor(R.styleable.ColorClipTabLayout_text_unselected_color, Color.parseColor("#000000"));
            tabSelectedTextColor = ta.getColor(R.styleable.ColorClipTabLayout_text_selected_color, Color.parseColor("#cc0000"));
            ta.recycle();
        }
    }

    @Override
    public void addTab(@NonNull Tab tab, int position, boolean setSelected) {
        //通過addTab的方式將colorClipView作為customView傳入tab
        ColorClipView colorClipView = new ColorClipView(getContext());
        colorClipView.setProgress(setSelected ? 1 : 0);
        colorClipView.setText(tab.getText() + "");
        colorClipView.setTextSize(tabTextSize);
        colorClipView.setTag(position);
        colorClipView.setTextSelectedColor(tabSelectedTextColor);
        colorClipView.setTextUnselectColor(tabTextColor);
        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
        colorClipView.setLayoutParams(layoutParams);
        tab.setCustomView(colorClipView);
        super.addTab(tab, position, setSelected);
        int selectedTabPosition = getSelectedTabPosition();
        if ((selectedTabPosition == INVALID_TAB_POS && position == 0) || (selectedTabPosition == position)) {
            setSelectedView(position);
        }

        setTabWidth(position, colorClipView);
    }

    @Override
    public void setupWithViewPager(@Nullable ViewPager viewPager, boolean autoRefresh) {
        super.setupWithViewPager(viewPager, autoRefresh);
        try {
            if (viewPager != null)
                this.viewPager = viewPager;
            colorClipTabLayoutOnPageChangeListener = new ColorClipTabLayoutOnPageChangeListener(this);
            colorClipTabLayoutOnPageChangeListener.reset();
            viewPager.addOnPageChangeListener(colorClipTabLayoutOnPageChangeListener);
//            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void removeAllTabs() {
        lastSelectedTabPosition = getSelectedTabPosition();
        super.removeAllTabs();
    }

    @Override
    public int getSelectedTabPosition() {
        final int selectedTabPositionAtParent = super.getSelectedTabPosition();
        return selectedTabPositionAtParent == INVALID_TAB_POS ?
                lastSelectedTabPosition : selectedTabPositionAtParent;
    }

    public void setLastSelectedTabPosition(int lastSelectedTabPosition) {
        lastSelectedTabPosition = lastSelectedTabPosition;
    }

    public void setCurrentItem(int position) {
        if (viewPager != null)
            viewPager.setCurrentItem(position);
    }

    private void setTabWidth(int position, ColorClipView colorClipView) {
        ViewGroup slidingTabStrip = (ViewGroup) getChildAt(0);
        ViewGroup tabView = (ViewGroup) slidingTabStrip.getChildAt(position);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.MATCH_PARENT);

        int w = MeasureSpec.makeMeasureSpec(0,
                MeasureSpec.UNSPECIFIED);
        int h = MeasureSpec.makeMeasureSpec(0,
                MeasureSpec.UNSPECIFIED);
        //手動(dòng)測量一下
        colorClipView.measure(w, h);
        params.width = colorClipView.getMeasuredWidth() + tabView.getPaddingLeft() + tabView.getPaddingRight();
        //設(shè)置tabView的寬度
        tabView.setLayoutParams(params);
    }

    private void setSelectedView(int position) {
        final int tabCount = getTabCount();
        if (position < tabCount) {
            for (int i = 0; i < tabCount; i++) {
                getColorClipView(i).setProgress(i == position ? 1 : 0);
            }
        }
    }

    public void tabScrolled(int position, float positionOffset) {

        if (positionOffset == 0.0F) {
            return;
        }
        ColorClipView currentTrackView = getColorClipView(position);
        ColorClipView nextTrackView = getColorClipView(position + 1);
        currentTrackView.setDirection(1);
        currentTrackView.setProgress(1.0F - positionOffset);
        nextTrackView.setDirection(0);
        nextTrackView.setProgress(positionOffset);
    }

    private ColorClipView getColorClipView(int position) {
        return (ColorClipView) getTabAt(position).getCustomView();
    }

    public static class ColorClipTabLayoutOnPageChangeListener extends TabLayoutOnPageChangeListener {

        private final WeakReference<ColorClipTabLayout> mTabLayoutRef;
        private int mPreviousScrollState;
        private int mScrollState;

        public ColorClipTabLayoutOnPageChangeListener(TabLayout tabLayout) {
            super(tabLayout);
            mTabLayoutRef = new WeakReference<>((ColorClipTabLayout) tabLayout);
        }

        @Override
        public void onPageScrollStateChanged(final int state) {
            mPreviousScrollState = mScrollState;
            mScrollState = state;
        }

        @Override
        public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
            super.onPageScrolled(position, positionOffset, positionOffsetPixels);
            ColorClipTabLayout tabLayout = mTabLayoutRef.get();
            if (tabLayout == null) return;
            final boolean updateText = mScrollState != SCROLL_STATE_SETTLING ||
                    mPreviousScrollState == SCROLL_STATE_DRAGGING;
            if (updateText) {
                Log.e("tag", "positionOffset" + positionOffset);
                tabLayout.tabScrolled(position, positionOffset);
            }
        }

        @Override
        public void onPageSelected(int position) {
            super.onPageSelected(position);
            ColorClipTabLayout tabLayout = mTabLayoutRef.get();
            mPreviousScrollState = SCROLL_STATE_SETTLING;
            tabLayout.setSelectedView(position);
        }

        void reset() {
            mPreviousScrollState = mScrollState = SCROLL_STATE_IDLE;
        }

    }
}

來,看下效果


xixi2.gif

OJBK,這就是我想要的效果,話不多說,代碼已經(jīng)上傳到github,可以下下來看一看,喜歡的可以star一下
恩,你們都是最帥的最美的...

最后推薦一波扔物線的自定義View教程,真的很有幫助HenCoder

參考:
Android 自定義控件玩轉(zhuǎn)字體變色 打造炫酷ViewPager指示器
自適應(yīng)Tab寬度可以滑動(dòng)文字逐漸變色的TabLayout

github地址:ColorTabLayout

下一篇算是自我學(xué)習(xí)的文章:Android的線程池

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末危融,一起剝皮案震驚了整個(gè)濱河市畏铆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌吉殃,老刑警劉巖及志,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件片排,死亡現(xiàn)場離奇詭異寨腔,居然都是意外死亡速侈,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門迫卢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來倚搬,“玉大人,你說我怎么就攤上這事乾蛤∶拷纾” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵家卖,是天一觀的道長眨层。 經(jīng)常有香客問我,道長上荡,這世上最難降的妖魔是什么趴樱? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮酪捡,結(jié)果婚禮上叁征,老公的妹妹穿的比我還像新娘。我一直安慰自己逛薇,他們只是感情好捺疼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著永罚,像睡著了一般啤呼。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呢袱,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天官扣,我揣著相機(jī)與錄音,去河邊找鬼产捞。 笑死醇锚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的坯临。 我是一名探鬼主播焊唬,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼看靠!你這毒婦竟也來了赶促?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤挟炬,失蹤者是張志新(化名)和其女友劉穎鸥滨,沒想到半個(gè)月后嗦哆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡婿滓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年老速,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片凸主。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡橘券,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卿吐,到底是詐尸還是另有隱情旁舰,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布嗡官,位于F島的核電站箭窜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏衍腥。R本人自食惡果不足惜磺樱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望紧阔。 院中可真熱鬧坊罢,春花似錦、人聲如沸擅耽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乖仇。三九已至憾儒,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乃沙,已是汗流浹背起趾。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留警儒,地道東北人训裆。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像蜀铲,于是被迫代替她去往敵國和親边琉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

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