Android圆角图片和圆形图片实现总结

转载注明出处:http://www.jianshu.com/p/818e1284158d

1. 概述

Android研发中经常会遇见圆角或者圆形图片的展示,但是系统中ImageView并不能直接支持,需要我们自己做一些处理,来实现圆角图片或者圆形图片,自己最近对这块的实现做了一下总结,看一下几种实现方法。

  • 图层叠加,上层覆盖一层蒙版,遮挡图片,让图片展示出圆角或者圆形效果
  • 重新绘制
    • BitmapShader
    • Xfermode
    • RoundedBitmapDrawable
  • CardView,使用官方控件,自动裁剪,达到圆角或者圆形效果。(5.0以上系统)

第一种方法,很傻,不太优雅,不推荐这种方法,了解这种方法是因为确实看见有人这么做过。推荐使用第二种方法,重新绘制图片,不仅可以绘制出四角圆角图片,还可以绘制出底部/顶部/左边/右边圆角效果,非常方便。如果想要偷懒,可以直接使用RoundedBitmapDrawable来实现圆角照片效果。而第三种方法,使用CardView控件有很大的局限性,它只在5.0以及以上的系统中有效。

下面就来看一下各种方法的具体情况吧。

2. 图层叠加

图层叠加原理很简单,就是在一张图片上面叠加一层图,覆盖部分,让图片展示成圆角。具体原理可以参考下面这张图。

图-1 图层叠加原理图

看一下布局代码,很简单。

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">

    <FrameLayout
        android:layout_width="100dp"
        android:layout_height="100dp"
        android:background="@drawable/demo_icon_android_logo">
        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:src="@drawable/demo_icon_shader"/>
    </FrameLayout>
</RelativeLayout>

运行结果如下:

图-2 图片叠层运行结果图

效果还是可以的,但是缺点也很明显,一是要准备两张图片,会增加额外的包体积;二是图片叠加一起,必然导致过度绘制;三是该方法太死板,使用时候要考虑图片大小,控件大小,以及蒙层图圆角锯齿效果,非常不灵活,Java里面不灵活就意味着可用性不强。

所以这种方法不建议使用,大家作为了解就行。提出这种方法是为了让大家了解一下图层,后面重新绘制过程中,有一种方法逻辑跟这个相似,也是绘制图层叠加,生成圆角图片。

3. 重新绘制

对图片的绘制要特别的注意,有时候可能图片太大需要我们压缩,关于图片压缩大家可以查看这片文章压缩图片。重新绘制图片,将图片绘制成圆角,有三种方法。

  • 使用BitmapShader
  • 使用Xfermode
  • 使用RoundedBitmapDrawable

从性能上讲并没有太大的区别,但是从使用灵活性上说,个人推荐使用BitmapShader。

在介绍这三个方法之前,先介绍一下图片的拉伸缩放适配,大多数情况先,要展示图片的控件(ImageView)的长宽和图片的长宽并不是一致的,甚至长宽比都不一致,所以在拿到一张图片时候,大多数情况下需要根据控件的大小对图片进行拉伸缩放处理,有人会问为什么不直接使用ImageView属性scaleType去控制拉伸缩放,这是因为当我们将一个Bitmap绘制成圆角后,再去进行拉伸缩放,圆角可能会变形,所以在Bitmap设置到控件之前就需要对Bitmap进行一下拉伸缩放处理,直接看下面代码。

// 图片根据控件大小等比例缩放拉伸
float widthScale = imageViewWidth * 1.0f / bitmap.getWidth();
float heightScale = imageViewHeight * 1.0f / bitmap.getHeight();
// 设置长宽拉伸缩放比
Matrix matrix = new Matrix();
matrix.setScale(widthScale, heightScale);
// 拉伸缩放图片
Bitmap newBt = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

注:拉伸缩放也可以在Canvas.drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint)方法中控制,后面会提及到。

3.1 BitmapShader绘制圆角

所有的绘制圆角的实现,推荐使用这个方法,不仅仅可以帮助我们实现圆角,连部分圆角都可以实现,比如顶部是两个圆角,底部是两个直角的图片。
首先介绍一下BitmapShader这个类,它作为纹理用于绘制一张图。新图可以是纹理图重复/镜像/边缘像素拉伸而绘制成的新图。这个类构造函数很简单,BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY),第一个参数是Bitmap,作为纹理图传入,tileX是指在水平方向上的绘制方式,tileY是指在竖直方向上的绘制方式。TileMode有三种属性,拉伸、重复、镜像。

  • TileMode.CLAMP 拉伸绘制,并不是指图片拉伸,而是指图片最后一个像素不断绘制,纹理图水平或者竖直方向最后一个像素不断绘制
  • TileMode.REPEAT 重复绘制,在水平或者竖直方向上不断重复绘制纹理图
  • TileMode.MIRROR 镜像绘制,水平或者竖直方向不断的绘制翻转纹理图

使用BitmapShader绘制图的时候,是从画布的左上角开始绘制的。我们是使用拉伸的绘制模式,直接来看一下代码,了解处理过程。

/**
 * 利用BitmapShader绘制圆角图片
 *
 * @param bitmap
 *              待处理图片
 * @param outWidth
 *              结果图片宽度,一般为控件的宽度
 * @param outHeight
 *              结果图片高度,一般为控件的高度
 * @param radius
 *              圆角半径大小
 * @return
 *              结果图片
 */
private Bitmap roundBitmapByShader(Bitmap bitmap, int outWidth, int outHeight, int radius) {
    if(bitmap == null) {
        throw new NullPointerException("Bitmap can't be null");
    }
    // 初始化缩放比
    float widthScale = outWidth * 1.0f / bitmap.getWidth();
    float heightScale = outHeight * 1.0f / bitmap.getHeight();
    Matrix matrix = new Matrix();
    matrix.setScale(widthScale, heightScale);

    // 初始化绘制纹理图
    BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    // 根据控件大小对纹理图进行拉伸缩放处理
    bitmapShader.setLocalMatrix(matrix);

    // 初始化目标bitmap
    Bitmap targetBitmap = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);

    // 初始化目标画布
    Canvas targetCanvas = new Canvas(targetBitmap);

    // 初始化画笔
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(bitmapShader);

    // 利用画笔将纹理图绘制到画布上面
    targetCanvas.drawRoundRect(new RectF(0, 0, outWidth, outWidth), radius, radius, paint);

    return targetBitmap;
}

首先初始化了绘制的纹理图,并对图片进行了拉伸缩放处理,没有用到上面提及的拉伸缩放处理方法是因为BitmapShader本身自带了这个属性,进行设置即可。然后初始化了画布和画笔,将设置画笔绘制的纹理图,画笔在绘制图形时候就不是使用单纯的颜色绘制了。最后在利用画笔在画布上面绘制出圆形图片。

看一下这个方法Canvas.drawRoundRect(RectF rect, float rx, float ry, Paint paint),第一个参数是指定画布的绘制区域,从画布的左上角开始计算;第二个第三个参数是圆角的x轴/y轴的绘制半径,一般设置成相同的值;第三个就是画笔。

我们看一下运行效果。

图-3 BitmapShader圆角效果图

看起来很简单,但这并不是我推荐使用这种方法的原因,丰富的绘制结果才是,有很多样式可以绘制,讲一个比较简单的,底部两个圆角,顶部两个直角,看一下运行效果图。

图-4 BitmapShader底部圆角效果图

已经感觉有点厉害了,先来看代码的实现。

/**
 * 利用BitmapShader绘制底部圆角图片
 *
 * @param bitmap
 *              待处理图片
 * @param outWidth
 *              结果图片宽度,一般为控件的宽度
 * @param outHeight
 *              结果图片高度,一般为控件的高度
 * @param radius
 *              圆角半径大小
 * @return
 *              结果图片
 */
private Bitmap roundBottomBitmapByShader(Bitmap bitmap, int outWidth, int outHeight, int radius) {
    if(bitmap == null) {
        throw new NullPointerException("Bitmap can't be null");
    }
    // 初始化缩放比
    float widthScale = outWidth * 1.0f / bitmap.getWidth();
    float heightScale = outHeight * 1.0f / bitmap.getHeight();
    Matrix matrix = new Matrix();
    matrix.setScale(widthScale, heightScale);

    // 初始化绘制纹理图
    BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
    // 根据控件大小对纹理图进行拉伸缩放处理
    bitmapShader.setLocalMatrix(matrix);

    // 初始化目标bitmap
    Bitmap targetBitmap = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);

    // 初始化目标画布
    Canvas targetCanvas = new Canvas(targetBitmap);

    // 初始化画笔
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(bitmapShader);

    // 利用画笔绘制底部圆角
    targetCanvas.drawRoundRect(new RectF(0, outHeight - 2 * radius, outWidth, outWidth), radius, radius, paint);

    // 利用画笔绘制顶部上面直角部分
    targetCanvas.drawRect(new RectF(0, 0, outWidth, outHeight - radius), paint);
    
    return targetBitmap;
}

仔细的同学已经发现了,这部分代码和上面很相似,只不过最后两句有些不同。对,因为后面两句是对图片的绘制,最后输出我们想要的效果。targetCanvas.drawRoundRect()先在底部绘制出圆角的矩形,然后targetCanvas.drawRect()绘制出上面的直角。targetCanvas.drawRoundRect()它在画布上面绘制了图片底部2*radius高度的部分,绘制出的结果是一个高度为2*radius的圆角图片,然后再在画布0到outHeight - radius部分绘制出一个直角矩形,这个直角矩形正好覆盖了之前绘制的圆角图片的上半部分,只露出下面的圆角,此时画布上面呈现出的图像就是刚才运行的效果图,看一下下面的原理图帮助我们理解一下。

图-5 Bitmapshader底部圆角原理

是不是有点类似上面提高的图层叠加的原理了,根据各种叠加情况,可以绘制出多种效果,有下面几种(同一个图中圆角半径都相同):

  • 四角都是圆角
  • 同边圆角,底部圆角/顶部圆角/左边圆角/右边圆角
  • 对角线圆角,左上右下圆角/左下右上圆角
  • 单个圆角,左上圆角/左下圆角/右上圆角/右下圆角
  • 三个圆角,左上非圆角/左下非圆角/右上非圆角/右下非圆角

除了这些绘制效果,我们还可以绘制出圆角半径不同的图,在此不做讨论。上述所有的绘制代码在后面会给出工程地址,或者直接点击这里查看

3.2 Xfermode绘制圆角

在使用画笔Paint去绘制东西,当绘制多个图层叠加的时候,有16中模式。效果如下图。

图-6 Xfermode类型效果图
模式 说明
PorterDuff.Mode.CLEAR 所有绘制不会绘制到画布上
PorterDuff.Mode.SRC 显示上层绘制图形
PorterDuff.Mode.DST 显示下层绘制图形
PorterDuff.Mode.SRC_OVER 图形叠加,上层盖住下层
PorterDuff.Mode.DST_OVER 图形叠加,下层盖住上层
PorterDuff.Mode.SRC_IN 显示上层交集部分
PorterDuff.Mode.DST_IN 显示下层交集部分
PorterDuff.Mode.SRC_OUT 显示上层非交集部分
PorterDuff.Mode.DST_OUT 显示下层非交集部分
PorterDuff.Mode.SRC_ATOP 显示下层非交集部分和上层交集部分
PorterDuff.Mode.DST_ATOP 显示下层交集部分与上层非交集部分
PorterDuff.Mode.XOR 去除交集部分
PorterDuff.Mode.DARKEN 交集部分颜色加深
PorterDuff.Mode.LIGHTEN 交集部分颜色变亮
PorterDuff.Mode.MULTIPLY 显示交集部分,颜色混合叠加
PorterDuff.Mode.SCREEN 取两图层全部区域,交集部分变为透明色

