如何绘制可变笔划宽度的路径 [英] How to draw a path with variable stroke width
问题描述
我的code是基本从这个例子(的http://角落.squareup.com / 2010/07 /平滑signatures.html )和谷歌的API(FingerPaint),但现在我想使用的类 VelocityTracker
以改变笔画宽度取决于我的手指的速度。
我以为我可以拆分路径成更小的部分,但我没有找到任何的例子。还有第二个职位( http://corner.squareup.com/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 >。我会建议你做 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 (http://corner.squareup.com/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 (http://corner.squareup.com/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.
这篇关于如何绘制可变笔划宽度的路径的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!