知乎和簡書的夜間模式實(shí)現(xiàn)套路

Hello郭膛,大家好闪檬,我是Clock星著。今天要寫的這篇文章主題是關(guān)于夜間模式的實(shí)現(xiàn)套路。本來這篇文章是上周要寫的粗悯,結(jié)果因?yàn)樯现苣┯衅渌虑樾檠酝系竭@個(gè)周末才完成。曾經(jīng)和薇薇(鈦媒體漂亮的程序媛)聊過夜間模式實(shí)現(xiàn)的問題,當(dāng)時(shí)薇薇醬負(fù)責(zé)鈦媒體客戶端的重構(gòu)工作横缔,有個(gè)夜間模式功能在考慮要不要用 Android M 新加的夜間模式特性铺遂。憑借稍微有點(diǎn)點(diǎn)老司機(jī)的經(jīng)驗(yàn),我直接說了 NO茎刚。按照以往的套路襟锐,通常新出的功能都會(huì)有坑,或者向下兼容性的問題膛锭。自己弄弄 Demo 玩玩是可以的粮坞,但是引入企業(yè)開發(fā)還是謹(jǐn)慎點(diǎn),說白了就是先等等泉沾,讓大家把坑填完了再用。果然妇押,Android M 發(fā)正式版的時(shí)候跷究,預(yù)覽版里面的夜間模式功能被暫時(shí)移除了(哈哈哈哈,機(jī)智如我敲霍,最新發(fā)布的 Android N 正式版已經(jīng)有夜間模式了俊马,大家可以去玩玩)。

前言

好了肩杈,回歸正題柴我,說回夜間模式。在網(wǎng)上看到很多童鞋都說用什么什么框架來實(shí)現(xiàn)這個(gè)功能扩然,然后仔細(xì)去看一下各個(gè)推薦的框架艘儒,發(fā)現(xiàn)其實(shí)都是動(dòng)態(tài)換膚的,動(dòng)態(tài)換膚可比夜間模式要復(fù)雜多了夫偶,未免大材小用了界睁。說實(shí)話,我一直沒用什么好思路兵拢,雖然網(wǎng)上有童鞋提供了一種思路是通過 setTheme 然后再 recreate Activity 的方式翻斟,但是這樣帶來的問題是非常多的,看起來就相當(dāng)不科學(xué)(為什么不科學(xué)说铃,后文會(huì)說)访惜。于是,直接想到了去逆向分析那些夜間模式做得好的應(yīng)用的源代碼腻扇,學(xué)習(xí)他們的實(shí)現(xiàn)套路债热。所以,本文的實(shí)現(xiàn)思路來自于編寫這些應(yīng)用的夜間模式功能的童鞋幼苛,先在這里向他們表示感謝阳柔。我的手機(jī)里面使用高頻的應(yīng)用不少,其中簡書和知乎是屬于夜間模式做得相當(dāng) nice 的蚓峦。先給兩個(gè)效果圖大家對(duì)比感受下

簡書 知乎

如果大家仔細(xì)觀察舌剂,肯定會(huì)發(fā)現(xiàn)济锄,知乎的切換效果更漂亮些,因?yàn)樗幸粋€(gè)漸變的效果霍转。那么它們的夜間模式到底是如何實(shí)現(xiàn)的呢荐绝?別急接著往下看,你也可以避消。

實(shí)現(xiàn)套路

這里先展示一下我的實(shí)現(xiàn)效果吧

簡書實(shí)現(xiàn)效果 知乎實(shí)現(xiàn)效果

此處分為兩個(gè)部分低滩,一部分是 xml 文件中要干的活,一部分是 Java 代碼要實(shí)現(xiàn)的活岩喷,先說 xml 吧恕沫。

XML 配置

首先,先寫一套UI界面出來纱意,上方左邊是兩個(gè) TextView婶溯,右邊是兩個(gè) CheckBox,下方是一個(gè) RecyclerView 偷霉,實(shí)現(xiàn)很簡單迄委,這里我不貼代碼了。

