Android 根据View生成图片简易参考

一、分类

开发中,我们有时候需要根据View生成图片。

本文根据不同情况的View生成图片进行了一些示例,分类如下
第一种,普通View生成图片(view已经渲染加载到界面上)
第二种,无中生有,通过java代码创建的或者inflate创建
第三种,WebView 生成图片
第四种,ScrollView 生成图片
第五种,ListView 生成图片
第六种,RecyclerView 生成图片

还是图来的直接


shot.gif

核心代码

public  class SimpleUtils {

    /**
     * 将 Bitmap 保存到SD卡
     * @param context
     * @param mybitmap
     * @param name
     * @return
     */
    public static boolean saveBitmapToSdCard(Context context, Bitmap mybitmap, String name){
        boolean result = false;
        //创建位图保存目录
        String path = Environment.getExternalStorageDirectory() + "/1000ttt/";
        File sd = new File(path);
        if (!sd.exists()){
            sd.mkdir();
        }

        File file = new File(path+name+".jpg");
        FileOutputStream fileOutputStream = null;
        if (!file.exists()){
            try {
                // 判断SD卡是否存在,并且是否具有读写权限
                if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
                    fileOutputStream = new FileOutputStream(file);
                    mybitmap.compress(Bitmap.CompressFormat.JPEG,100,fileOutputStream);
                    fileOutputStream.flush();
                    fileOutputStream.close();

                    //update gallery
                    Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
                    Uri uri = Uri.fromFile(file);
                    intent.setData(uri);
                    context.sendBroadcast(intent);
                    Toast.makeText(context, "保存成功", Toast.LENGTH_SHORT).show();
                    result = true;
                }
                else{
                    Toast.makeText(context, "不能读取到SD卡", Toast.LENGTH_SHORT).show();
                }

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }


    /**
     * 手动测量摆放View
     * 对于手动 inflate 或者其他方式代码生成加载的View进行测量,避免该View无尺寸
     * @param v
     * @param width
     * @param height
     */
    public static void layoutView(View v, int width, int height) {
        // validate view.width and view.height
        v.layout(0, 0, width, height);
        int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
        int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);

        // validate view.measurewidth and view.measureheight
        v.measure(measuredWidth, measuredHeight);
        v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
    }


    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }



    /**
     * 获取一个 View 的缓存视图
     *  (前提是这个View已经渲染完成显示在页面上)
     * @param view
     * @return
     */
    public static 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;
    }

    /**
     *  对ScrollView进行截图
     * @param scrollView
     * @return
     */
    public static Bitmap shotScrollView(ScrollView scrollView) {
        int h = 0;
        Bitmap bitmap = null;
        for (int i = 0; i < scrollView.getChildCount(); i++) {
            h += scrollView.getChildAt(i).getHeight();
            scrollView.getChildAt(i).setBackgroundColor(Color.parseColor("#ffffff"));
        }
        bitmap = Bitmap.createBitmap(scrollView.getWidth(), h, Bitmap.Config.RGB_565);
        final Canvas canvas = new Canvas(bitmap);
        scrollView.draw(canvas);
        return bitmap;
    }


    /**
     * 对ListView进行截图
     * http://stackoverflow.com/questions/12742343/android-get-screenshot-of-all-listview-items
     */
    public static Bitmap shotListView(ListView listview) {

        ListAdapter adapter = listview.getAdapter();
        int itemscount = adapter.getCount();
        int allitemsheight = 0;
        List<Bitmap> bmps = new ArrayList<Bitmap>();

        for (int i = 0; i < itemscount; i++) {

            View childView = adapter.getView(i, null, listview);
            childView.measure(
                    View.MeasureSpec.makeMeasureSpec(listview.getWidth(), View.MeasureSpec.EXACTLY),
                    View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));

            childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight());
            childView.setDrawingCacheEnabled(true);
            childView.buildDrawingCache();
            bmps.add(childView.getDrawingCache());
            allitemsheight += childView.getMeasuredHeight();
        }

        Bitmap bigbitmap =
                Bitmap.createBitmap(listview.getMeasuredWidth(), allitemsheight, Bitmap.Config.ARGB_8888);
        Canvas bigcanvas = new Canvas(bigbitmap);

        Paint paint = new Paint();
        int iHeight = 0;

        for (int i = 0; i < bmps.size(); i++) {
            Bitmap bmp = bmps.get(i);
            bigcanvas.drawBitmap(bmp, 0, iHeight, paint);
            iHeight += bmp.getHeight();

            bmp.recycle();
            bmp = null;
        }

        return bigbitmap;
    }


    /**
     * 对RecyclerView进行截图
     * https://gist.github.com/PrashamTrivedi/809d2541776c8c141d9a
     */
    public static Bitmap shotRecyclerView(RecyclerView view) {
        RecyclerView.Adapter adapter = view.getAdapter();
        Bitmap bigBitmap = null;
        if (adapter != null) {
            int size = adapter.getItemCount();
            int height = 0;
            Paint paint = new Paint();
            int iHeight = 0;
            final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);

            // Use 1/8th of the available memory for this memory cache.
            final int cacheSize = maxMemory / 8;
            LruCache<String, Bitmap> bitmaCache = new LruCache<>(cacheSize);
            for (int i = 0; i < size; i++) {
                RecyclerView.ViewHolder holder = adapter.createViewHolder(view, adapter.getItemViewType(i));
                adapter.onBindViewHolder(holder, i);
                holder.itemView.measure(
                        View.MeasureSpec.makeMeasureSpec(view.getWidth(), View.MeasureSpec.EXACTLY),
                        View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED));
                holder.itemView.layout(0, 0, holder.itemView.getMeasuredWidth(),
                        holder.itemView.getMeasuredHeight());
                holder.itemView.setDrawingCacheEnabled(true);
                holder.itemView.buildDrawingCache();
                Bitmap drawingCache = holder.itemView.getDrawingCache();
                if (drawingCache != null) {

                    bitmaCache.put(String.valueOf(i), drawingCache);
                }
                height += holder.itemView.getMeasuredHeight();
            }

            bigBitmap = Bitmap.createBitmap(view.getMeasuredWidth(), height, Bitmap.Config.ARGB_8888);
            Canvas bigCanvas = new Canvas(bigBitmap);
            Drawable lBackground = view.getBackground();
            if (lBackground instanceof ColorDrawable) {
                ColorDrawable lColorDrawable = (ColorDrawable) lBackground;
                int lColor = lColorDrawable.getColor();
                bigCanvas.drawColor(lColor);
            }

            for (int i = 0; i < size; i++) {
                Bitmap bitmap = bitmaCache.get(String.valueOf(i));
                bigCanvas.drawBitmap(bitmap, 0f, iHeight, paint);
                iHeight += bitmap.getHeight();
                bitmap.recycle();
            }
        }
        return bigBitmap;
    }
}

