Dialog 辅助工具

1. DialogHelper

这不是一个自定义的Dialog,而是一个Helper,一开始想这个Helper的目的侧重于配置组装Dialog,而尽量少的改变Dialog属性

项目中一共有10几个不同布局的Dialog,里面输入、点击、选择不同的事件都有,想要使用一个Dialog来满足所有的需求比较麻烦,一开始考虑的是写一个BaseDialog,之后根据各个Dialog来继承实现,然而还要写不同事件的接口回调,觉得继承BaseDialg也比较麻烦,想着写一个简单能满足基础需求类似Utils的东西

一开始考虑使用Builder的方式比较好

网上搜索时,看到利用建造者模式封装一个简单好用的dialog,但这个虽然标题写的叫建造者,但代码用的是单例,个人感觉使用单例不怎么合适,借鉴思路自己整理出来一个

希望各位同学能给出一些更好的思路

public final class DialogHelper {
    private final Builder mBuilder;

    private HummerDialogFragment mDialogFragment;

    /** Fragment Tag */
    private final String mTag;

    private DialogHelper(Builder builder) {
        this.mBuilder = builder;
        this.mTag = builder.tag;
    }

    public void show(@NonNull LifecycleOwner owner, @NonNull FragmentManager manager) {
        Lifecycle.State currentState = owner.getLifecycle().getCurrentState();
        if (currentState == Lifecycle.State.DESTROYED) {
            Log.d("DialogHelper", "--> owner State is DESTROYED");
            return;
        }

        if (mDialogFragment == null) {
            mDialogFragment = HummerDialogFragment.newInstance(mBuilder);
        }

        mDialogFragment.show(manager, mTag);
    }

    public void dismiss() {
        if (mDialogFragment != null && mDialogFragment.getDialog().isShowing()) {
            mDialogFragment.dismiss();
        }
    }

    public static Builder myBuilder() {
        return new Builder();
    }

    public static class Builder implements Parcelable {
        /** 布局 ID */
        private int mLayoutId;

        /** 弹窗 Gravity 值 : 默认为 CENTER */
        private int mGravity = Gravity.CENTER;

        /** padding 值 : Left,Right 默认 15 dp */
        private int mPaddingTop;
        private int mPaddingBottom;
        private int mPaddingRight = 15;
        private int mPaddingLeft = 15;

        /** 是否可以取消 */
        private boolean mCancelable = true;

        /** 点击外部是否可以消失 */
        private boolean mOutCancelable = true;

        /** 改变 View  内容 */
        private List<Integer> mViewIdList;
        private SparseArray<OnSetViewContentCallback> mArrayContentCallback;

        /** 点击事件 */
        private List<Integer> mClickViewIdList;
        private SparseArray<OnViewClickListener> mArrayPositiveClickListener;

        /** 点击事件是否需要自动消失 : 默认 true */
        private boolean mAutoDismissAble = true;

        /** Fragment Tag */
        private String tag = Builder.class.getSimpleName();

        /** 背景透明度 */
        private float alpha = 0.5F;

        /** Dialog 的 height : WRAP_CONTENT or MATCH_PARENT */
        private int layoutParams = WindowManager.LayoutParams.WRAP_CONTENT;

        private Builder() {
        }

        /** 布局 ID */
        public Builder layoutResId(@LayoutRes int layoutId) {
            this.mLayoutId = layoutId;
            return this;
        }

        int getLayoutId() {
            return mLayoutId;
        }

        /** 位置 */
        public Builder gravity(int gravity) {
            this.mGravity = gravity;
            return this;
        }

        public int getGravity() {
            return mGravity;
        }

        /** 内边距 */
        public Builder padding(int padding) {
            left(padding);
            top(padding);
            right(padding);
            bottom(padding);
            return this;
        }

        /** Top , Bottom 内边距 */
        public Builder topAndBottom(int padding) {
            this.mPaddingTop = padding;
            this.mPaddingBottom = padding;
            return this;
        }

        /** Top , Bottom 内边距 */
        public Builder leftAndRight(int padding) {
            this.mPaddingTop = padding;
            this.mPaddingBottom = padding;
            return this;
        }

        /** Top 内边距 */
        Builder top(int paddingTop) {
            this.mPaddingTop = paddingTop;
            return this;
        }

