Android高级UI--四色填充地图

先上效果图


image.png

明显是一个自定义view,先解析svg资源(该资源不严谨,请勿在正规),获取每个省的path,再用四色算法设置每个省的颜色
先列举主要方法解析svg文件

 InputStream inputStream = context.getResources().openRawResource(R.raw.china);
            proviceItems = new ArrayList<>();
            try {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = null;
                builder = factory.newDocumentBuilder();
                Document document = builder.parse(inputStream);
                Element rootElement = document.getDocumentElement();
                NodeList items = rootElement.getElementsByTagName("path");

items就是每个省份的边框了,遍历全部省份确定地图的最左最右最上最下,从而确定地图的真正宽高,然后再对比自定义View的宽度,确定画图的缩放比例,再定义自定义View的高度

           @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        if (totalRect != null && width != 0) {
            //获取到地图的矩形的宽度
            double mapWidth = totalRect.width();
            //获取到比例值
            scale = (float) (width / mapWidth);
            //用宽度重新定义高度
            heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (totalRect.height() * scale), MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec,heightMeasureSpec);

    }

重写onDraw方法,把每个省依次华进去,如果有点击事件,被点击有变化的话,多数情况下都是要最后一个话

   @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (proviceItems != null) {
            int tatalNum = proviceItems.size();
            canvas.save();
            canvas.scale(scale, scale);
            ProviceItem selsetProviceItem = null;
            // 先画没被选中的
            for (int i = 0; i < tatalNum; i++) {
                if (!proviceItems.get(i).isSelect()) {
                    proviceItems.get(i).drawItem(canvas, paint);
                } else {
                    selsetProviceItem = proviceItems.get(i);
                }
            }
            //被选中的最后画,因为被选中的有阴影
            if (selsetProviceItem != null) {
                selsetProviceItem.drawItem(canvas, paint);
            }
        }
    }

把每个省都画到地图上的方法

 paint.setStrokeWidth(1);
        paint.setColor(drawColor);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(path, paint);
        if (isSelect) {
            //被选择设置一下阴影
            paint.setShadowLayer(20, 0, 0, Color.WHITE);
        } else {
            //没选中去掉阴影
            paint.clearShadowLayer();
        }
        canvas.drawPath(path, paint);

接下来就是关于颜色的选择问题了,写一个获得颜色的工具类,主要参数和构造方法

    //存放颜色种类,并非真正的颜色
    private int[] colorTypes;
    //板块接壤矩阵,1为接壤
    private int[][] isBorder;
    //准备填充的颜色列表
    private int[] colors;
    //颜色多少种类
    private int TYPE_SIZE ;
    //总共有几个板块
    private int plateCount;

    public ColorFillUtil(int[][] isBorder, int[] colors) throws Exception{
        plateCount = isBorder.length;
        if (plateCount != isBorder[0].length) {//板块相邻关系必须是方阵,不能是矩阵
            throw new Exception("colors's length must be equal to isBorder's length!");
        }
        this.colors = colors;
        TYPE_SIZE = colors.length;
        this.isBorder = isBorder;
    }

思路就是从第一个省份开始慢慢尝试填充颜色,尝试方法就是从可选的颜色种类中,依次填充进去,然后再判断是否和已经填充的身份,是否有接壤并且同个颜色的,如果有就换一个颜色,如果最后每个颜色都尝试了还是不行就说明上一个板块填充有误,要回退到上个板块,如果上板块还是不行再回退,最后直到每个板块都设置好颜色,颜色种类如果小于4可能会填充失败。详细见后面代码

以下是自定义省份的been

import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Region;
import android.util.Log;


/**
 * Create by XieJunFeng on 2019/12/4.
 */
public class ProviceItem {
    private int index;
    private Path path;
    //省份颜色
    private int drawColor;
    //是否被点击
    private boolean isSelect;

    public ProviceItem(Path path) {
        this.path = path;
    }

    public void setDrawColor(int drawColor) {
        this.drawColor = drawColor;
    }


    public void setIndex(int index) {
        this.index = index;
    }

    public boolean isSelect() {
        return isSelect;
    }

    public void setSelect(boolean select) {
        isSelect = select;
    }

    public void drawItem(Canvas canvas, Paint paint) {
        paint.setStrokeWidth(1);
        paint.setColor(drawColor);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        canvas.drawPath(path, paint);
        if (isSelect) {
            //被选择设置一下阴影
            paint.setShadowLayer(20, 0, 0, Color.WHITE);
        } else {
            //没选中去掉阴影
            paint.clearShadowLayer();
        }
        canvas.drawPath(path, paint);
    }

    public boolean isTouch(float x, float y) {
        //创建一个矩形
        RectF rectF = new RectF();
        //获取到当前省份的矩形边界
        path.computeBounds(rectF, true);
        //创建一个区域对象
        Region region = new Region();
        //将path对象放入到Region区域对象中
        region.setPath(path, new Region((int) rectF.left, (int) rectF.top, (int) rectF.right, (int) rectF.bottom));
        //返回是否这个区域包含传进来的坐标
        boolean resule = region.contains((int) x, (int) y);
        //无法通过代码确定两个省份是否接壤所以只能获取下标,人工构造省份相邻矩阵,如果
      //  if (result) {
      //      Log.d("ProviceItemIndex-----", index + "");
       // }
        return result;
    }

}

自定义view的代码

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

/**
 * Create by XieJunFeng on 2019/12/4.
 */
public class MapView extends View {
    private Paint paint;
    private Context context;
    //整个地图所占用的矩形,在重新设配之前
    private RectF totalRect;
    private List<ProviceItem> proviceItems;
    //绘制地图的颜色
    private int[] colorArray = new int[]{0xFF1383f2, 0xFFFFDC00, 0xFFFF3D33, 0xFF4ADE8C};
    //适配比例
    private float scale = 0;
    int[] colors;
    //中国省份接壤关系矩阵,划分34个省份,自治区,市和特别行政区等,但是多一个颜色表示国外的颜色项目中最后没有用到
    int[][] isBorder = {
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1},
            {0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},

            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1},

            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},

            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},

            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0},

            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},

            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
            {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},


    };

    public MapView(Context context) {
        super(context);
    }

    public MapView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }


    public MapView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    private void init(Context context) {
        this.context = context;
        paint = new Paint();
        paint.setAntiAlias(true);
        //开线程解析数据
        loadThread.start();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        if (totalRect != null && width != 0) {
            //获取到地图的矩形的宽度
            double mapWidth = totalRect.width();
            //获取到比例值
            scale = (float) (width / mapWidth);
            //用宽度重新定义高度
            heightMeasureSpec = MeasureSpec.makeMeasureSpec((int) (totalRect.height() * scale), MeasureSpec.EXACTLY);
        }
        super.onMeasure(widthMeasureSpec,heightMeasureSpec);

    }

    @Override
    protected void onDraw(Canvas canvas) {
        //如果省份数据还没加载出来,实际缩放比例没定义出来啥都不用干
        if (proviceItems != null||scale==0) {
            super.onDraw(canvas);
            int tatalNum = proviceItems.size();
            canvas.save();
            canvas.scale(scale, scale);
            ProviceItem selsetProviceItem = null;
            // 先画没被选中的
            for (int i = 0; i < tatalNum; i++) {
                if (!proviceItems.get(i).isSelect()) {
                    proviceItems.get(i).drawItem(canvas, paint);
                } else {
                    selsetProviceItem = proviceItems.get(i);
                }
            }
            //被选中的最后画,因为被选中的有阴影
            if (selsetProviceItem != null) {
                selsetProviceItem.drawItem(canvas, paint);
            }
        }
    }

    private Thread loadThread = new Thread(new Runnable() {
        @Override
        public void run() {
            InputStream inputStream = context.getResources().openRawResource(R.raw.china);
            proviceItems = new ArrayList<>();
            try {
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                DocumentBuilder builder = null;
                builder = factory.newDocumentBuilder();
                Document document = builder.parse(inputStream);
                Element rootElement = document.getDocumentElement();
                NodeList items = rootElement.getElementsByTagName("path");
                //定义一个不可能存在屏幕上的很右边的点Integer.MAX_VALUE作为最左边,同理定义一个不能存在屏幕上的很左边的点-1作为为最左边
                //因为循环每个省份的最左最右最上最下,左边下标只会越来越小
                float left = Integer.MAX_VALUE;
                float right = -1;
                float top = Integer.MAX_VALUE;
                float bottom = -1;
                for (int i = 0; i < items.getLength(); i++) {
                    Element element = (Element) items.item(i);
                    String pathData = element.getAttribute("android:pathData");
                    Path path = PathParser.createPathFromPathData(pathData);
                    ProviceItem proviceItem = new ProviceItem(path);
                    //设置省份下标
                    //proviceItem.setIndex(i);
                    proviceItems.add(proviceItem);
                    RectF rectF = new RectF();
                    path.computeBounds(rectF, true);
                    left = Math.min(left, rectF.left);
                    right = Math.max(right, rectF.right);
                    top = Math.min(top, rectF.top);
                    bottom = Math.max(bottom, rectF.bottom);
                }
                //创建整个地图
                totalRect = new RectF(left, top, right, bottom);
                try {
                    if (colors == null) {
                        colors = new ColorFillUtil(isBorder, colorArray).getColors();
                        int totalNumber = proviceItems.size();
                        for (int i = 0; i < totalNumber; i++) {
                            proviceItems.get(i).setDrawColor(colors[i]);
                        }
                        handler.sendEmptyMessage(0);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }

            } catch (ParserConfigurationException e) {
                e.printStackTrace();
            } catch (SAXException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    });


    private Handler handler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(@NonNull Message msg) {
            //返回主线程调用以下方法
            //重新测量,调用onMeasure
            requestLayout();
            //重新绘图,系统调用onDraw
            invalidate();
        }
    };

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        //将当前手指触摸到位置传过去  判断当前点击的区域
        handlerTouch(event.getX(), event.getY());
        return super.onTouchEvent(event);
    }

    /**
     * 判断区域
     *
     * @param x
     * @param y
     */
    private void handlerTouch(float x, float y) {
        //判空
        if (proviceItems == null || proviceItems.size() == 0) {
            return;
        }
        for (ProviceItem proviceItem : proviceItems) {
            //入股点击的是这个省份的范围之内 就把当前省份的封装对象绘制的方法 传一个true
            proviceItem.setSelect(proviceItem.isTouch(x / scale, y / scale));
        }
        postInvalidate();
    }

颜色选择工具类

package com.dxt.mapapplication;

/**
 * 板块颜色填充工具
 * Create by XieJunFeng on 2019/12/6.
 */
public class ColorFillUtil {
    //存放颜色种类,并非真正的颜色
    private int[] colorTypes;
    //板块接壤矩阵,1为接壤
    private int[][] isBorder;
    //准备填充的颜色列表
    private int[] colors;
    //颜色多少种类
    private int TYPE_SIZE ;
    //总共有几个板块
    private int plateCount;

    public ColorFillUtil(int[][] isBorder, int[] colors) throws Exception{
        plateCount = isBorder.length;
        if (plateCount != isBorder[0].length) {//板块相邻关系必须是方阵,不能是矩阵
            throw new Exception("colors's length must be equal to isBorder's length!");
        }
        this.colors = colors;
        TYPE_SIZE = colors.length;
        this.isBorder = isBorder;
    }


    /**
     * 获取最后的结果
     * @return
     */
    public int[] getColors()  {

        colorTypes = new int[plateCount];
        int index = 0;
        int colorType = 0;
        while (index < plateCount) {

            if (setColor(index, colorType)) {
                //设置颜色种类暂时成功,接着下一个,直到全部颜色设置完成,设置颜色种类从0开始尝试
                index++;
                colorType = 0;
            } else {
                //找不到合适的颜色要回退,上一个板块修改颜色
                index--;
                colorType = colorTypes[index] + 1;
                if (index == 0)
                    //无法求解,可能是是颜色种类太少
                    return null;
            }

        }
        return getRealColors();
    }

    /**
     * 返回真正的颜色列表
     * @return
     */
    private int[] getRealColors() {
        int[] result = new int[plateCount];
        for (int i = 0; i < plateCount; i++) {
            result[i] = colors[colorTypes[i]];
        }
        return result;
    }

    /**
     * 尝试填充颜色 填充成功返回true
     * @param index 准备填充的板块下标
     * @param colorType 准备填充的颜色种类
     * @return
     */
    private boolean setColor(int index, int colorType) {
        if (colorType >= TYPE_SIZE) return false;
        while (colorType < TYPE_SIZE) {
            //是否可以设置颜色种类
            boolean canSet = true;
            //循环判断准备填充的颜色与之前的颜色是否冲突
            for (int i = 0; i < index; i++) {
                //isBorder[i][index] == 1 表示之前已经填充的第i个板块和准备填充的板块是接壤的
                //colorType == colorTypes[i] 同时准备填充的颜色种类又是一样的,则准备填充的颜色要改变,再重新尝试填充
                if (isBorder[i][index] == 1 && colorType == colorTypes[i]) {

                    ++colorType;
                    canSet = false;
                    break;
                }
            }
            if (canSet) {
                colorTypes[index] = colorType;
                return true;
            }
        }
        //找不到合适的颜色,要回退
        return false;
    }
}

部分资源文件
https://pan.baidu.com/s/1Tgq84epnaFhmiEBotGeBgw

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