簡體   English   中英

Android 使自定義視圖無效並重繪

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM