背景
Android 开发过程中, 或多或少会遇到需要使用自定义控件的情况, 而Paint作为画笔, 在整个开发过程中有着至关重要的地位, 用好它, 能让自定义控件展示出你期望的效果, 用不好… 或许会抱怨, 这平台/这工具/这类怎么设计得如此难用.
就如同本文将要阐述的问题, 希望能给遇到相似问题的朋友一点帮助, 若无碰到此类问题, 请自行略过.
问题
先看一张效果图 (图1):
两个网图, 同样设置的笔画宽度为1 setStrokeWidth(1), 左边的显示的大小是正常的, 右边则变成了2. 颜色也淡了.
下面这张图看起来会很明显,(一个方格为一个PIXEL) (图2):
而程序设计时, 所期望的效果是: (图3):
WHY
大概也猜到了, 这可能跟设置了抗锯齿有关, 没错, 确实的这样子
Paint paint; Paint paintAnti; @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { super.onSizeChanged(w, h, oldw, oldh); //无抗锯齿 paint = createPaint(false, Color.GREEN); //设置了抗锯齿 paintAnti = createPaint(true, Color.RED); } Paint createPaint(boolean anti, int color){ Paint paint = new Paint(anti ? Paint.ANTI_ALIAS_FLAG : 0); paint.setColor(color); paint.setStyle(Paint.Style.STROKE); //设置同样的宽度. paint.setStrokeWidth(1); return paint; }
创建画笔的唯一区别就是设置了Paint.ANTI_ALIAS_FLAG, 那么这个问题其实很好解决, 把抗锯齿关了就可以了.
确实是这样.
继续
同样上面的红网模糊的代码, 加入一个功能, 通过触摸更新红网的位置,
//添加直线. void addLine(Path p, float fx, float fy, float tx, float ty){ p.moveTo(fx + startX, fy + startY); p.lineTo(tx + startX, ty + startY); } //更新Path. void update(){ pathAnti.reset(); float left = 60; float right = 110; float top = 0; float bottom = 0; for(int i = 1; i < 10; i ++) { top = bottom = i * interval; addLine(pathAnti, left, top, right, bottom); } top = 0; bottom = 50; for(int i = 1; i < 10; i ++) { left = right = 60 + i * interval; addLine(pathAnti, left, top , right, bottom); } } float startX, startY; @Override public boolean onTouchEvent(MotionEvent event) { startX = event.getX()/30f; startY = event.getY()/30f; update(); postInvalidate(); return true; }
通过不停的触摸不同的位置并观察红网的效果, 发现一个现象,
当startX/startY的值, 去掉整数后, 剩下的小数值, 越接近0.5, 则线越实, 越接近期望的效果.
最接近期望效果 图4
于是, addLine稍微修改下:
void addLine(Path p, float fx, float fy, float tx, float ty){ //取整, 再加上0.5, 得到的结果永远是 x.5; fx = (int)(fx + startX) + 0.5f; tx = (int)(tx + startX) + 0.5f; fy = (int)(fy + startY) + 0.5f; ty = (int)(ty + startY) + 0.5f; p.moveTo(fx, fy); p.lineTo(tx, ty); }
不管如何更新坐标, 显示的效果都如下图: 图5
DashPathEffect dpe = new DashPathEffect(new float[]{3, 4}, 0); paint.setPathEffect(dpe); paintAnti.setPathEffect(dpe);
画个虚线 图6
最后
有点遗憾问题并不能够完美解决. 要能够彻底弄清楚是何原理, 估计得花不少精力去研究系统源码, 暂时没这时间精力, 只能听之任之, 坐等精于此道的先行者指点谜津. 共勉!