Android中日期選擇控件-DatePicker的使用

背景

項目中要增加一個日期選擇功能,以前寫了一個單滾輪的選擇控件,但是現(xiàn)在要用日歷模式,所以那個控件就不能用了。本著功能簡單,盡量使用系統(tǒng)提供的控件來完成,就沒去考慮第三方開源控件,結(jié)果Android SDK提供的日期選擇控件 - DatePicker 坑太多了。

DatePicker的缺陷

  1. 提供的API太少,沒辦法個性化定制。比如,不能指定某部分的顏色,不能控制顯示的部分等。
  2. xml中提供的屬性太少,同樣影響定制化。
  3. 兼容性問題太多,在4.x,5.x和6.0+上UI不同
  4. 同樣是兼容性問題,同一個屬性設(shè)置在不同的系統(tǒng)版本上有不同的效果
  5. bug太多,暫且發(fā)現(xiàn)下面這6個
    • bug1:日歷模式,在5.0以下設(shè)置的可選時間區(qū)間如果與當(dāng)前日期在同一欄會crash
    • bug2:LOLLIPOP上OnDateChangedListener回調(diào)無效(5.0上存在,5.1修復(fù))
    • bug3:5.0上超過可選區(qū)間的日期依然能選中,所以要手動校驗.5.1上已解決.
    • bug4:LOLLIPOP和Marshmallow上,使用spinner模式,然后隱藏滾輪,顯示日歷,日歷最底部一排日期被截去部分
    • bug5:5.1上,maxdate不可選。由于5.0有bug3,所以可能bug5被掩蓋了。4.x和6.0+版本沒有這個問題。
    • bug6:bug5在6.0+上有另一個表現(xiàn)形式,currentDate如果與MaxDate一樣,初始化時會觸發(fā)一個onDateChanged回調(diào)。其內(nèi)部原因都是一樣的。

DatePicker的使用

由于Google在Android4.x上采用的是holo風(fēng)格,在5.x及以上采用的Material Design風(fēng)格,所以從4.x到5.x,Google重構(gòu)了DatePicker,包括代碼和UI。所以這就產(chǎn)生了兼容性問題。

我要解決的問題

  1. UI的一致性。
    • 在4.x上,DatePicker沒有Mode的概念,默認就是滾輪和日歷并排顯示,但可通過xml或者代碼,控制只顯示滾輪或者只顯示日歷。但是日歷模式下,存在上述bug1的問題,所以與老大商量了一下,考慮到4.x系統(tǒng)占比太小,可以使用滾輪模式。


      DatePicker在4.x
    • 在5.x及以上,DatePicker引入了Mode的概念,spinner和calendar只能顯示其中一個,所以可以在xml直接指定calendar模式。但是5.x和6.0+的日歷都多了一個頭部,而且5.x和6.0+的頭部還不一樣,又沒有API可以隱藏頭部。所以,需要自己想辦法隱藏頭部。
DatePicker在5.x
DatePicker在6.0+
  1. 定制DatePicker,符合射雞師的要求。
    DatePicker的能用來做個性化的API和屬性值太少了,正常途徑我要改變選中日期的圓圈顏色都做到。其實,系統(tǒng)提供的控件多半是從系統(tǒng)提供的style中讀取配置,我們可以自己配置一個style給DatePicker。
    如果在Activity中使用DatePicker,DatePicker會讀取Activity的Theme;如果在Dialog中使用DatePicker,會讀取Dialog的Theme(如果Dialog沒有指定Theme,默認使用Activity的Theme)。我們要在Dialog中使用DatePicker,所以自定義一個DatePicker的style,傳給自定義的Dialog的Theme,再使用自定義的Theme創(chuàng)建Dialog就好了。
    其實系統(tǒng)提供了幾個默認Theme,通過它們可以簡單改變DatePicker的風(fēng)格,參考這個答案。但其實這些Theme內(nèi)部也是通過改變DatePicker(通過datepickerstyle)的屬性來做到的。

  2. 解決上述發(fā)現(xiàn)的bug。
    要解決兼容性問題,也要解決bug,所以在代碼中必須分情況處理。