官方demo中主要绘制代码如下:

// mDstB是黄色的圆形图bitmap
// mSrcB是蓝色的矩形图bitmap
canvas.drawBitmap(mDstB, 0, 0, paint);
paint.setXfermode(sModes[i]);
canvas.drawBitmap(mSrcB, 0, 0, paint)

可以看到在两个绘制图形过程中,添加Xfermode绘制模式,能够改变两个图的叠加效果,我们主要关注一下SrcIn模式,可以看见,用图层叠加的交集去截取mSrcB图,可以利用这个,想绘制一个圆角的图,然后设置绘制模式,接着绘制一个矩形的图,两者一叠加,正好是用圆角图去截取矩形图,矩形图也就是我们的原图片了。

直接看一下实现代码。

/**
 * 利用Xfermode绘制圆角图片
 *
 * @param bitmap
 *              待处理图片
 * @param outWidth
 *              结果图片宽度,一般为控件的宽度
 * @param outHeight
 *              结果图片高度,一般为控件的高度
 * @param radius
 *              圆角半径大小
 * @return
 *              结果图片
 */
private Bitmap roundBitmapByXfermode(Bitmap bitmap, int outWidth, int outHeight, int radius) {
    if(bitmap == null) {
        throw new NullPointerException("Bitmap can't be null");
    }

    // 等比例缩放拉伸
    float widthScale = outWidth * 1.0f / bitmap.getWidth();
    float heightScale = outHeight * 1.0f / bitmap.getHeight();
    Matrix matrix = new Matrix();
    matrix.setScale(widthScale, heightScale);
    Bitmap newBt = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

    // 初始化目标bitmap
    Bitmap targetBitmap = Bitmap.createBitmap(outWidth, outHeight, Bitmap.Config.ARGB_8888);

    Canvas canvas = new Canvas(targetBitmap);
    canvas.drawARGB(0, 0, 0, 0);

    Paint paint = new Paint();
    paint.setAntiAlias(true);

    RectF rectF = new RectF(0f, 0f, (float) outWidth, (float) outHeight);

    // 在画布上绘制圆角图
    canvas.drawRoundRect(rectF, radius, radius, paint);

    // 设置叠加模式
    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

    // 在画布上绘制原图片
    Rect ret = new Rect(0, 0, outWidth, outHeight);
    canvas.drawBitmap(newBt, ret, ret, paint);

    return targetBitmap;
}

最后展示一下运行的效果图。

图-7 Xfermode圆角效果图.png

3.3 RoundedBitmapDrawable绘制圆角

如果你觉得上面两种方法还是好麻烦,肯本不想去搞这些绘制的东西,有没有简单的方法呢?

有!

在V4包中有一个RoundedBitmapDrawable类,专门帮助实现圆角效果。

用法也很简单,看代码。

/**
 * 利用RoundedBitmapDrawable绘制圆角图片
 *
 * @param bitmap
 *              待处理图片
 * @param outWidth
 *              结果图片宽度,一般为控件的宽度
 * @param outHeight
 *              结果图片高度,一般为控件的高度
 * @param radius
 *              圆角半径大小
 * @return
 *              结果图片
 */
private Drawable roundBitmapByBitmapDrawable(Bitmap bitmap, int outWidth, int outHeight, int radius) {
    if(bitmap == null) {
        throw new NullPointerException("Bitmap can't be null");
    }

    // 等比例缩放拉伸
    float widthScale = outWidth * 1.0f / bitmap.getWidth();
    float heightScale = outHeight * 1.0f / bitmap.getHeight();
    Matrix matrix = new Matrix();
    matrix.setScale(widthScale, heightScale);
    Bitmap newBt = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);

    // 绘制圆角
    RoundedBitmapDrawable dr = RoundedBitmapDrawableFactory.create(getResources(), newBt);
    dr.setCornerRadius(radius);
    dr.setAntiAlias(true);

    return dr;
}