接著类少,在 styles 文件中添加兩個(gè) Theme叙身,一個(gè)是日間主題,一個(gè)是夜間主題硫狞。它們的屬性都是一樣的信轿,唯一區(qū)別在于顏色效果不同。


    <!--白天主題-->
    <style name="DayTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="clockBackground">@android:color/white</item>
        <item name="clockTextColor">@android:color/black</item>
    </style>

    <!--夜間主題-->
    <style name="NightTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/color3F3F3F</item>
        <item name="colorPrimaryDark">@color/color3A3A3A</item>
        <item name="colorAccent">@color/color868686</item>
        <item name="clockBackground">@color/color3F3F3F</item>
        <item name="clockTextColor">@color/color8A9599</item>
    </style>

需要注意的是残吩,上面的 clockTextColor 和 clockBackground 是我自定義的 color 類型屬性

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <attr name="clockBackground" format="color" />
    <attr name="clockTextColor" format="color" />
</resources>

然后再到所有需要實(shí)現(xiàn)夜間模式功能的 xml 布局文件中虏两,加入類似下面設(shè)置,比如我在 RecyclerView 的 Item 布局文件中做了如下設(shè)置

稍稍解釋下其作用世剖,如 TextView 里的 android:textColor="?attr/clockTextColor" 是讓其字體顏色跟隨所設(shè)置的 Theme定罢。到這里,xml 需要做的配置全部完成旁瘫,接下來是 Java 代碼實(shí)現(xiàn)了祖凫。

Java 代碼實(shí)現(xiàn)

大家可以先看下面的實(shí)現(xiàn)代碼,看不懂的童鞋可以邊結(jié)合我代碼下方實(shí)現(xiàn)思路解說酬凳。


package com.clock.study.activity;

import ...

/**
 * 夜間模式實(shí)現(xiàn)方案
 *
 * @author Clock
 * @since 2016-08-11
 */
public class DayNightActivity extends AppCompatActivity implements CompoundButton.OnCheckedChangeListener {

    private final static String TAG = DayNightActivity.class.getSimpleName();
    /**用于將主題設(shè)置保存到SharePreferences的工具類**/
    private DayNightHelper mDayNightHelper;

    private RecyclerView mRecyclerView;

