瀑布流的标签选择器

最近需要做一个类似标签选择的功能,类似饿了么的评价页面的标签选择,没办法,项目需要,代码撸起来

先来看看实现效果:

Lable.gif

最终的效果就是上面那个样子,接下来来看看实现步骤:

既然里面是一个个的标签,那我们就先把标签做出来,我这边是直接继承 RadioButton 来实现这个标签效果的

修改 RadioButton 的样式达到我们想要的效果,代码如下:

class LableItem extends RadioButton {
        public LableItem(Context context) {
            super(context);
            initStyle();
            Click();
        }
        public LableItem(Context context, AttributeSet attrs) {
            super(context, attrs);
            initStyle();
            Click();
        }
        /**
         * 设置标签item的样式 需要修改样式 直接修改drawable文件夹下select文件即可
         */
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        public void initStyle() {
            Bitmap bitmap = null;
            setButtonDrawable(new BitmapDrawable(bitmap));
            setBackground(getResources().getDrawable(R.drawable.select));
            setTextSize(textsize);
            setTextColor(no_textcolor);
            setPadding(padding, padding, padding, padding);
            setGravity(Gravity.CENTER);
        }
}

这里我们用到了 selector 文件和两个 shape 文件来更改 RadioButton 的选中和不选中的样式

selector 代码:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:state_checked="true" android:drawable="@drawable/checked"></item>
    <item android:state_checked="false" android:drawable="@drawable/uncheck"></item>
</selector>

未选中时的 shape 代码:

<?xml version="1.0" encoding="utf-8"?>
<shape  xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="3dp"></corners>
    <solid android:color="#ffffff"></solid>
    <stroke android:color="#bdbdbd" android:width="0.5dp"></stroke>
</shape>

选中时的 shape 代码:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <corners android:radius="3dp"></corners>
    <solid android:color="#fff5e9"></solid>
    <stroke android:color="#ff8977" android:width="0.5dp"></stroke>
</shape>

这样就达到了选中和不选中时的样式改变

然后我们接着给他设置点击事件 让点击选中,再次点击取消选中:

 public void Click() {
            this.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {

                    if (select == 0) {
                        setChecked(true);
                        select = 1;
                        setTextColor(select_textcolor);
                        if (onItemSelectClick != null) {
                            onItemSelectClick.selectclick(getText().toString(), Integer.parseInt(getTag().toString()));
                        }
                    } else if (select == 1) {
                        setChecked(false);
                        select = 0;
                        setTextColor(no_textcolor);
                     
                    }
                }
            });

这样就可以让他点击选中,再次点击取消选中

这样标签我们就做好了,完整的标签代码:

class LableItem extends RadioButton {

        private int select = 0;

        public LableItem(Context context) {
            super(context);
            initStyle();
            Click();
        }

        public LableItem(Context context, AttributeSet attrs) {
            super(context, attrs);
            initStyle();
            Click();
        }

        /**
         * 设置标签item的样式 需要修改样式 直接修改drawable文件夹下select文件即可
         */
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        public void initStyle() {
            Bitmap bitmap = null;
            setButtonDrawable(new BitmapDrawable(bitmap));
            setBackground(getResources().getDrawable(R.drawable.select));
            setTextSize(textsize);
            setTextColor(no_textcolor);
            setPadding(padding, padding, padding, padding);
            setGravity(Gravity.CENTER);
        }


        public void Click() {
            this.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (!ismultiple){
                        clearSelect();
                    }

                    if (select == 0) {
                        setChecked(true);
                        select = 1;
                        setTextColor(select_textcolor);
                        if (onItemSelectClick != null) {
                            onItemSelectClick.selectclick(getText().toString(), Integer.parseInt(getTag().toString()));
                        }
                    } else if (select == 1) {
                        setChecked(false);
                        select = 0;
                        setTextColor(no_textcolor);
                        if (onCancelSelectClick != null) {
                            onCancelSelectClick.cancelselectclick(getText().toString(), Integer.parseInt(getTag().toString()));
                        }
                    }
                }
            });
        }

        /**
         * 判断是否选中
         *
         * @return
         */
        public boolean isSelect() {
            return select == 0 ? false : true;
        }

        public void setSelect(int select){
            this.select=select;
        }

    }

