安卓 如何沿着你的手指画一条平滑的线
http://marakana.com/tutorials/android/2d-graphics-example.html
我在下面使用这个例子。但是,当我在屏幕上移动手指太快时,线条会变成单个点。
我不确定我是否可以加快绘图速度。或者我应该用一条直线连接最后两点。这两种解决方案中的第二种似乎是一个不错的选择,除了当手指移动得非常快时,您将有一条直线的长段,然后是尖锐的曲线。
如果有任何其他解决方案,那就太好了。
提前感谢您的任何帮助。
http://marakana.com/tutorials/android/2d-graphics-example.html
我在下面使用这个例子。但是,当我在屏幕上移动手指太快时,线条会变成单个点。
我不确定我是否可以加快绘图速度。或者我应该用一条直线连接最后两点。这两种解决方案中的第二种似乎是一个不错的选择,除了当手指移动得非常快时,您将有一条直线的长段,然后是尖锐的曲线。
如果有任何其他解决方案,那就太好了。
提前感谢您的任何帮助。
正如你所提到的,一个简单的解决方案是简单地用一条直线连接点。下面是执行此操作的代码:
public void onDraw(Canvas canvas) {
Path path = new Path();
boolean first = true;
for(Point point : points){
if(first){
first = false;
path.moveTo(point.x, point.y);
}
else{
path.lineTo(point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
确保将颜料从填充更改为描边:
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.WHITE);
另一种选择是使用 quadTo 方法通过迭代连接点:
public void onDraw(Canvas canvas) {
Path path = new Path();
boolean first = true;
for(int i = 0; i < points.size(); i += 2){
Point point = points.get(i);
if(first){
first = false;
path.moveTo(point.x, point.y);
}
else if(i < points.size() - 1){
Point next = points.get(i + 1);
path.quadTo(point.x, point.y, next.x, next.y);
}
else{
path.lineTo(point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
这仍然会导致一些锋利的边缘。
如果你真的雄心勃勃,你可以开始计算三次样条,如下所示:
public void onDraw(Canvas canvas) {
Path path = new Path();
if(points.size() > 1){
for(int i = points.size() - 2; i < points.size(); i++){
if(i >= 0){
Point point = points.get(i);
if(i == 0){
Point next = points.get(i + 1);
point.dx = ((next.x - point.x) / 3);
point.dy = ((next.y - point.y) / 3);
}
else if(i == points.size() - 1){
Point prev = points.get(i - 1);
point.dx = ((point.x - prev.x) / 3);
point.dy = ((point.y - prev.y) / 3);
}
else{
Point next = points.get(i + 1);
Point prev = points.get(i - 1);
point.dx = ((next.x - prev.x) / 3);
point.dy = ((next.y - prev.y) / 3);
}
}
}
}
boolean first = true;
for(int i = 0; i < points.size(); i++){
Point point = points.get(i);
if(first){
first = false;
path.moveTo(point.x, point.y);
}
else{
Point prev = points.get(i - 1);
path.cubicTo(prev.x + prev.dx, prev.y + prev.dy, point.x - point.dx, point.y - point.dy, point.x, point.y);
}
}
canvas.drawPath(path, paint);
}
另外,我发现您需要更改以下内容以避免重复的运动事件:
public boolean onTouch(View view, MotionEvent event) {
if(event.getAction() != MotionEvent.ACTION_UP){
Point point = new Point();
point.x = event.getX();
point.y = event.getY();
points.add(point);
invalidate();
Log.d(TAG, "point: " + point);
return true;
}
return super.onTouchEvent(event);
}
并将 dx & dy 值添加到 Point 类中:
class Point {
float x, y;
float dx, dy;
@Override
public String toString() {
return x + ", " + y;
}
}
这会产生平滑的线条,但有时必须使用循环连接点。此外,对于长时间的绘图会话,计算起来会变得计算密集。
希望有所帮助...有趣的东西可以玩。
编辑
我制作了一个快速项目来演示这些不同的技术,包括Square的suggessted签名实现。享受: https://github.com/johncarl81/androiddraw
这对你来说可能不再重要了,但我为解决它而挣扎了很多,我想分享,可能对其他人有用。
提供的解决方案@johncarl教程非常适合绘制,但它们为我的目的提供了限制。如果将手指移出屏幕并将其放回原处,此解决方案将在上次单击和新单击之间绘制一条线,从而使整个绘图始终连接。所以我试图找到一个解决方案,最后我得到了它!(抱歉,如果听起来很明显,我是图形初学者)
public class MainActivity extends Activity {
DrawView drawView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Set full screen view
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
requestWindowFeature(Window.FEATURE_NO_TITLE);
drawView = new DrawView(this);
setContentView(drawView);
drawView.requestFocus();
}
}
public class DrawingPanel extends View implements OnTouchListener {
private static final String TAG = "DrawView";
private static final float MINP = 0.25f;
private static final float MAXP = 0.75f;
private Canvas mCanvas;
private Path mPath;
private Paint mPaint;
private LinkedList<Path> paths = new LinkedList<Path>();
public DrawingPanel(Context context) {
super(context);
setFocusable(true);
setFocusableInTouchMode(true);
this.setOnTouchListener(this);
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setColor(Color.BLACK);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
mCanvas = new Canvas();
mPath = new Path();
paths.add(mPath);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
for (Path p : paths){
canvas.drawPath(p, mPaint);
}
}
private float mX, mY;
private static final float TOUCH_TOLERANCE = 4;
private void touch_start(float x, float y) {
mPath.reset();
mPath.moveTo(x, y);
mX = x;
mY = y;
}
private void touch_move(float x, float y) {
float dx = Math.abs(x - mX);
float dy = Math.abs(y - mY);
if (dx >= TOUCH_TOLERANCE || dy >= TOUCH_TOLERANCE) {
mPath.quadTo(mX, mY, (x + mX)/2, (y + mY)/2);
mX = x;
mY = y;
}
}
private void touch_up() {
mPath.lineTo(mX, mY);
// commit the path to our offscreen
mCanvas.drawPath(mPath, mPaint);
// kill this so we don't double draw
mPath = new Path();
paths.add(mPath);
}
@Override
public boolean onTouch(View arg0, MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
return true;
}
}
我用你的手指拿了Android示例进行绘图,并对其进行了一些修改,以存储每个路径而不仅仅是最后一个路径!希望它能帮助别人!
干杯。