    private LinearLayout mHeaderLayout;
    private List<RelativeLayout> mLayoutList;
    private List<TextView> mTextViewList;
    private List<CheckBox> mCheckBoxList;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
        initData();
        initTheme();
        setContentView(R.layout.activity_day_night);
        initView();
    }

    private void initView() {
        mRecyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false);
        mRecyclerView.setLayoutManager(layoutManager);
        mRecyclerView.setAdapter(new SimpleAuthorAdapter());

        mHeaderLayout = (LinearLayout) findViewById(R.id.header_layout);

        mLayoutList = new ArrayList<>();
        mLayoutList.add((RelativeLayout) findViewById(R.id.jianshu_layout));
        mLayoutList.add((RelativeLayout) findViewById(R.id.zhihu_layout));

        mTextViewList = new ArrayList<>();
        mTextViewList.add((TextView) findViewById(R.id.tv_jianshu));
        mTextViewList.add((TextView) findViewById(R.id.tv_zhihu));

        mCheckBoxList = new ArrayList<>();
        CheckBox ckbJianshu = (CheckBox) findViewById(R.id.ckb_jianshu);
        ckbJianshu.setOnCheckedChangeListener(this);
        mCheckBoxList.add(ckbJianshu);
        CheckBox ckbZhihu = (CheckBox) findViewById(R.id.ckb_zhihu);
        ckbZhihu.setOnCheckedChangeListener(this);
        mCheckBoxList.add(ckbZhihu);

    }

    @Override
    public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
        int viewId = buttonView.getId();
        if (viewId == R.id.ckb_jianshu) {
            changeThemeByJianShu();

        } else if (viewId == R.id.ckb_zhihu) {
            changeThemeByZhiHu();

        }
    }

    private void initData() {
        mDayNightHelper = new DayNightHelper(this);
    }

    private void initTheme() {
        if (mDayNightHelper.isDay()) {
            setTheme(R.style.DayTheme);
        } else {
            setTheme(R.style.NightTheme);
        }
    }

    /**
     * 切換主題設(shè)置
     */
    private void toggleThemeSetting() {
        if (mDayNightHelper.isDay()) {
            mDayNightHelper.setMode(DayNight.NIGHT);
            setTheme(R.style.NightTheme);
        } else {
            mDayNightHelper.setMode(DayNight.DAY);
            setTheme(R.style.DayTheme);
        }
    }

    /**
     * 使用簡書的實(shí)現(xiàn)套路來切換夜間主題
     */
    private void changeThemeByJianShu() {
        toggleThemeSetting();
        refreshUI();
    }

    /**
     * 使用知乎的實(shí)現(xiàn)套路來切換夜間主題
     */
    private void changeThemeByZhiHu() {
        showAnimation();
        toggleThemeSetting();
        refreshUI();
    }

    /**
     * 刷新UI界面
     */
    private void refreshUI() {
        TypedValue background = new TypedValue();//背景色
        TypedValue textColor = new TypedValue();//字體顏色
        Resources.Theme theme = getTheme();
        theme.resolveAttribute(R.attr.clockBackground, background, true);
        theme.resolveAttribute(R.attr.clockTextColor, textColor, true);

        mHeaderLayout.setBackgroundResource(background.resourceId);
        for (RelativeLayout layout : mLayoutList) {
            layout.setBackgroundResource(background.resourceId);
        }
        for (CheckBox checkBox : mCheckBoxList) {
            checkBox.setBackgroundResource(background.resourceId);
        }
        for (TextView textView : mTextViewList) {
            textView.setBackgroundResource(background.resourceId);
        }

        Resources resources = getResources();
        for (TextView textView : mTextViewList) {
            textView.setTextColor(resources.getColor(textColor.resourceId));
        }

        int childCount = mRecyclerView.getChildCount();
        for (int childIndex = 0; childIndex < childCount; childIndex++) {
            ViewGroup childView = (ViewGroup) mRecyclerView.getChildAt(childIndex);
            childView.setBackgroundResource(background.resourceId);
            View infoLayout = childView.findViewById(R.id.info_layout);
            infoLayout.setBackgroundResource(background.resourceId);
            TextView nickName = (TextView) childView.findViewById(R.id.tv_nickname);
            nickName.setBackgroundResource(background.resourceId);
            nickName.setTextColor(resources.getColor(textColor.resourceId));
            TextView motto = (TextView) childView.findViewById(R.id.tv_motto);
            motto.setBackgroundResource(background.resourceId);
            motto.setTextColor(resources.getColor(textColor.resourceId));
        }

        //讓 RecyclerView 緩存在 Pool 中的 Item 失效
        //那么惠况,如果是ListView,要怎么做呢宁仔?這里的思路是通過反射拿到 AbsListView 類中的 RecycleBin 對(duì)象稠屠,然后同樣再用反射去調(diào)用 clear 方法
        Class<RecyclerView> recyclerViewClass = RecyclerView.class;
        try {
            Field declaredField = recyclerViewClass.getDeclaredField("mRecycler");
            declaredField.setAccessible(true);
            Method declaredMethod = Class.forName(RecyclerView.Recycler.class.getName()).getDeclaredMethod("clear", (Class<?>[]) new Class[0]);
            declaredMethod.setAccessible(true);
            declaredMethod.invoke(declaredField.get(mRecyclerView), new Object[0]);
            RecyclerView.RecycledViewPool recycledViewPool = mRecyclerView.getRecycledViewPool();
            recycledViewPool.clear();

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        refreshStatusBar();
    }

    /**
     * 刷新 StatusBar
     */
    private void refreshStatusBar() {
        if (Build.VERSION.SDK_INT >= 21) {
            TypedValue typedValue = new TypedValue();
            Resources.Theme theme = getTheme();
            theme.resolveAttribute(R.attr.colorPrimary, typedValue, true);
            getWindow().setStatusBarColor(getResources().getColor(typedValue.resourceId));
        }
    }

    /**
     * 展示一個(gè)切換動(dòng)畫
     */
    private void showAnimation() {
        final View decorView = getWindow().getDecorView();
        Bitmap cacheBitmap = getCacheBitmapFromView(decorView);
        if (decorView instanceof ViewGroup && cacheBitmap != null) {
            final View view = new View(this);
            view.setBackgroundDrawable(new BitmapDrawable(getResources(), cacheBitmap));
            ViewGroup.LayoutParams layoutParam = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT);
            ((ViewGroup) decorView).addView(view, layoutParam);
            ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f);
            objectAnimator.setDuration(300);
            objectAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    ((ViewGroup) decorView).removeView(view);
                }
            });
            objectAnimator.start();
        }
    }

    /**
     * 獲取一個(gè) View 的緩存視圖
     *
     * @param view
     * @return
     */
    private Bitmap getCacheBitmapFromView(View view) {
        final boolean drawingCacheEnabled = true;
        view.setDrawingCacheEnabled(drawingCacheEnabled);
        view.buildDrawingCache(drawingCacheEnabled);
        final Bitmap drawingCache = view.getDrawingCache();
        Bitmap bitmap;
        if (drawingCache != null) {
            bitmap = Bitmap.createBitmap(drawingCache);
            view.setDrawingCacheEnabled(false);
        } else {
            bitmap = null;
        }
        return bitmap;
    }
}

實(shí)現(xiàn)思路和代碼解說:

  1. DayNightHelper 類是用于保存夜間模式設(shè)置到 SharePreferences 的工具類,在 initData 函數(shù)中被初始化,其他的 View 和 Layout 都是界面布局权埠,在 initView 函數(shù)中被初始化榨了;
  2. 在 Activity 的 onCreate 函數(shù)調(diào)用 setContentView 之前,需要先去 setTheme攘蔽,因?yàn)楫?dāng) View 創(chuàng)建成功后 龙屉,再去 setTheme 是無法對(duì) View 的 UI 效果產(chǎn)生影響的;
  3. onCheckedChanged 用于監(jiān)聽日間模式和夜間模式的切換操作满俗;
  4. refreshUI 是本實(shí)現(xiàn)的關(guān)鍵函數(shù)转捕,起著切換效果的作用,通過 TypedValue 和 Theme.resolveAttribute 在代碼中獲取 Theme 中設(shè)置的顏色唆垃,來重新設(shè)置控件的背景色或者字體顏色等等五芝。需要特別注意的是 RecyclerView 和 ListView 這種比較特殊的控件處理方式,代碼注釋中已經(jīng)說明辕万,大家可以看代碼中注釋枢步;
  5. refreshStatusBar 用于刷新頂部通知欄位置的顏色;
  6. showAnimation 和 getCacheBitmapFromView 同樣是本實(shí)現(xiàn)的關(guān)鍵函數(shù)蓄坏,getCacheBitmapFromView 用于將 View 中的內(nèi)容轉(zhuǎn)換成 Bitmap(類似于截屏操作那樣)价捧,showAnimation 是用于展示一個(gè)漸隱效果的屬性動(dòng)畫丑念,這個(gè)屬性作用在哪個(gè)對(duì)象上呢涡戳?是一個(gè) View ,一個(gè)在代碼中動(dòng)態(tài)填充到 DecorView 中的 View(不知道 DecorView 的童鞋得回去看看 Android Window 相關(guān)的知識(shí))脯倚。知乎之所以在夜間模式切換過程中會(huì)有漸隱效果渔彰,是因?yàn)樵谇袚Q前進(jìn)行了截屏,同時(shí)將截屏拿到的 Bitmap 設(shè)置到動(dòng)態(tài)填充到 DecorView 中的 View 上推正,并對(duì)這個(gè) View 執(zhí)行一個(gè)漸隱的屬性動(dòng)畫恍涂,所以使得我們能夠看到一個(gè)漂亮的漸隱過渡的動(dòng)畫效果。而且在動(dòng)畫結(jié)束的時(shí)候再把這個(gè)動(dòng)態(tài)添加的 View 給 remove 了植榕,避免了 Bitmap 造成內(nèi)存飆升問題再沧。對(duì)待知乎客戶端開發(fā)者這種處理方式,我必須雙手點(diǎn)贊外加一個(gè)大寫的服尊残。

到這里炒瘸,實(shí)現(xiàn)套路基本說完了,簡書和知乎的實(shí)現(xiàn)套路如上所述寝衫,區(qū)別就是知乎多了個(gè)截屏和漸隱過渡動(dòng)畫效果而已。

一些思考

整理逆向分析的過程,也對(duì)夜間模式的實(shí)現(xiàn)有了不少思考烂叔,希望與各位童鞋們探討分享嗅虏。

最初步的逆向分析過程就發(fā)現(xiàn)了,知乎和簡書并沒有引入任何第三方框架來實(shí)現(xiàn)夜間模式,為什么呢婶芭?

因?yàn)槲铱吹降拇蟛糠侄紝?shí)現(xiàn)夜間模式的思路都是用開源的換膚框架东臀,或多或少存在著些 BUG。簡書和知乎不用可能是出于框架不穩(wěn)定性雕擂,以及我前面提到的用換膚框架來實(shí)現(xiàn)夜間模式大材小用吧啡邑。(我也只是瞎猜,哈哈哈)

