Android知识总结——Path常用方法解析

版权声明:本文为博主原创文章,未经博主允许不得转载。
系列教程:Android开发之从零开始系列

大家要是看到有错误的地方或者有啥好的建议,欢迎留言评论

前言:开发过程中很容易忘记一些API的使用方法,网上搜索或者在源码里找也很难短时间内筛选出自己需要的,遂自己将这些知识总结一番


常用API解析与示例

一、xxxTo方法

Path类中提供了一套xxxTo方法,其作用是从起点到终点移动path画笔并绘制线(moveTo方法只移动path画笔不绘制线),线有直线和曲线。方法汇总如下表所示

方法名 参数解析
lineTo(float x, float y) 绘制直线x:终点x坐标值,y:终点y坐标值
moveTo(float x, float y) 移动画笔x:终点x坐标值,y:终点y坐标值
arcTo(RectF oval, float startAngle, float sweepAngle) 绘制圆弧oval:圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度
arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo) 绘制圆弧oval:圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度,forceMoveTo:是否在绘制圆弧前移动(moveTo)path画笔位置
arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo) 绘制圆弧left、top、right、bottom组成圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度,forceMoveTo:是否在绘制圆弧前移动(moveTo)path画笔位置
quadTo(float x1, float y1, float x2, float y2) 绘制二阶贝塞尔曲线控制点坐标:(x1,y1)终点坐标:(x2,y2)
cubicTo(float x1, float y1, float x2, float y2,float x3, float y3) 绘制三阶贝塞尔曲线,其中控制点1坐标为(x1,y1)控制点2坐标为(x2,y2)终点坐标为(x3,y3)

1.lineTo(float x, float y)

绘制直线,从当前画笔位置出发,连接终点(x,y),示例如下

示例如下

path.lineTo(300,300);
canvas.drawPath(path,paint);

2.moveTo(float x, float y)

移动画笔,从当前画笔位置移动到终点(x,y)

示例如下

path.moveTo(100,100);
path.lineTo(300,300);
canvas.drawPath(path,paint);

3.arcTo(RectF oval, float startAngle, float sweepAngle)

绘制圆弧,从当前画笔位置出发,连线到内切矩形区域oval的圆弧的起始角度startAngle位置(X轴正方向为0°),顺时针旋转绘制圆弧,旋转度数为sweepAngle(sweepAngle为负时则逆时针旋转)

示例如下

RectF rectF = new RectF(100,100,300,400);
path.arcTo(rectF,0,180);
canvas.drawPath(path,pathPaint);

arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)

绘制圆弧,若forceMoveTofalse,则用法和arcTo(RectF oval, float startAngle, float sweepAngle)一样,绘制圆弧之前不会移动(moveTo)path画笔位置。若为true,先强制调用moveTo移动path画笔至圆弧起点,再绘制圆弧。ps:如果调用arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)方法之前没有对path进行任何操作,则forceMoveTo设置truefalse效果都和设置true一样

示例如下,注意对比之间的差异

RectF rectF = new RectF(100,100,300,400);
path.moveTo(100,100);
path.arcTo(rectF,0,180,false);
path.close();
canvas.drawPath(path,pathPaint);
RectF rectF = new RectF(100,100,300,400);
path.moveTo(100,100);
path.arcTo(rectF,0,180,true);
path.close();
canvas.drawPath(path,pathPaint);
RectF rectF = new RectF(100,100,300,400);
path.arcTo(rectF,0,180,false);
path.close();
canvas.drawPath(path,pathPaint);

arcTo(float left, float top, float right, float bottom, float startAngle,float sweepAngle, boolean forceMoveTo)

arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)用法一样


4.quadTo(float x1, float y1, float x2, float y2)

从path画笔当前位置出发,以(x₁,y₁)为控制点,向终点(x₂,y₂)绘制一条二阶贝塞尔曲线

示例如下

path.moveTo(100,100);
path.quadTo(200,0,400,100);
canvas.drawPath(path,pathPaint);

5.cubicTo(float x1, float y1, float x2, float y2,float x3, float y3)

从path画笔当前位置出发,以(x1,y1)为控制点1,以(x2,y2)为控制点2,向终点(x3,y3)绘制一条三阶贝塞尔曲线

简单示例如下

path.moveTo(100,100);
path.cubicTo(200,0,300,90,500,100);
canvas.drawPath(path,pathPaint);