接下来我们开始做装这个标签的瀑布流,这边我是选择继承的 ViewGroup 然后把标签一个一个添加进去,然后进行计算排序,首先我们把要用到的自定义属性在 attrs 文件中定义好

自定义属性:

<declare-styleable name="Lable">
        <attr name="lable_textSize" format="dimension"></attr> //文字的大小
        <attr name="lable_opttextColor" format="color"></attr> //选中时文字的颜色
        <attr name="lable_notextColor" format="color"></attr> //未选中时文字的颜色
        <attr name="lable_padding" format="integer"></attr> //内边距(int型)
        <attr name="lable_margin" format="integer"></attr> //外边距(int型)
        <attr name="lable_ismultiple" format="boolean"></attr> //是否可多选 false-单选 true-多选
    </declare-styleable>

我这边的自定义属性就暂时只定义了这么多,然后我们在自定义控件里面获取一下它们:

public Lable(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.Lable);
        textsize=px2dip(typedArray.getDimensionPixelSize(R.styleable.Lable_lable_textSize,dip2px(16)));
        select_textcolor=typedArray.getColor(R.styleable.Lable_lable_opttextColor, Color.BLACK);
        no_textcolor=typedArray.getColor(R.styleable.Lable_lable_notextColor,Color.BLACK);
        padding=typedArray.getInteger(R.styleable.Lable_lable_padding,10);
        margin=typedArray.getInteger(R.styleable.Lable_lable_margin,8);
        ismultiple=typedArray.getBoolean(R.styleable.Lable_lable_ismultiple,true);
    }

接着我们把标签添加进来:

public void initLableItem() {
        if (listcount == null || listcount.size() == 0)
            return;
        for (int i = 0; i < listcount.size(); i++) {
            LableItem lableItem = new LableItem(mContext);
            lableItem.setText(listcount.get(i));
            lableItem.setTag(i + 1);
            addView(lableItem);
        }
    }

这个 listcount 就是一个 List<String> 里面装的就是标签的文字信息,有多少条内容就创建多少个标签并添加到我们的 View当中,添加完成之后,我们就要去在 onMeasure 方法中测量我们控件的宽高,在这里我们用 view.getWidth() 是获取不到我们标签的真实宽高的,获取不到,我们就无法做到瀑布流的效果,那么我们就用Paint 去获取文字宽高进行计算得到标签的真实宽高

我们先初始化一下 Paint :

public void init() {
        paint = new Paint();
        paint.setTextSize(dip2px(textsize));
        scenewidth = getScene(SCENEWIDTH);
    }

然后我们把要用到的计算封装成方法,方便以后调用

获取屏幕的宽高:

 /**
     * 获取屏幕的高宽
     *
     * @param i
     * @return
     */
    public int getScene(int i) {
        WindowManager wm = (WindowManager) getContext()
                .getSystemService(Context.WINDOW_SERVICE);
        int width = wm.getDefaultDisplay().getWidth();
        int height = wm.getDefaultDisplay().getHeight();
        if (i == SCENEWIDTH) {
            return width;
        } else if (i == SCENEHEIGHT) {
            return height;
        }
        return 0;
    }

获取标签的高度:

/**
     * 获取标签的高度
     *
     * @param paint
     * @return
     */
    public int getLableHeight(Paint paint) {
        Paint.FontMetrics fm = paint.getFontMetrics();
        return (int) Math.ceil(fm.descent - fm.ascent) + padding;
    }

获取标签的宽度:

 /**
     * 获取标签的宽度
     *
     * @param paint
     * @param str
     * @return
     */
    public int getLableWidth(Paint paint, String str) {
        int iRet = 0;
        if (str != null && str.length() > 0) {
            int len = str.length();
            float[] widths = new float[len];
            paint.getTextWidths(str, widths);
            for (int j = 0; j < len; j++) {
                iRet += (int) Math.ceil(widths[j]);
            }
        }
        return iRet + padding;
    }

因为我们后面会让他们有外边距和内边距的效果,所以把 padding 直接在这里计算了

接着我们真正的在 onMeasure 里面来测量控件的宽高:

/**
     * 控件的宽高测量
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width = 0;
        int height = getLableHeight(paint) + margin + padding;

        int widths = 0;

        if (listcount.size() == 0) {
            width = 0;
            height = 0;

        } else {
            for (int i = 0; i < listcount.size(); i++) {
                int itemWidth = getLableWidth(paint, listcount.get(i));
                if (widths + itemWidth > scenewidth) { //判断有没有换行
                    height += getLableHeight(paint) + margin + padding;
                    widths = margin;
                    isbr = false; //换行标识
                }
                if (isbr) {
                    width += itemWidth + margin;//如果没有换行 就按实际的宽度去测量
                } else {
                    width = widthSize; //只要换行了 就证明宽度是充满的
                }
                widths += itemWidth + margin;
            }
            height += margin;//在底部加上一个外边距
            if (isbr)
                width += margin;//这是为了在没有换行的情况下 最后在加上一个外边距
        }
        setMeasuredDimension(width, height);
    }

宽高测量好之后我们就要去在 onLayout 里面安排标签的位置:

/**
     * 安排摆放位置
     *
     * @param changed
     * @param l
     * @param t
     * @param r
     * @param b
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int count = getChildCount();

        int width = margin;
        int height = margin;

        if (count == 0) {
            width = 0;
            height = 0;
        }

        lableItems.clear();

        // 获取标签高度
        int itemheight = getLableHeight(paint);
        for (int i = 0; i < count; i++) {
            LableItem lableItem = (LableItem) getChildAt(i);
            lableItems.add(lableItem);
            // 获取标签宽度
            int itemWidth = getLableWidth(paint, listcount.get(i))+margin;

            if (width + itemWidth > scenewidth) { 
            //如果item的宽度加上下一个item的宽度大于屏幕宽度的话 那么这个时候就要换行了
                height += itemheight + margin + padding;
                width = margin;
            }
            lableItem.layout(width, height, width + itemWidth, height + itemheight + padding);
            width += itemWidth + margin;
        }
    }

这样就实现了瀑布流的效果,然后我们再给他加上一些供使用者调用的方法:

获取选中的内容字符串:

 public List<String> getSelectContent() {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < lableItems.size(); i++) {
            if (lableItems.get(i).isSelect()) {
                list.add(lableItems.get(i).getText().toString());
            }
        }
        return list;
    }

取消全部选中:

 public void clearSelect(){

       for (int i=0;i<getChildCount();i++){
           LableItem lableItem= (LableItem) getChildAt(i);
           if (lableItem.isSelect()){
               lableItem.setChecked(false);
               lableItem.setTextColor(no_textcolor);
               lableItem.setSelect(0);
               if (onCancelAllSelectListener!=null){
                   onCancelAllSelectListener.cancelalllistener();
               }
           }
       }
    }

然后添加对外部使用的点击事件的回调等,就大功告成了!

全部代码如下:

package com.example.yinshuai.thelabel;

import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.RadioButton;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

/**
 * Created by 尹帅 on 2017/8/7.
 *
 * 瀑布流的标签选择
 *
 * 作者:尹帅 1317972280@qq.com
 */
public class Lable extends ViewGroup {
    private final static int SCENEWIDTH = 1;
    private final static int SCENEHEIGHT = 2;
    private float textsize = 0;
    private int select_textcolor=0;
    private int no_textcolor=0;
    private int padding = 0;
    private int margin = 0;
    private boolean ismultiple=true;

    private int scenewidth;
    private boolean isbr = true;
    private Paint paint;
    private List<String> listcount = new ArrayList<>();
    private Context mContext;
    private List<LableItem> lableItems = new ArrayList<>();

    public OnItemSelectClickListener onItemSelectClick;
    public OnCancelSelectClickListener onCancelSelectClick;
    public OnCancelAllSelectListener onCancelAllSelectListener;

    public Lable(Context context) {
        super(context);
        mContext = context;
        init();
    }

    public Lable(Context context, AttributeSet attrs) {
        super(context, attrs);
        mContext = context;

        TypedArray typedArray=context.obtainStyledAttributes(attrs,R.styleable.Lable);
        textsize=px2dip(typedArray.getDimensionPixelSize(R.styleable.Lable_lable_textSize,dip2px(16)));
        select_textcolor=typedArray.getColor(R.styleable.Lable_lable_opttextColor, Color.BLACK);
        no_textcolor=typedArray.getColor(R.styleable.Lable_lable_notextColor,Color.BLACK);
        padding=typedArray.getInteger(R.styleable.Lable_lable_padding,10);
        margin=typedArray.getInteger(R.styleable.Lable_lable_margin,8);
        ismultiple=typedArray.getBoolean(R.styleable.Lable_lable_ismultiple,true);
        init();
    }