        int getTop() {
            return mPaddingTop;
        }

        /** Left 内边距 */
        public Builder left(int paddingLeft) {
            this.mPaddingLeft = paddingLeft;
            return this;
        }

        public int left() {
            return mPaddingLeft;
        }

        int getBottom() {
            return mPaddingBottom;
        }

        /** Bottom 内边距 */
        public Builder bottom(int paddingBottom) {
            this.mPaddingBottom = paddingBottom;
            return this;
        }

        public int getRight() {
            return mPaddingRight;
        }

        /** Right 内边距 */
        public Builder right(int paddingRight) {
            this.mPaddingRight = paddingRight;
            return this;
        }

        /** 设置 back 键是否可以取消 */
        public Builder cancelable(boolean cancelable) {
            this.mCancelable = cancelable;
            return this;
        }

        boolean isCancelable() {
            return mCancelable;
        }

        /** 点击外部是否可以取消 */
        public Builder outCancelable(boolean outCancelable) {
            this.mOutCancelable = outCancelable;
            return this;
        }

        boolean isOutCancelable() {
            return mOutCancelable;
        }


        /** 根据 id,设置控件内容 */
        public <T> Builder widget(@IdRes int id,
                                  @NonNull OnSetViewContentCallback<T> onSetViewContentCallback) {
            if (mViewIdList == null) {
                mViewIdList = new ArrayList<>();
            }
            // 防止重复添加
            if (mViewIdList.contains(id)) {
                return this;
            }
            mViewIdList.add(id);
            if (mArrayContentCallback == null) {
                mArrayContentCallback = new SparseArray<>();
            }
            this.mArrayContentCallback.put(id, onSetViewContentCallback);
            return this;
        }

        SparseArray<OnSetViewContentCallback> getArrayContentCallback() {
            return mArrayContentCallback;
        }

        /** 点击取消事件 */
        public Builder onCancelClick(@IdRes int id) {
            if (mClickViewIdList == null) {
                mClickViewIdList = new ArrayList<>();
            }
            // 过滤
            if (mClickViewIdList.contains(id)) {
                return this;
            }
            mClickViewIdList.add(id);
            return this;
        }

        List<Integer> getClickViewIdList() {
            return mClickViewIdList;
        }

        /** 点击事件 */
        public Builder onPositiveClick(@IdRes int id,
                                       @NonNull OnViewClickListener onViewClickListener) {
            if (mClickViewIdList == null) {
                mClickViewIdList = new ArrayList<>();
            }
            // 防止重复添加
            if (mClickViewIdList.contains(id)) {
                return this;
            }
            mClickViewIdList.add(id);
            if (mArrayPositiveClickListener == null) {
                mArrayPositiveClickListener = new SparseArray<>();
            }
            this.mArrayPositiveClickListener.put(id, onViewClickListener);
            return this;
        }

        List<Integer> getViewIdList() {
            return mViewIdList;
        }

        SparseArray<OnViewClickListener> getArrayPositiveClickListener() {
            return mArrayPositiveClickListener;
        }

        /** 点击时,是否自动关闭 */
        public Builder autoDismissOnClick(boolean auto) {
            this.mAutoDismissAble = auto;
            return this;
        }

        boolean isAutoDismissAble() {
            return mAutoDismissAble;
        }

        public String getTag() {
            return tag;
        }

        public Builder tag(String tag) {
            this.tag = tag;
            return this;
        }

        /** 背景透明度 */
        public Builder alpha(float alpha) {
            this.alpha = alpha;
            return this;
        }

        public float getAlpha() {
            return alpha;
        }

        public int getHeightLayoutParams() {
            return layoutParams;
        }

        /** 背景高度 */
        public Builder heightLayoutParams(int layoutParams) {
            this.layoutParams = layoutParams;
            return this;
        }

        public DialogHelper build() {
            return new DialogHelper(this);
        }

        @Override
        public int describeContents() {
            return 0;
        }