圆形其实也是由四段三阶贝塞尔曲线组成,我们绘制其中两段看看效果即可,示例如下

path.moveTo(300,200);
path.cubicTo(300,200+100*0.551915024494f,200+100*0.551915024494f,300,200,300);

path.moveTo(200-20,300);
path.cubicTo(200-100*0.551915024494f-20,300,100-20,200+100*0.551915024494f,100-20,200);
canvas.drawPath(path,pathPaint);

二、rXxxTo方法

rXxxTo方法r意思是relative,即相对的意思,方法有四个,如上图所示,其功能与对应的xxxTo方法一样,区别在于rXxxTo方法在绘制Path时是以当前path画笔位置为坐标原点,即相对于path画笔位置进行绘制,而xxxTo方法的坐标原点则与当前canvas坐标原点一致。例如,我们使用xxxTo方法

path.moveTo(100,100);
path.lineTo(300,300);
canvas.drawPath(path, pathPaint);

上述代码是从(100,100)到(300,300)绘制一条直线,那么如果用rXxxTo方法,相对(100,100)这个点绘制直线,则终点应为(300-100,300-100),即终点设为(200,200),如下所示

path.moveTo(100,100);
path.rLineTo(200,200);
canvas.drawPath(path, pathPaint);

效果都是一样的


三、addXxx方法

Path类中还提供了一套addXxx方法,字面理解就是添加一段相应的线,线可以是曲线、完整的圆形、矩形等,甚至可以是另一组Path的线。所谓添加的意思,我个人理解就是在绘制这段线前移动(moveTo)path画笔位置到线的起始位置,然后再绘制线,也就是说添加的这段线,与之前绘制的Path是分离的(除非后绘制的这段线的起始点与之前Path的终点一致)。方法汇总如下表所示

方法名 参数解析
addArc(RectF oval, float startAngle, float sweepAngle) 添加圆弧oval:圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度
addArc(float left, float top, float right, float bottom, float startAngle,float sweepAngle) 添加圆弧left、top、right、bottom组成圆弧矩形区域,startAngle:起始角度,sweepAngle:圆弧旋转的角度。ps:此方法在API 19以上有效
addCircle(float x, float y, float radius, Direction dir) 添加圆形x:圆形圆心的x坐标,y:圆形圆心的y坐标,radius:圆形半径,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addOval(RectF oval, Direction dir) 添加椭圆oval:椭圆内切的矩形区域,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addOval(float left, float top, float right, float bottom, Direction dir) 添加椭圆left、top、right、bottom组成椭圆内切的矩形区域,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addRect(RectF rect, Direction dir) 添加矩形rect:矩形区域,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addRect(float left, float top, float right, float bottom, Direction dir) 添加矩形left、top、right、bottom组成矩形区域,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addRoundRect(RectF rect, float rx, float ry, Direction dir) 添加统一圆角的圆角矩形rect:矩形区域,rx:椭圆圆角的横轴半径,ry:椭圆圆角的纵轴半径,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir) 添加统一圆角的圆角矩形left、top、right、bottom组成矩形区域,rx:椭圆圆角的横轴半径,ry:椭圆圆角的纵轴半径,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addRoundRect(RectF rect, float[] radii, Direction dir) 添加非统一圆角的圆角矩形rect:矩形区域,radii:矩形四个椭圆圆角的横轴半径和纵轴半径的数组,一共8个数值,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir) 添加非统一圆角的圆角矩形left、top、right、bottom组成矩形区域,radii:矩形四个椭圆圆角的横轴半径和纵轴半径的数组,一共8个数值,dir:线的闭合方向(CW顺时针方向 | CCW逆时针方向)
addPath(Path src) 添加一组Pathsrc:要添加的Path
addPath(Path src, float dx, float dy) 添加一组平移后的Pathsrc:要添加的Path,dx:平移的x坐标,dy:平移的y坐标
addPath(Path src, Matrix matrix) 添加一组经过矩阵变换后的Pathsrc:要添加的Path,matrix:3x3的矩阵

1.addArc(RectF oval, float startAngle, float sweepAngle)

addArc两个方法使用起来与arcTo(RectF oval, float startAngle, float sweepAngle,boolean forceMoveTo)forceMoveTo设置为true效果一致,就不展开赘述了


2.addCircle(float x, float y, float radius, Direction dir)

以点(x,y)为圆心,添加一个半径长为radius圆形,绘制起始角度为0°(x轴方向),绘制方向通过dir的值而定,dirCW时顺时针绘制,dirCCW时逆时针绘制

