Android视图不响应绘制

Posted

技术标签:

【中文标题】Android视图不响应绘制【英文标题】:Android view doesn't respond to draw 【发布时间】:2013-12-02 07:03:07 【问题描述】:

我目前正在尝试在 android 中使用我的第一个自定义视图,并一直尝试通过 onTouchEvent 在画布上绘制点,但多次尝试后都失败了。 View 确实检测到我的触摸并在触摸时成功打印出 System.out.println 消息,但它仍然没有在画布上绘制。

经过几次不同的尝试,这是我想出的:

package com.techdigy.testapp;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;

public class DrawingBoard extends View 
    Canvas canvas;
    Bitmap bmp;
    BitmapDrawable temp;

    public DrawingBoard(Context context, AttributeSet attributeSet) 
        super(context,attributeSet);
        // TODO Auto-generated constructor stub     
    
    protected void onSizeChanged(int w, int h, int oldw, int oldh) 
        super.onSizeChanged(w, h, oldw, oldh);
        bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        canvas = new Canvas();
        

    protected void onDraw(Canvas canvas) 
        //draw view
        
    public boolean onTouchEvent(MotionEvent event) 
        //detect user touch
        float touchX = event.getX();
        float touchY = event.getY();
        Paint paint = new Paint();
        System.out.println("test");
        this.canvas.drawPoint(touchX, touchY, paint);
        temp = new BitmapDrawable(this.bmp);
        this.setBackground(this.temp);
        invalidate();
        return true;
        

【问题讨论】:

【参考方案1】:

将此代码用于绘制点或画布上的任何东西...

public class signature extends View 
        private static final float STROKE_WIDTH = 5f;
        private static final float HALF_STROKE_WIDTH = STROKE_WIDTH / 2;
        private Paint paint = new Paint();
        private Path path = new Path();

        private float lastTouchX;
        private float lastTouchY;
        private final RectF dirtyRect = new RectF();

        public signature(Context context, AttributeSet attrs) 
            super(context, attrs);
            paint.setAntiAlias(true);
            paint.setColor(Color.BLACK);
            paint.setStyle(Paint.Style.STROKE);
            paint.setStrokeJoin(Paint.Join.ROUND);
            paint.setStrokeWidth(STROKE_WIDTH);
        

        public void save(View v) 
            Log.v("log_tag", "Width: " + v.getWidth());
            Log.v("log_tag", "Height: " + v.getHeight());
            if (mBitmap == null) 
                mBitmap = Bitmap.createBitmap(mContent.getWidth(),
                        mContent.getHeight(), Bitmap.Config.RGB_565);
                ;
            
            Canvas canvas = new Canvas(mBitmap);
            try 
                FileOutputStream mFileOutStream = new FileOutputStream(new File(Environment.getExternalStorageDirectory().toString()
                        , "sign.png"));

                v.draw(canvas);
                mBitmap.compress(Bitmap.CompressFormat.PNG, 90, mFileOutStream);
                mFileOutStream.flush();
                mFileOutStream.close();
                String url = Images.Media.insertImage(getContentResolver(),
                        mBitmap, "title", null);
                Log.v("log_tag", "url: " + url);
                // In case you want to delete the file
                // boolean deleted = mypath.delete();
                // Log.v("log_tag","deleted: " + mypath.toString() + deleted);
                // If you want to convert the image to string use base64
                // converter

             catch (Exception e) 
                Log.v("log_tag", e.toString());
            
        

        public void clear() 
            path.reset();
            invalidate();
        

        @Override
        protected void onDraw(Canvas canvas) 
            canvas.drawPath(path, paint);
        

        @Override
        public boolean onTouchEvent(MotionEvent event) 
            float eventX = event.getX();
            float eventY = event.getY();
            mGetSign.setEnabled(true);

            switch (event.getAction()) 
            case MotionEvent.ACTION_DOWN:
                path.moveTo(eventX, eventY);
                lastTouchX = eventX;
                lastTouchY = eventY;
                return true;

            case MotionEvent.ACTION_MOVE:

            case MotionEvent.ACTION_UP:

                resetDirtyRect(eventX, eventY);
                int historySize = event.getHistorySize();
                for (int i = 0; i < historySize; i++) 
                    float historicalX = event.getHistoricalX(i);
                    float historicalY = event.getHistoricalY(i);
                    expandDirtyRect(historicalX, historicalY);
                    path.lineTo(historicalX, historicalY);
                
                path.lineTo(eventX, eventY);
                break;

            default:
                debug("Ignored touch event: " + event.toString());
                return false;
            

            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 debug(String string) 
        

        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);
        
    

【讨论】:

【参考方案2】:

试试这个...

public class DrawingBoard extends View 
    private Bitmap bmp;
    private float touchX;
    private float touchY;
    private Paint paint;
    public DrawingBoard(Context context, AttributeSet attributeSet) 
        super(context, attributeSet);
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.GREEN);
        paint.setStyle(Paint.Style.STROKE);
    

    protected void onSizeChanged(int w, int h, int oldw, int oldh) 
        super.onSizeChanged(w, h, oldw, oldh);
        bmp = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
        setBackgroundDrawable(new BitmapDrawable(getResources(), bmp));
    

    protected void onDraw(Canvas canvas) 
        super.onDraw(canvas);
        canvas.drawPoint(touchX, touchY, paint);
    

    public boolean onTouchEvent(MotionEvent event) 
        // detect user touch
        touchX = event.getX();
        touchY = event.getY();
        System.out.println("test");
        invalidate();
        return true;
    

【讨论】:

感谢您的帮助。这有效,但只是暂时保留该值,当您单击其他位置时,它会被移动。还有关于我在原始代码中做错了什么的任何想法? 您正在创建的画布上绘制点。此画布与视图无关。当您想绘制任何东西时,请在 onDraw() 方法中作为参数获取的画布上绘制

以上是关于Android视图不响应绘制的主要内容,如果未能解决你的问题,请参考以下文章

MFC 对话框中的 QWinWidget 不重新绘制或响应 Tab/箭头键

Android 的某些 EditText 字段不响应长按(API 30+ with layout_width 0dp)

滚动视图底部的按钮不响应

子视图不响应父视图的手势识别

为不总是有响应的视图禁用 Django CSRF

为啥自定义 SwiftUI 视图不响应状态变化