    /**
     * 对外提供选中监听的接口
     */
    public interface OnItemSelectClickListener {
        void selectclick(String text, int position);
    }

    public void setOnItemSelectClickListener(OnItemSelectClickListener onItemClick) {
        this.onItemSelectClick = onItemClick;
    }

    /**
     * 对外提供取消item选中的接口
     */
    public interface OnCancelSelectClickListener {
        void cancelselectclick(String text, int position);
    }

    public void setOnCancelSelectClickListener(OnCancelSelectClickListener onCancelSelectClick) {
        this.onCancelSelectClick = onCancelSelectClick;
    }

    public interface OnCancelAllSelectListener{
        void cancelalllistener();
    }

    public void setOnCancelAllSelectListener(OnCancelAllSelectListener l){
         onCancelAllSelectListener=l;
    }

    /**
     * 初始化
     */
    public void initLableItem() {
        if (listcount == null || listcount.size() == 0)
            return;
        for (int i = 0; i < listcount.size(); i++) {
            LableItem lableItem = new LableItem(mContext);
            lableItem.setText(listcount.get(i));
            lableItem.setTag(i + 1);
            addView(lableItem);
        }
    }

    public void init() {
        paint = new Paint();
        paint.setTextSize(dip2px(textsize));
        scenewidth = getScene(SCENEWIDTH);
    }

    /**
     * 设置数据
     * @param data
     */
    public void setDataList(List<String> data) {
        this.listcount.addAll(data);
        initLableItem();
    }

    /**
     * 控件的宽高测量
     *
     * @param widthMeasureSpec
     * @param heightMeasureSpec
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(heightMeasureSpec);

        int width = 0;
        int height = getLableHeight(paint) + margin + padding;

        int widths = 0;

        if (listcount.size() == 0) {
            width = 0;
            height = 0;

        } else {
            for (int i = 0; i < listcount.size(); i++) {
                int itemWidth = getLableWidth(paint, listcount.get(i));
                if (widths + itemWidth > scenewidth) { //判断有没有换行
                    height += getLableHeight(paint) + margin + padding;
                    widths = margin;
                    isbr = false; //换行标识
                }
                if (isbr) {
                    width += itemWidth + margin;//如果没有换行 就按实际的宽度去测量
                } else {
                    width = widthSize; //只要换行了 就证明宽度是充满的
                }
                widths += itemWidth + margin;
            }
            height += margin;//在底部加上一个外边距
            if (isbr)
                width += margin;//这是为了在没有换行的情况下 最后在加上一个外边距
        }
        setMeasuredDimension(width, height);
    }

    /**
     * 安排摆放位置
     *
     * @param changed
     * @param l
     * @param t
     * @param r
     * @param b
     */
    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int count = getChildCount();

        int width = margin;
        int height = margin;

        if (count == 0) {
            width = 0;
            height = 0;
        }

        lableItems.clear();