核心代码都在上面了,下面开始分析。

二、普通View

普通View,在本文中就是已经绘制到界面的View。

Paste_Image.png

如上,点击截取View,并且我们会生成图片显示保存到sd卡

普通View生成图片参考代码

    /**
     * 获取一个 View 的缓存视图
     *  (前提是这个View已经渲染完成显示在页面上)
     * @param view
     * @return
     */
    public static 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;
    }

.
.
.
至于保存Bitmap到sd卡操作,虽然常见一些,代码还是附在顶部工具类了。

三、代码加载但是未显示在界面的View

inf.gif

有一些View,我们是通过代码加载出来的,但是没有加载界面上,我们也可以对这种View生成图片。

什么?既然没有显示在界面上,那还要加载来干嘛?
此言差矣,用处还是有的,YY即可。

如图,按下截图按钮,我们做的主要逻辑如下:

// 本View是inflate加载而来,不是Activity的xml本身的
        View view = getLayoutInflater().inflate(R.layout.item_group,null);
        ImageView mtv = (ImageView) view.findViewById(R.id.mIv);
        ViewGroup.LayoutParams upPartLayoutParams = mtv.getLayoutParams();
        int upPartMeasureHeight = View.MeasureSpec.makeMeasureSpec(upPartLayoutParams.height, View.MeasureSpec.EXACTLY);
        mtv.setImageDrawable(getResources().getDrawable(R.drawable.ccc));

        // 没有显示到界面上的view本身无大小可言,所以我们要手动指定一下
        SimpleUtils.layoutView(mtv,upPartMeasureHeight,upPartMeasureHeight);
        // View生成截图
        Bitmap cacheBitmapFromView = SimpleUtils.getCacheBitmapFromView(mtv);
        mIvResult.setImageBitmap(cacheBitmapFromView);
        // 保存bitmap到sd卡
        SimpleUtils.saveBitmapToSdCard(StyleTwoActivity.this,cacheBitmapFromView,"styleTwo");

.
.
.
代码中,我们看到,我们按下截图,inflate加载一个简单布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="200px"
              android:layout_height="200px"
    >

    <ImageView
        android:id="@+id/mIv"
        android:layout_width="200px"
        android:layout_height="200px"
        android:background="#623512"
        android:text="哇阿斯达撒大声地哈哈哈就是这样的按到"
        android:textColor="#ffffff"
        android:textSize="20sp"
        />