代碼

代碼量很少,注釋也寫的很清楚,相信看完就懂了。

  1. 內(nèi)部封裝DatePicker的DialogFragment
public class CustomDatePickerDialogFragment extends DialogFragment  implements DatePicker.OnDateChangedListener, View.OnClickListener{
    public static final String CURRENT_DATE = "datepicker_current_date";
    public static final String START_DATE = "datepicker_start_date";
    public static final String END_DATE = "datepicker_end_date";
    Calendar currentDate;
    Calendar startDate;
    Calendar endDate;

    DatePicker datePicker;
    TextView backButton;
    TextView ensureButton;
    View splitLineV;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setCancelable(false);
        Bundle bundle = getArguments();
        currentDate = (Calendar) bundle.getSerializable(CURRENT_DATE);
        startDate = (Calendar) bundle.getSerializable(START_DATE);
        endDate = (Calendar) bundle.getSerializable(END_DATE);
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        if (inflater == null) {
            return super.onCreateView(inflater, container, savedInstanceState);
        }
        getDialog().requestWindowFeature(Window.FEATURE_NO_TITLE);
        getDialog().getWindow().setDimAmount(0.8f);
        View view  = inflater.inflate(R.layout.dialog_date_picker_layout,container,false);
        return view;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        int style;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            style = R.style.ZZBDatePickerDialogLStyle;
        } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            style = R.style.ZZBDatePickerDialogLStyle;
        } else {
            style = getTheme();
        }
        return new Dialog(getActivity(), style);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        if (view != null) {
            datePicker = view.findViewById(R.id.datePickerView);
            backButton = view.findViewById(R.id.back);
            backButton.setOnClickListener(this);
            ensureButton = view.findViewById(R.id.ensure);
            ensureButton.setOnClickListener(this);
            splitLineV = view.findViewById(R.id.splitLineV);
            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
                //bug1:日歷模式,在5.0以下設(shè)置的可選時間區(qū)間如果與當(dāng)前日期在同一欄會crash,所以只能用滾輪模式
                datePicker.setCalendarViewShown(false);
                datePicker.setSpinnersShown(true);
                //滾輪模式必須使用確定菜單
                ensureButton.setVisibility(View.VISIBLE);
                splitLineV.setVisibility(View.VISIBLE);
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
                    && Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
                //bug2:LOLLIPOP上OnDateChangedListener回調(diào)無效(5.0存在,5.1修復(fù)),必須使用確定菜單回傳選定日期
                ensureButton.setVisibility(View.VISIBLE);
                splitLineV.setVisibility(View.VISIBLE);
                //如果只要日歷部分,隱藏header
                ViewGroup mContainer = (ViewGroup) datePicker.getChildAt(0);
                View header = mContainer.getChildAt(0);
                header.setVisibility(View.GONE);
            } else {
                //bug4:LOLLIPOP和Marshmallow上,使用spinner模式,然后隱藏滾輪,顯示日歷(spinner模式下的日歷沒有頭部),日歷最底部一排日期被截去部分。所以只能使用calender模式,然后手動隱藏header(系統(tǒng)沒有提供隱藏header的api)。
                //如果只要日歷部分,隱藏header
                ViewGroup mContainer = (ViewGroup) datePicker.getChildAt(0);
                View header = mContainer.getChildAt(0);
                header.setVisibility(View.GONE);
                //Marshmallow上底部留白太多,減小間距
                LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) datePicker.getLayoutParams();
                layoutParams.bottomMargin = 10;
                datePicker.setLayoutParams(layoutParams);
            }
            initDatePicker();
        }
    }

    private void initDatePicker() {
        if (datePicker == null) {
            return;
        }
        if (currentDate == null) {
            currentDate = Calendar.getInstance();
            currentDate.setTimeInMillis(System.currentTimeMillis());
        }
        datePicker.init(currentDate.get(Calendar.YEAR),currentDate.get(Calendar.MONTH),currentDate.get(Calendar.DAY_OF_MONTH),this);
        if (startDate != null) {
            datePicker.setMinDate(startDate.getTimeInMillis());
        }
        if (endDate != null) {  
            //bug5:5.1上,maxdate不可選。由于5.0有bug3,所以可能bug5被掩蓋了。4.x和6.0+版本沒有這個問題。
            //bug5在6.0+上有另一個表現(xiàn)形式:初始化時會觸發(fā)一次onDateChanged回調(diào)。通過源碼分析一下原因:init方法只會設(shè)置控件當(dāng)前日期的
            //年月日,而時分秒默認使用現(xiàn)在時間的時分秒,所以當(dāng)前日期大于>最大日期,執(zhí)行setMaxDate方法時,就會觸發(fā)一次onDateChanged回調(diào)。
            //同理,setMinDate方法也面臨同樣的方法。所以設(shè)置范圍時,MinDate取0時0分0秒,MaxDate取23時59分59秒。
            endDate.set(Calendar.HOUR_OF_DAY,23);
            endDate.set(Calendar.MINUTE,59);
            endDate.set(Calendar.SECOND,59);
            datePicker.setMaxDate(endDate.getTimeInMillis());
        }
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.back:
                dismiss();
                break;
            case R.id.ensure:
                returnSelectedDateUnderLOLLIPOP();
                break;
            default:
                break;
        }
    }

    private void returnSelectedDateUnderLOLLIPOP() {
        //bug3:5.0上超過可選區(qū)間的日期依然能選中,所以要手動校驗.5.1上已解決,但是為了與5.0保持一致,也采用確定菜單返回日期
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
                && Build.VERSION.SDK_INT < Build.VERSION_CODES.M){
            Calendar selectedDate = Calendar.getInstance();
            selectedDate.set(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth(),0,0,0);
            selectedDate.set(Calendar.MILLISECOND,0);
            if (selectedDate.before(startDate) || selectedDate.after(endDate)) {
                Toast.makeText(getActivity(), "日期超出有效范圍", Toast.LENGTH_SHORT).show();
                return;
            }
        }
        if (onSelectedDateListener != null) {
            onSelectedDateListener.onSelectedDate(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth());
        }
        dismiss();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        onSelectedDateListener = null;
    }

    public interface OnSelectedDateListener {
        void onSelectedDate(int year, int monthOfYear, int dayOfMonth);
    }

    OnSelectedDateListener onSelectedDateListener;

    public void setOnSelectedDateListener(OnSelectedDateListener onSelectedDateListener) {
        this.onSelectedDateListener = onSelectedDateListener;
    }

    @Override
    public void onDateChanged(DatePicker view, int year, int monthOfYear, int dayOfMonth) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
                && Build.VERSION.SDK_INT < Build.VERSION_CODES.M){ //LOLLIPOP上,這個回調(diào)無效,排除將來可能的干擾
            return;
        }
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { //5.0以下,必須采用滾輪模式,所以需借助確定菜單回傳選定值
            return;
        }
        if (onSelectedDateListener != null) {
            onSelectedDateListener.onSelectedDate(year, monthOfYear, dayOfMonth);
        }
        dismiss();
    }
}
  1. CustomDatePickerDialogFragment的layout文件 - R.layout.dialog_date_picker_layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <DatePicker
        android:id="@+id/datePickerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:spinnersShown="false"
        android:calendarViewShown="true"
        android:datePickerMode="calendar"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:layout_marginLeft="10dp"
        android:layout_marginRight="10dp"/>

    <View
        android:layout_width="match_parent"
        android:layout_height="1px"
        android:background="@android:color/black" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingTop="10dp"
            android:paddingBottom="10dp"
            android:text="返回"
            android:gravity="center"
            android:textColor="@android:color/black"
            android:id="@+id/back"/>

        <View
            android:layout_width="1px"
            android:layout_height="match_parent"
            android:background="@android:color/black"
            android:id="@+id/splitLineV"
            android:visibility="gone"/>

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:paddingTop="10dp"
            android:paddingBottom="10dp"
            android:text="確認"
            android:gravity="center"
            android:textColor="@android:color/black"
            android:id="@+id/ensure"
            android:visibility="gone"/>

    </LinearLayout>

