I have custom view called ArrowView
.
When this view is part of a layout which is part of an ArrayAdapter
everything is fine. (It is repainted as the underlying data changes.)
When I use that same layout as part of another Adapter
the ArrowView
doesn't repaint.
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.
Do I need to alter my ArrowView
so that it repaints properly?
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; invalidate() method not updating the view. So as per the sdk reference
http://developer.android.com/intl/es/reference/android/view/View.html postInvalidate() will solve the issue.
This can be done in two ways or more!!!.
Calling runOnUi thread in setter method
runOnUiThread(new Runnable() {
public void run() {
this.length = length;
this.invalidate();
}
});
Or Just call postInvalidate()
in setter method.
if onDraw() is called but the view doesn't update itself, the cause may be that it is called on the wrong thread.
In your adapter be sure to handle your view from a UI Thread
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(): Notifies the attached observers that the underlying data has been changed and any View reflecting the data set should refresh itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With