</LinearLayout>

我们看到,里面就是一个ImagView,我们待会就是要给这个ImageView 设置一张图片,然后对这个View进行生成图片,但是注意,这个ImageView从始至终都是没有显示在界面上的。

Paste_Image.png

这个ImageView并没有加载到布局。我们想直接调用正常View的生成图片方法,但是如果这样会生成图片失败。
因为刚刚inflate的View是没有经过measure和layout的,没有大小,所有我们需要指定一下大小。

所以我们调用layoutView方法指定大小

  /**
     * 手动测量摆放View
     * 对于手动 inflate 或者其他方式代码生成加载的View进行测量,避免该View无尺寸
     * @param v
     * @param width
     * @param height
     */
    public static void layoutView(View v, int width, int height) {
        // validate view.width and view.height
        v.layout(0, 0, width, height);
        int measuredWidth = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY);
        int measuredHeight = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY);

        // validate view.measurewidth and view.measureheight
        v.measure(measuredWidth, measuredHeight);
        v.layout(0, 0, v.getMeasuredWidth(), v.getMeasuredHeight());
    }


    public static int px2dip(Context context, float pxValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

有了大小,就可以生成图片了。

四、WebView、ScrollView、ListView和RecyclerView

其实在开篇的工具类都已经介绍了,就不一一说了。直接把demo的代码一下就差不多了。

四.1、WebView 生成图片

@RuntimePermissions
public class WebShotActivity extends BaseActivity {
    private WebView mWeb;
    private ImageView mIvResult;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_web);

        mWeb = (WebView) findViewById(R.id.mWeb);
        mIvResult = (ImageView) findViewById(R.id.mIvResult);


        mWeb.setDrawingCacheEnabled(true);


        //支持javascript
        mWeb.getSettings().setJavaScriptEnabled(true);
        mWeb.getSettings().setUseWideViewPort(true);
        mWeb.getSettings().setLoadWithOverviewMode(true);
        //支持页面缩放
        //webView.getSettings().setBuiltInZoomControls(true);
        //提升渲染优先级
        //webView.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
        //不加载网络中的图片资源
        //webView.getSettings().setBlockNetworkImage(true);
        //HTML5 Cache
        //*mWeb.getSettings().setDomStorageEnabled(true);
        mWeb.getSettings().setAllowFileAccess(true);
        mWeb.getSettings().setAppCacheEnabled(true);
        //优先从本地cache中载入,其次才是从网络中载入,即使内容已经过期*//*
        mWeb.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
        mWeb.setWebViewClient(new WebViewClient() {
            @Override
            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                view.loadUrl(url);
                return super.shouldOverrideUrlLoading(view, url);
            }
            @Override
            public void onPageStarted(WebView view, String url, Bitmap favicon) {
                super.onPageStarted(view, url, favicon);
            }
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
            }
            @Override
            public boolean shouldOverrideKeyEvent(WebView view, KeyEvent event) {
                //Android TV中可以在这里返回true,按键交由onKeyDown方法处理
                return super.shouldOverrideKeyEvent(view, event);
            }
            @Override
            public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
                super.onReceivedError(view, errorCode, description, failingUrl);
            }
        });


        mWeb.setWebChromeClient(new WebChromeClient() {
            @Override
            public void onProgressChanged(WebView view, int newProgress) {
                super.onProgressChanged(view, newProgress);

            }
            @Override
            public void onReceivedTitle(WebView view, String title) {
                super.onReceivedTitle(view, title);
            }
        });

        mWeb.loadUrl("https://m.baidu.com/?from=844b&vit=fps");


        findViewById(R.id.mTvShot).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                WebShotActivityPermissionsDispatcher.storageNeedWithCheck(WebShotActivity.this);
            }
        });


    }

    @NeedsPermission({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    void storageNeed() {
        int viewWidth = mWeb.getMeasuredWidth();
        int viewHeight = mWeb.getMeasuredHeight();
        if (viewWidth > 0 && viewHeight > 0) {
            Bitmap b = Bitmap.createBitmap(viewWidth, viewHeight, Bitmap.Config.RGB_565);
            Canvas cvs = new Canvas(b);
            mWeb.draw(cvs);
            mIvResult.setImageBitmap(b);
            SimpleUtils.saveBitmapToSdCard(WebShotActivity.this,b,"styleWeb");
        }

    }


    @OnShowRationale({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    void storageRationale(final PermissionRequest request) {
        showRationaleDialog("存储权限是本程序必不可少的权限,请开启",request);
    }

    @OnPermissionDenied({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    void storageDenied() {
        openAppSetting("您拒绝了存储权限,请授权");
    }

    @OnNeverAskAgain({Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})
    void storageAsk() {
        openAppSetting("您拒绝了存储权限,请授权");
    }
}

代码稍微长了一下,是因为做了存储权限检查和一些WebView的配置,我们该忽略的忽略,核心就是传入WebView生成图片那么一句而已。

.
.
.

四.2、ScrollView 生成图片

Paste_Image.png
public class StyleScrollView extends BaseActivity {

    private ImageView mIvRet;
    private ScrollView mScrollView;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_scroll);

        mIvRet = (ImageView) findViewById(R.id.mIvRet);
        mScrollView = (ScrollView) findViewById(R.id.mScrollView);

        findViewById(R.id.mTvShot).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bitmap bitmap = SimpleUtils.shotScrollView(mScrollView);
                mIvRet.setImageBitmap(bitmap);
            }
        });
    }
}

