如何用手指在字母上画线?

4
我希望在视图上动态创建字母和单词,也希望能够通过手指绘制它们之间的线条。
例如,我有像图片中给出的A这样的字母: enter image description here 我想要像图片中给出的那样进行绘制: enter image description here 问题在于该线条是在整个视图上绘制的。我想要找到包含字母的点,并仅在包含字母的点上绘制线条。如果您有任何想法或建议,请告诉我。

最好的方法是寻找一些具有此功能的现有库。如果没有,则矢量成像应该是前进的方向。您可以最初拥有所有26个字母的矢量表示。然后,当用户绘制时,您需要将该动作转换为矢量图像。最后,您可以将用户的输入矢量图形与26个标准字母集进行比较,并拥有一个选择最佳匹配项的算法。 - Parth Kapoor
这是一个相当广泛的问题。如果您想要一个现成的解决方案,我建议首先查看现有的手写识别库 - 这不是一个简单的问题。 - Arend
我认为这个库可能会对你有所帮助 https://github.com/McoyJiang/TracingSample - Kunchok Tashi
1个回答

8

我通过使用两个图像解决了我的问题,一个是常规的"A"图像,另一个是透明的"A"图像,在这两个图像之间,我添加了自定义视图,然后在此视图上绘制手绘线条。

使用以下代码:

public class MainActivity extends Activity {

    DrawingView dv ;   
    private Paint mPaint;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);
        RelativeLayout mtile=(RelativeLayout)findViewById(R.id.mtile);
        dv = new DrawingView(this);
        mtile.addView(dv);
        RelativeLayout rvtrans=new RelativeLayout(this);
        rvtrans.setBackgroundResource(R.drawable.at);
        mtile.addView(rvtrans);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setColor(Color.GREEN);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(12);  
    }

    public class DrawingView extends View {

        public int width;
        public  int height;
        private Bitmap  mBitmap;
        private Canvas  mCanvas;
        private Path    mPath;
        private Paint   mBitmapPaint;
        Context context;
        private Paint circlePaint;
        private Path circlePath;

        public DrawingView(Context c) {
            super(c);
            context=c;
            mPath = new Path();
            mBitmapPaint = new Paint(Paint.DITHER_FLAG);  
            circlePaint = new Paint();
            circlePath = new Path();
            circlePaint.setAntiAlias(true);
            circlePaint.setColor(Color.BLUE);
            circlePaint.setStyle(Paint.Style.STROKE);
            circlePaint.setStrokeJoin(Paint.Join.MITER);
            circlePaint.setStrokeWidth(4f); 
        }

        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);

            mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(mBitmap);

        }
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawBitmap( mBitmap, 0, 0, mBitmapPaint);
            canvas.drawPath( mPath,  mPaint);
            canvas.drawPath( circlePath,  circlePaint);
        }

        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;
            Log.d("start xy==>", x+","+y);
        }
        private void touch_move(float x, float y) {
            Log.d("move xy==>", x+","+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;
            /*  circlePath.reset();
                circlePath.addCircle(mX, mY, 30, Path.Direction.CW);*/
            }
        }
        private void touch_up() {
            mPath.lineTo(mX, mY);
            Log.d("end xy", mX+","+mY);
            circlePath.reset();
            // commit the path to our offscreen
            mCanvas.drawPath(mPath,  mPaint);
            // kill this so we don't double draw
            mPath.reset();
        }

        @Override
        public boolean onTouchEvent(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;
        }  
    }
}

activity_main.xml 是:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/mtile"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/a"
>
</RelativeLayout>

嗨,我使用了你的代码,真的很棒,但是我想在用户完成整个字母"A"后打开一个对话框,显示"完成字母“A”"。我该怎么做呢?如果您知道,请告诉我...!!! - bhumika rijiya
你能提供此代码的源代码吗?由于某些原因,它在我的电脑上无法运行。@Richard Tingle。 - blazing
@blazing 我不是这篇文章的作者,只是它的编辑者。这是bhavikkumar的答案。 - Richard Tingle
你能提供这个的源代码吗?不知道为什么它对我来说无法工作。@bhavikkumar - blazing
嘿,你有源代码吗,@bhumika rijiya? - blazing

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接