简体   繁体   English

Android自定义视图没有重新绘制,虽然正在调用onDraw

[英]Android custom view not repainting, though onDraw is being called

I have custom view called ArrowView . 我有一个名为ArrowView自定义视图。

When this view is part of a layout which is part of an ArrayAdapter everything is fine. 当这个视图是布局的一部分时,它是ArrayAdapter一部分,一切都很好。 (It is repainted as the underlying data changes.) (它被重新绘制为基础数据更改。)

When I use that same layout as part of another Adapter the ArrowView doesn't repaint. 当我使用相同的布局作为另一个Adapter的一部分时, ArrowView不会重新绘制。

I have debugged it, and found that onDraw is called, with different values for rot , when I expect it to be - it is just that the screen is not updating. 我调试了它,发现onDraw 调用,具有不同的rot值,当我预期它时 - 它只是屏幕没有更新。

Do I need to alter my ArrowView so that it repaints properly? 我是否需要更改我的ArrowView正确重新绘制?

public class ArrowView extends View {

    private Path path;
    public final Paint paint;
    public final Paint circlePaint;
    private float rot = 30;
    private float length = 0.5f;
    private float width = 1.0f;
    public final static int SIZE = 96;
    private float size = SIZE;
    private float xOff;
    private float yOff;

    public ArrowView(Context context, AttributeSet attrs) {
        super(context, attrs);

        path = new Path();
        path.moveTo( 0.0f,  -0.5f);
        path.lineTo( 0.5f,   0.0f);
        path.lineTo( 0.25f,  0.0f);
        path.lineTo( 0.25f,  0.5f);
        path.lineTo(-0.25f,  0.5f);
        path.lineTo(-0.25f,  0.0f);
        path.lineTo(-0.5f,   0.0f);
        path.close();

        paint = new Paint();
        paint.setARGB(150, 0, 150, 0);

        circlePaint = new Paint();
        circlePaint.setARGB(50, 150, 150, 150);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        canvas.translate(xOff, yOff);
        canvas.scale(size, size);
        canvas.save();
        canvas.translate(0.5f, 0.5f);
        canvas.drawCircle(-0.0f, -0.0f, 0.5f, circlePaint);
        canvas.save();
        canvas.rotate(rot, 0.0f, 0.0f);
        canvas.save();
        canvas.scale(width, length);
        canvas.drawPath(path, paint);
        canvas.restore();
        canvas.restore();
        canvas.restore();
        canvas.restore();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

        //Get the width measurement
        int widthSize = getMeasurement(widthMeasureSpec,
                SIZE);

        //Get the height measurement
        int heightSize = getMeasurement(heightMeasureSpec,
                SIZE);

        size = min(widthSize, heightSize) * 0.9f;
        xOff = 0.0f;
        yOff = 0.05f * size;

        //MUST call this to store the measurements
        setMeasuredDimension(widthSize, heightSize);
    }

    public static int getMeasurement(int measureSpec, int contentSize) {
        int specMode = View.MeasureSpec.getMode(measureSpec);
        int specSize = View.MeasureSpec.getSize(measureSpec);
        int resultSize = 0;
        switch (specMode) {
            case View.MeasureSpec.UNSPECIFIED:
                //Big as we want to be
                resultSize = contentSize;
                break;
            case View.MeasureSpec.AT_MOST:
                //Big as we want to be, up to the spec
                resultSize = min(contentSize, specSize);
                break;
            case View.MeasureSpec.EXACTLY:
                //Must be the spec size
                resultSize = specSize;
                break;
        }

        return resultSize;
    }

    public void setLength(float length) {
        this.length = length;
        invalidate();
    }

    public float getLength() {
        return length;
    }

    public void setWidth(float width) {
        this.width = width;
        invalidate();
    }

    public void setRot(float rot) {
        this.rot = rot;
        invalidate();
    }

}

I also faced the same problem when i want to update an view from the non-ui thread and fragment; 当我想从非ui线程和片段更新视图时,我也遇到了同样的问题; invalidate() method not updating the view. invalidate()方法不更新视图。 So as per the sdk reference 所以根据sdk参考

http://developer.android.com/intl/es/reference/android/view/View.html postInvalidate() will solve the issue. http://developer.android.com/intl/es/reference/android/view/View.html postInvalidate()将解决此问题。

This can be done in two ways or more!!!. 这可以通过两种方式或更多方式完成!!!

Calling runOnUi thread in setter method 在setter方法中调用runOnUi线程

runOnUiThread(new Runnable() {
    public void run() {
     this.length = length;
    this.invalidate();
    }
});

Or Just call postInvalidate() in setter method. 或者只需在setter方法中调用postInvalidate()

if onDraw() is called but the view doesn't update itself, the cause may be that it is called on the wrong thread. 如果调用onDraw()但视图不自行更新,原因可能是在错误的线程上调用它。

In your adapter be sure to handle your view from a UI Thread 在您的适配器中,请确保从UI线程处理您的视图

 getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
    mAdapter.updateRot(newRot);
 });

 public void updateRot(double newRot){
     arrowView.setRot(newRot);
     notifyDataSetChanged();
 }

from the adapter use notifyDataSetChanged() to refresh the view 从适配器使用notifyDataSetChanged()刷新视图

notifyDataSetChanged(): Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself. notifyDataSetChanged():通知附加的观察者基础数据已更改,反映数据集的任何视图都应刷新自身。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM