如何绘制可变笔划宽度的路径

编程入门 行业动态 更新时间:2024-10-27 12:36:49
本文介绍了如何绘制可变笔划宽度的路径的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我的code是基本从这个例子(的http://角落.squareup / 2010/07 /平滑signatures.html )和谷歌的API(FingerPaint),但现在我想使用的类 VelocityTracker 以改变笔画宽度取决于我的手指的速度。

我以为我可以拆分路径成更小的部分,但我没有找到任何的例子。还有第二个职位( corner.squareup/2012/07 /smoother-signatures.html ),但我既没有具体的贝塞尔曲线类况且我在收集所有百分点的ArrayList 让他们为榜样调整行程宽度是不是非常有帮助。

有没有人有一个想法如何处理呢?我开始学习code两个星期前,因此我pretty的新的这一切的东西。

编辑:我想实现我的MotionEvents的速度和我以前LogCat中跟踪当前的速度,同时运行的应用程序。它没有工作了,但是当我试图用速度为mPaint.setStrokeWidth参数的一部分,我没有得到什么,我其实是想。道路的宽度我画我的画布上是在不断地变化的那一刻起,我开始画一条线,直到我把我的手指。所以这就是为什么我要拆分的路径成较小的部分,因为它现在是,只有最后一个被跟踪的力度影响strokeWidth。

公共类SignatureView扩展视图{     私有静态最后字符串变量= SignatureView.class.getSimpleName();     私有静态最终浮动STROKE_WIDTH = 10;     私有静态最终浮动HALF_STROKE_WIDTH = STROKE_WIDTH / 2;     私人最终双TOUCH_TOLERANCE = 5;     私人诠释H = getResources()getDisplayMetrics()heightPixels。;     私人诠释W = getResources()getDisplayMetrics()widthPixels。;     私人路径的mpath =新路径();     民营涂料mPaint =新的油漆();     民营涂料mBitmapPaint =新的油漆(Paint.DITHER_FLAG);     私人位图mBitmap = Bitmap.createBitmap(W,H,Bitmap.Config.ARGB_8888);     私人帆布mCanvas =新的Canvas(mBitmap);     私人浮动MX,我的;     私人浮动lastTouchX,lastTouchY;     私人最终RectF dirtyRect =新RectF(); 公共SignatureView(上下文的背景下,ATTRS的AttributeSet){     超(背景下,ATTRS);     mPaint.setAntiAlias​​(真正的);     mPaint.setColor(Color.BLACK);     mPaint.setStyle(Paint.Style.STROKE);     mPaint.setStrokeJoin(Paint.Join.ROUND);     mPaint.setStrokeWidth(INITIAL_STROKE_WIDTH);     Log.d(TAG,TOUCH_TOLERANCE =+ TOUCH_TOLERANCE); } @覆盖 保护无效的OnDraw(帆布油画){     canvas.drawBitmap(mBitmap,0,0,mBitmapPaint);     canvas.drawPath(的mpath,mPaint); } @覆盖 公共布尔的onTouchEvent(MotionEvent事件){     浮eventX = event.getX();     浮eventY = event.getY();     INT historySize = event.getHistorySize();     开关(event.getAction()){         案例MotionEvent.ACTION_DOWN:             resetDirtyRect(eventX,eventY);             mPath.reset();             mPath.moveTo(eventX,eventY);             MX = eventX;             我= eventY;             打破;         案例MotionEvent.ACTION_MOVE:             浮DX = Math.abs(eventX - MX);             浮DY = Math.abs(eventY - 我的);             如果(DX> = TOUCH_TOLERANCE || DY> = TOUCH_TOLERANCE){                 mPath.quadTo(MX,MY,(eventX + MX)/ 2,(eventY +我)/ 2);                 MX = eventX;                 我= eventY;             }             的for(int i = 0; I< historySize;我++){                 浮historicalX = event.getHistoricalX(ⅰ);                 浮historicalY = event.getHistoricalY(ⅰ);                 expandDirtyRect(historicalX,historicalY);             }             打破;         案例MotionEvent.ACTION_UP:             的for(int i = 0; I< historySize;我++){                 浮historicalX = event.getHistoricalX(ⅰ);                 浮historicalY = event.getHistoricalY(ⅰ);                 expandDirtyRect(historicalX,historicalY);             }             mPath.lineTo(MX,MY);             mCanvas.drawPath(的mpath,mPaint);             mPath.reset();             打破;         默认:             Log.d(TAG,忽略触摸事件:+ event.toString());         返回false;     }     //包含一半的描边宽度,以避免削波。         无效((INT)(dirtyRect.left - HALF_STROKE_WIDTH)                         (INT)(dirtyRect.top - HALF_STROKE_WIDTH)                         (INT)(dirtyRect.right + HALF_STROKE_WIDTH)                         (中间体)(dirtyRect.bottom + HALF_STROKE_WIDTH));     lastTouchX = eventX;     lastTouchY = eventY;     返回true; } 私人无效expandDirtyRect(浮动historicalX,浮historicalY){     如果(historicalX< dirtyRect.left){         dirtyRect.left = historicalX;     }否则如果(historicalX> dirtyRect.right){         dirtyRect.right = historicalX;     }     如果(historicalY< dirtyRect.top){         dirtyRect.top = historicalY;     }否则如果(historicalY> dirtyRect.bottom){         dirtyRect.bottom = historicalY;     } } 私人无效resetDirtyRect(浮动eventX,浮eventY){     dirtyRect.left = Math.min(lastTouchX,eventX);     dirtyRect.right = Math.max(lastTouchX,eventX);     dirtyRect.top = Math.min(lastTouchY,eventY);     dirtyRect.bottom = Math.max(lastTouchY,eventY); } }

解决方案

您可以使用您的行程值的变化取决于速度,每次分割你的路径对象。在你 SignatureView 类添加

私人路径的mpath =新路径(); ArrayList的<路径> mPaths =新的ArrayList<路径>();

和采取另外的ArrayList保持行程值每条路径

的ArrayList< INT>笔=新的ArrayList<诠释>();

以及 lastTouchX 和 lastTouchY 。我会建议你做 lastStroke 类型 INT 。

私人INT lastStroke = -1; //得到一个初始值

现在你的的onTouchEvent 方法应该是这样的。

@覆盖 公共布尔的onTouchEvent(MotionEvent事件){     浮eventX = event.getX();     浮eventY = event.getY();     INT historySize = event.getHistorySize();     INT eventStroke = //计算笔触大小与速度,使其1-10或任何范围之间,你认为适合     开关(event.getAction()){         案例MotionEvent.ACTION_DOWN:             resetDirtyRect(eventX,eventY);             mPath.reset();             mPath.moveTo(eventX,eventY);             MX = eventX;             我= eventY;             打破;         案例MotionEvent.ACTION_MOVE:             浮DX = Math.abs(eventX - MX);             浮DY = Math.abs(eventY - 我的);             如果(DX> = TOUCH_TOLERANCE || DY> = TOUCH_TOLERANCE){                 如果(lastStroke!= evetnStroke){                     的mpath =新路径();                     mPath.moveTo(MX,MY);                     mPaths.Add(的mpath);                     mStrokes.Add(eventStroke);                 }                 mPath.quadTo(MX,MY,(eventX + MX)/ 2,(eventY +我)/ 2);                 MX = eventX;                 我= eventY;             }             的for(int i = 0; I< historySize;我++){                 浮historicalX = event.getHistoricalX(ⅰ);                 浮historicalY = event.getHistoricalY(ⅰ);                 expandDirtyRect(historicalX,historicalY);             }             打破;         案例MotionEvent.ACTION_UP:             的for(int i = 0; I< historySize;我++){                 浮historicalX = event.getHistoricalX(ⅰ);                 浮historicalY = event.getHistoricalY(ⅰ);                 expandDirtyRect(historicalX,historicalY);             }            mPath.lineTo(MX,MY);            打破;         默认:             Log.d(TAG,忽略触摸事件:+ event.toString());         返回false;     }     //包含一半的描边宽度,以避免削波。     无效((INT)(dirtyRect.left - HALF_STROKE_WIDTH)                     (INT)(dirtyRect.top - HALF_STROKE_WIDTH)                     (INT)(dirtyRect.right + HALF_STROKE_WIDTH)                     (中间体)(dirtyRect.bottom + HALF_STROKE_WIDTH));     lastTouchX = eventX;     lastTouchY = eventY;     lastStroke = eventStroke;     返回true; }

和你的OnDraw方法是

@覆盖 保护无效的OnDraw(帆布油画){     的for(int i = 0; I< mPaths.size();我++){         mPaint.setStrokeWidth(strokes.get(ⅰ));         canvas.drawPath(mPaths.get(i)中,mPaint);     } }

这是基本的思路。您需要修改它,使其工作。

My code is basically from this example (corner.squareup/2010/07/smooth-signatures.html) and Google APIs (FingerPaint) but now I want to use the class VelocityTracker in order to change the stroke width depending on the speed of my finger.

I thought I could split a path into smaller parts but I didn't find any examples. There's also this second post (corner.squareup/2012/07/smoother-signatures.html) but I do neither have a specific bezier curve class nor do I collect all the points in an ArrayList so their example for adjusting stroke width is not very helpful.

Does anyone have an idea how to handle this? I started to learn code two weeks ago so I'm pretty new in all this stuff.

Edit: I tried to implement the velocity of my MotionEvents and I used LogCat to track the current velocity while running the app. It did work out but when I tried to use the velocity as part of the parameter for mPaint.setStrokeWidth I did not get what I actually wanted. The width of the path I draw on my canvas was changing all the time from the moment I started drawing a line till I moved my finger up. So that's why I want to split a path into smaller parts because as it is now, only the last tracked velocity affects the strokeWidth.

public class SignatureView extends View { private static final String TAG = SignatureView.class.getSimpleName(); private static final float STROKE_WIDTH = 10; private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2; private final double TOUCH_TOLERANCE = 5; private int h = getResources().getDisplayMetrics().heightPixels; private int w = getResources().getDisplayMetrics().widthPixels; private Path mPath = new Path(); private Paint mPaint = new Paint(); private Paint mBitmapPaint = new Paint(Paint.DITHER_FLAG); private Bitmap mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); private Canvas mCanvas = new Canvas(mBitmap); private float mX, mY; private float lastTouchX, lastTouchY; private final RectF dirtyRect = new RectF(); public SignatureView(Context context, AttributeSet attrs) { super(context, attrs); mPaint.setAntiAlias(true); mPaint.setColor(Color.BLACK); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeJoin(Paint.Join.ROUND); mPaint.setStrokeWidth(INITIAL_STROKE_WIDTH); Log.d(TAG, "TOUCH_TOLERANCE = " +TOUCH_TOLERANCE); } @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(mBitmap, 0, 0, mBitmapPaint); canvas.drawPath(mPath, mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { float eventX = event.getX(); float eventY = event.getY(); int historySize = event.getHistorySize(); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: resetDirtyRect(eventX, eventY); mPath.reset(); mPath.moveTo(eventX, eventY); mX = eventX; mY = eventY; break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(eventX - mX); float dy = Math.abs(eventY - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { mPath.quadTo(mX, mY, (eventX + mX)/2, (eventY + mY)/2); mX = eventX; mY = eventY; } for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); } break; case MotionEvent.ACTION_UP: for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); } mPath.lineTo(mX, mY); mCanvas.drawPath(mPath, mPaint); mPath.reset(); break; default: Log.d(TAG, "Ignored touch event: " + event.toString()); return false; } // Include half the stroke width to avoid clipping. invalidate( (int) (dirtyRect.left - HALF_STROKE_WIDTH), (int) (dirtyRect.top - HALF_STROKE_WIDTH), (int) (dirtyRect.right + HALF_STROKE_WIDTH), (int) (dirtyRect.bottom + HALF_STROKE_WIDTH)); lastTouchX = eventX; lastTouchY = eventY; return true; } private void expandDirtyRect(float historicalX, float historicalY) { if (historicalX < dirtyRect.left) { dirtyRect.left = historicalX; } else if (historicalX > dirtyRect.right) { dirtyRect.right = historicalX; } if (historicalY < dirtyRect.top) { dirtyRect.top = historicalY; } else if (historicalY > dirtyRect.bottom) { dirtyRect.bottom = historicalY; } } private void resetDirtyRect(float eventX, float eventY) { dirtyRect.left = Math.min(lastTouchX, eventX); dirtyRect.right = Math.max(lastTouchX, eventX); dirtyRect.top = Math.min(lastTouchY, eventY); dirtyRect.bottom = Math.max(lastTouchY, eventY); } }

解决方案

You can use split your path object every time your stroke value changes depending on velocity. In you SignatureView class add

private Path mPath = new Path(); ArrayList<Path> mPaths = new ArrayList<Path>();

and take another ArrayList to keep stroke value for each path

ArrayList<int> strokes = new ArrayList<int>();

add a variable lastStroke along with lastTouchX and lastTouchY. I will recommend you to make lastStroke of type int.

private int lastStroke = -1; //give an initial value

now your onTouchEvent method should be something like this

@Override public boolean onTouchEvent(MotionEvent event) { float eventX = event.getX(); float eventY = event.getY(); int historySize = event.getHistorySize(); int eventStroke= //calculate stroke size with velocity and make it between 1-10 or any range you seem fit switch (event.getAction()) { case MotionEvent.ACTION_DOWN: resetDirtyRect(eventX, eventY); mPath.reset(); mPath.moveTo(eventX, eventY); mX = eventX; mY = eventY; break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(eventX - mX); float dy = Math.abs(eventY - mY); if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) { if(lastStroke != evetnStroke){ mPath = new Path(); mPath.moveTo(mX,mY); mPaths.Add(mPath); mStrokes.Add(eventStroke); } mPath.quadTo(mX, mY, (eventX + mX)/2, (eventY + mY)/2); mX = eventX; mY = eventY; } for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); } break; case MotionEvent.ACTION_UP: for (int i = 0; i < historySize; i++) { float historicalX = event.getHistoricalX(i); float historicalY = event.getHistoricalY(i); expandDirtyRect(historicalX, historicalY); } mPath.lineTo(mX, mY); break; default: Log.d(TAG, "Ignored touch event: " + event.toString()); return false; } // Include half the stroke width to avoid clipping. invalidate( (int) (dirtyRect.left - HALF_STROKE_WIDTH), (int) (dirtyRect.top - HALF_STROKE_WIDTH), (int) (dirtyRect.right + HALF_STROKE_WIDTH), (int) (dirtyRect.bottom + HALF_STROKE_WIDTH)); lastTouchX = eventX; lastTouchY = eventY; lastStroke = eventStroke; return true; }

and your ondraw method would be

@Override protected void onDraw(Canvas canvas) { for(int i=0; i<mPaths.size();i++){ mPaint.setStrokeWidth(strokes.get(i)); canvas.drawPath(mPaths.get(i), mPaint); } }

this is the basic idea. you need to modify it to make it work.

更多推荐

如何绘制可变笔划宽度的路径

本文发布于:2023-10-29 20:32:30,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1540672.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:宽度   路径   笔划

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!