方法比较简单,主要是对比CWCCW的区别,我们用canvas.drawTextOnPath方法突显顺时针逆时针绘制的效果,示例如下

path.addCircle(200,150,100, Path.Direction.CW);//顺时针绘制
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);
path.addCircle(200,150,100, Path.Direction.CCW);//逆时针绘制
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

3.addOval(RectF oval, Direction dir)

oval矩形区域中,添加一个内切的椭圆,绘制起始角度为0°(x轴方向),绘制方向通过dir的值而定,dirCW时顺时针绘制,dirCCW时逆时针绘制

addOval(RectF oval, Direction dir)addOval(float left, float top, float right, float bottom, Direction dir)效果是一样的,就不分开讲了

RectF rectF = new RectF(100,100,400,250);
path.addOval(rectF, Path.Direction.CW);
canvas.drawPath(path,pathPaint);

效果如图


4.addRect(RectF rect, Direction dir)

添加一个区域为rect矩形,绘制起点为左上角,绘制方向通过dir的值而定,dirCW时顺时针绘制,dirCCW时逆时针绘制

addRect(RectF rect, Direction dir)addRect(float left, float top, float right, float bottom, Direction dir)效果是一样的,就不分开讲了

RectF rectF = new RectF(100,100,400,250);
path.addRect(rectF, Path.Direction.CW);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

效果如图


5.addRoundRect(RectF rect, float rx, float ry, Direction dir)

添加一个区域为rect圆角矩形,四个角的圆角大小一致,圆角的横轴半径为rx纵轴半径为rydirCW时顺时针绘制,绘制起点为左下角dirCCW时逆时针绘制,绘制起点为左上角(注意对比顺时针和逆时针的绘制起点

addRoundRect(RectF rect, float rx, float ry, Direction dir)addRoundRect(float left, float top, float right, float bottom, float rx, float ry,Direction dir)效果是一样的,就不分开讲了

RectF rectF = new RectF(100,100,400,350);
path.addRoundRect(rectF,60,30,Path.Direction.CW);//顺时针
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);
RectF rectF = new RectF(100,100,400,350);
path.addRoundRect(rectF,60,30,Path.Direction.CCW);//逆时针
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

addRoundRect(RectF rect, float[] radii, Direction dir)