四.3、ListView 生成图片

Paste_Image.png
public class StyleLvActivity extends BaseActivity {
    private ListView mLv;
    private ImageView mIvRet;
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_lv);
        mLv = (ListView) findViewById(R.id.mLv);
        mLv.setAdapter(new MyAdapter());
        mIvRet = (ImageView) findViewById(R.id.mIvRet);
        findViewById(R.id.mTvShot).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bitmap bitmap = SimpleUtils.shotListView(mLv);
                mIvRet.setImageBitmap(bitmap);
            }
        });
    }
    
    class MyAdapter extends BaseAdapter{
        @Override
        public int getCount() {
            return 10;
        }

        @Override
        public Object getItem(int i) {
            return null;
        }
        @Override
        public long getItemId(int i) {
            return 0;
        }
        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
            // 简答粗暴了一些,只是为演示
            View  vi = getLayoutInflater().inflate(R.layout.item_lv,null);
            TextView textView = (TextView) vi.findViewById(R.id.mTv);
            textView.setText(i+"");


            return vi;
        }
    }
}

.
.
.

四.4、RecyclerView 生成图片

Paste_Image.png
public class StyleRecyclerView extends BaseActivity {
    private RecyclerView mRecycler;
    private ImageView mIvRet;
    private List<DataBean> mDatas;
    private TestAdapter mAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_rv);

        initData();
        mRecycler = (RecyclerView) findViewById(R.id.mRecycler);
        mRecycler.setLayoutManager(new LinearLayoutManager(this));
        mRecycler.setAdapter(mAdapter = new TestAdapter());

        mIvRet = (ImageView) findViewById(R.id.mIvRet);
        findViewById(R.id.mTvShot).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Bitmap bitmap = SimpleUtils.shotRecyclerView(mRecycler);
                mIvRet.setImageBitmap(bitmap);
            }
        });
    }

    private void initData()
    {
        mDatas = new ArrayList<DataBean>();
        DataBean dataBean = null;
        for (int i = 0; i < 6; i++)
        {
            dataBean = new DataBean();
            dataBean.title = "标题  "+i;
            dataBean.desc = "描述一下  "+i;
            mDatas.add(dataBean);
        }
    }

    class TestAdapter extends RecyclerView.Adapter<TestAdapter.MyViewHolder>{
        // 孩子数
        @Override
        public int getItemCount() {
            return mDatas.size();
        }


        // 创建视图
        @Override
        public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            MyViewHolder myViewHolder = new MyViewHolder(LayoutInflater.from(StyleRecyclerView.this)
                    .inflate(R.layout.item_rv,parent, false));
            return myViewHolder;
        }

        // 绑定视图视图  以前getView的事情  关键方法
        @Override
        public void onBindViewHolder(MyViewHolder holder, int position) {
            DataBean dataBean = mDatas.get(position);
            holder.mTvTitle.setText(dataBean.title);
            holder.mTvDesc.setText(dataBean.desc);

        }

        // 必须实现的Holder
        class MyViewHolder extends RecyclerView.ViewHolder
        {
            TextView mTvTitle;
            TextView mTvDesc;

            public MyViewHolder(View itemView) {
                super(itemView);
                mTvTitle = (TextView) itemView.findViewById(R.id.mTvTitle);
                mTvDesc = (TextView) itemView.findViewById(R.id.mTvDesc);
            }
        }

    }
}

如上,这么一些类型就介绍完了。

本篇完。

GIT下载链接

参考

【Android】获取View的截图
Android滚动截屏,ScrollView截屏,Listview截屏,Recyclerview截屏

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

推荐阅读更多精彩内容