安卓自定义视图不重绘,即使onDraw被调用

6

我有一个名为ArrowView的自定义视图。

当这个视图是作为ArrayAdapter的一部分的布局的一部分时,一切都很好。(它会随着底层数据的更改而重新绘制。)

当我将相同的布局作为另一个Adapter的一部分时,ArrowView不会被重新绘制。

我已经调试过了,发现onDraw确实被调用了,并且rot的值与我期望的不同-只是屏幕没有更新。

我需要修改我的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();
    }

}

你尝试过在适配器中使视图无效吗? - Groco
1
尝试在数组适配器上调用notifydatasetchanged()方法,并调用invalidate()方法。如果它是非UI调用,则在Arrowview上调用postInvalidate()方法。 - Madhukar Hebbar
1
@MadhukarHebbar 谢谢,postInvalidate()解决了问题。如果您写一个答案,我会授予50点赏金。 - fadedbee
1
@chrisdew 要小心,当从其他线程调用postInvalidate()时会出现一些问题。通常更喜欢使用invalidate()和runOnUiThread。 - Luca S.
@LucaS。我从UI线程调用了postInvalidate(),所以应该是安全的... invalidate() 对我没用。 - fadedbee
2个回答

5
我也曾面临同样的问题,当我想从非UI线程和片段更新视图时,invalidate()方法无法更新视图。因此,根据SDK参考资料,postInvalidate()将解决此问题。这可以通过两种或更多方式完成!!!其中一种是在setter方法中调用runOnUiThread。
runOnUiThread(new Runnable() {
    public void run() {
     this.length = length;
    this.invalidate();
    }
});

或者在setter方法中调用postInvalidate()


1
如果调用 onDraw() 但视图没有更新,原因可能是在错误的线程上调用了该方法。
在您的适配器中,请务必从 UI 线程处理您的视图。
 getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
    mAdapter.updateRot(newRot);
 });

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

使用适配器时,可以使用notifyDataSetChanged()来刷新视图

notifyDataSetChanged():通知已附加的观察者底层数据已更改,并且任何反映数据集的视图都应该刷新自己。


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