Example usage for android.graphics DashPathEffect DashPathEffect

List of usage examples for android.graphics DashPathEffect DashPathEffect

Introduction

In this page you can find the example usage for android.graphics DashPathEffect DashPathEffect.

Prototype

public DashPathEffect(float intervals[], float phase) 

Source Link

Document

The intervals array must contain an even number of entries (>=2), with the even indices specifying the "on" intervals, and the odd indices specifying the "off" intervals.

Usage

From source file:com.app.jdy.ui.MyCommunityActivity.java

private void initLineChart() {

    my_community_linechart = (LineChartView) findViewById(R.id.my_community_linechart);
    my_community_linechart.setOnEntryClickListener(lineEntryListener);
    my_community_linechart.setOnClickListener(lineClickListener);

    mLineGridPaint = new Paint();
    mLineGridPaint.setColor(this.getResources().getColor(R.color.line_grid));
    mLineGridPaint.setPathEffect(new DashPathEffect(new float[] { 5, 5 }, 0));
    mLineGridPaint.setStyle(Paint.Style.STROKE);
    mLineGridPaint.setAntiAlias(true);//from  ww w. ja v a2s  .  c  om
    mLineGridPaint.setStrokeWidth(Tools.fromDpToPx(.75f));
}

From source file:dimchoi.com.my.widget.AnimatedSvgView.java

@SuppressLint("DrawAllocation")
@Override//from   w  ww.j  av a 2s .c o  m
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mState == STATE_NOT_STARTED || mGlyphData == null) {
        return;
    }

    long t = System.currentTimeMillis() - mStartTime;

    // Draw outlines (starts as traced)
    for (int i = 0; i < mGlyphData.length; i++) {
        float phase = constrain(0, 1,
                (t - (mTraceTime - mTraceTimePerGlyph) * i * 1f / mGlyphData.length) * 1f / mTraceTimePerGlyph);
        float distance = INTERPOLATOR.getInterpolation(phase) * mGlyphData[i].length;
        mGlyphData[i].paint.setColor(mTraceResidueColors[i]);
        mGlyphData[i].paint
                .setPathEffect(new DashPathEffect(new float[] { distance, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);

        mGlyphData[i].paint.setColor(mTraceColors[i]);
        mGlyphData[i].paint.setPathEffect(new DashPathEffect(
                new float[] { 0, distance, phase > 0 ? mMarkerLength : 0, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);
    }

    if (t > mFillStart) {
        if (mState < STATE_FILL_STARTED) {
            changeState(STATE_FILL_STARTED);
        }

        // If after fill start, draw fill
        float phase = constrain(0, 1, (t - mFillStart) * 1f / mFillTime);
        for (int i = 0; i < mGlyphData.length; i++) {
            GlyphData glyphData = mGlyphData[i];
            int fillColor = mFillColors[i];
            int a = (int) (phase * ((float) Color.alpha(fillColor) / (float) 255) * 255);
            int r = Color.red(fillColor);
            int g = Color.green(fillColor);
            int b = Color.blue(fillColor);
            mFillPaint.setARGB(a, r, g, b);
            canvas.drawPath(glyphData.path, mFillPaint);
        }
    }

    if (t < mFillStart + mFillTime) {
        // draw next frame if animation isn't finished
        ViewCompat.postInvalidateOnAnimation(this);
    } else {
        changeState(STATE_FINISHED);
    }
}

From source file:com.heneryh.aquanotes.ui.controllers.GraphsFragment.java

/**
 * Handle {@link VendorsQuery} {@link Cursor}.
 *///  w  w w  .j a  va  2s .  c  om
private void onProbeDataQueryComplete(Cursor cursor) {
    if (mCursor != null) {
        // In case cancelOperation() doesn't work and we end up with consecutive calls to this
        // callback.
        getActivity().stopManagingCursor(mCursor);
        mCursor = null;
    }
    mySimpleXYPlot = (XYPlot) mRootView.findViewById(R.id.mySimpleXYPlot);
    mySimpleXYPlot.setOnTouchListener(this);
    mySimpleXYPlot.clear();

    //Creation of the series
    final Vector<Double> vector = new Vector<Double>();
    int numDataPoints = 0;
    String probeName = null;
    Long timestamp = (long) 0;
    String valueS = null;
    try {
        /** For each datapoint in the database, */
        while (cursor.moveToNext()) {
            probeName = cursor.getString(ProbeDataViewQuery.NAME);
            timestamp = cursor.getLong(ProbeDataViewQuery.TIMESTAMP);
            valueS = cursor.getString(ProbeDataViewQuery.VALUE);
            Double valueD = Double.valueOf(valueS);
            vector.add(timestamp.doubleValue());
            vector.add(valueD);
            numDataPoints++;
        } // end of while()
    } finally {
        cursor.close();
        if (numDataPoints < 2)
            return;
    }
    // create our series from our array of nums:
    mySeries = new SimpleXYSeries(vector, ArrayFormat.XY_VALS_INTERLEAVED, probeName);

    mySimpleXYPlot.getGraphWidget().getGridBackgroundPaint().setColor(Color.WHITE);
    mySimpleXYPlot.getGraphWidget().getGridLinePaint().setColor(Color.BLACK);
    mySimpleXYPlot.getGraphWidget().getGridLinePaint()
            .setPathEffect(new DashPathEffect(new float[] { 1, 1 }, 1));
    mySimpleXYPlot.getGraphWidget().getDomainOriginLinePaint().setColor(Color.BLACK);
    mySimpleXYPlot.getGraphWidget().getRangeOriginLinePaint().setColor(Color.BLACK);

    mySimpleXYPlot.setBorderStyle(Plot.BorderStyle.SQUARE, null, null);
    mySimpleXYPlot.getBorderPaint().setStrokeWidth(1);
    mySimpleXYPlot.getBorderPaint().setAntiAlias(false);
    mySimpleXYPlot.getBorderPaint().setColor(Color.WHITE);

    // Create a formatter to use for drawing a series using LineAndPointRenderer:
    LineAndPointFormatter series1Format = new LineAndPointFormatter(Color.rgb(0, 100, 0), // line color
            Color.rgb(0, 100, 0), // point color
            Color.rgb(100, 200, 0)); // fill color

    // setup our line fill paint to be a slightly transparent gradient:
    Paint lineFill = new Paint();
    lineFill.setAlpha(200);
    //lineFill.setShader(new LinearGradient(0, 0, 0, 250, Color.WHITE, Color.GREEN, Shader.TileMode.MIRROR));

    LineAndPointFormatter formatter = new LineAndPointFormatter(Color.rgb(0, 0, 0), Color.BLUE, Color.RED);
    //       formatter.setFillPaint(lineFill);
    formatter.setFillPaint(null);
    //       formatter.setVertexPaint(null);
    formatter.getLinePaint().setShadowLayer(0, 0, 0, 0);
    mySimpleXYPlot.getGraphWidget().setPaddingRight(2);
    mySimpleXYPlot.addSeries(mySeries, formatter);

    // draw a domain tick for each year:
    //mySimpleXYPlot.setDomainStep(XYStepMode.SUBDIVIDE, numDataPoints);

    // customize our domain/range labels
    mySimpleXYPlot.setDomainLabel("Time");
    mySimpleXYPlot.setRangeLabel(probeName);

    // get rid of decimal points in our range labels:
    mySimpleXYPlot.setRangeValueFormat(new DecimalFormat("#0.00"));

    mySimpleXYPlot.setDomainValueFormat(new MyDateFormat());

    // by default, AndroidPlot displays developer guides to aid in laying out your plot.
    // To get rid of them call disableAllMarkup():
    mySimpleXYPlot.disableAllMarkup();

    //Set of internal variables for keeping track of the boundaries
    mySimpleXYPlot.calculateMinMaxVals();
    minXY = new PointF(mySimpleXYPlot.getCalculatedMinX().floatValue(),
            mySimpleXYPlot.getCalculatedMinY().floatValue()); //initial minimum data point
    absMinX = minXY.x; //absolute minimum data point
    //absolute minimum value for the domain boundary maximum
    minNoError = Math.round(mySeries.getX(1).floatValue() + 2);
    maxXY = new PointF(mySimpleXYPlot.getCalculatedMaxX().floatValue(),
            mySimpleXYPlot.getCalculatedMaxY().floatValue()); //initial maximum data point
    absMaxX = maxXY.x; //absolute maximum data point
    //absolute maximum value for the domain boundary minimum
    maxNoError = (float) Math.round(mySeries.getX(mySeries.size() - 1).floatValue()) - 2;

    //Check x data to find the minimum difference between two neighboring domain values
    //Will use to prevent zooming further in than this distance
    double temp1 = mySeries.getX(0).doubleValue();
    double temp2 = mySeries.getX(1).doubleValue();
    double temp3;
    double thisDif;
    minDif = 100000000; //increase if necessary for domain values
    for (int i = 2; i < mySeries.size(); i++) {
        temp3 = mySeries.getX(i).doubleValue();
        thisDif = Math.abs(temp1 - temp3);
        if (thisDif < minDif)
            minDif = thisDif;
        temp1 = temp2;
        temp2 = temp3;
    }
    minDif = minDif + difPadding; //with padding, the minimum difference

    mySimpleXYPlot.redraw();

}

From source file:com.daitu_liang.study.mytest.svg.AnimatedSvgView.java

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mState == STATE_NOT_STARTED || mGlyphData == null) {
        return;//w  w w . jav a  2s . com
    }

    long t = System.currentTimeMillis() - mStartTime;

    // ?
    for (int i = 0; i < mGlyphData.length; i++) {
        float phase = MathUtil.constrain(0, 1,
                (t - (mTraceTime - mTraceTimePerGlyph) * i * 1f / mGlyphData.length) * 1f / mTraceTimePerGlyph);
        float distance = INTERPOLATOR.getInterpolation(phase) * mGlyphData[i].length;
        mGlyphData[i].paint.setColor(mTraceResidueColors[i]);
        mGlyphData[i].paint
                .setPathEffect(new DashPathEffect(new float[] { distance, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);

        mGlyphData[i].paint.setColor(mTraceColors[i]);
        mGlyphData[i].paint.setPathEffect(new DashPathEffect(
                new float[] { 0, distance, phase > 0 ? mMarkerLength : 0, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);
    }

    if (t > mFillStart) {
        if (mState < STATE_FILL_STARTED) {
            changeState(STATE_FILL_STARTED);
        }

        // ????alpha
        float phase = MathUtil.constrain(0, 1, (t - mFillStart) * 1f / mFillTime);
        for (int i = 0; i < mGlyphData.length; i++) {
            GlyphData glyphData = mGlyphData[i];
            mFillPaint.setARGB((int) (phase * ((float) mFillAlphas[i] / (float) 255) * 255), mFillReds[i],
                    mFillGreens[i], mFillBlues[i]);
            canvas.drawPath(glyphData.path, mFillPaint);
        }
    }

    if (t < mFillStart + mFillTime) {
        ViewCompat.postInvalidateOnAnimation(this);
    } else {
        changeState(STATE_FINISHED);
    }
}

From source file:org.ayo.robot.anim.svg.AnimatedSvgView.java

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mState == STATE_NOT_STARTED || mGlyphData == null) {
        return;//from  ww  w  .ja v a  2s. com
    }

    long t = System.currentTimeMillis() - mStartTime;

    // 
    for (int i = 0; i < mGlyphData.length; i++) {
        float phase = MathUtil.constrain(0, 1,
                (t - (mTraceTime - mTraceTimePerGlyph) * i * 1f / mGlyphData.length) * 1f / mTraceTimePerGlyph);
        float distance = INTERPOLATOR.getInterpolation(phase) * mGlyphData[i].length;
        mGlyphData[i].paint.setColor(mTraceResidueColors[i]);
        mGlyphData[i].paint
                .setPathEffect(new DashPathEffect(new float[] { distance, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);

        mGlyphData[i].paint.setColor(mTraceColors[i]);
        mGlyphData[i].paint.setPathEffect(new DashPathEffect(
                new float[] { 0, distance, phase > 0 ? mMarkerLength : 0, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);
    }

    if (t > mFillStart) {
        if (mState < STATE_FILL_STARTED) {
            changeState(STATE_FILL_STARTED);
        }

        // alpha
        float phase = MathUtil.constrain(0, 1, (t - mFillStart) * 1f / mFillTime);
        for (int i = 0; i < mGlyphData.length; i++) {
            GlyphData glyphData = mGlyphData[i];
            mFillPaint.setARGB((int) (phase * ((float) mFillAlphas[i] / (float) 255) * 255), mFillReds[i],
                    mFillGreens[i], mFillBlues[i]);
            canvas.drawPath(glyphData.path, mFillPaint);
        }
    }

    if (t < mFillStart + mFillTime) {
        ViewCompat.postInvalidateOnAnimation(this);
    } else {
        changeState(STATE_FINISHED);
    }
}

From source file:com.jrummyapps.android.widget.AnimatedSvgView.java

@SuppressLint("DrawAllocation")
@Override/*from  w w w  . ja  va2s  .c om*/
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mState == STATE_NOT_STARTED || mGlyphData == null) {
        return;
    }

    long t = System.currentTimeMillis() - mStartTime;

    // Draw outlines (starts as traced)
    if (t < mFillStart + mFillTime) {
        for (int i = 0; i < mGlyphData.length; i++) {
            float phase = constrain(0, 1, (t - (mTraceTime - mTraceTimePerGlyph) * i * 1f / mGlyphData.length)
                    * 1f / mTraceTimePerGlyph);
            float distance = INTERPOLATOR.getInterpolation(phase) * mGlyphData[i].length;
            mGlyphData[i].paint.setColor(mTraceResidueColors[i]);
            mGlyphData[i].paint
                    .setPathEffect(new DashPathEffect(new float[] { distance, mGlyphData[i].length }, 0));
            canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);

            mGlyphData[i].paint.setColor(mTraceColors[i]);
            mGlyphData[i].paint.setPathEffect(new DashPathEffect(
                    new float[] { 0, distance, phase > 0 ? mMarkerLength : 0, mGlyphData[i].length }, 0));
            canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);
        }
    }

    if (t > mFillStart && t < mFillStart + mFillTime) {
        if (mState < STATE_FILL_STARTED) {
            changeState(STATE_FILL_STARTED);
        }

        // If after fill start, draw fill
        float phase = constrain(0, 1, (t - mFillStart) * 1f / mFillTime);
        for (int i = 0; i < mGlyphData.length; i++) {
            GlyphData glyphData = mGlyphData[i];
            int fillColor = mFillColors[i];
            int a = (int) (phase * ((float) Color.alpha(fillColor) / (float) 255) * 255);
            int r = Color.red(fillColor);
            int g = Color.green(fillColor);
            int b = Color.blue(fillColor);
            mFillPaint.setARGB(a, r, g, b);

            canvas.drawPath(glyphData.path, mFillPaint);
        }
    }

    if (t > mFillStart + mFillTime) {
        float phase = (t - mDisappearTime - mFillStart) * 1f / mFillTime;
        if (phase < 0)
            phase = 0;
        else if (phase > 1)
            phase = 1;

        for (int i = 0; i < mGlyphData.length; i++) {
            GlyphData glyphData = mGlyphData[i];
            int fillColor = mFillColors[i];
            int a = 255 - (int) (phase * ((float) Color.alpha(fillColor) / (float) 255) * 255);
            int r = Color.red(fillColor);
            int g = Color.green(fillColor);
            int b = Color.blue(fillColor);
            mFillPaint.setARGB(a, r, g, b);
            canvas.drawPath(glyphData.path, mFillPaint);

            mGlyphData[i].paint.setAlpha(a);
            canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);

        }

    }

    if (t < mFillStart + mDisappearTime + mFillTime) {
        // draw next frame if animation isn't finished
        ViewCompat.postInvalidateOnAnimation(this);
    } else {
        changeState(STATE_FINISHED);
    }
}

From source file:cc.kenai.common.AnimatedSvgView.java

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mState == STATE_NOT_STARTED || mGlyphData == null) {
        return;//from  ww w  .  ja v  a2  s. c  o  m
    }

    long t = System.currentTimeMillis() - mStartTime;

    for (int i = 0; i < mGlyphData.length; i++) {
        float phase = MathUtil.constrain(0, 1,
                (t - (mTraceTime - mTraceTimePerGlyph) * i * 1f / mGlyphData.length) * 1f / mTraceTimePerGlyph);
        float distance = INTERPOLATOR.getInterpolation(phase) * mGlyphData[i].length;
        mGlyphData[i].paint.setColor(mTraceResidueColors[i]);
        mGlyphData[i].paint
                .setPathEffect(new DashPathEffect(new float[] { distance, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);

        mGlyphData[i].paint.setColor(mTraceColors[i]);
        mGlyphData[i].paint.setPathEffect(new DashPathEffect(
                new float[] { 0, distance, phase > 0 ? mMarkerLength : 0, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);
    }

    if (t > mFillStart) {
        if (mState < STATE_FILL_STARTED) {
            changeState(STATE_FILL_STARTED);
        }

        float phase = MathUtil.constrain(0, 1, (t - mFillStart) * 1f / mFillTime);
        for (int i = 0; i < mGlyphData.length; i++) {
            GlyphData glyphData = mGlyphData[i];
            mFillPaint.setARGB((int) (phase * ((float) mFillAlphas[i] / (float) 255) * 255), mFillReds[i],
                    mFillGreens[i], mFillBlues[i]);
            canvas.drawPath(glyphData.path, mFillPaint);
        }
    }

    if (t < mFillStart + mFillTime) {
        ViewCompat.postInvalidateOnAnimation(this);
    } else {
        changeState(STATE_FINISHED);
    }
}

From source file:com.donsen.svg.ui.common.AnimatedSvgView.java

@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    if (mState == STATE_NOT_STARTED || mGlyphData == null) {
        return;/*  ww w  . ja v a  2s  .c  o  m*/
    }

    long t = System.currentTimeMillis() - mStartTime;

    // Draw outlines (starts as traced)
    for (int i = 0; i < mGlyphData.length; i++) {
        float phase = MathUtil.constrain(0, 1,
                (t - (mTraceTime - mTraceTimePerGlyph) * i * 1f / mGlyphData.length) * 1f / mTraceTimePerGlyph);
        float distance = INTERPOLATOR.getInterpolation(phase) * mGlyphData[i].length;
        mGlyphData[i].paint.setColor(mTraceResidueColors[i]);
        mGlyphData[i].paint
                .setPathEffect(new DashPathEffect(new float[] { distance, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);

        mGlyphData[i].paint.setColor(mTraceColors[i]);
        mGlyphData[i].paint.setPathEffect(new DashPathEffect(
                new float[] { 0, distance, phase > 0 ? mMarkerLength : 0, mGlyphData[i].length }, 0));
        canvas.drawPath(mGlyphData[i].path, mGlyphData[i].paint);
    }

    if (t > mFillStart) {
        if (mState < STATE_FILL_STARTED) {
            changeState(STATE_FILL_STARTED);
        }

        // If after fill start, draw fill
        float phase = MathUtil.constrain(0, 1, (t - mFillStart) * 1f / mFillTime);
        for (int i = 0; i < mGlyphData.length; i++) {
            GlyphData glyphData = mGlyphData[i];
            mFillPaint.setARGB((int) (phase * ((float) mFillAlphas[i] / (float) 255) * 255), mFillReds[i],
                    mFillGreens[i], mFillBlues[i]);
            canvas.drawPath(glyphData.path, mFillPaint);
        }
    }

    if (t < mFillStart + mFillTime) {
        // draw next frame if animation isn't finished
        ViewCompat.postInvalidateOnAnimation(this);
    } else {
        changeState(STATE_FINISHED);
    }
}

From source file:com.google.android.apps.forscience.whistlepunk.RunReviewOverlay.java

private void init() {
    Resources res = getResources();

    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setStyle(Paint.Style.FILL);

    mDotPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mDotPaint.setStyle(Paint.Style.FILL);

    mDotBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mDotBackgroundPaint.setColor(res.getColor(R.color.chart_margins_color));
    mDotBackgroundPaint.setStyle(Paint.Style.FILL);

    Typeface valueTypeface = Typeface.create("sans-serif-medium", Typeface.NORMAL);
    Typeface timeTimeface = Typeface.create("sans-serif", Typeface.NORMAL);

    mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTextPaint.setTypeface(valueTypeface);
    mTextPaint.setTextSize(res.getDimension(R.dimen.run_review_overlay_label_text_size));
    mTextPaint.setColor(res.getColor(R.color.text_color_white));

    mTimePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTimePaint.setTypeface(timeTimeface);
    mTimePaint.setTextSize(res.getDimension(R.dimen.run_review_overlay_label_text_size));
    mTimePaint.setColor(res.getColor(R.color.text_color_white));

    mCenterLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mCenterLinePaint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.chart_grid_line_width));
    mCenterLinePaint.setStyle(Paint.Style.STROKE);
    mCenterLinePaint.setColor(res.getColor(R.color.text_color_white));

    mLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mLinePaint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.recording_overlay_bar_width));
    int dashSize = res.getDimensionPixelSize(R.dimen.run_review_overlay_dash_size);
    mLinePaint.setPathEffect(new DashPathEffect(new float[] { dashSize, dashSize }, dashSize));
    mLinePaint.setColor(res.getColor(R.color.note_overlay_line_color));
    mLinePaint.setStyle(Paint.Style.STROKE);

    mPath = new Path();

    // TODO: Need to make sure this is at least as detailed as the SensorAppearance number
    // format!/*from  ww  w.j  a  va 2s .  c o  m*/
    mTextFormat = res.getString(R.string.run_review_chart_label_format);
    mTimeFormat = ElapsedTimeAxisFormatter.getInstance(getContext());

    mCropBackgroundPaint = new Paint();
    mCropBackgroundPaint.setStyle(Paint.Style.FILL);
    mCropBackgroundPaint.setColor(res.getColor(R.color.text_color_black));
    mCropBackgroundPaint.setAlpha(40);

    mCropVerticalLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mCropVerticalLinePaint.setStyle(Paint.Style.STROKE);
    mCropVerticalLinePaint.setStrokeWidth(res.getDimensionPixelSize(R.dimen.chart_grid_line_width));
}

From source file:de.uni_weimar.mheinz.androidtouchscope.display.ScopeView.java

private void initGridV(ShapeDrawable drawable, Path path, int color, int width, int height) {
    path.rewind();/*  w  ww. ja  v a2 s.  c  om*/
    float cellWidth = width / NUM_COLUMNS;
    for (int i = 0; i < NUM_COLUMNS; ++i) {
        path.moveTo(i * cellWidth, 0);
        path.lineTo(i * cellWidth, height);
    }

    float offset = NUM_ROWS * 5;
    drawable.setShape(new PathShape(path, width, height));
    drawable.getPaint().setStyle(Paint.Style.STROKE);
    drawable.getPaint().setColor(color);
    drawable.getPaint().setPathEffect(new DashPathEffect(new float[] { 1, (height - offset) / offset }, 0));
    drawable.setBounds(0, 0, width, height);
}