</LinearLayout>
  1. 自定義的DatePicker的style
<style name="ZZBDatePickerDialogLStyle" parent="android:Theme.DeviceDefault.Light.Dialog">
        <item name="android:datePickerStyle">@style/ZZBDatePickerLStyle</item>
        <!-- 初始化的那一天和選中時的圓圈的顏色-->
        <item name="android:colorControlActivated">@android:color/holo_blue_dark</item>
        <!-- LOLLIPOP,整個日歷字體的顏色。Marshmallow,日歷中星期字體顏色-->
        <item name="android:textColorSecondary">@android:color/holo_blue_dark</item>
        <!-- Marshmallow,日歷字體的顏色,不可選的日期依然有置灰效果。LOLLIPOP,無效-->
        <item name="android:textColorPrimary">@android:color/holo_purple</item>
    </style>

    <style name="ZZBDatePickerLStyle" parent="android:Widget.Material.Light.DatePicker">
        <!-- LOLLIPOP,最頂部,星期標題的背景色。Marshmallow星期標題被合并到header,所以字段無效-->
        <item name="android:dayOfWeekBackground">@android:color/holo_blue_light</item>
        <!-- LOLLIPOP,最頂部,星期字體的顏色、大小等。Marshmallow星期標題被合并到header,所以字段無效-->
        <item name="android:dayOfWeekTextAppearance">@style/ZZBTitleDayOfWeekTextAppearance</item>
        <!-- 中間部分,header的背景色 -->
        <item name="android:headerBackground" >@android:color/holo_orange_dark</item>
        <!-- 中間部分,header的字體大小和顏色-->
        <!-- 對LOLLIPOP有效,對Marshmallow無效-->
        <item name="android:headerYearTextAppearance">@style/ZZBHeaderYearTextAppearance</item>
        <!-- 對LOLLIPOP和Marshmallow都是部分有效-->
        <item name="android:headerMonthTextAppearance">@style/ZZBHeaderMonthTextAppearance</item>
        <!-- 對LOLLIPOP有效,對Marshmallow無效-->
        <item name="android:headerDayOfMonthTextAppearance">@style/ZZBHeaderDayOfMonthTextAppearance</item>
        <!-- LOLLIPOP,控制整個日歷字體顏色的最終字段,優(yōu)先級最高,但是一旦使用了這個字段,不可選的日期就失去了置灰效果。對Marshmallow無效-->
        <item name="android:calendarTextColor">@android:color/holo_green_dark</item>
    </style>

    <style name="ZZBTitleDayOfWeekTextAppearance" parent="android:TextAppearance.Material">
        <item name="android:textColor">@android:color/black</item>
        <item name="android:textSize">12sp</item>
    </style>
    <style name="ZZBHeaderYearTextAppearance" parent="android:TextAppearance.Material">
        <item name="android:textColor">@android:color/holo_blue_light</item>
        <item name="android:textSize">50sp</item>
    </style>
    <style name="ZZBHeaderMonthTextAppearance" parent="android:TextAppearance.Material">
        <!-- LOLLIPOP無效,Marshmallow有效。控制Marshmallow中header部分所有的字體顏色。LOLLIPOP沒有找到控制字體顏色的字段-->
        <item name="android:textColor">@android:color/holo_blue_light</item>
        <!-- LOLLIPOP有效,Marshmallow無效。Marshmallow沒有找到控制header字體大小的字段-->
        <item name="android:textSize">50sp</item>
    </style>
    <style name="ZZBHeaderDayOfMonthTextAppearance" parent="android:TextAppearance.Material">
        <!-- 只可以控制字體的大小,沒有找到控制字體顏色的字段-->
        <item name="android:textSize">50sp</item>
    </style>
  1. MainActivity的代碼