添加一个区域为rect圆角矩形,四个角的圆角的横轴和纵轴半径由radii数组中的8个数值决定dirCW时顺时针绘制,绘制起点为左下角dirCCW时逆时针绘制,绘制起点为左上角(注意对比顺时针和逆时针的绘制起点

需要注意的是,如果radii数组中的元素小于8,系统会抛出错误信息radii[] needs 8 values,如下图所示

addRoundRect(RectF rect, float[] radii, Direction dir)addRoundRect(float left, float top, float right, float bottom, float[] radii,Direction dir)效果是一样的,就不分开讲了

RectF rectF = new RectF(100,100,400,350);
float[] radii = {60,30,30,70,100,100,10,40};
path.addRoundRect(rectF,radii,Path.Direction.CW);
canvas.drawPath(path,pathPaint);
canvas.drawTextOnPath("绘制顺序", path, 0, 0, paint);

6.addPath(Path src)

添加一组名为srcPath副本

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();
path.addPath(copyPath);
canvas.drawPath(path,pathPaint);

addPath(Path src, float dx, float dy)

添加一组名为srcPath副本,然后将其进行平移x轴上的平移距离为dxy轴上的平移距离为dy

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();
path.addPath(copyPath,300,0);//向x轴正方向平移300像素距离
canvas.drawPath(path,pathPaint);

addPath(Path src, Matrix matrix)

添加一组名为srcPath副本,然后将其进行矩阵变换,矩阵为matrix(3x3的矩阵)

Path copyPath = new Path();
copyPath.moveTo(100,100);
copyPath.lineTo(150,200);
copyPath.quadTo(200,100,350,200);
copyPath.lineTo(100,250);
copyPath.close();

Matrix mMatrix = new Matrix();
mMatrix.setScale(1,-1);//以x轴为中线进行翻转
mMatrix.postRotate(90);//以坐标轴原点为中心点顺时针旋转90°

path.addPath(copyPath,mMatrix);
canvas.drawPath(path,pathPaint);

四、填充模式

方法名 参数解析
setFillType(FillType ft) 设置Path的填充模式ft:填充类型,有EVEN_ODDINVERSE_EVEN_ODDWINDINGINVERSE_WINDING 四种模式
getFillType() 获取当前Path的填充模式
isInverseFillType() 判断当前Path填充模式是否是反向规则(INVERSE_XXX)
toggleInverseFillType() 当前Path的填充模式与其反向规则模式进行相互切换

填充模式要解释起来还是挺费口舌的,这里就把前辈们的博客贴出来,他们解释得都非常清楚,我就不多赘述了
安卓自定义 View 进阶:Path 完结篇(伪)
[转]Android Path里FillType功能


五、其他方法

方法名 参数解析
close() 封闭当前Path,连接起点终点
reset() 清空Path中的所有直线和曲线,保留填充模式设置,不保留Path上相关的数据结构
rewind() 清空Path中的所有直线和曲线,不保留填充模式设置,但会保留Path上相关的数据结构,以便高效地复用
set(Path src) 用名为src的Path替换当前的Path
op(Path path, Op op) 当前Path名为path的Path进行布尔运算(取差集、交集、并集等)op:运算逻辑,有DIFFERENCE(差集)REVERSE_DIFFERENCE(差集)INTERSECT(交集)UNION(并集)XOR(异或)五种运算逻辑可选。ps:此方法在API 19以上有效
offset(float dx, float dy) 平移当前Pathx轴上平移的距离为dxy轴上平移的距离为dy
offset(float dx, float dy, Path dst) 平移名为dst的Pathx轴上平移的距离为dxy轴上平移的距离为dy
transform(Matrix matrix) 对当前Path进行矩阵变换,矩阵为matrix(3x3矩阵)
transform(Matrix matrix, Path dst) 对名为dst的Path进行矩阵变换,矩阵为matrix(3x3矩阵)
setLastPoint(float dx, float dy) 设置终点,设置当前Path最后一个点的位置为(dx,dy)
isEmpty() 判断当前Path是否为空
isConvex() 判断当前Path围成的图形是否凸多边形。ps:此方法在API 21以上有效
isRect(RectF rect) 判断当前Path是否为矩形,如是,则将当前Path存储到新建的rect中

这里大多数方法都比较简单,有些之前已经应用过,就不展开来讲了,下面介绍一下其中比较特别且常用的几个方法

1.op(Path path, Op op) 布尔运算

前面的表格我们提到参数op共有五种运算逻辑可选,下面我们就来看看这五种运算逻辑是如何影响两个Path之间的关系的,我们先用不同的颜色绘制出一个矩形和一个圆形,观察一下它们的位置和关系

Path path1 = new Path();
path1.addRect(100,100,300,300, Path.Direction.CW);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path1,pathPaint);

Path path2 = new Path();
path2.addCircle(300,250,100,Path.Direction.CW);
pathPaint.setColor(Color.RED);
canvas.drawPath(path2,pathPaint);

下面我们对这两个Path进行布尔运算

DIFFERENCE(差集)

若op方法的调用关系为path1.op(path2, Path.Op.DIFFERENCE),则运算结果是path1减去与path2的交集后剩下的部分,即path1与path2的并集减去path2部分

Path path1 = new Path();
path1.addRect(100,100,300,300, Path.Direction.CW);

Path path2 = new Path();
path2.addCircle(300,250,100,Path.Direction.CW);

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path1.op(path2, Path.Op.DIFFERENCE);//path1与path2进行布尔运算,结果保存至path1
    canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path3.op(path1,path2,Path.Op.DIFFERENCE);//path1与path2进行布尔运算,结果保存至path3
    canvas.drawPath(path3,pathPaint);
}

可以用path1.op直接运算,也可以新建一个path3保存path1和path2的运算结果,效果都是一样的

REVERSE_DIFFERENCE(差集)

若op方法的调用关系为path1.op(path2, Path.Op.REVERSE_DIFFERENCE),则运算结果是path2减去与path1的交集后剩下的部分,即path1与path2的并集减去path1部分

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path1.op(path2, Path.Op.REVERSE_DIFFERENCE);//path1与path2进行布尔运算,结果保存至path1
    canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path3.op(path1,path2,Path.Op.REVERSE_DIFFERENCE);//path1与path2进行布尔运算,结果保存至path3
    canvas.drawPath(path3,pathPaint);
}
INTERSECT(交集)