代码就是三行,初始化,然后设置圆角半径dr.setCornerRadius(),设置边缘平滑dr.setAntiAlias()(这步可以不需要)。运行效果如下。

图-8 RoundedBitmapDrawable圆角效果图

其实去查看dr.setCornerRadius()源代码,会发现它内部就是使用的BitmapShader来绘制圆角效果。官方做了一层封装,使得我们使用起来更加方便。

public void setCornerRadius(float cornerRadius) {
    if (mCornerRadius == cornerRadius) return;

    mIsCircular = false;
    if (isGreaterThanZero(cornerRadius)) {
        mPaint.setShader(mBitmapShader);
    } else {
        mPaint.setShader(null);
    }

    mCornerRadius = cornerRadius;
    invalidateSelf();
}

4. CardView控件圆角

CardView是官方在V7包中新增的一个控件,继承FrameLayout布局,拥有圆角和阴影属性的控件,既然是新控件,看一下它的一些属性。

  • cardElevation 阴影的大小
  • cardMaxElevation 阴影最大高度
  • cardBackgroundColor 卡片的背景色
  • cardCornerRadius 卡片的圆角大小
  • contentPadding 卡片内容于边距的间隔
    • contentPaddingBottom
    • contentPaddingTop
    • contentPaddingLeft
    • contentPaddingRight
    • contentPaddingStart
    • contentPaddingEnd
  • cardUseCompatPadding 设置内边距,V21+的版本和之前的版本仍旧具有一样的计算方式
  • cardPreventConrerOverlap 在V20和之前的版本中添加内边距,这个属性为了防止内容和边角的

比较关注的是cardCornerRadiuscardElevation这两个属性,为了实现圆角图片的效果,将cardElevation属性也就是阴影效果,设置为0dp,看一下具体的布局文件代码。

<android.support.v7.widget.CardView
    android:layout_width="@dimen/round_bitmap_width"
    android:layout_height="@dimen/round_bitmap_width"
    app:cardCornerRadius="5dp"
    app:cardElevation="0dp">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitXY"
        android:src="@drawable/demo_icon_android_logo"/>
</android.support.v7.widget.CardView>

CardView作为父布局,容纳ImageView控件。看一下运行效果。

图-9 CardView圆角效果图-5.0系统

这个控件用起来非常偷懒,可惜的是CardView调用了View的setClipToOutline(true)方法来裁边,5.0一下的系统没有这个API,也就是说,5.0以下的系统不会呈现出圆角。

图-10 CardView圆角效果图-4.4系统

虽然这个控件不能帮助我们实现圆角图片的效果,但是给我们提供了一个圆角控件,也能帮助我们解决很多需求场景。

5. 圆形图片的实现

了解了圆角照片的实现,圆形照片的实现就很简单了。圆形图片需要的是一个正方形的图片,将圆角半径设置为正方形图片边长一半即可。但是有时候,我们拿到的图片是一个矩形,长宽不一样长!!!我们需要对图片做裁剪处理,取矩形中间部分,让它变成一个正方形图片。

BitmapShader为例。

/**
 * 利用BitmapShader绘制底部圆角图片
 *
 * @param bitmap
 *              待处理图片
 * @param edgeWidth
 *              正方形控件大小
 * @param radius
 *              圆角半径大小
 * @return
 *              结果图片
 */