public class MainActivity extends AppCompatActivity implements View.OnClickListener,CustomDatePickerDialogFragment.OnSelectedDateListener{
    Button button;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = (Button) findViewById(R.id.datepicker);
        button.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.datepicker:
                showDatePickDialog();
                break;
            default:
                break;
        }
    }

    long day = 24 * 60 * 60 * 1000;

    private void showDatePickDialog() {
        CustomDatePickerDialogFragment fragment = new CustomDatePickerDialogFragment();
        fragment.setOnSelectedDateListener(this);
        Bundle bundle = new Bundle();
        Calendar currentDate = Calendar.getInstance();
        currentDate.setTimeInMillis(System.currentTimeMillis());
        currentDate.set(Calendar.HOUR_OF_DAY,0);
        currentDate.set(Calendar.MINUTE,0);
        currentDate.set(Calendar.SECOND,0);
        currentDate.set(Calendar.MILLISECOND,0);
        bundle.putSerializable(CustomDatePickerDialogFragment.CURRENT_DATE,currentDate);


        long start = currentDate.getTimeInMillis() - day * 2;
        long end = currentDate.getTimeInMillis() - day;
        Calendar startDate = Calendar.getInstance();
        startDate.setTimeInMillis(start);
        Calendar endDate = Calendar.getInstance();
        endDate.setTimeInMillis(end);
        bundle.putSerializable(CustomDatePickerDialogFragment.START_DATE,startDate);
        bundle.putSerializable(CustomDatePickerDialogFragment.END_DATE,currentDate);

        fragment.setArguments(bundle);
        fragment.show(getSupportFragmentManager(),CustomDatePickerDialogFragment.class.getSimpleName());
    }

    @Override
    public void onSelectedDate(int year, int monthOfYear, int dayOfMonth) {
        Toast.makeText(MainActivity.this,year+"年"+(monthOfYear+1)+"月"+dayOfMonth+"日",Toast.LENGTH_SHORT).show();
    }
  1. MainActivity的Layout文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="10dp" >

    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="DatePickerDialog"
        android:id="@+id/datepicker"/>