        // 获取标签高度
        int itemheight = getLableHeight(paint);
        for (int i = 0; i < count; i++) {
            LableItem lableItem = (LableItem) getChildAt(i);
            lableItems.add(lableItem);
            // 获取标签宽度
            int itemWidth = getLableWidth(paint, listcount.get(i))+margin;

            if (width + itemWidth > scenewidth) { //如果item的宽度加上下一个item的宽度大于屏幕宽度的话 那么这个时候就要换行了
                height += itemheight + margin + padding;
                width = margin;
            }
            lableItem.layout(width, height, width + itemWidth, height + itemheight + padding);
            width += itemWidth + margin;
        }
    }


    /**
     * 获取选中的内容字符串
     */
    public List<String> getSelectContent() {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < lableItems.size(); i++) {
            if (lableItems.get(i).isSelect()) {
                list.add(lableItems.get(i).getText().toString());
            }
        }
        return list;
    }

    /**
     * 取消全部选中
     */
    public void clearSelect(){

       for (int i=0;i<getChildCount();i++){
           LableItem lableItem= (LableItem) getChildAt(i);
           if (lableItem.isSelect()){
               lableItem.setChecked(false);
               lableItem.setTextColor(no_textcolor);
               lableItem.setSelect(0);
               if (onCancelAllSelectListener!=null){
                   onCancelAllSelectListener.cancelalllistener();
               }
           }
       }
    }

    /**
     * 获取标签的高度
     *
     * @param paint
     * @return
     */
    public int getLableHeight(Paint paint) {
        Paint.FontMetrics fm = paint.getFontMetrics();
        return (int) Math.ceil(fm.descent - fm.ascent) + padding;
    }

    /**
     * 获取标签的宽度
     *
     * @param paint
     * @param str
     * @return
     */
    public int getLableWidth(Paint paint, String str) {
        int iRet = 0;
        if (str != null && str.length() > 0) {
            int len = str.length();
            float[] widths = new float[len];
            paint.getTextWidths(str, widths);
            for (int j = 0; j < len; j++) {
                iRet += (int) Math.ceil(widths[j]);
            }
        }
        return iRet + padding;
    }


    /**
     * 标签的Item
     */
    class LableItem extends RadioButton {

        private int select = 0;

        public LableItem(Context context) {
            super(context);
            initStyle();
            Click();
        }

        public LableItem(Context context, AttributeSet attrs) {
            super(context, attrs);
            initStyle();
            Click();
        }

        /**
         * 设置标签item的样式 需要修改样式 直接修改drawable文件夹下select文件即可
         */
        @TargetApi(Build.VERSION_CODES.JELLY_BEAN)
        public void initStyle() {
            Bitmap bitmap = null;
            setButtonDrawable(new BitmapDrawable(bitmap));
            setBackground(getResources().getDrawable(R.drawable.select));
            setTextSize(textsize);
            setTextColor(no_textcolor);
            setPadding(padding, padding, padding, padding);
            setGravity(Gravity.CENTER);
        }


        public void Click() {
            this.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (!ismultiple){
                        clearSelect();
                    }

                    if (select == 0) {
                        setChecked(true);
                        select = 1;
                        setTextColor(select_textcolor);
                        if (onItemSelectClick != null) {
                            onItemSelectClick.selectclick(getText().toString(), Integer.parseInt(getTag().toString()));
                        }
                    } else if (select == 1) {
                        setChecked(false);
                        select = 0;
                        setTextColor(no_textcolor);
                        if (onCancelSelectClick != null) {
                            onCancelSelectClick.cancelselectclick(getText().toString(), Integer.parseInt(getTag().toString()));
                        }
                    }
                }
            });
        }

        /**
         * 判断是否选中
         *
         * @return
         */
        public boolean isSelect() {
            return select == 0 ? false : true;
        }

        public void setSelect(int select){
            this.select=select;
        }

    }


    /**
     * 获取屏幕的高宽
     *
     * @param i
     * @return
     */
    public int getScene(int i) {
        WindowManager wm = (WindowManager) getContext()
                .getSystemService(Context.WINDOW_SERVICE);
        int width = wm.getDefaultDisplay().getWidth();
        int height = wm.getDefaultDisplay().getHeight();
        if (i == SCENEWIDTH) {
            return width;
        } else if (i == SCENEHEIGHT) {
            return height;
        }
        return 0;
    }


    /**
     * dp-->px
     *
     * @param dipValue
     * @return
     */
    private int dip2px(float dipValue) {
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    /**
     * sp转px
     *
     * @return
     */

    public int sp2px(float spVal) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, spVal, mContext.getResources().getDisplayMetrics());
    }

    /**
     * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
     */
    public int px2dip( float pxValue) {
        final float scale = mContext.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

    /**
     * 将px值转换为sp值,保证文字大小不变
     *
     * @param pxValue
     * @return
     */
    public  int px2sp( float pxValue) {
        final float fontScale = mContext.getResources().getDisplayMetrics().scaledDensity;
        return (int) (pxValue / fontScale + 0.5f);
    }
}

项目 GitHub 地址:Lable
个人博客:小白的博客

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

推荐阅读更多精彩内容