本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布
20181207日更新博客,写这篇文章的时候,我对简书的写作技巧还不熟悉,现在更新下说明
写在前面的话:我就一直纠结啊,这种可以啊,没毛病啊,老铁,我就一直做啊做,实现的效果,就是一直Move事件中的笔的宽度都是一样的,是不是崩溃啊,的确很崩溃,最后我在想,能不能拿到按压值MotionEvent.getPressure();但是最后通过一查,这个方法的返回值是这样决定的:感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的,我一直用手写,这个值永远不变,奔溃,又一次崩溃,最后在研究一个opengl写的Demo的时候,我发现了一个真理:那就是,我要画多长,是用户手指决定的,但是它的Move事件中接受到的点的数量是和这个距离没有相对应的关系,啊哈哈,对不对,我接受了这个多点,但是我要画很长的线,是不是我的线就细了,但Move中的接受到的点数量一样,我画的距离短了,是不是线就粗了,这就是这个Demo的原理,顿时豁然开朗,春暖花开!
不逼逼,看效果,感觉我的书法还阔以,哈哈!!
设置笔宽度为60,效果如下
微信图片_20170910184918.png
image.png
这个效果明显一点,哈哈,是不是很有大师的写字风格
微信图片_20170902142924.jpg
实现这个效果,大体用了40个小时,熬了3天夜,我未来的女朋友给我作证,看了无数的文档,在git上有个哥们用opengGl3.0实现比我这个更牛逼的效果,但是发现在低端手机上会报错,原因是不支持openGL3.0,导致Apk装入失败,1.0的api有看不懂,你说我能怎么办,我也很绝望啊!同时感觉opengl更加节手机性能,but我错了,在低端手机上使用opengl简直就是噩梦,卡的一逼,算了不提了,此功能的实现还是基于安卓的Paint,通过事件去绘制路径。
1.创建DrawPenView类继承View
image.png
初始化笔,笔锋的效果,我个人尝试了使用三个笔,每次绘制的时候,三个笔一起绘制,根据手指的滑动速率的快慢去使其中的某个笔不用绘制,但是这个效果稀烂,所以view的还是用一只笔即可,
mPaint = new Paint();
mPaint.setColor(Color.parseColor("#FF4081"));
mPaint.setStrokeWidth(14);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);//结束的笔画为圆心
mPaint.setStrokeJoin(Paint.Join.ROUND);//连接处元
mPaint.setAlpha(0xFF);
mPaint.setAntiAlias(true);
mPaint.setStrokeMiter(1.0f);
初始化bitmap,和画布,画布在这里主要是生成一张bitmap的
private void initParameter(Context context) {
mContext = context;
DisplayMetrics dm = new DisplayMetrics();
((Activity) mContext).getWindowManager().getDefaultDisplay().getMetrics(dm);
mBitmap = Bitmap.createBitmap(dm.widthPixels, dm.heightPixels, Bitmap.Config.ARGB_8888);
//笔的控制类
mVisualStrokePen=new VisualStrokePen(mContext);
initPaint(mContext);
initCanvas();
}
private void initCanvas() {
mCanvas = new Canvas(mBitmap);
//设置画布的颜色的问题
mCanvas.drawColor(Color.TRANSPARENT);
}
重写onDraw()方法:由于项目需要,在这里我仅仅提供了两个方法:清除画布和绘制。扩展的功能有:返回上一步的绘制步骤,设置画笔的属性,mark笔,毛笔,钢笔,圆珠笔,铅笔等一切的控制都在这里进行
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBitmap, 0, 0, mPaint);
switch (mCanvasCode) {
case CANVAS_NORMAL:
mVisualStrokePen.draw(canvas);
break;
case CANVAS_RESET:
reset();
break;
default:
Log.e(TAG, "onDraw" + Integer.toString(mCanvasCode));
break;
}
super.onDraw(canvas);
}
2.认识MotionEvent对象
当用户触摸屏幕时,将创建一个MontionEvent对象。MotionEvent包含了关于发生触摸的位置和时间的信息,以及触摸事件的其他细节。
/**
event.getAction() //获取触控动作比如ACTION_DOWN
event.getPointerCount(); //获取触控点的数量,比如2则可能是两个手指同时按压屏幕
event.getPointerId(nID); //对于每个触控的点的细节,我们可以通过一个循环执行getPointerId方法获取索引
event.getX(nID); //获取第nID个触控点的x位置,记录的第一个点为getX,getY
event.getY(nID); //获取第nID个点触控的y位置
event.getPressure(nID); //LCD可以感应出用户的手指压力,当然具体的级别由驱动和物理硬件决定的
event.getDownTime() //按下开始时间
event.getEventTime() // 事件结束时间
event.getEventTime()-event.getDownTime()); //总共按下时花费时间
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
//测试过程中,当使用到event的时候,产生了没有收到事件的问题,所以在这里需要obtian的一下
MotionEvent event2 = MotionEvent.obtain(event);
switch (event2.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
setCanvasCode(CANVAS_NORMAL);
mVisualStrokePen.onDown(mVisualStrokePen.createMotionElement(event2));
break;
case MotionEvent.ACTION_MOVE:
mVisualStrokePen.onMove(mVisualStrokePen.createMotionElement(event2));
break;
case MotionEvent.ACTION_UP:
long time = System.currentTimeMillis();</