private Bitmap circleBitmapByShader(Bitmap bitmap, int edgeWidth, int radius) {
    if(bitmap == null) {
        throw new NullPointerException("Bitmap can't be null");
    }
    
    float btWidth = bitmap.getWidth();
    float btHeight = bitmap.getHeight();
    // 水平方向开始裁剪的位置
    float btWidthCutSite = 0;
    // 竖直方向开始裁剪的位置
    float btHeightCutSite = 0;
    // 裁剪成正方形图片的边长,未拉伸缩放
    float squareWidth = 0f;
    if(btWidth > btHeight) { // 如果矩形宽度大于高度
        btWidthCutSite = (btWidth - btHeight) / 2f;
        squareWidth = btHeight;
    } else { // 如果矩形宽度不大于高度
        btHeightCutSite = (btHeight - btWidth) / 2f;
        squareWidth = btWidth;
    }

    // 设置拉伸缩放比
    float scale = edgeWidth * 1.0f / squareWidth;
    Matrix matrix = new Matrix();
    matrix.setScale(scale, scale);

    // 将矩形图片裁剪成正方形并拉伸缩放到控件大小
    Bitmap squareBt = Bitmap.createBitmap(bitmap, (int)btWidthCutSite, (int)btHeightCutSite, (int)squareWidth, (int)squareWidth, matrix, true);

    // 初始化绘制纹理图
    BitmapShader bitmapShader = new BitmapShader(squareBt, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);

    // 初始化目标bitmap
    Bitmap targetBitmap = Bitmap.createBitmap(edgeWidth, edgeWidth, Bitmap.Config.ARGB_8888);

    // 初始化目标画布
    Canvas targetCanvas = new Canvas(targetBitmap);

    // 初始化画笔
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShader(bitmapShader);

    // 利用画笔绘制圆形图
    targetCanvas.drawRoundRect(new RectF(0, 0, edgeWidth, edgeWidth), radius, radius, paint);

    return targetBitmap;
}

裁剪拉伸的逻辑比较复杂,主要是因为图片长宽和正方形边长各种关系复杂导致。将图片处理成正方形图片后,后面代码和切圆角代码基本类似。

  • 如果矩形图片的宽大于高,那么竖直方向上不需要裁剪,以矩形图片高度为裁剪后的正方形的边长,同时计算出水平方向上的裁剪位置
  • 如果矩形图片的高不小于宽,那么水平方向上不需要裁剪,以矩形图片宽度为裁剪后的正方形的边长,同时计算出竖直方向上的裁剪位置
  • 最后计算出裁剪后的正方形图边长与控件边长的拉伸缩放比例,因为都是正方形,只需要计算一边的缩放比即可。

最后来看一下圆形图片的实现效果。

图-11 BitmapShader圆形效果图

看到这里你会发现,其实圆形图片的实现和圆角图片的实现基本是相同的,了解圆角图片的实现方法,圆形图片的实现自然不在话下。

6. 总结

上述介绍了大概五种圆角图片的实现方法,方法没有优劣,在具体的业务场景选择最适合的方法才是最重要的,但是最为一个有追求的程序员,还是建议大家多了解重新绘制里面的几种方法。

最后附上Demo工程的地址:地址链接,里面包含了利用BitmapShader绘制多种效果的单例类RoundBitmapTransformation。在写demo过程中,因为使用的图片太大,有出现OOM的异常,如果觉得图片太大,你可以替换掉Demo工程中的图片,其实在实际中对图片操作也很容易引起OOM,关于图片的压缩处理,大家可以参考这篇文章

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,568评论 25 707
  • ​未雨绸缪,明确方向。 “毕业后想做什么工作啊?” 这个问题大概是即将毕业的大学生最怕却又不得不面对的问题。在倒计...
    桃之夭0310阅读 631评论 0 0
  • 结婚二十多年,他们一直是村里人羡慕的对象! 1、爱是相互嫌弃,相互需要 他说她做事毛毛躁躁,比如收庄稼时她收第一遍...
    树海云天阅读 199评论 0 5
  • 这就是德庆的样子吧! 德庆,你好! 记得那是2015年11月份的日子,那一天,算是我正式认识你吧,虽然前面有过几次...
    初三一班阅读 725评论 0 0
  • 有个流传甚广的故事:一个去海岛度假的富翁告诉一位同在海边晒太阳的渔夫如何成为富翁,然后就可以享受富翁的生活,去度假...
    LvJack阅读 225评论 0 0