若op方法的调用关系为path1.op(path2, Path.Op.INTERSECT),则运算结果是path1与path2的交集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path1.op(path2, Path.Op.INTERSECT);//path1与path2进行布尔运算,结果保存至path1
    canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path3.op(path1,path2,Path.Op.INTERSECT);//path1与path2进行布尔运算,结果保存至path3
    canvas.drawPath(path3,pathPaint);
}
UNION(并集)

若op方法的调用关系为path1.op(path2, Path.Op.UNION),则运算结果是path1与path2的并集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path1.op(path2, Path.Op.UNION);//path1与path2进行布尔运算,结果保存至path1
    canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path3.op(path1,path2,Path.Op.UNION);//path1与path2进行布尔运算,结果保存至path3
    canvas.drawPath(path3,pathPaint);
}
XOR(异或)

若op方法的调用关系为path1.op(path2, Path.Op.XOR),则运算结果是path1与path2的并集减去path1与path2的交集

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path1.op(path2, Path.Op.XOR);//path1与path2进行布尔运算,结果保存至path1
    canvas.drawPath(path1,pathPaint);
}

//也可以这样写
Path path3 = new Path();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
    path3.op(path1,path2,Path.Op.XOR);//path1与path2进行布尔运算,结果保存至path3
    canvas.drawPath(path3,pathPaint);
}

2.setLastPoint(float dx, float dy)

Path在调用setLastPoint方法之前执行了某项操作时(绘制直线或曲线等),会将该操作的终点强制设置为(dx,dy)连线(线的曲直取决于该操作本身是绘制直线还是曲线)

理解这个方法之前,首先我们要知道无论是使用addXxx方法还是xxxTo方法等在绘制过程中其实都是根据一堆点的集合,按顺序连线(直线或曲线)后绘制出Path最终的样子setLastPoint方法正是改变此方法调用之前点的集合中最后一个点的位置。下面我们通过封闭图形(矩形)非封闭图形(一段圆弧)的例子更好地理解这个方法

//用绿线绘制一个矩形
path.addRect(new RectF(100,100,300,300), Path.Direction.CW);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path,pathPaint);

//强制设置最后一个点为(150,250),用红线绘制观察变化
path.reset();
path.addRect(new RectF(100,100,300,300), Path.Direction.CW);
path.setLastPoint(150,250);
pathPaint.setColor(Color.RED);
canvas.drawPath(path,pathPaint);
//用绿线绘制一个旋转180°的圆弧
path.addArc(new RectF(100,100,300,300),0,180);
pathPaint.setColor(Color.GREEN);
canvas.drawPath(path,pathPaint);

//强制设置最后一个点为(200,200),用红线绘制观察变化
path.reset();
path.addArc(new RectF(100,100,300,300),0,180);
path.setLastPoint(200,200);
pathPaint.setColor(Color.RED);
canvas.drawPath(path,pathPaint);

至此本篇总结到此结束,若有什么遗漏和错误的地方欢迎留言指出,如果大家看了感觉还不错麻烦点个赞,你们的支持是我最大的动力~

看完觉得手痒还可以去瞧瞧下面的教程博客练手哦๑乛乛๑
Android自定义View——从零开始实现圆形进度条
Android自定义View——从零开始实现水波浪进度框
Android自定义View——从零开始实现书籍翻页效果(一)
Android自定义View——从零开始实现书籍翻页效果(二)
Android自定义View——从零开始实现书籍翻页效果(三)
Android自定义View——从零开始实现书籍翻页效果(四)
Android自定义View——从零开始实现书籍翻页效果(性能优化篇)
Android自定义View——从零开始实现可展开收起的水平菜单栏


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

推荐阅读更多精彩内容

  • 最近项目中要实现加速球效果。是时候该学习一波了,好了废话不多说,记笔记,还是从自己发憷的自定义view开始。 先来...
    laifrog阅读 1,453评论 0 4
  • 参考:android绘图之Path总结Path相关方法讲解(一)path类的简化结构图 内部枚举类 构造方法 构造...
    蒸汽飞船阅读 4,647评论 0 3
  • Paint 属性配置 setAntiAlias:抗锯齿 setDither:抗抖动 setColor,setARG...
    简祖明阅读 907评论 0 3
  • 参考:https://juejin.im/post/58ce7fe561ff4b006c9a63c6https:/...
    zhaoyubetter阅读 5,966评论 0 6
  • 来到简书,原因很简单,希望用笔触记录思考,希望用思考挖掘发现,希望用发现学会感恩,希望用感恩来引导美好。 ...
    银河里的小黑猪阅读 287评论 0 0