[英]Android invalidate and redraw custom view
我在相對布局中有一個自定義視圖:
<my.app.com.GardenCalendarView
android:id="@+id/gardenCalendar"
android:layout_width="match_parent"
android:layout_height="84dp"
/>
它繪制了一個日歷。
GardenCalendarView.java :
public class GardenCalendarView extends View {
private Plant plant;
private Rect bounds;
private Paint boundPaint;
private Paint subLinePaint;
private Paint textPaint;
private Paint barPaint;
private RectF startInsideRect;
private RectF transplantRect;
private RectF sowOutsideRect;
private static final int MARGIN = 40;
private static final int PADDING = 5;
private float partWidth;
public GardenCalendarView(Context context) {
super(context);
init(context);
}
public GardenCalendarView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public GardenCalendarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
public void setPlant(Plant plant) {
this.plant = plant;
invalidate();
}
public void init(Context context) {
bounds = new Rect();
boundPaint = new Paint();
boundPaint.setColor(Color.parseColor("#5E8364"));
boundPaint.setStyle(Paint.Style.STROKE);
boundPaint.setAntiAlias(true);
boundPaint.setStrokeWidth(1);
boundPaint.setStrokeJoin(Paint.Join.ROUND);
boundPaint.setStrokeCap(Paint.Cap.ROUND);
subLinePaint = new Paint(boundPaint);
subLinePaint.setColor(Color.parseColor("#B8CCBB"));
textPaint = new Paint(boundPaint);
textPaint.setColor(Color.DKGRAY);
textPaint.setTextSize(Utils.dpToPx(10f, context));
startInsideRect = new RectF();
transplantRect = new RectF();
sowOutsideRect = new RectF();
barPaint = new Paint();
barPaint.setAntiAlias(true);
barPaint.setStyle(Paint.Style.FILL_AND_STROKE);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (plant != null) {
paint(canvas);
}
}
private void paint(Canvas canvas) {
canvas.drawRect(bounds, boundPaint);
// draw vertical lines
for (int i = 0; i < 36; ++i) {
if (i % 3 == 0) {
canvas.drawLine(
bounds.left + partWidth * i,
bounds.top,
bounds.left + partWidth * i,
bounds.bottom, boundPaint
);
//Paint month label
canvas.drawText(
Plant.MONTHS[i / 3],
bounds.left + 10 + partWidth * i,
bounds.top - 8, textPaint);
} else {
canvas.drawLine(
bounds.left + partWidth * i,
bounds.top,
bounds.left + partWidth * i,
bounds.bottom, subLinePaint);
}
}
// draw start inside bar
barPaint.setColor(plant.startInside.color);
canvas.drawRect(startInsideRect, barPaint);
// draw transplant bar
barPaint.setColor(plant.transplant.color);
canvas.drawRect(transplantRect, barPaint);
// draw sow outside bar
barPaint.setColor(plant.sowOutside.color);
canvas.drawRect(sowOutsideRect, barPaint);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
int xpad = getPaddingLeft() + getPaddingRight();
int ypad = getPaddingTop() + getPaddingBottom();
int ww = w - xpad;
int hh = h - ypad;
bounds.set(0, 0, ww, hh);
Utils.reduceRectBy(bounds, MARGIN);
partWidth = bounds.width() / 36f;
float partHeight = bounds.height() / 3f;
float monthWidth = partWidth * 1; //partWidth * 3; if full month column
startInsideRect.set(
bounds.left + (plant.startInside.startMonth - 1) * monthWidth,
bounds.top + 0 * partHeight + PADDING,
bounds.left + (plant.startInside.endMonth ) * monthWidth, //(plant.startInside.endMonth - 1) * monthWidth,
bounds.top + 1 * partHeight - PADDING
);
transplantRect.set(
bounds.left + (plant.transplant.startMonth - 1) * monthWidth,
bounds.top + 1 * partHeight + PADDING,
bounds.left + (plant.transplant.endMonth ) * monthWidth,
bounds.top + 2 * partHeight - PADDING
);
sowOutsideRect.set(
bounds.left + (plant.sowOutside.startMonth - 1) * monthWidth,
bounds.top + 2 * partHeight + PADDING,
bounds.left + (plant.sowOutside.endMonth ) * monthWidth,
bounds.top + 3 * partHeight - PADDING
);
}
}
然后是 Plant.java :
public class Plant {
public String name;
public Bar startInside;
public Bar transplant;
public Bar sowOutside;
public static String[] MONTHS = new String[]{
"JAN", "FEB", "MAR", "APR", "MÁJ", "JÚN",
"JÚL", "AUG", "SEP", "OKT", "NOV", "DEC"
};
public Plant(String name, Bar startInside, Bar transplant, Bar sowOutside) {
this.name = name;
this.startInside = startInside;
this.transplant = transplant;
this.sowOutside = sowOutside;
}
}
和Bar.java :
public class Bar {
public int startMonth;
public int endMonth;
public int color;
public Bar(int start, int end, String color) {
this.startMonth = start;
this.endMonth = end;
this.color = Color.parseColor(color);
}
}
現在我調用它來繪制日歷:
GardenCalendarView gardenCalendar = findViewById(R.id.gardenCalendar);
Bar startInsideBar = new Bar(5, 8, "#CCff8040");
Bar transplantBar = new Bar(9, 12, "#CC5E8364");
Bar sowOutsideBar = new Bar(15, 18, "#CCd2d200");
Plant myPlant = new Plant(
"plantName",
startInsideBar,
transplantBar,
sowOutsideBar);
gardenCalendar.setPlant(myPlant);
這工作正常,顯示視圖。
但是我有一個按鈕,單擊它后,我想用另一個參數重繪該視圖。
public void ResetCalendar(View view)
{
GardenCalendarView gardenCalendar = findViewById(R.id.gardenCalendar);
gardenCalendar.invalidate();
Bar startInsideBar = new Bar(1, 5, "#CCff8040");
Bar transplantBar = new Bar(20, 25, "#CC5E8364");
Bar sowOutsideBar = new Bar(6, 8, "#CCd2d200");
Plant myPlant = new Plant(
"platName2",
startInsideBar,
transplantBar,
sowOutsideBar);
gardenCalendar.setPlant(myPlant);
}
您可以看到,只有 Bars 中的數字發生了變化,但沒有任何反應,View 具有舊值並且沒有重繪。 我也嘗試調用gardenCalendar.invalidate();
沒有運氣。
我也嘗試用上下文調用init
,但隨后整個 View 消失了,沒有重繪。
從原始問題Android 表作為全年的日歷視圖
不要使用更新后的onSizeChanged
優化,因為它不會重新計算條形的 position,除非視圖大小發生變化。
如果您為條形使用不同的顏色,您會注意到它們以新顏色重新繪制。
所以你的paint
方法應該看起來像
private void paint(Canvas canvas) {
getDrawingRect(bounds);
Utils.reduceRectBy(bounds, MARGIN);
canvas.drawRect(bounds, boundPaint);
float partWidth = bounds.width() / 36f;
// draw vertical lines
for (int i = 0; i< 36; ++i) {
if (i % 3 == 0) {
canvas.drawLine(
bounds.left + partWidth *i,
bounds.top,
bounds.left + partWidth *i,
bounds.bottom, boundPaint);
//Paint month label
String month = Plant.MONTHS[i/3].toString();
canvas.drawText(month, bounds.left + partWidth *i, bounds.top - 4, textPaint);
} else {
canvas.drawLine(
bounds.left + partWidth *i,
bounds.top,
bounds.left + partWidth *i,
bounds.bottom, subLinePaint);
}
}
float partHeight = bounds.height() / 3f;
float monthWidth = partWidth*3;
// draw start inside bar
startInsideRect.left = bounds.left + (plant.startInside.startMonth - 1)* monthWidth;
startInsideRect.right = bounds.left + (plant.startInside.endMonth - 1)* monthWidth;
startInsideRect.top = bounds.top + 0* partHeight + PADDING;
startInsideRect.bottom = bounds.top + 1* partHeight - PADDING;
barPaint.setColor(plant.startInside.color);
canvas.drawRect(startInsideRect, barPaint);
// draw transplant bar
transplantRect.left = bounds.left + (plant.transplant.startMonth - 1)* monthWidth;
transplantRect.right = bounds.left + (plant.transplant.endMonth - 1)* monthWidth;
transplantRect.top = bounds.top + 1* partHeight + PADDING;
transplantRect.bottom = bounds.top + 2* partHeight - PADDING;
barPaint.setColor(plant.transplant.color);
canvas.drawRect(transplantRect, barPaint);
// draw sow outside bar
sowOutsideRect.left = bounds.left + (plant.sowOutside.startMonth - 1)* monthWidth;
sowOutsideRect.right = bounds.left + (plant.sowOutside.endMonth - 1)* monthWidth;
sowOutsideRect.top = bounds.top + 2* partHeight + PADDING;
sowOutsideRect.bottom = bounds.top + 3* partHeight - PADDING;
barPaint.setColor(plant.sowOutside.color);
canvas.drawRect(sowOutsideRect, barPaint);
}
也調用gardenCalendar.invalidate();
是不必要的,因為它是在setPlant
中完成的
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.