Search code examples
javaandroidcanvashandlerondraw

Draw multiple rectangles with delays between them


I am using Handler post delay to call onDraw each time I want to draw new rectangle, but for every new rectangle erase the previous one ..
How can I make the canvas keep the content of all rectangles: My code:

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.CountDownTimer;
import android.os.Handler;
import android.util.Log;

import com.adhamenaya.microchart.model.ChartData;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;

/**
 * Created by Admin on 18/12/2016.
 */

public class ColumnChart extends Chart implements Runnable {

    private int mSpace = 0;
    private int mColumnSize = 0;
    private int mColumnsCount = 0;
    private int mCurrentStart = 0;
    private float mHeightUnit = 0;
    private int mHeightDiff;
    int columnIndex = 0;

    private Handler mHandler;
    private Canvas mCanvas;
    private Iterator mDataIterator;

    static final long FRAME_TIME = 100;
    private ArrayList<Rect> rectangles = new ArrayList<Rect>();


    public ColumnChart(Context context) {
        super(context);
        mHandler = new Handler();
    }

    @Override
    protected void prepare() {
        if (mChartData != null && mChartData.getSingleData().size() > 0) {
            mColumnsCount = mChartData.getSingleData().size();

            // Column size, 1 is added to reserve a space at the end of the chart
            mColumnSize = (int) ((mWidth / (mColumnsCount)) * 0.9);

            // Calculate the space between the bars
            mSpace = (mWidth / mColumnsCount) - mColumnSize;

            // Calculate height unit
            // Calculate 80% of the total height
            float height08 = mHeight * 0.8f;
            mHeightUnit = height08 / mChartData.getMax();

            // Draw bars
            mDataIterator = mChartData.getSingleData().entrySet().iterator();

            mMainPaint = getRectPaint();


            // Create rect objects
            while (mDataIterator.hasNext()) {
                Map.Entry entry = (Map.Entry) mDataIterator.next();

                int columnHeight = (int) ((int) entry.getValue() * mHeightUnit);
                String key = (String) entry.getKey();

                // Shift the
                mCurrentStart += mSpace;

                // Calculate the difference between the total height and the height of the column
                mHeightDiff = mHeight - columnHeight;

                mCurrentStart += mColumnSize;

                mDataIterator.remove();

                Rect rect = new Rect(mCurrentStart, mHeightDiff,
                        mCurrentStart + mColumnSize, mHeight);
                rectangles.add(rect);
            }
        }
    }

    @Override
    protected void paintChart(Canvas canvas) {

    }

    @Override
    public void setData(ChartData data) {
        this.mChartData = data;
        prepare();
        mHandler.post(this);
    }

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

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // Get measured height and width of the view
        setMeasuredDimension(getMeasurement(widthMeasureSpec, mWidth),
                getMeasurement(heightMeasureSpec, mHeight));

        // mWidth = MeasureSpec.getSize(widthMeasureSpec);
        // mHeight = MeasureSpec.getSize(heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(columnIndex > 0 && columnIndex<rectangles.size())
            canvas.drawRect(rectangles.get(columnIndex), getRectPaint());
    }

    @Override
    public void run() {

        if(columnIndex<rectangles.size()){
            invalidate();
            columnIndex++;
            mHandler.postDelayed(this,FRAME_TIME);
        }else{
            mHandler.removeCallbacks(this);
        }
    }
}

Solution

  • Create a FrameLayout on which you want to draw rectangles. Create a view every time you are drawing a new circle. Draw circle on newly created view and the add that view to FrameLayout. Background of the view will be transparent by default. If not then set the background as transparent. This way your previous rectangles will be visible and new rectangle will be drawn on existing rectangles.