        @SuppressWarnings("unchecked")
        @Override
        public void writeToParcel(Parcel dest, int flags) {
            dest.writeInt(this.mLayoutId);
            dest.writeInt(this.mGravity);
            dest.writeInt(this.mPaddingTop);
            dest.writeInt(this.mPaddingBottom);
            dest.writeInt(this.mPaddingRight);
            dest.writeInt(this.mPaddingLeft);
            dest.writeByte(this.mCancelable ? (byte) 1 : (byte) 0);
            dest.writeByte(this.mOutCancelable ? (byte) 1 : (byte) 0);
            dest.writeList(this.mViewIdList);
            dest.writeSparseArray((SparseArray) this.mArrayContentCallback);
            dest.writeList(this.mClickViewIdList);
            dest.writeSparseArray((SparseArray) this.mArrayPositiveClickListener);
            dest.writeByte(this.mAutoDismissAble ? (byte) 1 : (byte) 0);
            dest.writeString(this.tag);
            dest.writeFloat(this.alpha);
            dest.writeInt(this.layoutParams);
        }

        @SuppressWarnings("unchecked")
        protected Builder(Parcel in) {
            this.mLayoutId = in.readInt();
            this.mGravity = in.readInt();
            this.mPaddingTop = in.readInt();
            this.mPaddingBottom = in.readInt();
            this.mPaddingRight = in.readInt();
            this.mPaddingLeft = in.readInt();
            this.mCancelable = in.readByte() != 0;
            this.mOutCancelable = in.readByte() != 0;
            this.mViewIdList = new ArrayList<Integer>();
            in.readList(this.mViewIdList, Integer.class.getClassLoader());
            this.mArrayContentCallback =
                    in.readSparseArray(OnSetViewContentCallback.class.getClassLoader());
            this.mClickViewIdList = new ArrayList<Integer>();
            in.readList(this.mClickViewIdList, Integer.class.getClassLoader());
            this.mArrayPositiveClickListener =
                    in.readSparseArray(OnViewClickListener.class.getClassLoader());
            this.mAutoDismissAble = in.readByte() != 0;
            this.tag = in.readString();
            this.alpha = in.readFloat();
            this.layoutParams = in.readInt();
        }

        public static final Parcelable.Creator<Builder>
                CREATOR = new Parcelable.Creator<Builder>() {
            @Override
            public Builder createFromParcel(Parcel source) {
                return new Builder(source);
            }

            @Override
            public Builder[] newArray(int size) {
                return new Builder[size];
            }
        };
    }

    /** 改变 View 内容 */
    public interface OnSetViewContentCallback<T> {
        /**
         * View 内容
         *
         * @param v widget
         */
        void setViewContent(T v);
    }

    /** 点击监听 : dialog 用来获取内部控件用,findViewById() */
    public interface OnViewClickListener {
        /**
         * View 点击
         *
         * @param dialog 弹窗
         */
        void setPositiveClick(Dialog dialog);
    }
}

HummerDialogFragment

public class HummerDialogFragment extends DialogFragment {
    private static final String BUNDLE_KEY = "Builder";
    @LayoutRes
    private int mLayoutId;
    private int mGravity;
    private int mPaddingTop;
    private int mPaddingBottom;
    private int mPaddingRight;
    private int mPaddingLeft;
    private boolean mCancelable;
    private boolean mOutCancelable;
    private float mAlpha;
    private Context mContext;
    private SparseArray<View> mViewSparseArray;
    private List<Integer> mViewIdList;
    private SparseArray<DialogHelper.OnSetViewContentCallback> mArrayContentCallback;
    private List<Integer> mClickViewIdList;
    private SparseArray<DialogHelper.OnViewClickListener> mArrayPositiveClickListener;
    private boolean mAutoDismissAble;
    private int mHeightLayoutParams = WindowManager.LayoutParams.WRAP_CONTENT;

    public static HummerDialogFragment newInstance(@NonNull DialogHelper.Builder builder) {
        Bundle args = new Bundle();
        HummerDialogFragment fragment = new HummerDialogFragment();
        args.putParcelable(BUNDLE_KEY, builder);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        this.mContext = context;
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 设置样式
        setStyle(DialogFragment.STYLE_NO_TITLE, R.style.HummerDialogStyle);

        init();
    }