前面我提到井赌,通過 setTheme 然后再去 Activity recreate 的方案不可行谤逼,為什么呢?

我認(rèn)為不可行的原因有兩點(diǎn)仇穗,一個(gè)是 Activity recreate 會(huì)有閃爍效果體驗(yàn)不加流部,二是 Activity recreate 涉及到狀態(tài)狀態(tài)保存問題,如自身的狀態(tài)保存纹坐,如果 Activity 中包含著多個(gè) Fragment 枝冀,那就更加頭疼了。

知乎和簡書設(shè)置夜間模式的位置耘子,有點(diǎn)巧妙果漾,巧妙在哪?

知乎和簡書出發(fā)夜間模式切換的地方谷誓,都是在 MainActivity 的一個(gè) Fragment 中绒障。也就是說,如果你要切換模式時(shí)捍歪,必須回到主界面户辱,此時(shí)只存在主界面一個(gè) Activity,只需要遍歷主界面更新控件色調(diào)即可糙臼。而對(duì)于其他設(shè)置夜間模式后新建的 Activity 庐镐,只需要在 setContentView 之前做一下判斷并 setTheme 即可。

總結(jié)

關(guān)于簡書和知乎夜間模式功能實(shí)現(xiàn)的套路就講解到這里变逃,整個(gè)實(shí)現(xiàn)套路都是我通過逆向分析簡書和知乎的代碼取得必逆,這里再一次向?qū)崿F(xiàn)這些代碼的童鞋以示感謝。當(dāng)然揽乱,上面的代碼我是經(jīng)過精簡提煉過的名眉,在原先簡書和知乎客戶端中的實(shí)現(xiàn)代碼還做了相應(yīng)的抽象設(shè)計(jì)和遞歸遍歷等等,這里是為了方便講解而做了精簡锤窑。如果有童鞋喜歡這種實(shí)現(xiàn)套路璧针,也可以自己加以抽象封裝。這里也推薦各位童鞋一個(gè)我常用的思路渊啰,就是當(dāng)你對(duì)一個(gè)功能沒有思路時(shí)探橱,大可找一些實(shí)現(xiàn)了這類功能的優(yōu)秀應(yīng)用進(jìn)行逆向代碼分析申屹。需要實(shí)現(xiàn)代碼的童鞋,可以訪問:

https://github.com/D-clock/AndroidStudyCode

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末隧膏,一起剝皮案震驚了整個(gè)濱河市哗讥,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胞枕,老刑警劉巖杆煞,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異腐泻,居然都是意外死亡决乎,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門派桩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來构诚,“玉大人,你說我怎么就攤上這事铆惑》吨觯” “怎么了?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵员魏,是天一觀的道長丑蛤。 經(jīng)常有香客問我,道長撕阎,這世上最難降的妖魔是什么受裹? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮闻书,結(jié)果婚禮上名斟,老公的妹妹穿的比我還像新娘脑慧。我一直安慰自己魄眉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布闷袒。 她就那樣靜靜地躺著坑律,像睡著了一般。 火紅的嫁衣襯著肌膚如雪囊骤。 梳的紋絲不亂的頭發(fā)上晃择,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音也物,去河邊找鬼宫屠。 笑死,一個(gè)胖子當(dāng)著我的面吹牛滑蚯,可吹牛的內(nèi)容都是我干的浪蹂。 我是一名探鬼主播抵栈,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼坤次!你這毒婦竟也來了古劲?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤缰猴,失蹤者是張志新(化名)和其女友劉穎产艾,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滑绒,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡闷堡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了疑故。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缚窿。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖焰扳,靈堂內(nèi)的尸體忽然破棺而出倦零,到底是詐尸還是另有隱情,我是刑警寧澤吨悍,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布扫茅,位于F島的核電站,受9級(jí)特大地震影響育瓜,放射性物質(zhì)發(fā)生泄漏葫隙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一躏仇、第九天 我趴在偏房一處隱蔽的房頂上張望恋脚。 院中可真熱鬧,春花似錦焰手、人聲如沸糟描。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽船响。三九已至,卻和暖如春躲履,著一層夾襖步出監(jiān)牢的瞬間见间,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工工猜, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留米诉,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓篷帅,卻偏偏與公主長得像史侣,于是被迫代替她去往敵國和親汗销。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

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