</LinearLayout>

效果截圖

  1. Jelly Bean
DatePicker效果在4.x
  1. Lollipop
DatePicker效果在5.x
  1. Marshmallow
DatePicker效果在6.0
  1. 最后再貼一張符合設(shè)計稿的效果圖
    我隱藏了頭部,并且把ZZBDatePickerDialogLStyle中的顏色值都改成了設(shè)計稿中的顏色。
datepickerfordesign在6.0+
datepickerfordesign在5.x
datepickerfordesign在4.x

可見在6.0+上效果最好。

最后

除了自己用DialogFragment封裝,系統(tǒng)還直接給提供了DatePickerDialog,可以直接以對話框的形式使用,但是這樣就不夠靈活了。

參考文章

  1. Change Datepicker dialog color for Android 5.0
  2. 【Android開源庫合集】日歷效果 - 如果需要更強大的效果,還是第三方開源庫靠譜
  3. 修改DatePicker、 NumberPicker 默認屬性(間距、分割線顏色和高度) - 這篇文章提出了用反射和getIdentifier方法獲取并修改隱藏屬性,很有啟發(fā)性。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,428評論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,024評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,285評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,548評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,328評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 54,878評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,971評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,098評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,616評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,554評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,725評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,243評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 43,971評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,361評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,613評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,339評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,695評論 2 370

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,582評論 25 707
  • ¥開啟¥ 【iAPP實現(xiàn)進入界面執(zhí)行逐一顯】 〖2017-08-25 15:22:14〗 《//首先開一個線程,因...
    小菜c閱讀 6,477評論 0 17
  • 內(nèi)容抽屜菜單ListViewWebViewSwitchButton按鈕點贊按鈕進度條TabLayout圖標下拉刷新...
    皇小弟閱讀 46,837評論 22 665
  • 分開一年之后,又重新見到你,依然是心動的感覺,我們都不優(yōu)秀,但是至少我愿意在你面前做最好的自己,你心里想的什么?我...
    哥哥521閱讀 169評論 0 0
  • 如要鍛煉一個能做大事的人,必定要叫他吃苦受累,百不稱心,才能養(yǎng)成堅韌的性格。一個人經(jīng)過不同程度的鍛煉,就獲得不同程...
    浮光掠影且于咫尺閱讀 643評論 2 1