    private void init() {
        Bundle arguments = getArguments();
        if (arguments == null) {
            return;
        }
        DialogHelper.Builder builder = arguments.getParcelable(BUNDLE_KEY);
        if (builder == null) {
            return;
        }
        mLayoutId = builder.getLayoutId();
        mGravity = builder.getGravity();
        mPaddingTop = builder.getTop();
        mPaddingLeft = builder.left();
        mPaddingBottom = builder.getBottom();
        mPaddingRight = builder.getRight();
        mCancelable = builder.isCancelable();
        mOutCancelable = builder.isOutCancelable();
        mViewIdList = builder.getViewIdList();
        mArrayContentCallback = builder.getArrayContentCallback();
        mClickViewIdList = builder.getClickViewIdList();
        mArrayPositiveClickListener = builder.getArrayPositiveClickListener();
        mAutoDismissAble = builder.isAutoDismissAble();
        mAlpha = builder.getAlpha();
        mHeightLayoutParams = builder.getHeightLayoutParams();
    }

    /** 为了兼容性更好,在 onActivityCreated() 进行设置 setContentView() */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        Dialog dialog = getDialog();
        // 点击消失
        dialog.setCancelable(mCancelable);
        dialog.setCanceledOnTouchOutside(mOutCancelable);
        // 直接使用 layoutId 填充
        dialog.setContentView(mLayoutId);
        // window
        initWindow(dialog);
        // 监听
        initSetContentCallback(dialog);
        initClickListener(dialog);
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        clean();
    }

    /** Window 配置 */
    private void initWindow(Dialog dialog) {
        final Window window = dialog.getWindow();
        if (window == null) {
            return;
        }
        // 背景透明度 0 - 1F
        window.setDimAmount(mAlpha);
        window.setGravity(mGravity);
        window.getDecorView().setPadding(dp2Pix(mPaddingLeft)
                , dp2Pix(mPaddingTop), dp2Pix(mPaddingRight), dp2Pix(mPaddingBottom));
        // mHeightLayoutParams,根据布局确定。默认使用 WRAP_CONTENT
        window.setLayout(WindowManager.LayoutParams.MATCH_PARENT, mHeightLayoutParams);
    }

    /** 点击监听 */
    private void initClickListener(Dialog dialog) {
        if (mClickViewIdList == null) {
            return;
        }
        for (int id : mClickViewIdList) {
            View view = getViewById(dialog, id);
            if (view == null) {
                throw new NullPointerException("点击回调, 内部 View 没有找到");
            }
            view.setOnClickListener(v -> {
                // 是否自动 dismiss
                boolean isAutoDis = mAutoDismissAble || (mArrayPositiveClickListener == null) ||
                        (mArrayPositiveClickListener.get(id) == null);
                if (isAutoDis) {
                    // 当 mArrayPositiveClickListener == null
                    // mArrayPositiveClickListener.get(id) 为 null,说明当前 id 为点击取消事件
                    dismiss();
                }
                if (mArrayPositiveClickListener != null
                        && mArrayPositiveClickListener.get(id) != null) {
                    mArrayPositiveClickListener.get(id).setPositiveClick(dialog);
                }
            });
        }
    }

    /** 设置View 内容 */
    @SuppressWarnings("unchecked")
    private void initSetContentCallback(Dialog dialog) {
        if (mViewIdList == null || mArrayContentCallback == null) {
            return;
        }
        for (int id : mViewIdList) {
            View view = getViewById(dialog, id);
            if (view == null) {
                throw new NullPointerException("设置 View 内容, 内部 View 没有找到");
            }
            mArrayContentCallback.get(id).setViewContent(view);
        }
    }

    /**
     * 根据 id 获取 widget
     *
     * @param id id
     * @return widget
     */
    private View getViewById(Dialog dialog, int id) {
        if (mViewSparseArray == null) {
            mViewSparseArray = new SparseArray<>();
        }
        View view = mViewSparseArray.get(id);
        if (view == null) {
            view = dialog.findViewById(id);
            mViewSparseArray.put(id, view);
        }
        return view;
    }

    /** 请空集合 */
    private void clean() {
        if (mViewSparseArray != null) {
            mViewSparseArray.clear();
        }

        if (mViewIdList != null) {
            mViewIdList.clear();
        }

        if (mArrayContentCallback != null) {
            mArrayContentCallback.clear();
        }

        if (mClickViewIdList != null) {
            mClickViewIdList.clear();
        }

        if (mArrayPositiveClickListener != null) {
            mArrayPositiveClickListener.clear();
        }
    }

    /** dp 转为 pix */
    private int dp2Pix(int dp) {
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }
}

HummerDialogStyle

    <style name="HummerDialogStyle" parent="@android:style/Theme.Holo.Light.Dialog">
        <!-- 窗口背景色 -->
        <item name="android:windowBackground">@android:color/transparent</item>
        <!--是否有覆盖-->
        <item name="android:windowContentOverlay">@null</item>
        <!-- 浮于Activity之上 -->
        <item name="android:windowIsFloating">true</item>
        <!-- 边框 -->
        <item name="android:windowFrame">@null</item>
        <!-- Dialog以外的区域模糊效果 -->
        <item name="android:backgroundDimEnabled">true</item>
        <!-- 无标题 -->
        <item name="android:windowNoTitle">true</item>
        <!-- 半透明 -->
        <item name="android:windowIsTranslucent">true</item>
        <!--进出动画-->
        <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
    </style>

2. 用法

dialog.png

2.1 布局

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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="180dp"
    android:background="@color/lighter_gray">

    <TextView
        android:id="@+id/dialog_help_tv_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="@string/dialog_helper_name"
        android:textColor="@color/colorPrimary"
        android:textSize="16sp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/dialog_help_tv_cancel"
        android:layout_width="100dp"
        android:layout_height="44dp"
        android:background="@color/colorPrimary"
        android:gravity="center"
        android:text="@string/button_cancel"
        android:textColor="@color/write"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.3"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/dialog_help_tv_ok"
        android:layout_width="100dp"
        android:layout_height="44dp"
        android:background="@color/colorAccent"
        android:gravity="center"
        android:text="@string/button_ok"
        android:textColor="@color/write"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.8"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/dialog_help_tv_msg"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:text="@string/dialog_helper_name"
        android:textColor="@color/colorPrimary"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>

就四个TextView


2.2 代码

private void showDialog() {
       DialogHelper.myBuilder()
                .tag("Hummer")
                .layoutResId(R.layout.dialog_help_layout) // 布局
                .cancelable(false) // back 是否消失
                .outCancelable(false) // 点击外部是否消失
                .left(0) // 屏幕左边距
                .right(0) // 屏幕右边距
                .bottom(40) // 屏幕底部边距
                .alpha(0.6F) // 透明度
                .gravity(Gravity.BOTTOM) // 位于底部
                .<TextView>widget(R.id.dialog_help_tv_title, tv -> {
                    // 用于改变内部控件内容
                    String title = "20180901 15:17";
                    tv.setText(title);
                })
                .onCancelClick(R.id.dialog_help_tv_cancel) // 点击取消 Dialog
                .onCancelClick(R.id.dialog_help_tv_cancel) // 点击取消 Dialog,测试重复添加
                .onCancelClick(R.id.dialog_help_tv_title) // 点击取消 Dialog
                .autoDismissOnClick(false) // 点击确定事件,是否消失
                .onPositiveClick(R.id.dialog_help_tv_ok, dialog -> {
                    // 点击时,可以通过Dialog.findViewById 来获取控件
                    TextView tvTitle = dialog.findViewById(R.id.dialog_help_tv_msg);
                    String msg = tvTitle.getText().toString();
                    ToastUtils.showShort(msg);
                })
                 .heightLayoutParams(WindowManager.LayoutParams.MATCH_PARENT) // 大部分情况下默认使用 WRAP_CONTENT,必要时修改
                .build()
                .show(getSupportFragmentManager());
    }

两个月来,身体不好,有个感触:

生活终究还是要讲究些的,讲究些,养成好习惯

尽量不把钱花在看病上,一定要注意身体

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • Day1: 在代码中通过R.string.hello_world可以获得该字符串的引用; 在XML中通过@stri...
    冰凝雪国阅读 1,357评论 0 5
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,204评论 0 17
  • 以失忆为主题的电影有很多,大部分都是女主得了类似阿尔茨海默症等会丧失记忆的病之后,男主依旧不离不弃的剧情。印象比较...
    Limyar阅读 353评论 0 1
  • 前几天在跟我的论文指导老师交流取经的时候,她提到了经济学发展一些误区,我很赞同,也希望有机会能发表一下我一直以来的...
    AlexNG吴瀚阅读 475评论 0 2