android.graphics.PathEffect

Here are the examples of the java api android.graphics.PathEffect taken from open source projects. By voting up you can indicate which examples are most useful and appropriate.

67 Examples 7

19 Source : SunriseSunsetView.java
with Apache License 2.0
from tianma8023

public void setTrackPathEffect(PathEffect trackPathEffect) {
    mTrackPathEffect = trackPathEffect;
}

19 Source : AbstractPaintSubject.java
with Apache License 2.0
from pkware

public void hasPathEffect(@Nullable PathEffect effect) {
    check("getPathEffect()").that(actual.getPathEffect()).isSameInstanceAs(effect);
}

19 Source : CustomCalendar.java
with Apache License 2.0
from openXu

/**
 * 绘制某一行的日期
 * @param canvas
 * @param top 顶部坐标
 * @param count 此行需要绘制的日期数量(不一定都是7天)
 * @param overDay 已经绘制过的日期,从overDay+1开始绘制
 * @param startIndex 此行第一个日期的星期索引
 */
private void drawDayAndPre(Canvas canvas, float top, int count, int overDay, int startIndex) {
    // Log.e(TAG, "总共"+dayOfMonth+"天  有"+lineNum+"行"+ "  已经画了"+overDay+"天,下面绘制:"+count+"天");
    // 背景
    float topPre = top + mLineSpac + dayHeight;
    bgPaint.setColor(mBgDay);
    RectF rect = new RectF(0, top, getWidth(), topPre);
    canvas.drawRect(rect, bgPaint);
    bgPaint.setColor(mBgPre);
    rect = new RectF(0, topPre, getWidth(), topPre + mTextSpac + dayHeight);
    canvas.drawRect(rect, bgPaint);
    mPaint.setTextSize(mTextSizeDay);
    float dayTextLeading = FontUtil.getFontLeading(mPaint);
    mPaint.setTextSize(mTextSizePre);
    float preTextLeading = FontUtil.getFontLeading(mPaint);
    // Log.v(TAG, "当前日期:"+currentDay+"   选择日期:"+selectDay+"  是否为当前月:"+isCurrentMonth);
    for (int i = 0; i < count; i++) {
        int left = (startIndex + i) * columnWidth;
        int day = (overDay + i + 1);
        mPaint.setTextSize(mTextSizeDay);
        // 如果是当前月,当天日期需要做处理
        if (isCurrentMonth && currentDay == day) {
            mPaint.setColor(mTextColorDay);
            bgPaint.setColor(mCurrentBg);
            // 空心
            bgPaint.setStyle(Paint.Style.STROKE);
            PathEffect effect = new DashPathEffect(mCurrentBgDashPath, 1);
            // 设置画笔曲线间隔
            bgPaint.setPathEffect(effect);
            // 画笔宽度
            bgPaint.setStrokeWidth(mCurrentBgStrokeWidth);
            // 绘制空心圆背景
            canvas.drawCircle(left + columnWidth / 2, top + mLineSpac + dayHeight / 2, mSelectRadius - mCurrentBgStrokeWidth, bgPaint);
        }
        // 绘制完后将画笔还原,避免脏笔
        bgPaint.setPathEffect(null);
        bgPaint.setStrokeWidth(0);
        bgPaint.setStyle(Paint.Style.FILL);
        // 选中的日期,如果是本月,选中日期正好是当天日期,下面的背景会覆盖上面绘制的虚线背景
        if (selectDay == day) {
            // 选中的日期字体白色,橙色背景
            mPaint.setColor(mSelectTextColor);
            bgPaint.setColor(mSelectBg);
            // 绘制橙色圆背景,参数一是中心点的x轴,参数二是中心点的y轴,参数三是半径,参数四是paint对象;
            canvas.drawCircle(left + columnWidth / 2, top + mLineSpac + dayHeight / 2, mSelectRadius, bgPaint);
        } else {
            mPaint.setColor(mTextColorDay);
        }
        int len = (int) FontUtil.getFontlength(mPaint, day + "");
        int x = left + (columnWidth - len) / 2;
        canvas.drawText(day + "", x, top + mLineSpac + dayTextLeading, mPaint);
        // 绘制次数
        mPaint.setTextSize(mTextSizePre);
        DayFinish finish = map.get(day);
        String preStr = "0/0";
        if (isCurrentMonth) {
            if (day > currentDay) {
                mPaint.setColor(mTextColorPreNull);
            } else if (finish != null) {
                // 区分完成未完成
                if (finish.finish >= finish.all) {
                    mPaint.setColor(mTextColorPreFinish);
                } else {
                    mPaint.setColor(mTextColorPreUnFinish);
                }
                preStr = finish.finish + "/" + finish.all;
            } else {
                mPaint.setColor(mTextColorPreNull);
            }
        } else {
            if (finish != null) {
                // 区分完成未完成
                if (finish.finish >= finish.all) {
                    mPaint.setColor(mTextColorPreFinish);
                } else {
                    mPaint.setColor(mTextColorPreUnFinish);
                }
                preStr = finish.finish + "/" + finish.all;
            } else {
                mPaint.setColor(mTextColorPreNull);
            }
        }
        len = (int) FontUtil.getFontlength(mPaint, preStr);
        x = left + (columnWidth - len) / 2;
        canvas.drawText(preStr, x, topPre + mTextSpac + preTextLeading, mPaint);
    }
}

19 Source : Line.java
with Apache License 2.0
from lwd1815

/**
 * Sets the path effect.
 *
 * @param pe
 *            {@link PathEffect PathEffect} for line drawing
 * @return this
 */
public Line setPathEffect(PathEffect pe) {
    mPaint.setPathEffect(pe);
    return this;
}

19 Source : JustContext.java
with MIT License
from LiuHongtao

public void setLineDash(V8Array intervals) {
    float[] floatIntervals = new float[intervals.length()];
    for (int i = 0; i < intervals.length(); i++) {
        floatIntervals[i] = (float) ((double) intervals.getDouble(i));
    }
    PathEffect effects = new DashPathEffect(floatIntervals, 1);
    mPaintStroke.setPathEffect(effects);
    intervals.release();
}

19 Source : ChartLineView.java
with MIT License
from lihangleo2

private void drawLine(Canvas canvas) {
    for (int i = 0; i < utilBeans.size(); i++) {
        ChartUtilBean chartUtilBean = utilBeans.get(i);
        // 绘制渐变阴影
        if (items.get(i).isWithShadow()) {
            canvas.drawPath(chartUtilBean.getmPathShadow(), chartUtilBean.getmPaintShadow());
        }
        // 是否带动画
        if (items.get(i).isWithAnim()) {
            PathMeasure measure = new PathMeasure(chartUtilBean.getmPath(), false);
            float pathLength = measure.getLength();
            PathEffect effect = new DashPathEffect(new float[] { pathLength, pathLength }, pathLength - pathLength * mProgress);
            chartUtilBean.getmPaintLine().setPathEffect(effect);
        }
        canvas.drawPath(chartUtilBean.getmPath(), chartUtilBean.getmPaintLine());
    }
}

19 Source : ChartHistogramView.java
with MIT License
from lihangleo2

private void drawLine(Canvas canvas) {
    for (int i = 0; i < utilBeans.size(); i++) {
        ChartUtilBean chartUtilBean = utilBeans.get(i);
        // 绘制渐变阴影
        canvas.drawPath(chartUtilBean.getmPathShadow(), chartUtilBean.getmPaintShadow());
        // 是否带动画
        if (items.get(i).isWithAnim()) {
            PathMeasure measure = new PathMeasure(chartUtilBean.getmPath(), false);
            float pathLength = measure.getLength();
            PathEffect effect = new DashPathEffect(new float[] { pathLength, pathLength }, pathLength - pathLength * mProgress);
            chartUtilBean.getmPaintLine().setPathEffect(effect);
        }
        canvas.drawPath(chartUtilBean.getmPath(), chartUtilBean.getmPaintLine());
    }
}

19 Source : Line.java
with Apache License 2.0
from huashengzzz

/**
 * Set path effect for this line, note: it will slow down drawing, try to not use complicated effects,
 * DashPathEffect should be safe choice.
 *
 * @param pathEffect
 */
public void setPathEffect(PathEffect pathEffect) {
    this.pathEffect = pathEffect;
}

19 Source : Shape.java
with Apache License 2.0
from florent37

public Shape setPathEffect(final PathEffect pathEffect) {
    paint.setPathEffect(pathEffect);
    return this;
}

19 Source : LineShape.java
with Apache License 2.0
from florent37

public LineShape setPathEffect(final PathEffect pathEffect) {
    return (LineShape) super.setPathEffect(pathEffect);
}

19 Source : Border.java
with Apache License 2.0
from facebook

/**
 * Represents a collection of attributes that describe how a border should be applied to a layout
 */
public clreplaced Border implements Equivalence<Border> {

    static final int EDGE_LEFT = 0;

    static final int EDGE_TOP = 1;

    static final int EDGE_RIGHT = 2;

    static final int EDGE_BOTTOM = 3;

    static final int EDGE_COUNT = 4;

    @Retention(RetentionPolicy.SOURCE)
    @IntDef(flag = true, value = { Corner.TOP_LEFT, Corner.TOP_RIGHT, Corner.BOTTOM_RIGHT, Corner.BOTTOM_LEFT })
    public @interface Corner {

        int TOP_LEFT = 0;

        int TOP_RIGHT = 1;

        int BOTTOM_RIGHT = 2;

        int BOTTOM_LEFT = 3;
    }

    static final int RADIUS_COUNT = 4;

    final float[] mRadius = new float[RADIUS_COUNT];

    final int[] mEdgeWidths = new int[EDGE_COUNT];

    final int[] mEdgeColors = new int[EDGE_COUNT];

    PathEffect mPathEffect;

    public static Builder create(ComponentContext context) {
        return new Builder(context);
    }

    private Border() {
    }

    void setEdgeWidth(YogaEdge edge, int width) {
        if (width < 0) {
            throw new IllegalArgumentException("Given negative border width value: " + width + " for edge " + edge.name());
        }
        setEdgeValue(mEdgeWidths, edge, width);
    }

    void setEdgeColor(YogaEdge edge, @ColorInt int color) {
        setEdgeValue(mEdgeColors, edge, color);
    }

    static int getEdgeColor(int[] colorArray, YogaEdge edge) {
        if (colorArray.length != EDGE_COUNT) {
            throw new IllegalArgumentException("Given wrongly sized array");
        }
        return colorArray[edgeIndex(edge)];
    }

    static YogaEdge edgeFromIndex(int i) {
        if (i < 0 || i >= EDGE_COUNT) {
            throw new IllegalArgumentException("Given index out of range of acceptable edges: " + i);
        }
        switch(i) {
            case EDGE_LEFT:
                return YogaEdge.LEFT;
            case EDGE_TOP:
                return YogaEdge.TOP;
            case EDGE_RIGHT:
                return YogaEdge.RIGHT;
            case EDGE_BOTTOM:
                return YogaEdge.BOTTOM;
        }
        throw new IllegalArgumentException("Given unknown edge index: " + i);
    }

    /**
     * @param values values pertaining to {@link YogaEdge}s
     * @return whether the values are equal for each edge
     */
    static boolean equalValues(int[] values) {
        if (values.length != EDGE_COUNT) {
            throw new IllegalArgumentException("Given wrongly sized array");
        }
        int lastValue = values[0];
        for (int i = 1, length = values.length; i < length; ++i) {
            if (lastValue != values[i]) {
                return false;
            }
        }
        return true;
    }

    private static void setEdgeValue(int[] edges, YogaEdge edge, int value) {
        switch(edge) {
            case ALL:
                for (int i = 0; i < EDGE_COUNT; ++i) {
                    edges[i] = value;
                }
                break;
            case VERTICAL:
                edges[EDGE_TOP] = value;
                edges[EDGE_BOTTOM] = value;
                break;
            case HORIZONTAL:
                edges[EDGE_LEFT] = value;
                edges[EDGE_RIGHT] = value;
                break;
            case LEFT:
            case TOP:
            case RIGHT:
            case BOTTOM:
            case START:
            case END:
                edges[edgeIndex(edge)] = value;
                break;
        }
    }

    private static int edgeIndex(YogaEdge edge) {
        switch(edge) {
            case START:
            case LEFT:
                return EDGE_LEFT;
            case TOP:
                return EDGE_TOP;
            case END:
            case RIGHT:
                return EDGE_RIGHT;
            case BOTTOM:
                return EDGE_BOTTOM;
            case HORIZONTAL:
            case VERTICAL:
            case ALL:
        }
        throw new IllegalArgumentException("Given unsupported edge " + edge.name());
    }

    public static clreplaced Builder {

        private static final int MAX_PATH_EFFECTS = 2;

        private final Border mBorder;

        @Nullable
        private ResourceResolver mResourceResolver;

        private PathEffect[] mPathEffects = new PathEffect[MAX_PATH_EFFECTS];

        private int mNumPathEffects;

        Builder(ComponentContext context) {
            mResourceResolver = context.getResourceResolver();
            mBorder = new Border();
        }

        /**
         * Specifies a width for a specific edge
         *
         * <p>Note: Having a border effect with varying widths per edge is currently not supported
         *
         * @param edge The {@link YogaEdge} that will have its width modified
         * @param width The desired width in raw pixels
         */
        public Builder widthPx(YogaEdge edge, @Px int width) {
            checkNotBuilt();
            mBorder.setEdgeWidth(edge, width);
            return this;
        }

        /**
         * Specifies a width for a specific edge
         *
         * <p>Note: Having a border effect with varying widths per edge is currently not supported
         *
         * @param edge The {@link YogaEdge} that will have its width modified
         * @param width The desired width in density independent pixels
         */
        public Builder widthDip(YogaEdge edge, @Dimension(unit = DP) float width) {
            checkNotBuilt();
            return widthPx(edge, mResourceResolver.dipsToPixels(width));
        }

        /**
         * Specifies a width for a specific edge
         *
         * <p>Note: Having a border effect with varying widths per edge is currently not supported
         *
         * @param edge The {@link YogaEdge} that will have its width modified
         * @param widthRes The desired width resource to resolve
         */
        public Builder widthRes(YogaEdge edge, @DimenRes int widthRes) {
            checkNotBuilt();
            return widthPx(edge, mResourceResolver.resolveDimenSizeRes(widthRes));
        }

        /**
         * Specifies a width for a specific edge
         *
         * <p>Note: Having a border effect with varying widths per edge is currently not supported
         *
         * @param edge The {@link YogaEdge} that will have its width modified
         * @param attrId The attribute to resolve a width value from
         */
        public Builder widthAttr(YogaEdge edge, @AttrRes int attrId) {
            checkNotBuilt();
            return widthAttr(edge, attrId, 0);
        }

        /**
         * Specifies a width for a specific edge
         *
         * <p>Note: Having a border effect with varying widths per edge is currently not supported
         *
         * @param edge The {@link YogaEdge} that will have its width modified
         * @param attrId The attribute to resolve a width value from
         * @param defaultResId Default resource value to utilize if the attribute is not set
         */
        public Builder widthAttr(YogaEdge edge, @AttrRes int attrId, @DimenRes int defaultResId) {
            checkNotBuilt();
            return widthPx(edge, mResourceResolver.resolveDimenSizeAttr(attrId, defaultResId));
        }

        /**
         * Specifies the border radius for all corners
         *
         * @param radius The desired border radius for all corners
         */
        public Builder radiusPx(@Px int radius) {
            checkNotBuilt();
            for (int i = 0; i < RADIUS_COUNT; ++i) {
                mBorder.mRadius[i] = radius;
            }
            return this;
        }

        /**
         * Specifies the border radius for all corners
         *
         * @param radius The desired border radius for all corners
         */
        public Builder radiusDip(@Dimension(unit = DP) float radius) {
            checkNotBuilt();
            return radiusPx(mResourceResolver.dipsToPixels(radius));
        }

        /**
         * Specifies the border radius for all corners
         *
         * @param radiusRes The resource id to retrieve the border radius value from
         */
        public Builder radiusRes(@DimenRes int radiusRes) {
            checkNotBuilt();
            return radiusPx(mResourceResolver.resolveDimenSizeRes(radiusRes));
        }

        /**
         * Specifies the border radius for all corners
         *
         * @param attrId The attribute id to retrieve the border radius value from
         */
        public Builder radiusAttr(@AttrRes int attrId) {
            return radiusAttr(attrId, 0);
        }

        /**
         * Specifies the border radius for all corners
         *
         * @param attrId The attribute id to retrieve the border radius value from
         * @param defaultResId Default resource to utilize if the attribute is not set
         */
        public Builder radiusAttr(@AttrRes int attrId, @DimenRes int defaultResId) {
            checkNotBuilt();
            return radiusPx(mResourceResolver.resolveDimenSizeAttr(attrId, defaultResId));
        }

        /**
         * Specifies the border radius for the given corner
         *
         * @param corner The {@link Corner} to specify the radius of
         * @param radius The desired radius
         */
        public Builder radiusPx(@Corner int corner, @Px int radius) {
            checkNotBuilt();
            if (corner < 0 || corner >= RADIUS_COUNT) {
                throw new IllegalArgumentException("Given invalid corner: " + corner);
            }
            mBorder.mRadius[corner] = radius;
            return this;
        }

        /**
         * Specifies the border radius for the given corner
         *
         * @param corner The {@link Corner} to specify the radius of
         * @param radius The desired radius
         */
        public Builder radiusDip(@Corner int corner, @Dimension(unit = DP) float radius) {
            checkNotBuilt();
            return radiusPx(corner, mResourceResolver.dipsToPixels(radius));
        }

        /**
         * Specifies the border radius for the given corner
         *
         * @param corner The {@link Corner} to specify the radius of
         * @param res The desired dimension resource to use for the radius
         */
        public Builder radiusRes(@Corner int corner, @DimenRes int res) {
            checkNotBuilt();
            return radiusPx(corner, mResourceResolver.resolveDimenSizeRes(res));
        }

        /**
         * Specifies the border radius for the given corner
         *
         * @param corner The {@link Corner} to specify the radius of
         * @param attrId The attribute ID to retrieve the radius from
         * @param defaultResId Default resource ID to use if the attribute is not set
         */
        public Builder radiusAttr(@Corner int corner, @AttrRes int attrId, @DimenRes int defaultResId) {
            checkNotBuilt();
            return radiusPx(corner, mResourceResolver.resolveDimenSizeAttr(attrId, defaultResId));
        }

        /**
         * Specifies a color for a specific edge
         *
         * @param edge The {@link YogaEdge} that will have its color modified
         * @param color The raw color value to use
         */
        public Builder color(YogaEdge edge, @ColorInt int color) {
            checkNotBuilt();
            mBorder.setEdgeColor(edge, color);
            return this;
        }

        /**
         * Specifies a color for a specific edge
         *
         * @param edge The {@link YogaEdge} that will have its color modified
         * @param colorRes The color resource to use
         */
        public Builder colorRes(YogaEdge edge, @ColorRes int colorRes) {
            checkNotBuilt();
            return color(edge, mResourceResolver.resolveColorRes(colorRes));
        }

        /**
         * Applies a dash effect to the border
         *
         * <p>Specifying two effects will compose them where the first specified effect acts as the
         * outer effect and the second acts as the inner path effect, e.g. outer(inner(path))
         *
         * @param intervals Must be even-sized >= 2. Even indices specify "on" intervals and odd indices
         *     specify "off" intervals
         * @param phase Offset into the given intervals
         */
        public Builder dashEffect(float[] intervals, float phase) {
            checkNotBuilt();
            checkEffectCount();
            mPathEffects[mNumPathEffects++] = new DashPathEffect(intervals, phase);
            return this;
        }

        /**
         * Applies a corner effect to the border
         *
         * @deprecated Please use {@link #radiusPx(int)} instead
         * @param radius The amount to round sharp angles when drawing the border
         */
        @Deprecated
        public Builder cornerEffect(float radius) {
            checkNotBuilt();
            if (radius < 0f) {
                throw new IllegalArgumentException("Can't have a negative radius value");
            }
            radiusPx(Math.round(radius));
            return this;
        }

        /**
         * Applies a discrete effect to the border
         *
         * <p>Specifying two effects will compose them where the first specified effect acts as the
         * outer effect and the second acts as the inner path effect, e.g. outer(inner(path))
         *
         * @param segmentLength Length of line segments
         * @param deviation Maximum amount of deviation. Utilized value is random in the range
         *     [-deviation, deviation]
         */
        public Builder discreteEffect(float segmentLength, float deviation) {
            checkNotBuilt();
            checkEffectCount();
            mPathEffects[mNumPathEffects++] = new DiscretePathEffect(segmentLength, deviation);
            return this;
        }

        /**
         * Applies a path dash effect to the border
         *
         * <p>Specifying two effects will compose them where the first specified effect acts as the
         * outer effect and the second acts as the inner path effect, e.g. outer(inner(path))
         *
         * @param shape The path to stamp along
         * @param advance The spacing between each stamp
         * @param phase Amount to offset before the first stamp
         * @param style How to transform the shape at each position
         */
        public Builder pathDashEffect(Path shape, float advance, float phase, PathDashPathEffect.Style style) {
            checkNotBuilt();
            checkEffectCount();
            mPathEffects[mNumPathEffects++] = new PathDashPathEffect(shape, advance, phase, style);
            return this;
        }

        public Border build() {
            checkNotBuilt();
            mResourceResolver = null;
            if (mNumPathEffects == MAX_PATH_EFFECTS) {
                mBorder.mPathEffect = new ComposePathEffect(mPathEffects[0], mPathEffects[1]);
            } else if (mNumPathEffects > 0) {
                mBorder.mPathEffect = mPathEffects[0];
            }
            if (mBorder.mPathEffect != null && !Border.equalValues(mBorder.mEdgeWidths)) {
                throw new IllegalArgumentException("Borders do not currently support different widths with a path effect");
            }
            return mBorder;
        }

        private void checkNotBuilt() {
            if (mResourceResolver == null) {
                throw new IllegalStateException("This builder has already been disposed / built!");
            }
        }

        private void checkEffectCount() {
            if (mNumPathEffects >= MAX_PATH_EFFECTS) {
                throw new IllegalArgumentException("You cannot specify more than 2 effects to compose");
            }
        }
    }

    @Override
    public boolean isEquivalentTo(@Nullable Border other) {
        if (this == other) {
            return true;
        }
        if (other == null) {
            return false;
        }
        return Arrays.equals(mRadius, other.mRadius) && Arrays.equals(mEdgeWidths, other.mEdgeWidths) && Arrays.equals(mEdgeColors, other.mEdgeColors) && mPathEffect == other.mPathEffect;
    }
}

19 Source : LineStyle.java
with Apache License 2.0
from didi

public clreplaced LineStyle implements IStyle {

    private float width = -1;

    private int color = -1;

    private boolean isFill;

    private PathEffect effect = new PathEffect();

    private static float defaultLineSize = 2f;

    private static int defaultLineColor = Color.parseColor("#e6e6e6");

    public LineStyle() {
    }

    public LineStyle(float width, int color) {
        this.width = width;
        this.color = color;
    }

    public LineStyle(Context context, float dp, int color) {
        this.width = DensityUtils.dp2px(context, dp);
        this.color = color;
    }

    public static void setDefaultLineSize(float width) {
        defaultLineSize = width;
    }

    public static void setDefaultLineSize(Context context, float dp) {
        defaultLineSize = DensityUtils.dp2px(context, dp);
    }

    public static void setDefaultLineColor(int color) {
        defaultLineColor = color;
    }

    public float getWidth() {
        if (width == -1) {
            return defaultLineSize;
        }
        return width;
    }

    public LineStyle setWidth(float width) {
        this.width = width;
        return this;
    }

    public LineStyle setWidth(Context context, int dp) {
        this.width = DensityUtils.dp2px(context, dp);
        return this;
    }

    public int getColor() {
        if (color == -1) {
            return defaultLineColor;
        }
        return color;
    }

    public boolean isFill() {
        return isFill;
    }

    public LineStyle setFill(boolean fill) {
        isFill = fill;
        return this;
    }

    public LineStyle setColor(int color) {
        this.color = color;
        return this;
    }

    public LineStyle setEffect(PathEffect effect) {
        this.effect = effect;
        return this;
    }

    @Override
    public void fillPaint(Paint paint) {
        paint.setColor(getColor());
        paint.setStyle(isFill ? Paint.Style.FILL : Paint.Style.STROKE);
        paint.setStrokeWidth(getWidth());
        paint.setPathEffect(effect);
    }
}

19 Source : LineStyle.java
with Apache License 2.0
from didi

public LineStyle setEffect(PathEffect effect) {
    this.effect = effect;
    return this;
}

19 Source : AnimationRouteHelper.java
with MIT License
from amalChandran

public void setUpdate1(float update) {
    PathEffect effect = new DashPathEffect(dashValue, -length * update);
    overlayPolyline.getTopLayerPaint().setPathEffect(effect);
    routeOverlayView.invalidate();
}

19 Source : AnimationRouteHelper.java
with MIT License
from amalChandran

public void setUpdate(float update) {
    PathEffect effect = new DashPathEffect(dashValue, length * update);
    overlayPolyline.getTopLayerPaint().setPathEffect(effect);
    routeOverlayView.invalidate();
}

19 Source : AnimationArcHelper.java
with MIT License
from amalChandran

public void setUpdate(float update) {
    PathEffect effect = new DashPathEffect(arcdDashValue, arcLength * update);
    overlayPolyline.getTopLayerPaint().setPathEffect(effect);
    PathEffect shadowEffect = new DashPathEffect(shadowDashValue, shadowLength * update);
    overlayPolyline.getShadowPaint().setPathEffect(shadowEffect);
    mRouteOverlayView.invalidate();
}

19 Source : AnimationArcHelper.java
with MIT License
from amalChandran

public void setUpdate1(float update) {
    PathEffect effect = new DashPathEffect(arcdDashValue, -arcLength * update);
    overlayPolyline.getTopLayerPaint().setPathEffect(effect);
    mRouteOverlayView.invalidate();
}

18 Source : StandLinesChart.java
with Apache License 2.0
from openXu

private void drawAxisLine(Canvas canvas, AxisLine axisLine) {
    if (axisLine.type == AxisLineType.SOLID) {
        // 实线
        paint.setStrokeWidth(axisLine.lineWidth);
        paint.setColor(axisLine.lineColor);
        canvas.drawLine(axisLine.pointStart.x, axisLine.pointStart.y, axisLine.pointEnd.x, axisLine.pointEnd.y, paint);
    }
    if (axisLine.type == AxisLineType.DASHE) {
        // 虚线
        paintEffect.setStrokeWidth(axisLine.lineWidth);
        paintEffect.setColor(axisLine.lineColor);
        Path path = new Path();
        path.moveTo(axisLine.pointStart.x, axisLine.pointStart.y);
        path.lineTo(axisLine.pointEnd.x, axisLine.pointEnd.y);
        PathEffect effects = new DashPathEffect(new float[] { 15, 8, 15, 8 }, 0);
        paintEffect.setPathEffect(effects);
        canvas.drawPath(path, paintEffect);
    }
}

18 Source : LineChartView.java
with Apache License 2.0
from nicolite

private void initPaint() {
    // 虚线
    bgLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    bgLinePaint.setStyle(Paint.Style.STROKE);
    bgLinePaint.setColor(Color.parseColor("#ADADAD"));
    bgLinePaint.setStrokeWidth(2);
    PathEffect effects = new DashPathEffect(new float[] { 13, 13 }, 5);
    bgLinePaint.setPathEffect(effects);
    // 发光线一号
    BlurMaskFilter bmf = new BlurMaskFilter(4, BlurMaskFilter.Blur.SOLID);
    linePaint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
    linePaint1.setStyle(Paint.Style.STROKE);
    linePaint1.setColor(Color.parseColor("#fdeb6b"));
    linePaint1.setStrokeWidth(lineWidth);
    linePaint1.setMaskFilter(bmf);
    // 发光线2号
    linePaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
    linePaint2.setStyle(Paint.Style.STROKE);
    linePaint2.setColor(Color.parseColor("#6effb6"));
    linePaint2.setStrokeWidth(lineWidth);
    linePaint2.setMaskFilter(bmf);
    // 标题
    replacedlePaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    replacedlePaint.setTextSize(sp14);
    replacedlePaint.setColor(Color.parseColor("#adadad"));
    // 数值一号
    valuePaint1 = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    valuePaint1.setTextSize(sp10);
    valuePaint1.setColor(Color.parseColor(COLOR_1));
    // 数值二号
    valuePaint2 = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    valuePaint2.setTextSize(sp10);
    valuePaint2.setColor(Color.parseColor(COLOR_2));
    // 文本
    textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    textPaint.setTextSize(sp10);
    textPaint.setColor(Color.WHITE);
    // 标注
    labelPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
    labelPaint.setTextSize(sp10);
    labelPaint.setColor(Color.parseColor("#adadad"));
    // 圆点
    circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    circlePaint.setStyle(Paint.Style.FILL);
    circlePaint.setColor(Color.WHITE);
}

18 Source : DashedLineView.java
with BSD 3-Clause "New" or "Revised" License
from Kommunicate-io

public clreplaced DashedLineView extends View {

    private float density;

    private Paint paint;

    private Path path;

    private PathEffect effects;

    private String dashColor = "#BEBBBB";

    private float dashWidth = DimensionsUtils.convertDpToPixel(4);

    private float dashSpacing = DimensionsUtils.convertDpToPixel(2);

    public DashedLineView(Context context) {
        super(context);
        init(context);
    }

    public DashedLineView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    public DashedLineView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    private void init(Context context) {
        density = context.getResources().getDisplayMetrics().density;
        paint = new Paint();
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(density * 4);
        // set your own color
        paint.setColor(Color.parseColor(dashColor));
        path = new Path();
        // array is ON and OFF distances in px (4px line then 2px space)
        effects = new DashPathEffect(new float[] { dashWidth, dashSpacing, dashWidth, dashSpacing }, 0);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);
        paint.setPathEffect(effects);
        int measuredHeight = getMeasuredHeight();
        int measuredWidth = getMeasuredWidth();
        if (measuredHeight <= measuredWidth) {
            // horizontal
            path.moveTo(0, 0);
            path.lineTo(measuredWidth, 0);
            canvas.drawPath(path, paint);
        } else {
            // vertical
            path.moveTo(0, 0);
            path.lineTo(0, measuredHeight);
            canvas.drawPath(path, paint);
        }
    }
}

18 Source : OldCreditSesameView.java
with Apache License 2.0
from HotBitmapGG

/**
 * 初始化
 */
private void init() {
    // 设置默认宽高值
    defaultSize = dp2px(250);
    // 设置图片线条的抗锯齿
    mPaintFlagsDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    // 最外层圆环渐变画笔设置
    mGradientRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    // 设置圆环渐变色渲染
    mGradientRingPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
    float[] position = { 0.1f, 0.3f, 0.8f };
    Shader mShader = new SweepGradient(width / 2, radius, mColors, position);
    mGradientRingPaint.setShader(mShader);
    mGradientRingPaint.setStrokeCap(Paint.Cap.ROUND);
    mGradientRingPaint.setStyle(Paint.Style.STROKE);
    mGradientRingPaint.setStrokeWidth(40);
    // 最外层圆环大小刻度画笔设置
    mSmallCalibrationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mSmallCalibrationPaint.setColor(Color.WHITE);
    mSmallCalibrationPaint.setStyle(Paint.Style.STROKE);
    mSmallCalibrationPaint.setStrokeWidth(1);
    mBigCalibrationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mBigCalibrationPaint.setColor(Color.WHITE);
    mBigCalibrationPaint.setStyle(Paint.Style.STROKE);
    mBigCalibrationPaint.setStrokeWidth(4);
    // 中间圆环画笔设置
    mMiddleRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mMiddleRingPaint.setStyle(Paint.Style.STROKE);
    mMiddleRingPaint.setStrokeCap(Paint.Cap.ROUND);
    mMiddleRingPaint.setStrokeWidth(5);
    mMiddleRingPaint.setColor(GRAY_COLOR);
    // 内层圆环画笔设置
    mInnerRingPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mInnerRingPaint.setStyle(Paint.Style.STROKE);
    mInnerRingPaint.setStrokeCap(Paint.Cap.ROUND);
    mInnerRingPaint.setStrokeWidth(4);
    mInnerRingPaint.setColor(GRAY_COLOR);
    PathEffect mPathEffect = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);
    mInnerRingPaint.setPathEffect(mPathEffect);
    // 外层圆环文本画笔设置
    mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTextPaint.setColor(GRAY_COLOR);
    mTextPaint.setTextSize(30);
    // 中间文字画笔设置
    mCenterTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mCenterTextPaint.setTextAlign(Paint.Align.CENTER);
    // 中间圆环进度画笔设置
    mMiddleProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mMiddleProgressPaint.setColor(GREEN_COLOR);
    mMiddleProgressPaint.setStrokeCap(Paint.Cap.ROUND);
    mMiddleProgressPaint.setStrokeWidth(5);
    mMiddleProgressPaint.setStyle(Paint.Style.STROKE);
    // 指针图片画笔
    mPointerBitmapPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPointerBitmapPaint.setColor(GREEN_COLOR);
    // 获取指针图片
    mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_pointer);
    mBitmapHeight = mBitmap.getHeight();
    mBitmapWidth = mBitmap.getWidth();
}

17 Source : RecyclerViewItemDecoration.java
with GNU General Public License v3.0
from z-chu

/**
 * draw vertival decoration
 *
 * @param c
 * @param parent
 */
private void drawVertical(Canvas c, RecyclerView parent) {
    int childrenCount = parent.getChildCount();
    if (mDrawableRid != 0) {
        if (mFirstLineVisible) {
            View childView = parent.getChildAt(0);
            int myX = childView.getLeft();
            if (hasNinePatch) {
                Rect rect = new Rect(myX - mCurrentThickness, mPaddingStart, myX, parent.getHeight() - mPaddingEnd);
                mNinePatch.draw(c, rect);
            } else {
                c.drawBitmap(mBmp, myX - mCurrentThickness, mPaddingStart, mPaint);
            }
        }
        for (int i = 0; i < childrenCount; i++) {
            if (!mLastLineVisible && i == childrenCount - 1)
                break;
            View childView = parent.getChildAt(i);
            int myX = childView.getRight();
            if (hasNinePatch) {
                Rect rect = new Rect(myX, mPaddingStart, myX + mCurrentThickness, parent.getHeight() - mPaddingEnd);
                mNinePatch.draw(c, rect);
            } else {
                c.drawBitmap(mBmp, myX, mPaddingStart, mPaint);
            }
        }
    } else {
        boolean isPureLine = isPureLine();
        if (!isPureLine) {
            PathEffect effects = new DashPathEffect(new float[] { 0, 0, mDashWidth, mThickness }, mDashGap);
            mPaint.setPathEffect(effects);
        }
        if (mFirstLineVisible) {
            View childView = parent.getChildAt(0);
            int myX = childView.getLeft() - mThickness / 2;
            if (isPureLine) {
                c.drawLine(myX, mPaddingStart, myX, parent.getHeight() - mPaddingEnd, mPaint);
            } else {
                Path path = new Path();
                path.moveTo(myX, mPaddingStart);
                path.lineTo(myX, parent.getHeight() - mPaddingEnd);
                c.drawPath(path, mPaint);
            }
        }
        for (int i = 0; i < childrenCount; i++) {
            if (!mLastLineVisible && i == childrenCount - 1)
                break;
            View childView = parent.getChildAt(i);
            int myX = childView.getRight() + mThickness / 2;
            if (isPureLine) {
                c.drawLine(myX, mPaddingStart, myX, parent.getHeight() - mPaddingEnd, mPaint);
            } else {
                Path path = new Path();
                path.moveTo(myX, mPaddingStart);
                path.lineTo(myX, parent.getHeight() - mPaddingEnd);
                c.drawPath(path, mPaint);
            }
        }
    }
}

17 Source : RecyclerViewItemDecoration.java
with GNU General Public License v3.0
from z-chu

/**
 * draw horizontal decoration
 *
 * @param c
 * @param parent
 */
private void drawHorinzontal(Canvas c, RecyclerView parent) {
    int childrenCount = parent.getChildCount();
    if (mDrawableRid != 0) {
        if (mFirstLineVisible) {
            View childView = parent.getChildAt(0);
            int myY = childView.getTop();
            if (hasNinePatch) {
                Rect rect = new Rect(mPaddingStart, myY - mCurrentThickness, parent.getWidth() - mPaddingEnd, myY);
                mNinePatch.draw(c, rect);
            } else {
                c.drawBitmap(mBmp, mPaddingStart, myY - mCurrentThickness, mPaint);
            }
        }
        for (int i = 0; i < childrenCount; i++) {
            if (!mLastLineVisible && i == childrenCount - 1)
                break;
            View childView = parent.getChildAt(i);
            int myY = childView.getBottom();
            if (hasNinePatch) {
                Rect rect = new Rect(mPaddingStart, myY, parent.getWidth() - mPaddingEnd, myY + mCurrentThickness);
                mNinePatch.draw(c, rect);
            } else {
                c.drawBitmap(mBmp, mPaddingStart, myY, mPaint);
            }
        }
    } else {
        boolean isPureLine = isPureLine();
        if (!isPureLine) {
            PathEffect effects = new DashPathEffect(new float[] { 0, 0, mDashWidth, mThickness }, mDashGap);
            mPaint.setPathEffect(effects);
        }
        if (mFirstLineVisible) {
            View childView = parent.getChildAt(0);
            int myY = childView.getTop() - mThickness / 2;
            if (isPureLine) {
                c.drawLine(mPaddingStart, myY, parent.getWidth() - mPaddingEnd, myY, mPaint);
            } else {
                Path path = new Path();
                path.moveTo(mPaddingStart, myY);
                path.lineTo(parent.getWidth() - mPaddingEnd, myY);
                c.drawPath(path, mPaint);
            }
        }
        for (int i = 0; i < childrenCount; i++) {
            if (!mLastLineVisible && i == childrenCount - 1)
                break;
            View childView = parent.getChildAt(i);
            int myY = childView.getBottom() + mThickness / 2;
            if (isPureLine) {
                c.drawLine(mPaddingStart, myY, parent.getWidth() - mPaddingEnd, myY, mPaint);
            } else {
                Path path = new Path();
                path.moveTo(mPaddingStart, myY);
                path.lineTo(parent.getWidth() - mPaddingEnd, myY);
                c.drawPath(path, mPaint);
            }
        }
    }
}

17 Source : CSSBoxModelView.java
with Apache License 2.0
from weexteam

/**
 * Description:
 *  绘制css盒模型
 * Created by rowandjj(chuyi)<br/>
 */
public clreplaced CSSBoxModelView extends View {

    private static final int COLOR_MARGIN = 0xBAFACC9E;

    private static final int COLOR_BORDER = 0xBAFCDC9B;

    private static final int COLOR_PADDING = 0xBAC3CE8A;

    private static final int COLOR_CONTENT = 0xBA12B6C1;

    private static final int COLOR_TEXT = 0xFFFFFFFF;

    private static final String TEXT_MARGIN = "margin";

    private static final String TEXT_BORDER = "border";

    private static final String TEXT_PADDING = "padding";

    private static final String TEXT_UNKNOWN = "?";

    private static final String TEXT_ZERO = "0";

    private static final String TEXT_NULL = "-";

    private final float DEFAULT_VIEW_HEIGHT = ViewUtils.dp2px(getContext(), 160);

    private final float DEFAULT_VIEW_WIDTH = ViewUtils.dp2px(getContext(), 200);

    private final float DEFAULT_BOX_GAP = ViewUtils.dp2px(getContext(), 45);

    private float mViewMinWidth = DEFAULT_VIEW_WIDTH;

    private float mViewMinHeight = DEFAULT_VIEW_HEIGHT;

    private Paint mShapePaint;

    private Paint mTextPaint;

    private RectF mOuterBounds;

    private RectF mBorderBounds;

    private RectF mPaddingBounds;

    private RectF mContentBounds;

    private float mTextOffsetX;

    private float mTextOffsetY;

    private PathEffect mPathEffect;

    private Rect mCachedTextBounds;

    // 动态文案
    private String mMarginLeftText;

    private String mMarginTopText;

    private String mMarginRightText;

    private String mMarginBottomText;

    private String mPaddingLeftText;

    private String mPaddingTopText;

    private String mPaddingRightText;

    private String mPaddingBottomText;

    private String mBorderLeftText;

    private String mBorderTopText;

    private String mBorderRightText;

    private String mBorderBottomText;

    private String mWidthText;

    private String mHeightText;

    private boolean isNative = false;

    public CSSBoxModelView(Context context) {
        super(context);
        init();
    }

    public CSSBoxModelView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CSSBoxModelView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mShapePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mShapePaint.setStrokeWidth(ViewUtils.dp2px(getContext(), 1));
        mShapePaint.setDither(true);
        mShapePaint.setColor(COLOR_TEXT);
        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mTextPaint.setDither(true);
        mTextPaint.setTextSize(ViewUtils.sp2px(getContext(), 12));
        mTextPaint.setColor(COLOR_TEXT);
        mTextPaint.setTypeface(Typeface.DEFAULT);
        Paint.FontMetrics metrics = mTextPaint.getFontMetrics();
        mTextOffsetY = -(metrics.descent + metrics.ascent) / 2.0f;
        mTextOffsetX = (metrics.descent - metrics.ascent) / 2.0f;
        mCachedTextBounds = new Rect();
        mViewMinWidth = DEFAULT_VIEW_WIDTH;
        mViewMinHeight = DEFAULT_VIEW_HEIGHT;
        mPathEffect = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        float width = Math.max(getWidth(), mViewMinWidth);
        float height = Math.max(getHeight(), mViewMinHeight);
        mOuterBounds = new RectF(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + width, getPaddingTop() + height);
        mBorderBounds = new RectF(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + width - DEFAULT_BOX_GAP, getPaddingTop() + 3 * height / 4.0f);
        mPaddingBounds = new RectF(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + width - DEFAULT_BOX_GAP * 2, getPaddingTop() + height / 2.0f);
        mContentBounds = new RectF(getPaddingLeft(), getPaddingTop(), getPaddingLeft() + width - DEFAULT_BOX_GAP * 3, getPaddingTop() + height / 4.0f);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = (int) (mViewMinWidth + getPaddingLeft() + getPaddingRight());
        int height = (int) (mViewMinHeight + getPaddingTop() + getPaddingBottom());
        setMeasuredDimension(getResolvedSize(width, widthMeasureSpec), getResolvedSize(height, heightMeasureSpec));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // step1 绘制背景
        mShapePaint.setStyle(Paint.Style.FILL);
        // 最外层背景
        canvas.save();
        mShapePaint.setColor(COLOR_MARGIN);
        // 使用clipRect避免重绘
        canvas.clipRect((mOuterBounds.width() - mBorderBounds.width()) / 2.0f, (mOuterBounds.height() - mBorderBounds.height()) / 2.0f, (mOuterBounds.width() + mBorderBounds.width()) / 2.0f, (mOuterBounds.height() + mBorderBounds.height()) / 2.0f, Region.Op.DIFFERENCE);
        canvas.drawRect(mOuterBounds, mShapePaint);
        canvas.restore();
        // border背景
        canvas.save();
        canvas.translate((mOuterBounds.width() - mBorderBounds.width()) / 2.0f, (mOuterBounds.height() - mBorderBounds.height()) / 2.0f);
        mShapePaint.setColor(COLOR_BORDER);
        canvas.clipRect((mBorderBounds.width() - mPaddingBounds.width()) / 2.0f, (mBorderBounds.height() - mPaddingBounds.height()) / 2.0f, (mBorderBounds.width() + mPaddingBounds.width()) / 2.0f, (mBorderBounds.height() + mPaddingBounds.height()) / 2.0f, Region.Op.DIFFERENCE);
        canvas.drawRect(mBorderBounds, mShapePaint);
        canvas.restore();
        // padding背景
        canvas.save();
        canvas.translate((mOuterBounds.width() - mPaddingBounds.width()) / 2.0f, (mOuterBounds.height() - mPaddingBounds.height()) / 2.0f);
        mShapePaint.setColor(COLOR_PADDING);
        canvas.clipRect((mPaddingBounds.width() - mContentBounds.width()) / 2.0f, (mPaddingBounds.height() - mContentBounds.height()) / 2.0f, (mPaddingBounds.width() + mContentBounds.width()) / 2.0f, (mPaddingBounds.height() + mContentBounds.height()) / 2.0f, Region.Op.DIFFERENCE);
        canvas.drawRect(mPaddingBounds, mShapePaint);
        canvas.restore();
        // content背景
        canvas.save();
        canvas.translate((mOuterBounds.width() - mContentBounds.width()) / 2.0f, (mOuterBounds.height() - mContentBounds.height()) / 2.0f);
        mShapePaint.setColor(COLOR_CONTENT);
        canvas.drawRect(mContentBounds, mShapePaint);
        canvas.restore();
        // step2 绘制框
        mShapePaint.setColor(COLOR_TEXT);
        mShapePaint.setStyle(Paint.Style.STROKE);
        mShapePaint.setPathEffect(mPathEffect);
        canvas.save();
        // 最外层框
        canvas.drawRect(mOuterBounds, mShapePaint);
        // border框
        canvas.translate((mOuterBounds.width() - mBorderBounds.width()) / 2.0f, (mOuterBounds.height() - mBorderBounds.height()) / 2.0f);
        mShapePaint.setPathEffect(null);
        canvas.drawRect(mBorderBounds, mShapePaint);
        // padding框
        canvas.translate((mBorderBounds.width() - mPaddingBounds.width()) / 2.0f, (mBorderBounds.height() - mPaddingBounds.height()) / 2.0f);
        mShapePaint.setPathEffect(mPathEffect);
        canvas.drawRect(mPaddingBounds, mShapePaint);
        // content框
        canvas.translate((mPaddingBounds.width() - mContentBounds.width()) / 2.0f, (mPaddingBounds.height() - mContentBounds.height()) / 2.0f);
        mShapePaint.setPathEffect(null);
        canvas.drawRect(mContentBounds, mShapePaint);
        canvas.restore();
        // step3 绘制文案
        canvas.save();
        // 最外层文案
        canvas.drawText(TEXT_MARGIN, mTextOffsetX + mOuterBounds.left, (mOuterBounds.height() - mBorderBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // margin-left
        String tempText = prepareText(mMarginLeftText, TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mOuterBounds.left + (mOuterBounds.width() - mBorderBounds.width()) / 4.0f - mCachedTextBounds.width() / 2.0f, mOuterBounds.top + mOuterBounds.height() / 2.0f + mTextOffsetY, mTextPaint);
        // margin-top
        tempText = prepareText(mMarginTopText, TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mOuterBounds.left + mOuterBounds.width() / 2.0f - mCachedTextBounds.width() / 2.0f, mOuterBounds.top + (mOuterBounds.height() - mBorderBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // margin-right
        tempText = prepareText(mMarginRightText, TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mOuterBounds.width() - (mOuterBounds.width() - mBorderBounds.width()) / 4.0f - mCachedTextBounds.width() / 2.0f, mOuterBounds.top + mOuterBounds.height() / 2.0f + mTextOffsetY, mTextPaint);
        // margin-bottom
        tempText = prepareText(mMarginBottomText, TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mOuterBounds.left + mOuterBounds.width() / 2.0f - mCachedTextBounds.width() / 2.0f, mOuterBounds.bottom - (mOuterBounds.height() - mBorderBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // border文案
        canvas.translate((mOuterBounds.width() - mBorderBounds.width()) / 2.0f, (mOuterBounds.height() - mBorderBounds.height()) / 2.0f);
        canvas.drawText(TEXT_BORDER, mTextOffsetX, (mBorderBounds.height() - mPaddingBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // border-left
        tempText = prepareText(mBorderLeftText, isNative ? TEXT_NULL : TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mBorderBounds.left + (mBorderBounds.width() - mPaddingBounds.width()) / 4.0f - mCachedTextBounds.width() / 2.0f, mBorderBounds.top + mBorderBounds.height() / 2.0f + mTextOffsetY, mTextPaint);
        // border-top
        tempText = prepareText(mBorderTopText, isNative ? TEXT_NULL : TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mBorderBounds.left + mBorderBounds.width() / 2.0f - mCachedTextBounds.width() / 2.0f, mBorderBounds.top + (mBorderBounds.height() - mPaddingBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // border-right
        tempText = prepareText(mBorderRightText, isNative ? TEXT_NULL : TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mBorderBounds.width() - (mBorderBounds.width() - mPaddingBounds.width()) / 4.0f - mCachedTextBounds.width() / 2.0f, mBorderBounds.top + mBorderBounds.height() / 2.0f + mTextOffsetY, mTextPaint);
        // border-bottom
        tempText = prepareText(mBorderBottomText, isNative ? TEXT_NULL : TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mBorderBounds.left + mBorderBounds.width() / 2.0f - mCachedTextBounds.width() / 2.0f, mBorderBounds.bottom - (mBorderBounds.height() - mPaddingBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // padding文案
        canvas.translate((mBorderBounds.width() - mPaddingBounds.width()) / 2.0f, (mBorderBounds.height() - mPaddingBounds.height()) / 2.0f);
        canvas.drawText(TEXT_PADDING, mTextOffsetX / 2.0f, (mPaddingBounds.height() - mContentBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // padding-left
        tempText = prepareText(mPaddingLeftText, TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mPaddingBounds.left + (mPaddingBounds.width() - mContentBounds.width()) / 4.0f - mCachedTextBounds.width() / 2.0f, mPaddingBounds.top + mPaddingBounds.height() / 2.0f + mTextOffsetY, mTextPaint);
        // padding-top
        tempText = prepareText(mPaddingTopText, TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mPaddingBounds.left + mPaddingBounds.width() / 2.0f - mCachedTextBounds.width() / 2.0f, mPaddingBounds.top + (mPaddingBounds.height() - mContentBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // padding-right
        tempText = prepareText(mPaddingRightText, TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mPaddingBounds.width() - (mPaddingBounds.width() - mContentBounds.width()) / 4.0f - mCachedTextBounds.width() / 2.0f, mPaddingBounds.top + mPaddingBounds.height() / 2.0f + mTextOffsetY, mTextPaint);
        // padding-bottom
        tempText = prepareText(mPaddingBottomText, TEXT_ZERO);
        mTextPaint.getTextBounds(tempText, 0, tempText.length(), mCachedTextBounds);
        canvas.drawText(tempText, mPaddingBounds.left + mPaddingBounds.width() / 2.0f - mCachedTextBounds.width() / 2.0f, mPaddingBounds.bottom - (mPaddingBounds.height() - mContentBounds.height()) / 4.0f + mTextOffsetY, mTextPaint);
        // content文案
        canvas.translate((mPaddingBounds.width() - mContentBounds.width()) / 2.0f, (mPaddingBounds.height() - mContentBounds.height()) / 2.0f);
        String content = prepareText(mWidthText, TEXT_UNKNOWN) + " x " + prepareText(mHeightText, TEXT_UNKNOWN);
        mTextPaint.getTextBounds(content, 0, content.length(), mCachedTextBounds);
        canvas.drawText(content, mContentBounds.width() / 2.0f - mCachedTextBounds.width() / 2.0f, mContentBounds.height() / 2.0f + mTextOffsetY, mTextPaint);
        canvas.restore();
    }

    private String prepareText(@Nullable String text, @NonNull String placeHolder) {
        return TextUtils.isEmpty(text) || "0".equals(text) ? placeHolder : text;
    }

    private int getResolvedSize(int desiredSize, int measureSpec) {
        int mode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);
        int size;
        if (mode == MeasureSpec.EXACTLY) {
            size = specSize;
        } else {
            size = desiredSize;
            if (mode == MeasureSpec.AT_MOST) {
                size = Math.min(desiredSize, specSize);
            }
        }
        return size;
    }

    public boolean isNative() {
        return isNative;
    }

    public void setNative(boolean aNative) {
        isNative = aNative;
    }

    public String getMarginTopText() {
        return mMarginTopText;
    }

    public void setMarginTopText(String mMarginTopText) {
        this.mMarginTopText = mMarginTopText;
    }

    public String getMarginLeftText() {
        return mMarginLeftText;
    }

    public void setMarginLeftText(String mMarginLeftText) {
        this.mMarginLeftText = mMarginLeftText;
    }

    public String getMarginRightText() {
        return mMarginRightText;
    }

    public void setMarginRightText(String mMarginRightText) {
        this.mMarginRightText = mMarginRightText;
    }

    public String getMarginBottomText() {
        return mMarginBottomText;
    }

    public void setMarginBottomText(String mMarginBottomText) {
        this.mMarginBottomText = mMarginBottomText;
    }

    public String getPaddingLeftText() {
        return mPaddingLeftText;
    }

    public void setPaddingLeftText(String mPaddingLeftText) {
        this.mPaddingLeftText = mPaddingLeftText;
    }

    public String getPaddingTopText() {
        return mPaddingTopText;
    }

    public void setPaddingTopText(String mPaddingTopText) {
        this.mPaddingTopText = mPaddingTopText;
    }

    public String getPaddingRightText() {
        return mPaddingRightText;
    }

    public void setPaddingRightText(String mPaddingRightText) {
        this.mPaddingRightText = mPaddingRightText;
    }

    public String getPaddingBottomText() {
        return mPaddingBottomText;
    }

    public void setPaddingBottomText(String mPaddingBottomText) {
        this.mPaddingBottomText = mPaddingBottomText;
    }

    public String getWidthText() {
        return mWidthText;
    }

    public void setWidthText(String mWidthText) {
        this.mWidthText = mWidthText;
    }

    public String getHeightText() {
        return mHeightText;
    }

    public void setHeightText(String mHeightText) {
        this.mHeightText = mHeightText;
    }

    public String getBorderBottomText() {
        return mBorderBottomText;
    }

    public void setBorderBottomText(String mBorderBottomText) {
        this.mBorderBottomText = mBorderBottomText;
    }

    public String getBorderRightText() {
        return mBorderRightText;
    }

    public void setBorderRightText(String mBorderRightText) {
        this.mBorderRightText = mBorderRightText;
    }

    public String getBorderTopText() {
        return mBorderTopText;
    }

    public void setBorderTopText(String mBorderTopText) {
        this.mBorderTopText = mBorderTopText;
    }

    public String getBorderLeftText() {
        return mBorderLeftText;
    }

    public void setBorderLeftText(String mBorderLeftText) {
        this.mBorderLeftText = mBorderLeftText;
    }
}

17 Source : MISportsConnectView.java
with MIT License
from sickworm

private void init(Context context) {
    mainreplacedlePaint = new Paint();
    mainreplacedlePaint.setColor(ContextCompat.getColor(context, R.color.white));
    mainreplacedlePaint.setTextAlign(Paint.Align.CENTER);
    mainreplacedlePaint.setTextSize(DensityUtils.sp2px(context, MAIN_replacedLE_FONT_SIZE_SP));
    mainreplacedleOffsetY = -(mainreplacedlePaint.getFontMetrics().ascent + mainreplacedlePaint.getFontMetrics().descent) / 2;
    mainreplacedlePaint.setAntiAlias(true);
    circleColor = ContextCompat.getColor(context, R.color.whiteTransparent);
    subreplacedlePaint = new Paint();
    subreplacedlePaint.setColor(circleColor);
    subreplacedlePaint.setTextSize(DensityUtils.sp2px(context, SUB_replacedLE_FONT_SIZE_SP));
    subreplacedleOffsetY = DensityUtils.sp2px(context, SUB_replacedLE_FONT_OFFSET_DP);
    subreplacedleSeparator = getResources().getString(R.string.sub_replacedle_separator);
    subreplacedlePaint.setAntiAlias(true);
    bigCirclePaint = new Paint();
    bigCirclePaint.setStrokeWidth(DensityUtils.dp2px(context, BIG_CIRCLE_SIZE));
    bigCirclePaint.setStyle(Paint.Style.STROKE);
    bigCirclePaint.setAntiAlias(true);
    blurPaint = new Paint(bigCirclePaint);
    blurSize = DensityUtils.dp2px(context, CIRCLE_BLUR_SIZE);
    PathEffect pathEffect1 = new CornerPathEffect(DensityUtils.dp2px(getContext(), BIG_CIRCLE_SHAKE_RADIUS));
    PathEffect pathEffect2 = new DiscretePathEffect(DensityUtils.dp2px(getContext(), BIG_CIRCLE_SHAKE_RADIUS), DensityUtils.dp2px(getContext(), BIG_CIRCLE_SHAKE_OFFSET));
    PathEffect pathEffect = new ComposePathEffect(pathEffect1, pathEffect2);
    bigCirclePaint.setPathEffect(pathEffect);
    dottedCirclePaint = new Paint();
    dottedCirclePaint.setStrokeWidth(DensityUtils.dp2px(context, DOTTED_CIRCLE_WIDTH));
    dottedCirclePaint.setColor(ContextCompat.getColor(context, R.color.whiteTransparent));
    dottedCirclePaint.setStyle(Paint.Style.STROKE);
    float gagPx = DensityUtils.dp2px(context, DOTTED_CIRCLE_GAG);
    dottedCirclePaint.setPathEffect(new DashPathEffect(new float[] { gagPx, gagPx }, 0));
    dottedCirclePaint.setAntiAlias(true);
    solidCirclePaint = new Paint();
    solidCirclePaint.setStrokeWidth(DensityUtils.dp2px(context, SOLID_CIRCLE_WIDTH));
    solidCirclePaint.setColor(ContextCompat.getColor(context, R.color.white));
    solidCirclePaint.setStyle(Paint.Style.STROKE);
    solidCirclePaint.setStrokeCap(Paint.Cap.ROUND);
    solidCirclePaint.setAntiAlias(true);
    dotPaint = new Paint();
    dotPaint.setStrokeWidth(DensityUtils.dp2px(context, DOT_SIZE));
    dotPaint.setStrokeCap(Paint.Cap.ROUND);
    dotPaint.setColor(ContextCompat.getColor(context, R.color.white));
    dotPaint.setAntiAlias(true);
    backgroundBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.bg_step_law);
    // 设置手表 icon 的大小
    watchBitmap = BitmapFactory.decodeResource(context.getResources(), R.mipmap.icon_headview_watch);
    float scale = DensityUtils.dp2px(context, WATCH_SIZE) / watchBitmap.getWidth();
    Matrix matrix = new Matrix();
    matrix.postScale(scale, scale);
    watchBitmap = Bitmap.createBitmap(watchBitmap, 0, 0, watchBitmap.getWidth(), watchBitmap.getHeight(), matrix, true);
    watchOffset = DensityUtils.sp2px(context, WATCH_OFFSET_DP);
    fireworksCircle = new FireworksCircleGraphics(context);
    animationThread = new AnimationThread();
    animationThread.start();
}

17 Source : LineChart.java
with Apache License 2.0
from openXu

/**
 * 绘制焦点
 */
private void drawFocus(Canvas canvas) {
    if (null == focusData)
        return;
    // 绘制竖直虚线
    PathEffect effects = new DashPathEffect(new float[] { 8, 5, 8, 5 }, 0);
    paintEffect.setStyle(Paint.Style.STROKE);
    paintEffect.setStrokeWidth(focusLineSize);
    paintEffect.setColor(focusLineColor);
    paintEffect.setPathEffect(effects);
    Path path = new Path();
    path.moveTo(focusData.getPoint().x, rectChart.bottom);
    path.lineTo(focusData.getPoint().x, rectChart.top);
    canvas.drawPath(path, paintEffect);
    // 绘制焦点
    // paint.setAntiAlias(true);
    // paint.setStyle(Paint.Style.STROKE);
    // paint.setStrokeWidth(lineSize);
    // paint.setColor(lineColor[0]);
    // canvas.drawCircle(point1.x, point1.y, dotRadius, paint);
    // paint.setColor(lineColor[1]);
    // canvas.drawCircle(point2.x, point2.y, dotRadius, paint);
    // 面板
    boolean showLeft = focusData.getPoint().x - rectChart.left > (rectChart.right - rectChart.left) / 2;
    RectF rect = new RectF(showLeft ? focusData.getPoint().x - foucsRectWidth - 30 : focusData.getPoint().x + 30, rectChart.top, /*+ (rectChart.bottom - rectChart.top)/2 - foucsRectHeight/2*/
    showLeft ? focusData.getPoint().x - 30 : focusData.getPoint().x + foucsRectWidth + 30, rectChart.top + foucsRectHeight);
    paint.setStyle(Paint.Style.FILL);
    paint.setColor(Color.WHITE);
    paint.setAlpha(230);
    canvas.drawRect(rect, paint);
    // 面板中的文字
    // 2020-10-16 06:00
    // 零序电流:15.2KW
    // A相电流:15.2KW
    // A相电流:15.2KW
    // A相电流:15.2KW
    String text;
    float top = rect.top + foucsRectSpace;
    for (int i = 0; i < focusPanelText.length; i++) {
        if (focusPanelText[i].show) {
            paintText.setTextSize(focusPanelText[i].textSize);
            paintText.setColor(focusPanelText[i].textColor);
            if (i == 0) {
                // x轴数据
                text = focusData.getData().get(0).getValuex();
            } else {
                top += foucsRectTextSpace;
                text = focusPanelText[i].text + focusData.getData().get(i - 1).getValuey() + yAxisMark.unit;
            }
            canvas.drawText(text, rect.left + foucsRectSpace, top + FontUtil.getFontLeading(paintText), paintText);
            top += FontUtil.getFontHeight(paintText);
        }
    }
}

17 Source : SshqLinesChart.java
with Apache License 2.0
from openXu

/**
 * 绘制X轴方向辅助网格
 */
private void drawGrid(Canvas canvas) {
    float yMarkSpace = (rectChart.bottom - rectChart.top) / (yLeft.lableNum - 1);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(lineWidth);
    paint.setColor(defColor);
    paintEffect.setStyle(Paint.Style.STROKE);
    paintEffect.setStrokeWidth(lineWidth);
    paintEffect.setColor(defColor);
    // canvas.drawLine(rectChart.left, rectChart.top, rectChart.left, rectChart.bottom, paint);
    // canvas.drawLine(rectChart.right, rectChart.top, rectChart.right, rectChart.bottom, paint);
    PathEffect effects = new DashPathEffect(new float[] { 15, 6, 15, 6 }, 0);
    Path path = new Path();
    for (int i = 0; i < yLeft.lableNum; i++) {
        path.reset();
        path.moveTo(rectChart.left, rectChart.bottom - yMarkSpace * i);
        path.lineTo(rectChart.right, rectChart.bottom - yMarkSpace * i);
        paintEffect.setPathEffect(effects);
        canvas.drawPath(path, paintEffect);
    }
}

17 Source : QsrdLinesChart.java
with Apache License 2.0
from openXu

/**
 * 绘制焦点
 */
private void drawFocus(Canvas canvas) {
    if (!onFocus || null == focusData)
        return;
    // 竖直线
    PathEffect effects = new DashPathEffect(new float[] { 15, 10, 15, 10 }, 0);
    paintEffect.setStyle(Paint.Style.STROKE);
    paintEffect.setStrokeWidth(focusLineSize);
    paintEffect.setColor(focusLineColor);
    paintEffect.setPathEffect(effects);
    Path path = new Path();
    path.moveTo(focusData.getPoint().getPoint().x, rectChart.bottom);
    path.lineTo(focusData.getPoint().getPoint().x, rectChart.top);
    canvas.drawPath(path, paintEffect);
}

17 Source : DashboardView.java
with Apache License 2.0
from openXu

/**
 * 仪表盘图表
 */
public clreplaced DashboardView extends BaseChart {

    // 总数量
    private int total;

    // 占比数量
    private int progress;

    // 动画计算的占比数量
    private float animPro;

    // 开始角度  (正常情况正下方为90度,这里的30是指正下方向左偏30度,也就是120度)
    private int startAngle = 30;

    // 虚线宽度
    private int dashesSize = DensityUtil.dip2px(getContext(), 20);

    // 实线宽度
    private int solidSize = DensityUtil.dip2px(getContext(), 9);

    // 中心白圈与 实线间隙
    private int rSpace1 = DensityUtil.dip2px(getContext(), 25);

    // 虚线 实线间隙
    private int rSpace2 = DensityUtil.dip2px(getContext(), 4);

    // 指针颜色和长度(长度应该比rSpace1小)
    private int pointerColor = Color.parseColor("#d55942");

    private int pointerRaidus = DensityUtil.dip2px(getContext(), 20);

    private int pointerSize = DensityUtil.dip2px(getContext(), 10);

    /**
     * 文字大小颜色
     */
    // 中间文字 (5000亿)
    private int centerTextSize = DensityUtil.sp2px(getContext(), 18);

    private int centerTextColor = Color.parseColor("#d55942");

    // 仪表名称 (量能)
    private String nameText = "能量";

    private int nameTextSize = DensityUtil.sp2px(getContext(), 20);

    private int nameTextColor = Color.parseColor("#dc3929");

    // 仪表刻度 (0  一万亿)
    private int lableTextSize = DensityUtil.sp2px(getContext(), 18);

    private int lableTextColor = Color.parseColor("#e2978a");

    private String lableLeft = "0";

    private String lableRight = "一万亿";

    // 0  一万亿 文字与扇形间距
    private int lableSpace = DensityUtil.dip2px(getContext(), 4);

    // 渐变色
    int[] proColors = new int[] { // 初始颜色
    Color.parseColor("#e7ac6a"), // 中间颜色
    Color.parseColor("#e47f3f"), // 最终颜色
    Color.parseColor("#df422c") };

    float[] proPositions = new float[] { 0.3f, .5f, .7f };

    SweepGradient proShader;

    // 中间灰色边缘渐变色
    RadialGradient sideShader;

    int[] sideColors = new int[] { // 灰色
    Color.parseColor("#b2c2dd"), // 全透明灰色
    Color.parseColor("#00b2c2dd") };

    // 虚线间隔
    PathEffect effects = new DashPathEffect(new float[] { 9, 11, 9, 11 }, 0);

    /**
     * 计算
     */
    // 中间白色圆圈半径
    private int centerRaidus;

    // 半径
    private int chartRaidus;

    // 虚线扇形矩形框(位于扇形中心)
    protected RectF rectDashes;

    // 实线扇形矩形框(位于扇形中心)
    protected RectF rectSolid;

    // 0  一万亿 lable绘制点
    private PointF startPointLeft, startPointRight;

    // 量能   绘制点
    private PointF startPointName;

    public DashboardView(Context context) {
        super(context, null);
    }

    public DashboardView(Context context, AttributeSet attrs) {
        super(context, attrs, 0);
    }

    public DashboardView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public void init(Context context, AttributeSet attrs, int defStyleAttr) {
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);
        int heightSize = MeasureSpec.getSize(widthMeasureSpec);
        LogUtil.i(TAG, "建议宽高:" + widthSize + " * " + heightSize);
        // 根据中间文字大小计算白色圆圈半径
        paintLabel.setTextSize(centerTextSize);
        int textWidth = (int) FontUtil.getFontlength(paintLabel, "100000");
        // int textHeight = (int)FontUtil.getFontHeight(paintLabel);
        centerRaidus = textWidth / 2 + DensityUtil.dip2px(getContext(), 5);
        // 最大半径
        chartRaidus = centerRaidus + rSpace1 + solidSize + rSpace2 + dashesSize;
        paintLabel.setTextSize(lableTextSize);
        LogUtil.d(TAG, "centerRaidus:" + centerRaidus);
        LogUtil.d(TAG, "chartRaidus:" + chartRaidus);
        // 计算控件宽高
        int raidus = chartRaidus;
        // 下切面高度  Math.toRadians将角度转换成弧度值
        int sectionRaidus = (int) (Math.cos(Math.toRadians(startAngle)) * raidus);
        widthSize = getPaddingLeft() + getPaddingRight() + chartRaidus * 2;
        heightSize = getPaddingTop() + getPaddingBottom() + chartRaidus + sectionRaidus + lableSpace + (int) FontUtil.getFontHeight(paintLabel);
        setMeasuredDimension(MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(heightSize, MeasureSpec.EXACTLY));
        LogUtil.i(TAG, "宽高:" + getMeasuredWidth() + " * " + getMeasuredHeight());
        centerPoint = new PointF(getPaddingLeft() + chartRaidus, getPaddingTop() + chartRaidus);
        rectChart = new RectF(getPaddingLeft(), getPaddingTop(), getMeasuredWidth() - getPaddingRight(), getPaddingTop() + chartRaidus * 2);
        // 计算实线扇形矩形区域-----------------
        raidus = centerRaidus + rSpace1 + solidSize / 2;
        rectSolid = new RectF(centerPoint.x - raidus, centerPoint.y - raidus, centerPoint.x + raidus, centerPoint.y + raidus);
        // 量能 绘制点
        startPointName = new PointF(centerPoint.x, rectSolid.bottom);
        // 虚线部分--------------------------
        raidus = centerRaidus + rSpace1 + solidSize + rSpace2 + dashesSize / 2;
        rectDashes = new RectF(centerPoint.x - raidus, centerPoint.y - raidus, centerPoint.x + raidus, centerPoint.y + raidus);
        // lable绘制开始和结束点 ----------------
        raidus = centerRaidus + rSpace1 + solidSize + rSpace2 + dashesSize;
        sectionRaidus = (int) (Math.cos(Math.toRadians(startAngle)) * raidus);
        startPointLeft = new PointF((int) (centerPoint.x - Math.sin(Math.toRadians(startAngle)) * raidus), centerPoint.y + sectionRaidus);
        startPointRight = new PointF((int) (centerPoint.x + Math.sin(Math.toRadians(startAngle)) * raidus), centerPoint.y + sectionRaidus);
        // 渐变色
        proShader = new SweepGradient(centerPoint.x, centerPoint.y, proColors, proPositions);
        sideShader = new RadialGradient(centerPoint.x, centerPoint.y, centerRaidus + rSpace1, sideColors, new float[] { 0.2f, .75f }, Shader.TileMode.CLAMP);
        LogUtil.d(TAG, "centerPoint:" + centerPoint);
        LogUtil.d(TAG, "rectChart:" + rectChart);
        invalidate();
    }

    public void setData(int total, int progress) {
        if (progress > total)
            progress = total;
        this.total = total;
        this.progress = progress;
        startDraw = false;
        invalidate();
    }

    @Override
    public void drawDebug(Canvas canvas) {
        super.drawDebug(canvas);
        paint.setStyle(Paint.Style.STROKE);
        paint.setColor(Color.GREEN);
        canvas.drawRect(rectChart.left, rectChart.top, rectChart.right, rectChart.bottom, paint);
        paint.setColor(Color.BLACK);
        canvas.drawRect(rectDashes.left, rectDashes.top, rectDashes.right, rectDashes.bottom, paint);
        paint.setColor(Color.GRAY);
        canvas.drawRect(rectSolid.left, rectSolid.top, rectSolid.right, rectSolid.bottom, paint);
    }

    /**
     * 绘制图表基本框架
     */
    @Override
    public void drawDefult(Canvas canvas) {
        // 量能
        paintLabel.setTextSize(nameTextSize);
        paintLabel.setColor(nameTextColor);
        canvas.drawText(nameText, startPointName.x - FontUtil.getFontlength(paintLabel, nameText) / 2, startPointName.y - FontUtil.getFontHeight(paintLabel) / 3 * 2 + FontUtil.getFontLeading(paintLabel), paintLabel);
        // 0 一万亿
        paintLabel.setTextSize(lableTextSize);
        paintLabel.setColor(lableTextColor);
        canvas.drawText(lableLeft, startPointLeft.x - FontUtil.getFontlength(paintLabel, lableLeft) / 2, startPointLeft.y + lableSpace + FontUtil.getFontLeading(paintLabel), paintLabel);
        canvas.drawText(lableRight, startPointRight.x - FontUtil.getFontlength(paintLabel, lableRight) / 2, startPointRight.y + lableSpace + FontUtil.getFontLeading(paintLabel), paintLabel);
        // 实线扇形
        // 由于渐变色shader是从正东方开始绘制,导致颜色排版错误,这里将画布旋转90度,正下方为0度
        canvas.rotate(90, centerPoint.x, centerPoint.y);
        paint.setShader(proShader);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(solidSize);
        canvas.drawArc(rectSolid, startAngle, 360.0f - startAngle * 2, false, paint);
        paint.setShader(null);
        // 绘制虚线
        paintEffect.setShader(null);
        paintEffect.setStyle(Paint.Style.STROKE);
        paintEffect.setPathEffect(effects);
        paintEffect.setColor(defColor);
        paintEffect.setStrokeWidth(dashesSize);
        canvas.drawArc(rectDashes, startAngle, 360.0f - startAngle * 2, false, paintEffect);
        // 绘制中间灰色边缘
        paint.setShader(sideShader);
        // paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(rSpace1);
        canvas.drawCircle(centerPoint.x, centerPoint.y, centerRaidus + rSpace1 / 2, paint);
        paint.setShader(null);
        // 中间白色圆圈
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.WHITE);
        canvas.drawCircle(centerPoint.x, centerPoint.y, centerRaidus, paint);
        // 反转90度还原
        canvas.rotate(-90, centerPoint.x, centerPoint.y);
    }

    /**
     * 绘制图表
     */
    @Override
    public void drawChart(Canvas canvas) {
        if (progress > 0) {
            // 数量文字
            paintLabel.setTextSize(centerTextSize);
            paintLabel.setColor(centerTextColor);
            String text = ((int) animPro) + "";
            canvas.drawText(text, centerPoint.x - FontUtil.getFontlength(paintLabel, text) / 2, centerPoint.y - FontUtil.getFontHeight(paintLabel) + FontUtil.getFontLeading(paintLabel), paintLabel);
            text = "亿";
            canvas.drawText(text, centerPoint.x - FontUtil.getFontlength(paintLabel, text) / 2, centerPoint.y + DensityUtil.dip2px(getContext(), 2) + FontUtil.getFontLeading(paintLabel), paintLabel);
            // 绘制彩色虚线
            // 再次寻转90度
            canvas.rotate(90, centerPoint.x, centerPoint.y);
            float proAngle = (360.0f - startAngle * 2) * (animPro / total * 1.0f);
            paintEffect.setStyle(Paint.Style.STROKE);
            paintEffect.setPathEffect(effects);
            paintEffect.setShader(proShader);
            paintEffect.setStrokeWidth(dashesSize);
            // 消除由于虚线间隔导致视觉上仪表进度不够的情况,默认多绘制2.5度
            canvas.drawArc(rectDashes, startAngle, proAngle < (360.0f - startAngle * 2 - 5) ? proAngle + 2.5f : proAngle, false, paintEffect);
            paintEffect.setShader(null);
            // 绘制指针
            /*画一个实心三角形*/
            // 以正东面为0度起点计算指定角度所对应的圆周上的点的坐标:
            double asin = Math.toDegrees(Math.asin(pointerSize / 2f / centerRaidus));
            float centerArcX1 = centerPoint.x + (float) (centerRaidus * Math.cos(Math.toRadians(startAngle - asin + proAngle)));
            float centerArcY1 = centerPoint.y + (float) (centerRaidus * Math.sin(Math.toRadians(startAngle - asin + proAngle)));
            // LogUtil.i(TAG, "角度   "+(startAngle-asin+proAngle)+"   弧度:"+Math.toRadians(startAngle-asin+proAngle));
            // LogUtil.i(TAG, "cos   "+Math.cos(Math.toRadians(startAngle-asin+proAngle)));
            // LogUtil.i(TAG, "sin   "+Math.sin(Math.toRadians(startAngle-asin+proAngle)));
            float endx2 = centerPoint.x + (float) ((pointerRaidus + centerRaidus) * Math.cos(Math.toRadians(startAngle + proAngle)));
            float endy2 = centerPoint.y + (float) ((pointerRaidus + centerRaidus) * Math.sin(Math.toRadians(startAngle + proAngle)));
            float centerArcX2 = centerPoint.x + (float) (centerRaidus * Math.cos(Math.toRadians(startAngle + asin + proAngle)));
            float centerArcY2 = centerPoint.y + (float) (centerRaidus * Math.sin(Math.toRadians(startAngle + asin + proAngle)));
            // LogUtil.d(TAG, "角度   "+(startAngle+asin+proAngle)+"   弧度:"+Math.toRadians(startAngle+asin+proAngle));
            // LogUtil.d(TAG, "cos   "+Math.cos(Math.toRadians(startAngle+asin+proAngle)));
            // LogUtil.d(TAG, "sin   "+Math.sin(Math.toRadians(startAngle+asin+proAngle)));
            Path path2 = new Path();
            path2.moveTo(centerArcX1, centerArcY1);
            path2.lineTo(endx2, endy2);
            path2.lineTo(centerArcX2, centerArcY2);
            path2.close();
            paint.setColor(pointerColor);
            canvas.drawPath(path2, paint);
        }
    }

    /**
     * 创建动画
     */
    @Override
    protected ValueAnimator initAnim() {
        anim = ValueAnimator.ofObject(new AngleEvaluator(), 0f, 1.0f);
        anim.setInterpolator(new AccelerateDecelerateInterpolator());
        return anim;
    }

    /**
     * 动画值变化之后计算数据
     */
    @Override
    protected void evaluatorData(ValueAnimator animation) {
        animPro = (float) animation.getAnimatedValue() * progress;
    }
}

17 Source : CustomCurveChart.java
with Apache License 2.0
from liuwan1992

/**
 * 初始化数据值和画笔
 */
public void init() {
    xPoint = margin + marginX;
    yPoint = this.getHeight() - margin;
    xScale = (this.getWidth() - 2 * margin - marginX) / (xLabel.length - 1);
    yScale = (this.getHeight() - 2 * margin) / (yLabel.length - 1);
    paintAxes = new Paint();
    paintAxes.setStyle(Paint.Style.STROKE);
    paintAxes.setAntiAlias(true);
    paintAxes.setDither(true);
    paintAxes.setColor(ContextCompat.getColor(getContext(), R.color.color14));
    paintAxes.setStrokeWidth(4);
    paintCoordinate = new Paint();
    paintCoordinate.setStyle(Paint.Style.STROKE);
    paintCoordinate.setDither(true);
    paintCoordinate.setAntiAlias(true);
    paintCoordinate.setColor(ContextCompat.getColor(getContext(), R.color.color14));
    paintCoordinate.setTextSize(15);
    paintTable = new Paint();
    paintTable.setStyle(Paint.Style.STROKE);
    paintTable.setAntiAlias(true);
    paintTable.setDither(true);
    paintTable.setColor(ContextCompat.getColor(getContext(), R.color.color4));
    paintTable.setStrokeWidth(2);
    paintCurve = new Paint();
    paintCurve.setStyle(Paint.Style.STROKE);
    paintCurve.setDither(true);
    paintCurve.setAntiAlias(true);
    paintCurve.setStrokeWidth(3);
    PathEffect pathEffect = new CornerPathEffect(25);
    paintCurve.setPathEffect(pathEffect);
    paintRectF = new Paint();
    paintRectF.setStyle(Paint.Style.FILL);
    paintRectF.setDither(true);
    paintRectF.setAntiAlias(true);
    paintRectF.setStrokeWidth(3);
    paintValue = new Paint();
    paintValue.setStyle(Paint.Style.STROKE);
    paintValue.setAntiAlias(true);
    paintValue.setDither(true);
    paintValue.setColor(ContextCompat.getColor(getContext(), R.color.color1));
    paintValue.setTextAlign(Paint.Align.CENTER);
    paintValue.setTextSize(15);
}

17 Source : OkView.java
with MIT License
from lihangleo2

/**
 * Created by leo
 * on 2019/11/21.
 */
public clreplaced OkView extends View {

    // 绘制一个小圆圈
    private Paint paint;

    // 绘制打勾paint
    private Paint okPaint;

    // 背景圆圈的半径
    private int myRadius;

    // 绘制打勾的路径
    private Path path = new Path();

    // 绘制路径的长度,也可以理解为完成度
    private PathMeasure pathMeasure;

    // 绘制对勾(√)的动画
    private ValueAnimator animator_draw_ok;

    // 对路径处理实现绘制动画效果
    private PathEffect effect;

    private boolean startDrawOk;

    public OkView(Context context) {
        this(context, null);
    }

    public OkView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public OkView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        okPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        okPaint.setStrokeWidth(5);
        okPaint.setStyle(Paint.Style.STROKE);
        okPaint.setStrokeCap(Paint.Cap.ROUND);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawCircle(getWidth() / 2, getHeight() / 2, myRadius, paint);
        if (startDrawOk) {
            canvas.drawPath(path, okPaint);
        }
    }

    public void setOkColor(int color) {
        okPaint.setColor(color);
    }

    public void setCircleColor(int color) {
        paint.setColor(color);
    }

    public void setRadius(int radius) {
        myRadius = radius;
        // 对勾的路径
        int cHeight = radius * 2;
        path.moveTo(+cHeight / 8 * 3, cHeight / 2);
        path.lineTo(+cHeight / 2, cHeight / 5 * 3);
        path.lineTo(+cHeight / 3 * 2, cHeight / 5 * 2);
        pathMeasure = new PathMeasure(path, true);
        invalidate();
    }

    public void start(int duration) {
        animator_draw_ok = ValueAnimator.ofFloat(1, 0);
        animator_draw_ok.setDuration(duration);
        animator_draw_ok.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                startDrawOk = true;
                float value = (Float) animation.getAnimatedValue();
                effect = new DashPathEffect(new float[] { pathMeasure.getLength(), pathMeasure.getLength() }, value * pathMeasure.getLength());
                okPaint.setPathEffect(effect);
                invalidate();
            }
        });
        animator_draw_ok.start();
    }
}

17 Source : TimeLineChartRenderer.java
with MIT License
from LambdaXiao

public void drawCircleDashMarker(Canvas canvas, ILineDataSet dataSet, int count) {
    // 画虚线圆点和MarkerView
    PathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);
    Path path = new Path();
    // 应为这里会复用之前的mLineBuffer,在总长度不变的情况下,取一般就是之前的位置,mXBounds.range + mXBounds.min 是最新的K线的变动范围
    int pointOffset = (mXBounds.range + mXBounds.min + 1) * 4;
    if (dataSet.getEntryCount() != 0) {
        // 画虚线参数设置
        path.moveTo(mLineBuffer[pointOffset - 2], mLineBuffer[pointOffset - 1]);
        path.lineTo(mViewPortHandler.contentRight(), mLineBuffer[pointOffset - 1]);
        mRenderPaint.setPathEffect(effects);
        // Utils.convertDpToPixel(35)
        Entry e = dataSet.getEntryForIndex(count - 1);
        mRenderPaint.setTextSize(Utils.convertDpToPixel(10));
        String text = NumberUtils.keepPrecisionR(e.getY(), dataSet.getPrecision());
        int width = Utils.calcTextWidth(mRenderPaint, text);
        int height = Utils.calcTextHeight(mRenderPaint, text);
        float rectLeft = mViewPortHandler.contentRight() - width - Utils.convertDpToPixel(4);
        float circleX = mLineBuffer[pointOffset - 2];
        if (circleX >= rectLeft) {
            mRenderPaint.setColor(Color.parseColor("#A65198FA"));
            mRenderPaint.setStyle(Paint.Style.FILL);
            float x = mLineBuffer[pointOffset - 2];
            float y = mLineBuffer[pointOffset - 1];
            if (y > mViewPortHandler.contentTop() + mViewPortHandler.getChartHeight() / 2) {
                canvas.drawRect(rectLeft, y - Utils.convertDpToPixel(22), mViewPortHandler.contentRight(), y - Utils.convertDpToPixel(6), mRenderPaint);
                Path pathS = new Path();
                // 此点为多边形的起点
                pathS.moveTo(x, y - Utils.convertDpToPixel(3));
                pathS.lineTo(x - Utils.convertDpToPixel(3), y - Utils.convertDpToPixel(6));
                pathS.lineTo(x + Utils.convertDpToPixel(3), y - Utils.convertDpToPixel(6));
                // 使这些点构成封闭的多边形
                pathS.close();
                canvas.drawPath(pathS, mRenderPaint);
                mRenderPaint.setColor(Color.parseColor("#66FFFFFF"));
                canvas.drawText(text, rectLeft + Utils.convertDpToPixel(2), y - Utils.convertDpToPixel(10), mRenderPaint);
            } else {
                canvas.drawRect(rectLeft, y + Utils.convertDpToPixel(6), mViewPortHandler.contentRight(), y + Utils.convertDpToPixel(22), mRenderPaint);
                Path pathS = new Path();
                // 此点为多边形的起点
                pathS.moveTo(x, y + Utils.convertDpToPixel(1));
                pathS.lineTo(x - Utils.convertDpToPixel(3), y + Utils.convertDpToPixel(6));
                pathS.lineTo(x + Utils.convertDpToPixel(3), y + Utils.convertDpToPixel(6));
                // 使这些点构成封闭的多边形
                pathS.close();
                canvas.drawPath(pathS, mRenderPaint);
                mRenderPaint.setColor(Color.parseColor("#66FFFFFF"));
                canvas.drawText(text, rectLeft + Utils.convertDpToPixel(2), y + Utils.convertDpToPixel(10) + height, mRenderPaint);
            }
        } else {
            canvas.drawPath(path, mRenderPaint);
            mRenderPaint.setStyle(Paint.Style.FILL);
            canvas.drawRect(rectLeft, mLineBuffer[pointOffset - 1] - Utils.convertDpToPixel(8), mViewPortHandler.contentRight(), mLineBuffer[pointOffset - 1] + Utils.convertDpToPixel(8), mRenderPaint);
            mRenderPaint.setColor(Color.parseColor("#FFFFFF"));
            canvas.drawText(text, rectLeft + Utils.convertDpToPixel(2), mLineBuffer[pointOffset - 1] + Utils.convertDpToPixel(3), mRenderPaint);
        }
    }
    mRenderPaint.setColor(Color.RED);
    postPosition(dataSet, mLineBuffer[pointOffset - 2], mLineBuffer[pointOffset - 1]);
}

17 Source : PathPaintView.java
with Apache License 2.0
from InnoFang

/**
 * Author: Inno Fang
 * Time: 2017/1/12 21:40
 * Description:
 */
public clreplaced PathPaintView extends View {

    private static final String TAG = "PathTracingView";

    private Path mPath;

    private Paint mPaint;

    private float mLength;

    private float mAnimValue;

    private PathMeasure mPathMeasure;

    private PathEffect mPathEffect;

    public PathPaintView(Context context) {
        super(context);
    }

    public PathPaintView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPath = new Path();
        mPath.moveTo(100, 100);
        mPath.lineTo(100, 500);
        mPath.lineTo(400, 300);
        mPath.close();
        mPathMeasure = new PathMeasure();
        mPathMeasure.setPath(mPath, true);
        mLength = mPathMeasure.getLength();
        ValueAnimator animator = ValueAnimator.ofFloat(1, 0);
        animator.setDuration(2000);
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimValue = (float) animation.getAnimatedValue();
                mPathEffect = new DashPathEffect(new float[] { mLength, mLength }, mLength * mAnimValue);
                mPaint.setPathEffect(mPathEffect);
                invalidate();
            }
        });
        animator.start();
    }

    public PathPaintView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPath(mPath, mPaint);
    }
}

17 Source : Line.java
with Apache License 2.0
from huashengzzz

/**
 * Single line for line chart.
 */
public clreplaced Line {

    private static final int DEFAULT_LINE_STROKE_WIDTH_DP = 3;

    private static final int DEFAULT_POINT_RADIUS_DP = 6;

    private static final int DEFAULT_AREA_TRANSPARENCY = 64;

    public static final int UNINITIALIZED = 0;

    private int color = ChartUtils.DEFAULT_COLOR;

    private int pointColor = UNINITIALIZED;

    private int darkenColor = ChartUtils.DEFAULT_DARKEN_COLOR;

    /**
     * Transparency of area when line is filled. *
     */
    private int areaTransparency = DEFAULT_AREA_TRANSPARENCY;

    private int strokeWidth = DEFAULT_LINE_STROKE_WIDTH_DP;

    private int pointRadius = DEFAULT_POINT_RADIUS_DP;

    private boolean hasGradientToTransparent = false;

    private boolean hasPoints = true;

    private boolean hasLines = true;

    private boolean hasLabels = false;

    private boolean hasLabelsOnlyForSelected = false;

    private boolean isCubic = false;

    private boolean isSquare = false;

    private boolean isFilled = false;

    private ValueShape shape = ValueShape.CIRCLE;

    private PathEffect pathEffect;

    private LineChartValueFormatter formatter = new SimpleLineChartValueFormatter();

    private List<PointValue> values = new ArrayList<PointValue>();

    public Line() {
    }

    public Line(List<PointValue> values) {
        setValues(values);
    }

    public Line(Line line) {
        this.color = line.color;
        this.pointColor = line.pointColor;
        this.darkenColor = line.darkenColor;
        this.areaTransparency = line.areaTransparency;
        this.strokeWidth = line.strokeWidth;
        this.pointRadius = line.pointRadius;
        this.hasGradientToTransparent = line.hasGradientToTransparent;
        this.hasPoints = line.hasPoints;
        this.hasLines = line.hasLines;
        this.hasLabels = line.hasLabels;
        this.hasLabelsOnlyForSelected = line.hasLabelsOnlyForSelected;
        this.isSquare = line.isSquare;
        this.isCubic = line.isCubic;
        this.isFilled = line.isFilled;
        this.shape = line.shape;
        this.pathEffect = line.pathEffect;
        this.formatter = line.formatter;
        for (PointValue pointValue : line.values) {
            this.values.add(new PointValue(pointValue));
        }
    }

    public void update(float scale) {
        for (PointValue value : values) {
            value.update(scale);
        }
    }

    public void finish() {
        for (PointValue value : values) {
            value.finish();
        }
    }

    public List<PointValue> getValues() {
        return this.values;
    }

    public void setValues(List<PointValue> values) {
        if (null == values) {
            this.values = new ArrayList<PointValue>();
        } else {
            this.values = values;
        }
    }

    public int getColor() {
        return color;
    }

    public Line setColor(int color) {
        this.color = color;
        if (pointColor == UNINITIALIZED) {
            this.darkenColor = ChartUtils.darkenColor(color);
        }
        return this;
    }

    public int getPointColor() {
        if (pointColor == UNINITIALIZED) {
            return color;
        } else {
            return pointColor;
        }
    }

    public Line setPointColor(int pointColor) {
        this.pointColor = pointColor;
        if (pointColor == UNINITIALIZED) {
            this.darkenColor = ChartUtils.darkenColor(color);
        } else {
            this.darkenColor = ChartUtils.darkenColor(pointColor);
        }
        return this;
    }

    public int getDarkenColor() {
        return darkenColor;
    }

    /**
     * @see #setAreaTransparency(int)
     */
    public int getAreaTransparency() {
        return areaTransparency;
    }

    /**
     * Set area transparency(255 is full opacity) for filled lines
     *
     * @param areaTransparency
     * @return
     */
    public Line setAreaTransparency(int areaTransparency) {
        this.areaTransparency = areaTransparency;
        return this;
    }

    public int getStrokeWidth() {
        return strokeWidth;
    }

    public Line setStrokeWidth(int strokeWidth) {
        this.strokeWidth = strokeWidth;
        return this;
    }

    public boolean hasPoints() {
        return hasPoints;
    }

    public Line setHasPoints(boolean hasPoints) {
        this.hasPoints = hasPoints;
        return this;
    }

    public boolean hasLines() {
        return hasLines;
    }

    public Line setHasLines(boolean hasLines) {
        this.hasLines = hasLines;
        return this;
    }

    public boolean hasLabels() {
        return hasLabels;
    }

    public Line setHasLabels(boolean hasLabels) {
        this.hasLabels = hasLabels;
        if (hasLabels) {
            this.hasLabelsOnlyForSelected = false;
        }
        return this;
    }

    /**
     * @see #setHasLabelsOnlyForSelected(boolean)
     */
    public boolean hasLabelsOnlyForSelected() {
        return hasLabelsOnlyForSelected;
    }

    /**
     * Set true if you want to show value labels only for selected value, works best when chart has
     * isValueSelectionEnabled set to true {@link Chart#setValueSelectionEnabled(boolean)}.
     */
    public Line setHasLabelsOnlyForSelected(boolean hasLabelsOnlyForSelected) {
        this.hasLabelsOnlyForSelected = hasLabelsOnlyForSelected;
        if (hasLabelsOnlyForSelected) {
            this.hasLabels = false;
        }
        return this;
    }

    public int getPointRadius() {
        return pointRadius;
    }

    /**
     * Set radius for points for this line.
     *
     * @param pointRadius
     * @return
     */
    public Line setPointRadius(int pointRadius) {
        this.pointRadius = pointRadius;
        return this;
    }

    public boolean getGradientToTransparent() {
        return hasGradientToTransparent;
    }

    public Line setHasGradientToTransparent(boolean hasGradientToTransparent) {
        this.hasGradientToTransparent = hasGradientToTransparent;
        return this;
    }

    public boolean isCubic() {
        return isCubic;
    }

    public Line setCubic(boolean isCubic) {
        this.isCubic = isCubic;
        if (isSquare)
            setSquare(false);
        return this;
    }

    public boolean isSquare() {
        return isSquare;
    }

    public Line setSquare(boolean isSquare) {
        this.isSquare = isSquare;
        if (isCubic)
            setCubic(false);
        return this;
    }

    public boolean isFilled() {
        return isFilled;
    }

    public Line setFilled(boolean isFilled) {
        this.isFilled = isFilled;
        return this;
    }

    /**
     * @see #setShape(ValueShape)
     */
    public ValueShape getShape() {
        return shape;
    }

    /**
     * Set shape for points, possible values: SQUARE, CIRCLE
     *
     * @param shape
     * @return
     */
    public Line setShape(ValueShape shape) {
        this.shape = shape;
        return this;
    }

    public PathEffect getPathEffect() {
        return pathEffect;
    }

    /**
     * Set path effect for this line, note: it will slow down drawing, try to not use complicated effects,
     * DashPathEffect should be safe choice.
     *
     * @param pathEffect
     */
    public void setPathEffect(PathEffect pathEffect) {
        this.pathEffect = pathEffect;
    }

    public LineChartValueFormatter getFormatter() {
        return formatter;
    }

    public Line setFormatter(LineChartValueFormatter formatter) {
        if (null != formatter) {
            this.formatter = formatter;
        }
        return this;
    }
}

17 Source : Line.java
with Apache License 2.0
from hanFengSan

/**
 * Single line for line chart.
 */
public clreplaced Line {

    private static final int DEFAULT_LINE_STROKE_WIDTH_DP = 3;

    private static final int DEFAULT_POINT_RADIUS_DP = 6;

    private static final int DEFAULT_AREA_TRANSPARENCY = 64;

    public static final int UNINITIALIZED = 0;

    private int color = ChartUtils.DEFAULT_COLOR;

    private int pointColor = UNINITIALIZED;

    private int darkenColor = ChartUtils.DEFAULT_DARKEN_COLOR;

    /**
     * Transparency of area when line is filled. *
     */
    private int areaTransparency = DEFAULT_AREA_TRANSPARENCY;

    private int strokeWidth = DEFAULT_LINE_STROKE_WIDTH_DP;

    private int pointRadius = DEFAULT_POINT_RADIUS_DP;

    private boolean hasPoints = true;

    private boolean hasLines = true;

    private boolean hasLabels = false;

    private boolean hasLabelsOnlyForSelected = false;

    private boolean isCubic = false;

    private boolean isSquare = false;

    private boolean isFilled = false;

    private ValueShape shape = ValueShape.CIRCLE;

    private PathEffect pathEffect;

    private LineChartValueFormatter formatter = new SimpleLineChartValueFormatter();

    private List<PointValue> values = new ArrayList<PointValue>();

    public Line() {
    }

    public Line(List<PointValue> values) {
        setValues(values);
    }

    public Line(Line line) {
        this.color = line.color;
        this.pointColor = line.pointColor;
        this.darkenColor = line.darkenColor;
        this.areaTransparency = line.areaTransparency;
        this.strokeWidth = line.strokeWidth;
        this.pointRadius = line.pointRadius;
        this.hasPoints = line.hasPoints;
        this.hasLines = line.hasLines;
        this.hasLabels = line.hasLabels;
        this.hasLabelsOnlyForSelected = line.hasLabelsOnlyForSelected;
        this.isSquare = line.isSquare;
        this.isCubic = line.isCubic;
        this.isFilled = line.isFilled;
        this.shape = line.shape;
        this.pathEffect = line.pathEffect;
        this.formatter = line.formatter;
        for (PointValue pointValue : line.values) {
            this.values.add(new PointValue(pointValue));
        }
    }

    public void update(float scale) {
        for (PointValue value : values) {
            value.update(scale);
        }
    }

    public void finish() {
        for (PointValue value : values) {
            value.finish();
        }
    }

    public List<PointValue> getValues() {
        return this.values;
    }

    public void setValues(List<PointValue> values) {
        if (null == values) {
            this.values = new ArrayList<PointValue>();
        } else {
            this.values = values;
        }
    }

    public int getColor() {
        return color;
    }

    public Line setColor(int color) {
        this.color = color;
        if (pointColor == UNINITIALIZED) {
            this.darkenColor = ChartUtils.darkenColor(color);
        }
        return this;
    }

    public int getPointColor() {
        if (pointColor == UNINITIALIZED) {
            return color;
        } else {
            return pointColor;
        }
    }

    public Line setPointColor(int pointColor) {
        this.pointColor = pointColor;
        if (pointColor == UNINITIALIZED) {
            this.darkenColor = ChartUtils.darkenColor(color);
        } else {
            this.darkenColor = ChartUtils.darkenColor(pointColor);
        }
        return this;
    }

    public int getDarkenColor() {
        return darkenColor;
    }

    /**
     * @see #setAreaTransparency(int)
     */
    public int getAreaTransparency() {
        return areaTransparency;
    }

    /**
     * Set area transparency(255 is full opacity) for filled lines
     *
     * @param areaTransparency
     * @return
     */
    public Line setAreaTransparency(int areaTransparency) {
        this.areaTransparency = areaTransparency;
        return this;
    }

    public int getStrokeWidth() {
        return strokeWidth;
    }

    public Line setStrokeWidth(int strokeWidth) {
        this.strokeWidth = strokeWidth;
        return this;
    }

    public boolean hasPoints() {
        return hasPoints;
    }

    public Line setHasPoints(boolean hasPoints) {
        this.hasPoints = hasPoints;
        return this;
    }

    public boolean hasLines() {
        return hasLines;
    }

    public Line setHasLines(boolean hasLines) {
        this.hasLines = hasLines;
        return this;
    }

    public boolean hasLabels() {
        return hasLabels;
    }

    public Line setHasLabels(boolean hasLabels) {
        this.hasLabels = hasLabels;
        if (hasLabels) {
            this.hasLabelsOnlyForSelected = false;
        }
        return this;
    }

    /**
     * @see #setHasLabelsOnlyForSelected(boolean)
     */
    public boolean hasLabelsOnlyForSelected() {
        return hasLabelsOnlyForSelected;
    }

    /**
     * Set true if you want to show value labels only for selected value, works best when chart has
     * isValueSelectionEnabled set to true {@link Chart#setValueSelectionEnabled(boolean)}.
     */
    public Line setHasLabelsOnlyForSelected(boolean hasLabelsOnlyForSelected) {
        this.hasLabelsOnlyForSelected = hasLabelsOnlyForSelected;
        if (hasLabelsOnlyForSelected) {
            this.hasLabels = false;
        }
        return this;
    }

    public int getPointRadius() {
        return pointRadius;
    }

    /**
     * Set radius for points for this line.
     *
     * @param pointRadius
     * @return
     */
    public Line setPointRadius(int pointRadius) {
        this.pointRadius = pointRadius;
        return this;
    }

    public boolean isCubic() {
        return isCubic;
    }

    public Line setCubic(boolean isCubic) {
        this.isCubic = isCubic;
        if (isSquare)
            setSquare(false);
        return this;
    }

    public boolean isSquare() {
        return isSquare;
    }

    public Line setSquare(boolean isSquare) {
        this.isSquare = isSquare;
        if (isCubic)
            setCubic(false);
        return this;
    }

    public boolean isFilled() {
        return isFilled;
    }

    public Line setFilled(boolean isFilled) {
        this.isFilled = isFilled;
        return this;
    }

    /**
     * @see #setShape(ValueShape)
     */
    public ValueShape getShape() {
        return shape;
    }

    /**
     * Set shape for points, possible values: SQUARE, CIRCLE
     *
     * @param shape
     * @return
     */
    public Line setShape(ValueShape shape) {
        this.shape = shape;
        return this;
    }

    public PathEffect getPathEffect() {
        return pathEffect;
    }

    /**
     * Set path effect for this line, note: it will slow down drawing, try to not use complicated effects,
     * DashPathEffect should be safe choice.
     *
     * @param pathEffect
     */
    public void setPathEffect(PathEffect pathEffect) {
        this.pathEffect = pathEffect;
    }

    public LineChartValueFormatter getFormatter() {
        return formatter;
    }

    public Line setFormatter(LineChartValueFormatter formatter) {
        if (null != formatter) {
            this.formatter = formatter;
        }
        return this;
    }
}

17 Source : ChatHeadOverlayView.java
with BSD 2-Clause "Simplified" License
from Denny966

public clreplaced ChatHeadOverlayView extends View {

    private static final long ANIMATION_DURATION = 600;

    private float OVAL_RADIUS;

    private float STAMP_SPACING;

    private Path arrowDashedPath;

    private Paint paint = new Paint();

    private ObjectAnimator animator;

    private PathEffect pathDashEffect;

    public ChatHeadOverlayView(Context context) {
        super(context);
        init(context);
    }

    public ChatHeadOverlayView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        STAMP_SPACING = ChatHeadUtils.dpToPx(context, 20);
        OVAL_RADIUS = ChatHeadUtils.dpToPx(context, 3);
        animator = ObjectAnimator.ofFloat(this, "phase", 0f, -STAMP_SPACING);
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatMode(ValueAnimator.RESTART);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setDuration(ANIMATION_DURATION);
    }

    public ChatHeadOverlayView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (arrowDashedPath != null) {
            paint.setPathEffect(pathDashEffect);
            canvas.drawPath(arrowDashedPath, paint);
        }
    }

    /**
     * taken from https://github.com/romainguy/road-trip/blob/master/application/src/main/java/org/curiouscreature/android/roadtrip/IntroView.java *
     */
    private Path makeDot(float radius) {
        Path p = new Path();
        p.addCircle(0, 0, radius, Path.Direction.CCW);
        return p;
    }

    public void drawPath(float fromX, float fromY, float toX, float toY) {
        arrowDashedPath = new Path();
        arrowDashedPath.moveTo(fromX, fromY);
        arrowDashedPath.lineTo(toX, toY);
        paint.setColor(Color.parseColor("#77FFFFFF"));
        // width = diameter
        paint.setStrokeWidth(OVAL_RADIUS * 2);
        animatePath();
        invalidate();
    }

    /**
     * Will be called by animator
     * @param phase
     */
    private void setPhase(float phase) {
        pathDashEffect = new PathDashPathEffect(makeDot(OVAL_RADIUS), STAMP_SPACING, phase, PathDashPathEffect.Style.ROTATE);
        invalidate();
    }

    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
    private void animatePath() {
        animator.start();
    }

    public void clearPath() {
        animator.cancel();
        arrowDashedPath = null;
        invalidate();
    }
}

17 Source : RecyclerViewItemDecoration.java
with Apache License 2.0
from arjinmc

/**
 * draw horizonal decoration
 *
 * @param c
 * @param parent
 */
private void drawHorinzonal(Canvas c, RecyclerView parent) {
    int childrentCount = parent.getChildCount();
    if (drawableRid != 0) {
        if (hasNinePatch) {
            for (int i = 0; i < childrentCount; i++) {
                if (i != childrentCount - 1) {
                    View childView = parent.getChildAt(i);
                    int myY = childView.getBottom();
                    Rect rect = new Rect(0, myY, parent.getWidth(), myY + bmp.getHeight());
                    ninePatch.draw(c, rect);
                }
            }
        } else {
            for (int i = 0; i < childrentCount; i++) {
                if (i != childrentCount - 1) {
                    View childView = parent.getChildAt(i);
                    int myY = childView.getBottom();
                    c.drawBitmap(bmp, 0, myY, paint);
                }
            }
        }
    } else if (dashWidth == 0 && dashGap == 0) {
        for (int i = 0; i < childrentCount; i++) {
            if (i != childrentCount - 1) {
                View childView = parent.getChildAt(i);
                int myY = childView.getBottom() + thick / 2;
                c.drawLine(0, myY, parent.getWidth(), myY, paint);
            }
        }
    } else {
        PathEffect effects = new DashPathEffect(new float[] { 0, 0, dashWidth, thick }, dashGap);
        paint.setPathEffect(effects);
        for (int i = 0; i < childrentCount; i++) {
            if (i != childrentCount - 1) {
                View childView = parent.getChildAt(i);
                int myY = childView.getBottom() + thick / 2;
                Path path = new Path();
                path.moveTo(0, myY);
                path.lineTo(parent.getWidth(), myY);
                c.drawPath(path, paint);
            }
        }
    }
}

17 Source : RecyclerViewItemDecoration.java
with Apache License 2.0
from arjinmc

/**
 * 画网格分割线
 *
 * @param c
 * @param parent
 */
private void drawGrid(Canvas c, RecyclerView parent) {
    int childrentCount = parent.getChildCount();
    int columnSize = ((GridLayoutManager) parent.getLayoutManager()).getSpanCount();
    int adapterChildrenCount = parent.getAdapter().gereplacedemCount();
    if (drawableRid != 0) {
        if (hasNinePatch) {
            for (int i = 0; i < childrentCount; i++) {
                View childView = parent.getChildAt(i);
                int myX = childView.getRight();
                int myY = childView.getBottom();
                // horizonal
                if (!isLastRowGrid(i, adapterChildrenCount, columnSize)) {
                    Rect rect = new Rect(0, myY, myX, myY + bmp.getHeight());
                    ninePatch.draw(c, rect);
                }
                // vertical
                if (isLastRowGrid(i, adapterChildrenCount, columnSize) && !isLastGridColumn(i, columnSize)) {
                    Rect rect = new Rect(myX, childView.getTop(), myX + bmp.getWidth(), myY);
                    ninePatch.draw(c, rect);
                } else if (!isLastGridColumn(i, columnSize)) {
                    Rect rect = new Rect(myX, childView.getTop(), myX + bmp.getWidth(), myY + bmp.getHeight());
                    ninePatch.draw(c, rect);
                }
            }
        } else {
            for (int i = 0; i < childrentCount; i++) {
                View childView = parent.getChildAt(i);
                int myX = childView.getRight();
                int myY = childView.getBottom();
                // horizonal
                if (!isLastRowGrid(i, adapterChildrenCount, columnSize)) {
                    c.drawBitmap(bmp, childView.getLeft(), myY, paint);
                }
                // vertical
                if (!isLastGridColumn(i, columnSize)) {
                    c.drawBitmap(bmp, myX, childView.getTop(), paint);
                }
            }
        }
    } else if (dashWidth == 0 && dashGap == 0) {
        for (int i = 0; i < childrentCount; i++) {
            View childView = parent.getChildAt(i);
            int myX = childView.getRight() + thick / 2;
            int myY = childView.getBottom() + thick / 2;
            // horizonal
            if (!isLastRowGrid(i, adapterChildrenCount, columnSize)) {
                c.drawLine(childView.getLeft(), myY, childView.getRight() + thick, myY, paint);
            }
            // vertical
            if (isLastRowGrid(i, adapterChildrenCount, columnSize) && !isLastGridColumn(i, columnSize)) {
                c.drawLine(myX, childView.getTop(), myX, childView.getBottom(), paint);
            } else if (!isLastGridColumn(i, columnSize)) {
                c.drawLine(myX, childView.getTop(), myX, myY, paint);
            }
        }
    } else {
        PathEffect effects = new DashPathEffect(new float[] { 0, 0, dashWidth, thick }, dashGap);
        paint.setPathEffect(effects);
        for (int i = 0; i < childrentCount; i++) {
            View childView = parent.getChildAt(i);
            int myX = childView.getRight() + thick / 2;
            int myY = childView.getBottom() + thick / 2;
            // horizonal
            if (!isLastRowGrid(i, adapterChildrenCount, columnSize)) {
                Path path = new Path();
                path.moveTo(0, myY);
                path.lineTo(myX, myY);
                c.drawPath(path, paint);
            }
            // vertical
            if (isLastRowGrid(i, adapterChildrenCount, columnSize) && !isLastGridColumn(i, columnSize)) {
                Path path = new Path();
                path.moveTo(myX, childView.getTop());
                path.lineTo(myX, childView.getBottom());
                c.drawPath(path, paint);
            } else if (!isLastGridColumn(i, columnSize)) {
                Path path = new Path();
                path.moveTo(myX, childView.getTop());
                path.lineTo(myX, childView.getBottom());
                c.drawPath(path, paint);
            }
        }
    }
}

17 Source : RecyclerViewItemDecoration.java
with Apache License 2.0
from arjinmc

/**
 * draw vertival decoration
 *
 * @param c
 * @param parent
 */
private void drawVertical(Canvas c, RecyclerView parent) {
    int childrentCount = parent.getChildCount();
    if (drawableRid != 0) {
        if (hasNinePatch) {
            for (int i = 0; i < childrentCount; i++) {
                if (i != childrentCount - 1) {
                    View childView = parent.getChildAt(i);
                    int myX = childView.getRight();
                    Rect rect = new Rect(myX, 0, myX + bmp.getWidth(), parent.getHeight());
                    ninePatch.draw(c, rect);
                }
            }
        } else {
            for (int i = 0; i < childrentCount; i++) {
                if (i != childrentCount - 1) {
                    View childView = parent.getChildAt(i);
                    int myX = childView.getRight();
                    c.drawBitmap(bmp, myX, 0, paint);
                }
            }
        }
    } else if (dashWidth == 0 && dashGap == 0) {
        for (int i = 0; i < childrentCount; i++) {
            if (i != childrentCount - 1) {
                View childView = parent.getChildAt(i);
                int myX = childView.getRight() + thick / 2;
                c.drawLine(myX, 0, myX, parent.getHeight(), paint);
            }
        }
    } else {
        PathEffect effects = new DashPathEffect(new float[] { 0, 0, dashWidth, thick }, dashGap);
        paint.setPathEffect(effects);
        for (int i = 0; i < childrentCount; i++) {
            if (i != childrentCount - 1) {
                View childView = parent.getChildAt(i);
                int myX = childView.getRight() + thick / 2;
                Path path = new Path();
                path.moveTo(myX, 0);
                path.lineTo(myX, parent.getHeight());
                c.drawPath(path, paint);
            }
        }
    }
}

17 Source : VirtualLine.java
with MIT License
from alibaba

@Override
public void onParseValueFinished() {
    super.onParseValueFinished();
    mPaint.setStrokeWidth(mLineWidth);
    mPaint.setColor(mLineColor);
    switch(mStyle) {
        case LineBaseCommon.STYLE_DASH:
            if (mPath == null) {
                mPath = new Path();
            }
            mPath.reset();
            mPaint.setStyle(Paint.Style.STROKE);
            PathEffect effects = new DashPathEffect(mDashEffect, 1);
            mPaint.setPathEffect(effects);
            break;
        case LineBaseCommon.STYLE_SOLID:
            mPaint.setStyle(Paint.Style.FILL);
            break;
        default:
            break;
    }
}

16 Source : aaLinesChart.java
with Apache License 2.0
from openXu

/**
 * 绘制X轴方向辅助网格
 */
private void drawGrid(Canvas canvas) {
    float yMarkSpace = (rectChart.bottom - rectChart.top) / (YMARK_NUM - 1);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(lineWidth);
    paint.setColor(defColor);
    paintEffect.setStyle(Paint.Style.STROKE);
    paintEffect.setStrokeWidth(lineWidth);
    paintEffect.setColor(defColor);
    canvas.drawLine(rectChart.left, rectChart.top, rectChart.left, rectChart.bottom, paint);
    canvas.drawLine(rectChart.right, rectChart.top, rectChart.right, rectChart.bottom, paint);
    for (int i = 0; i < YMARK_NUM; i++) {
        if (i == 0 || i == YMARK_NUM - 1) {
            // 实线
            canvas.drawLine(rectChart.left, rectChart.bottom - yMarkSpace * i, rectChart.right, rectChart.bottom - yMarkSpace * i, paint);
        } else {
            // 虚线
            Path path = new Path();
            path.moveTo(rectChart.left, rectChart.bottom - yMarkSpace * i);
            path.lineTo(rectChart.right, rectChart.bottom - yMarkSpace * i);
            PathEffect effects = new DashPathEffect(new float[] { 15, 8, 15, 8 }, 0);
            paintEffect.setPathEffect(effects);
            canvas.drawPath(path, paintEffect);
        }
    }
}

16 Source : NorthSouthChart.java
with Apache License 2.0
from openXu

/**
 * 绘制X轴方向辅助网格
 */
private void drawGrid(Canvas canvas) {
    float yMarkSpace = (rectChart.bottom - rectChart.top) / (YMARK_NUM - 1);
    paint.setStyle(Paint.Style.STROKE);
    paint.setStrokeWidth(lineWidth);
    paint.setColor(defColor);
    paintEffect.setStyle(Paint.Style.STROKE);
    paintEffect.setStrokeWidth(lineWidth);
    paintEffect.setColor(defColor);
    canvas.drawLine(rectChart.left, rectChart.top, rectChart.left, rectChart.bottom, paint);
    canvas.drawLine(rectChart.right, rectChart.top, rectChart.right, rectChart.bottom, paint);
    if (chartType == ChartType.TYPE_T_SOUTH || chartType == ChartType.TYPE_T_NORTH) {
        // 今日图表,需要绘制x刻度线
        for (DataPoint lable : lableXPointList) {
            canvas.drawLine(lable.getValueY(), rectChart.bottom, lable.getValueY(), rectChart.bottom - DensityUtil.dip2px(getContext(), 3), paint);
        }
    }
    for (int i = 0; i < YMARK_NUM; i++) {
        if (i == 0 || i == YMARK_NUM - 1) {
            // 实线
            canvas.drawLine(rectChart.left, rectChart.bottom - yMarkSpace * i, rectChart.right, rectChart.bottom - yMarkSpace * i, paint);
        } else {
            // 虚线
            Path path = new Path();
            path.moveTo(rectChart.left, rectChart.bottom - yMarkSpace * i);
            path.lineTo(rectChart.right, rectChart.bottom - yMarkSpace * i);
            PathEffect effects = new DashPathEffect(new float[] { 15, 8, 15, 8 }, 0);
            paintEffect.setPathEffect(effects);
            canvas.drawPath(path, paintEffect);
        }
    }
}

16 Source : WeekWeatherView.java
with MIT License
from byhieg

private void init(Context context) {
    baseLinePaint = new Paint();
    baseLinePaint.setColor(ContextCompat.getColor(context, R.color.maincolor));
    baseLinePaint.setAntiAlias(true);
    baseLinePaint.setStyle(Paint.Style.FILL);
    baseLinePaint.setStrokeWidth(10);
    verticalLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    verticalLinePaint.setStyle(Paint.Style.STROKE);
    verticalLinePaint.setColor(ContextCompat.getColor(context, R.color.lightgray));
    verticalLinePaint.setAntiAlias(true);
    verticalLinePaint.setStrokeWidth(5);
    verticalLinePaint.setStrokeCap(Paint.Cap.ROUND);
    PathEffect effect = new DashPathEffect(new float[] { 1, 2, 4, 8 }, 1);
    verticalLinePaint.setPathEffect(effect);
    verticalLinePaint.setStrokeJoin(Paint.Join.ROUND);
    highPointPaint = new Paint();
    highPointPaint.setColor(ContextCompat.getColor(context, R.color.red));
    highPointPaint.setAntiAlias(true);
    highPointPaint.setStyle(Paint.Style.STROKE);
    highPointPaint.setStrokeWidth(5);
    lowPointPaint = new Paint();
    lowPointPaint.setColor(ContextCompat.getColor(context, R.color.maincolor));
    lowPointPaint.setAntiAlias(true);
    lowPointPaint.setStyle(Paint.Style.STROKE);
    lowPointPaint.setStrokeWidth(5);
    highLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    highLinePaint.setColor(ContextCompat.getColor(context, R.color.red));
    highLinePaint.setAntiAlias(true);
    highLinePaint.setStrokeWidth(5);
    highLinePaint.setStrokeCap(Paint.Cap.ROUND);
    highLinePaint.setStrokeJoin(Paint.Join.ROUND);
    highLinePaint.setStyle(Paint.Style.STROKE);
    lowLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    lowLinePaint.setColor(ContextCompat.getColor(context, R.color.cadetblue));
    lowLinePaint.setAntiAlias(true);
    lowLinePaint.setStrokeWidth(5);
    lowLinePaint.setStrokeCap(Paint.Cap.ROUND);
    lowLinePaint.setStrokeJoin(Paint.Join.ROUND);
    lowLinePaint.setStyle(Paint.Style.STROKE);
    mPath = new Path();
    dPath = new Path();
    textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    textPaint.setColor(ContextCompat.getColor(context, R.color.black));
    String familyName = "宋体";
    Typeface font = Typeface.create(familyName, Typeface.BOLD);
    textPaint.setTypeface(font);
    textPaint.setTextAlign(Paint.Align.CENTER);
    lowTempPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    lowTempPaint.setColor(ContextCompat.getColor(context, R.color.cadetblue));
    lowTempPaint.setTypeface(font);
    lowTempPaint.setTextAlign(Paint.Align.CENTER);
    highTempPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    highTempPaint.setColor(ContextCompat.getColor(context, R.color.red));
    highTempPaint.setTypeface(font);
    highTempPaint.setTextAlign(Paint.Align.CENTER);
}

15 Source : SunriseSunsetView.java
with Apache License 2.0
from tianma8023

/**
 * A view which can show sunrise and sunset animation
 */
public clreplaced SunriseSunsetView extends View {

    private static final int DEFAULT_TRACK_COLOR = Color.WHITE;

    private static final int DEFAULT_TRACK_WIDTH_PX = 4;

    private static final int DEFAULT_SUN_COLOR = Color.YELLOW;

    private static final int DEFAULT_SUN_RADIUS_PX = 20;

    private static final int DEFAULT_SUN_STROKE_WIDTH_PX = 4;

    private static final int DEFAULT_SHADOW_COLOR = Color.parseColor("#32FFFFFF");

    private static final int DEFAULT_LABEL_TEXT_COLOR = Color.WHITE;

    private static final int DEFAULT_LABEL_TEXT_SIZE = 40;

    private static final int DEFAULT_LABEL_VERTICAL_OFFSET_PX = 5;

    private static final int DEFAULT_LABEL_HORIZONTAL_OFFSET_PX = 20;

    /**
     * 当前日出日落比率, mRatio < 0: 未日出, mRatio > 1 已日落
     */
    private float mRatio;

    // 绘制半圆轨迹的Paint
    private Paint mTrackPaint;

    // 轨迹的颜色
    private int mTrackColor = DEFAULT_TRACK_COLOR;

    // 轨迹的宽度
    private int mTrackWidth = DEFAULT_TRACK_WIDTH_PX;

    // 轨迹的PathEffect
    private PathEffect mTrackPathEffect = new DashPathEffect(new float[] { 15, 15 }, 1);

    // 轨迹圆的半径
    private float mTrackRadius;

    // 绘制日出日落阴影的Paint
    private Paint mShadowPaint;

    // 阴影颜色
    private int mShadowColor = DEFAULT_SHADOW_COLOR;

    // 绘制太阳的Paint
    private Paint mSunPaint;

    // 太阳颜色
    private int mSunColor = DEFAULT_SUN_COLOR;

    // 太阳半径
    private float mSunRadius = DEFAULT_SUN_RADIUS_PX;

    // 太阳Paint样式,默认FILL
    private Paint.Style mSunPaintStyle = Paint.Style.FILL;

    // 绘制日出日落时间的Paint
    private TextPaint mLabelPaint;

    // 标签文字大小
    private int mLabelTextSize = DEFAULT_LABEL_TEXT_SIZE;

    // 标签颜色
    private int mLabelTextColor = DEFAULT_LABEL_TEXT_COLOR;

    // 竖直方向间距
    private int mLabelVerticalOffset = DEFAULT_LABEL_VERTICAL_OFFSET_PX;

    // 水平方向间距
    private int mLabelHorizontalOffset = DEFAULT_LABEL_HORIZONTAL_OFFSET_PX;

    // 半圆轨迹最小半径
    private static final int MINIMAL_TRACK_RADIUS_PX = 300;

    /**
     * 日出时间
     */
    private Time mSunriseTime;

    /**
     * 日落时间
     */
    private Time mSunsetTime;

    /**
     * 绘图区域
     */
    private RectF mBoardRectF = new RectF();

    // Label Formatter - Default is a Simple label formatter.
    private SunriseSunsetLabelFormatter mLabelFormatter = new SimpleSunriseSunsetLabelFormatter();

    public SunriseSunsetView(Context context) {
        super(context);
        init();
    }

    public SunriseSunsetView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SunriseSunsetView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SunriseSunsetView, defStyleAttr, 0);
        if (a != null) {
            mTrackColor = a.getColor(R.styleable.SunriseSunsetView_ssv_track_color, DEFAULT_TRACK_COLOR);
            mTrackWidth = a.getDimensionPixelSize(R.styleable.SunriseSunsetView_ssv_track_width, DEFAULT_TRACK_WIDTH_PX);
            mShadowColor = a.getColor(R.styleable.SunriseSunsetView_ssv_shadow_color, DEFAULT_SHADOW_COLOR);
            mSunColor = a.getColor(R.styleable.SunriseSunsetView_ssv_sun_color, DEFAULT_SUN_COLOR);
            mSunRadius = a.getDimensionPixelSize(R.styleable.SunriseSunsetView_ssv_sun_radius, DEFAULT_SUN_RADIUS_PX);
            mLabelTextColor = a.getColor(R.styleable.SunriseSunsetView_ssv_label_text_color, DEFAULT_LABEL_TEXT_COLOR);
            mLabelTextSize = a.getDimensionPixelSize(R.styleable.SunriseSunsetView_ssv_label_text_size, DEFAULT_LABEL_TEXT_SIZE);
            mLabelVerticalOffset = a.getDimensionPixelOffset(R.styleable.SunriseSunsetView_ssv_label_vertical_offset, DEFAULT_LABEL_VERTICAL_OFFSET_PX);
            mLabelHorizontalOffset = a.getDimensionPixelOffset(R.styleable.SunriseSunsetView_ssv_label_horizontal_offset, DEFAULT_LABEL_HORIZONTAL_OFFSET_PX);
            a.recycle();
        }
        init();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int paddingRight = getPaddingRight();
        int paddingLeft = getPaddingLeft();
        int paddingTop = getPaddingTop();
        int paddingBottom = getPaddingBottom();
        int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
        int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
        // 处理wrap_content这种情况
        if (widthSpecMode == MeasureSpec.AT_MOST) {
            widthSpecSize = paddingLeft + paddingRight + MINIMAL_TRACK_RADIUS_PX * 2 + (int) mSunRadius * 2;
        }
        mTrackRadius = 1.0f * (widthSpecSize - paddingLeft - paddingRight - 2 * mSunRadius) / 2;
        int expectedHeight = (int) (mTrackRadius + mSunRadius + paddingBottom + paddingTop);
        mBoardRectF.set(paddingLeft + mSunRadius, paddingTop + mSunRadius, widthSpecSize - paddingRight - mSunRadius, expectedHeight - paddingBottom);
        setMeasuredDimension(widthSpecSize, expectedHeight);
    }

    private void init() {
        // 初始化半圆轨迹的画笔
        mTrackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        // 画笔的样式为线条
        mTrackPaint.setStyle(Paint.Style.STROKE);
        prepareTrackPaint();
        // 初始化日出日落阴影的画笔
        mShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mShadowPaint.setStyle(Paint.Style.FILL_AND_STROKE);
        prepareShadowPaint();
        // 初始化太阳的Paint
        mSunPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mSunPaint.setStrokeWidth(DEFAULT_SUN_STROKE_WIDTH_PX);
        prepareSunPaint();
        mLabelPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);
        prepareLabelPaint();
    }

    // 半圆轨迹的画笔
    private void prepareTrackPaint() {
        mTrackPaint.setColor(mTrackColor);
        mTrackPaint.setStrokeWidth(mTrackWidth);
        mTrackPaint.setPathEffect(mTrackPathEffect);
    }

    // 阴影的画笔
    private void prepareShadowPaint() {
        mShadowPaint.setColor(mShadowColor);
    }

    // 太阳的画笔
    private void prepareSunPaint() {
        mSunPaint.setColor(mSunColor);
        mSunPaint.setStrokeWidth(DEFAULT_SUN_STROKE_WIDTH_PX);
        mSunPaint.setStyle(mSunPaintStyle);
    }

    // 标签的画笔
    private void prepareLabelPaint() {
        mLabelPaint.setColor(mLabelTextColor);
        mLabelPaint.setTextSize(mLabelTextSize);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawSunTrack(canvas);
        drawShadow(canvas);
        drawSun(canvas);
        drawSunriseSunsetLabel(canvas);
    }

    // 绘制太阳轨道(半圆)
    private void drawSunTrack(Canvas canvas) {
        prepareTrackPaint();
        canvas.save();
        RectF rectF = new RectF(mBoardRectF.left, mBoardRectF.top, mBoardRectF.right, mBoardRectF.bottom + mBoardRectF.height());
        canvas.drawArc(rectF, 180, 180, false, mTrackPaint);
        canvas.restore();
    }

    // 绘制日出日落阴影部分
    private void drawShadow(Canvas canvas) {
        prepareShadowPaint();
        canvas.save();
        Path path = new Path();
        float endY = mBoardRectF.bottom;
        RectF rectF = new RectF(mBoardRectF.left, mBoardRectF.top, mBoardRectF.right, mBoardRectF.bottom + mBoardRectF.height());
        float curPointX = mBoardRectF.left + mTrackRadius - mTrackRadius * (float) Math.cos(Math.PI * mRatio);
        path.moveTo(0, endY);
        path.arcTo(rectF, 180, 180 * mRatio);
        path.lineTo(curPointX, endY);
        path.close();
        canvas.drawPath(path, mShadowPaint);
        canvas.restore();
    }

    // 绘制太阳
    private void drawSun(Canvas canvas) {
        prepareSunPaint();
        canvas.save();
        float curPointX = mBoardRectF.left + mTrackRadius - mTrackRadius * (float) Math.cos(Math.PI * mRatio);
        float curPointY = mBoardRectF.bottom - mTrackRadius * (float) Math.sin(Math.PI * mRatio);
        canvas.drawCircle(curPointX, curPointY, mSunRadius, mSunPaint);
        canvas.restore();
    }

    // 绘制日出日落标签
    private void drawSunriseSunsetLabel(Canvas canvas) {
        if (mSunriseTime == null || mSunsetTime == null) {
            return;
        }
        prepareLabelPaint();
        canvas.save();
        // 绘制日出时间
        String sunriseStr = mLabelFormatter.formatSunriseLabel(mSunriseTime);
        mLabelPaint.setTextAlign(Paint.Align.LEFT);
        Paint.FontMetricsInt metricsInt = mLabelPaint.getFontMetricsInt();
        float baseLineX = mBoardRectF.left + mSunRadius + mLabelHorizontalOffset;
        float baseLineY = mBoardRectF.bottom - metricsInt.bottom - mLabelVerticalOffset;
        canvas.drawText(sunriseStr, baseLineX, baseLineY, mLabelPaint);
        // 绘制日落时间
        mLabelPaint.setTextAlign(Paint.Align.RIGHT);
        String sunsetStr = mLabelFormatter.formatSunsetLabel(mSunsetTime);
        baseLineX = mBoardRectF.right - mSunRadius - mLabelHorizontalOffset;
        canvas.drawText(sunsetStr, baseLineX, baseLineY, mLabelPaint);
        canvas.restore();
    }

    public void setRatio(float ratio) {
        mRatio = ratio;
        invalidate();
    }

    public void setSunriseTime(Time sunriseTime) {
        mSunriseTime = sunriseTime;
    }

    public Time getSunriseTime() {
        return mSunriseTime;
    }

    public void setSunsetTime(Time sunsetTime) {
        mSunsetTime = sunsetTime;
    }

    public Time getSunsetTime() {
        return mSunsetTime;
    }

    public float getSunRadius() {
        return mSunRadius;
    }

    public SunriseSunsetLabelFormatter getLabelFormatter() {
        return mLabelFormatter;
    }

    public void setLabelFormatter(SunriseSunsetLabelFormatter labelFormatter) {
        mLabelFormatter = labelFormatter;
    }

    public void setTrackColor(int trackColor) {
        mTrackColor = trackColor;
    }

    public void setTrackWidth(int trackWidthInPx) {
        mTrackWidth = trackWidthInPx;
    }

    public void setTrackPathEffect(PathEffect trackPathEffect) {
        mTrackPathEffect = trackPathEffect;
    }

    public void setSunColor(int sunColor) {
        mSunColor = sunColor;
    }

    public void setSunRadius(float sunRadius) {
        mSunRadius = sunRadius;
    }

    public void setSunPaintStyle(Paint.Style sunPaintStyle) {
        mSunPaintStyle = sunPaintStyle;
    }

    public void setShadowColor(int shadowColor) {
        mShadowColor = shadowColor;
    }

    public void setLabelTextSize(int labelTextSize) {
        mLabelTextSize = labelTextSize;
    }

    public void setLabelTextColor(int labelTextColor) {
        mLabelTextColor = labelTextColor;
    }

    public void setLabelVerticalOffset(int labelVerticalOffset) {
        mLabelVerticalOffset = labelVerticalOffset;
    }

    public void setLabelHorizontalOffset(int labelHorizontalOffset) {
        mLabelHorizontalOffset = labelHorizontalOffset;
    }

    public void startAnimate() {
        if (mSunriseTime == null || mSunsetTime == null) {
            throw new RuntimeException("You need to set both sunrise and sunset time before start animation");
        }
        int sunrise = mSunriseTime.transformToMinutes();
        int sunset = mSunsetTime.transformToMinutes();
        Calendar calendar = Calendar.getInstance(Locale.getDefault());
        int currentHour = calendar.get(Calendar.HOUR_OF_DAY);
        int currentMinute = calendar.get(Calendar.MINUTE);
        int currentTime = currentHour * Time.MINUTES_PER_HOUR + currentMinute;
        float ratio = 1.0f * (currentTime - sunrise) / (sunset - sunrise);
        ratio = ratio <= 0 ? 0 : (ratio > 1.0f ? 1 : ratio);
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "ratio", 0f, ratio);
        animator.setDuration(1500L);
        animator.setInterpolator(new LinearInterpolator());
        animator.start();
    }
}

15 Source : HistoryChartView.java
with Apache License 2.0
from Horrarndoo

/**
 * 历史记录查询图表 基于pathMeasure+DashPathEffect+属性动画实现
 * 绘制时采取双缓冲绘制
 *
 * @author zyw
 * @creation 2017-03-06
 */
public clreplaced HistoryChartView extends View {

    private String TAG = "HistoryChartView";

    TypedArray ta;

    private float MarginTop = 100;

    private float MarginBottom = 100;

    private float MarginLeft = 100;

    private float MarginRight = 100;

    private float mYLabelSize = 50;

    private float mXlabelSize = 35;

    private float mXUnitTextSize;

    private float mYUnitTextSize;

    // 圆半径
    private int circleRadius = 8;

    private int lineStrokeWidth = 3;

    private int dataStrokeWidth = 3;

    private static final long ANIM_DURATION = 1500;

    private PathMeasure mRoomTempPathMeasure;

    private PathMeasure mTargetTempPathMeasure;

    private Path mRoomTempPath;

    private Path mTargetTempPath;

    private Paint mBmpPaint;

    /**
     * 柱形绘制进度
     */
    private float mRectFration;

    // X,Y轴的单位长度
    private float Xscale = 20;

    private float Yscale = 20;

    // 绘制X轴总长度
    private float xLength;

    // 绘制Y轴总长度
    private float yLength;

    // X轴第1个节点的偏移位置
    private float xFirstPointOffset;

    // y轴显示的节点间隔距离
    private int yScaleForData = 1;

    // x轴显示的节点间隔距离
    private int xScaleForData = 1;

    // 画线颜色
    private int lineColor;

    private int roomTempLineColor;

    private int targetTempLineColor;

    private int powerTimeLineColor;

    private int mUnitColor;

    private String mXUnitText;

    private String mY1UnitText;

    private String mY2UnitText;

    // 从Activity传过来的模式值 1:天 2:周 3:月 4:年
    private int mMode = 1;

    // 原点坐标
    private float Xpoint;

    private float Ypoint;

    // X,Y轴上面的显示文字
    private String[] Xlabel = { "1", "2", "3", "4", "5", "6", "7" };

    private String[] Ylabel = { "0", "9", "18", "27", "36" };

    private String[] Ylabel2 = { "0", "25", "50", "75", "100" };

    private final static int X_SCALE_FOR_DATA_DAY = 2;

    private final static int X_SCALE_FOR_DATA_WEEK = 1;

    private final static int X_SCALE_FOR_DATA_YEAR = 1;

    private final static int X_SCALE_FOR_DATA_MOUNTH = 5;

    private final static int DAY_MODE = 0;

    private final static int WEEK_MODE = 1;

    private final static int MONTH_MODE = 2;

    private final static int YEAR_MODE = 3;

    // 曲线数据
    private float[] roomTempDataArray = { 15, 15, 15, 15, 15, 15, 15 };

    private float[] targetTempDataArray = { 16, 16, 16, 16, 16, 16, 16 };

    private float[] powerOnTimeDataArray = { 100, 100, 100, 100, 100, 100, 100 };

    /**
     * 各条柱形图当前top值数组
     */
    private Float[] rectCurrentTops;

    private ValueAnimator mValueAnimator;

    private Paint linePaint;

    private Paint targetTempPaint;

    private Paint roomTempPaint;

    private PathEffect mRoomTempEffect;

    private PathEffect mtargetTempEffect;

    // 定义一个内存中的图片,该图片将作为缓冲区
    Bitmap mCacheBitmap = null;

    // 定义cacheBitmap上的Canvas对象
    Canvas mCacheCanvas = null;

    public HistoryChartView(Context context, String[] xlabel, String[] ylabel, float[] roomDataArray) {
        super(context);
        this.Xlabel = xlabel;
        this.Ylabel = ylabel;
        this.roomTempDataArray = roomDataArray;
    }

    public HistoryChartView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        // Logger.e("HistoryChartView(Context context, AttributeSet attrs, int defStyleAttr)");
        ta = context.obtainStyledAttributes(attrs, R.styleable.HistoryChartView);
        setDefaultAttrrbutesValue();
        initPaint();
        initData();
        initParams();
        initPath();
        ta.recycle();
    }

    public HistoryChartView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public HistoryChartView(Context context) {
        this(context, null);
    }

    /**
     * 设置显示数据
     *
     * @param strAlldata 历史数据全状态
     * @param mode       历史数据模式
     */
    public void setData(String strAlldata, int mode) {
        // Logger.e("history chart view strAlldata = " + strAlldata);
        String[] allHistroyArray = strAlldata.split("-");
        String[] arrayRoomTempData = allHistroyArray[0].split(",");
        String[] arraySetTempData = allHistroyArray[1].split(",");
        String[] arrayPowerTimeData = allHistroyArray[2].split(",");
        mMode = mode;
        initXData(arrayRoomTempData);
        initRoomTempData(arrayRoomTempData);
        initTargetTempData(arraySetTempData);
        initPowerOnTimeData(arrayPowerTimeData);
        initData();
        initParams();
        initPath();
        startAnimation();
    }

    private void initPaint() {
        linePaint = new Paint();
        linePaint.setStyle(Paint.Style.STROKE);
        linePaint.setAntiAlias(true);
        linePaint.setColor(lineColor);
        linePaint.setDither(true);
        linePaint.setStrokeWidth(lineStrokeWidth);
        roomTempPaint = new Paint();
        roomTempPaint.setStyle(Paint.Style.STROKE);
        roomTempPaint.setAntiAlias(true);
        roomTempPaint.setColor(roomTempLineColor);
        roomTempPaint.setDither(true);
        roomTempPaint.setStrokeWidth(dataStrokeWidth);
        targetTempPaint = new Paint();
        targetTempPaint.setStyle(Paint.Style.STROKE);
        targetTempPaint.setAntiAlias(true);
        targetTempPaint.setColor(targetTempLineColor);
        targetTempPaint.setDither(true);
        targetTempPaint.setStrokeWidth(dataStrokeWidth);
        mBmpPaint = new Paint();
    }

    /**
     * 初始化数据
     */
    private void initData() {
        mRoomTempPath = new Path();
        mTargetTempPath = new Path();
        rectCurrentTops = new Float[roomTempDataArray.length];
    }

    /**
     * 初始化宽高比例等数据
     */
    public void initParams() {
        // LogUtils.error(TAG, "initParams");
        Xpoint = MarginLeft;
        xLength = this.getWidth() - MarginLeft - MarginRight - (MarginRight + MarginLeft) / 16;
        yLength = this.getHeight() - MarginTop - MarginBottom;
        Ypoint = this.getHeight() - MarginBottom + mYLabelSize / 3;
        Xscale = (xLength - xFirstPointOffset * 2) / (this.Xlabel.length - 1);
        Yscale = yLength / (this.Ylabel.length - 1);
    }

    /**
     * 初始化path
     */
    private void initPath() {
        initRoomTempPath(roomTempDataArray);
        initTargetTempPath(targetTempDataArray);
    }

    /**
     * 初始化设定温度数据
     *
     * @param arraySetTempData 设定温度数据
     */
    private void initTargetTempData(String[] arraySetTempData) {
        targetTempDataArray = new float[arraySetTempData.length];
        for (int i = 0; i < arraySetTempData.length; i++) {
            if (arraySetTempData[i].length() > 0) {
                targetTempDataArray[i] = Float.parseFloat(arraySetTempData[i]);
            }
        }
    }

    /**
     * 初始化房间温度数据
     *
     * @param arrayRoomTempData 房间温度数据
     */
    private void initRoomTempData(String[] arrayRoomTempData) {
        roomTempDataArray = new float[arrayRoomTempData.length];
        for (int i = 0; i < arrayRoomTempData.length; i++) {
            if (arrayRoomTempData[i].length() > 0) {
                roomTempDataArray[i] = Float.parseFloat(arrayRoomTempData[i]);
            // LogUtils.error(TAG, "" + roomTempDataArray[i]);
            }
        }
    }

    /**
     * 初始化开机时间数据
     *
     * @param arrayPowerTimeData 开机时间数据
     */
    private void initPowerOnTimeData(String[] arrayPowerTimeData) {
        powerOnTimeDataArray = new float[arrayPowerTimeData.length];
        for (int i = 0; i < arrayPowerTimeData.length; i++) {
            if (arrayPowerTimeData[i].length() > 0) {
                powerOnTimeDataArray[i] = Float.parseFloat(arrayPowerTimeData[i]);
            }
        }
    }

    /**
     * 初始化X轴数据
     */
    private void initXData(String[] tempData) {
        switch(mMode) {
            case DAY_MODE:
                xScaleForData = X_SCALE_FOR_DATA_DAY;
                setXUnitText(getResources().getString(R.string.history_x_unit_hour));
                break;
            case WEEK_MODE:
                xScaleForData = X_SCALE_FOR_DATA_WEEK;
                setXUnitText(getResources().getString(R.string.history_x_unit_day));
                break;
            case MONTH_MODE:
                xScaleForData = X_SCALE_FOR_DATA_MOUNTH;
                setXUnitText(getResources().getString(R.string.history_x_unit_day));
                break;
            case YEAR_MODE:
                xScaleForData = X_SCALE_FOR_DATA_YEAR;
                setXUnitText(getResources().getString(R.string.history_x_unit_month));
                break;
            default:
                break;
        }
        Xlabel = new String[tempData.length];
        for (int i = 0; i < Xlabel.length; i++) {
            Xlabel[i] = Integer.toString(i + 1);
        }
    }

    private void setDefaultAttrrbutesValue() {
        float MarginTopPx = ta.getDimension(R.styleable.HistoryChartView_margin_top, 50);
        float MarginBottomPx = ta.getDimension(R.styleable.HistoryChartView_margin_bottom, 50);
        float MarginLeftPx = ta.getDimension(R.styleable.HistoryChartView_margin_left, 50);
        float MarginRightPx = ta.getDimension(R.styleable.HistoryChartView_margin_right, 50);
        float yLabelSizePx = ta.getDimension(R.styleable.HistoryChartView_ylabel_text_size, 30);
        float xlabelSizePx = ta.getDimension(R.styleable.HistoryChartView_xlabel_text_size, 20);
        float xUnitSizePx = ta.getDimension(R.styleable.HistoryChartView_x_unit_text_size, 30);
        float yUnitSizePx = ta.getDimension(R.styleable.HistoryChartView_y_unit_text_size, 30);
        float xFirstPointOffsetPx = ta.getDimension(R.styleable.HistoryChartView_x_first_point_offset, 30);
        float lineStrokeWidthPx = ta.getDimension(R.styleable.HistoryChartView_line_stroke_width, 5);
        float dataStrokeWidthPx = ta.getDimension(R.styleable.HistoryChartView_data_stroke_width, 5);
        float circleRadiusPx = ta.getDimension(R.styleable.HistoryChartView_circle_radius, 6);
        xFirstPointOffset = DisplayUtils.px2sp(xFirstPointOffsetPx);
        MarginTop = DisplayUtils.px2dp(MarginTopPx);
        MarginBottom = DisplayUtils.px2dp(MarginBottomPx);
        MarginLeft = DisplayUtils.px2dp(MarginLeftPx);
        MarginRight = DisplayUtils.px2dp(MarginRightPx);
        mYLabelSize = DisplayUtils.px2sp(yLabelSizePx);
        mXlabelSize = DisplayUtils.px2sp(xlabelSizePx);
        mXUnitTextSize = DisplayUtils.px2sp(xUnitSizePx);
        mYUnitTextSize = DisplayUtils.px2sp(yUnitSizePx);
        lineStrokeWidth = DisplayUtils.px2sp(lineStrokeWidthPx);
        dataStrokeWidth = DisplayUtils.px2sp(dataStrokeWidthPx);
        circleRadius = DisplayUtils.px2sp(circleRadiusPx);
        lineColor = ta.getColor(R.styleable.HistoryChartView_line_color, getResources().getColor(R.color.light_yellow));
        roomTempLineColor = ta.getColor(R.styleable.HistoryChartView_first_data_line_color, getResources().getColor(R.color.indoor_temp));
        targetTempLineColor = ta.getColor(R.styleable.HistoryChartView_second_data_line_color, getResources().getColor(R.color.setpoint_temp));
        powerTimeLineColor = ta.getColor(R.styleable.HistoryChartView_rect_background_color, getResources().getColor(R.color.power_time));
        mUnitColor = ta.getColor(R.styleable.HistoryChartView_unit_color, getResources().getColor(R.color.light_grey));
        mXUnitText = ta.getString(R.styleable.HistoryChartView_x_unit_text);
        mY1UnitText = ta.getString(R.styleable.HistoryChartView_y1_unit_text);
        mY2UnitText = ta.getString(R.styleable.HistoryChartView_y2_unit_text);
    }

    /**
     * 设置X轴单位符号
     *
     * @param xUnit x轴单位符号
     */
    public void setXUnitText(String xUnit) {
        mXUnitText = xUnit;
    }

    /**
     * 绘制单位符号
     *
     * @param canvas canvas
     */
    private void drawUnit(Canvas canvas) {
        Paint p = new Paint();
        p.setAntiAlias(true);
        p.setStrokeWidth(dataStrokeWidth);
        p.setColor(mUnitColor);
        drawXUnit(canvas, p);
        drawY1Unit(canvas, p);
        drawY2Unit(canvas, p);
    }

    // 画横轴
    private void drawXLine(Canvas canvas, Paint p) {
        p.setColor(getResources().getColor(R.color.light_yellow));
        canvas.drawLine(Xpoint, Ypoint, xLength + MarginLeft, Ypoint, p);
    }

    // 画灰色横轴
    private void drawGreyXLine(Canvas canvas, Paint p) {
        p.setColor(getResources().getColor(R.color.grey_line));
        float startX = Xpoint + MarginLeft / 4;
        // 纵向
        for (int i = yScaleForData; (yLength - i * Yscale) >= 0; i += yScaleForData) {
            float startY = Ypoint - i * Yscale;
            canvas.drawLine(startX - MarginLeft / 4, startY, xLength + MarginLeft, startY, p);
        }
    }

    // 画数据
    private void drawData(Canvas canvas, float[] data, int dataColor) {
        Paint p = new Paint();
        p.setAntiAlias(true);
        p.setStrokeWidth(dataStrokeWidth);
        p.setTextSize(mXlabelSize);
        // 横向
        for (int i = 0; i < Xlabel.length; i++) {
            int xLableInt = Integer.parseInt(Xlabel[i]);
            float startX = Xpoint + i * Xscale + xFirstPointOffset;
            if (xLableInt % xScaleForData == 0) {
                p.setColor(lineColor);
                canvas.drawText(this.Xlabel[i], startX - mXlabelSize / 3, Ypoint + mXlabelSize * 3 / 2, p);
            }
            p.setColor(dataColor);
            canvas.drawCircle(startX, getDataY(data[i], Ylabel), circleRadius, p);
        }
        p.setTextSize(mYLabelSize);
        // 纵向
        for (int i = 0; (yLength - i * Yscale) >= 0; i += yScaleForData) {
            p.setColor(lineColor);
            canvas.drawText(this.Ylabel[i], MarginLeft / 4, getDataY(Float.valueOf(Ylabel[i]), Ylabel) + mYLabelSize / 3, p);
            canvas.drawText(this.Ylabel2[i], this.getWidth() - MarginLeft, getDataY(Float.valueOf(Ylabel2[i]), Ylabel2) + mYLabelSize / 3, p);
        }
    }

    // 获取room temp绘线Path数据
    private void initRoomTempPath(float[] data) {
        mRoomTempPath.reset();
        // Path path = new Path();
        float pointX;
        float pointY;
        // 横向
        mRoomTempPath.moveTo(Xpoint + xFirstPointOffset, getDataY(data[0], Ylabel));
        mRoomTempPath.moveTo(Xpoint + xFirstPointOffset, getDataY(data[0], Ylabel));
        for (int i = 0; i < Xlabel.length; i++) {
            float startX = Xpoint + i * Xscale + xFirstPointOffset;
            // 绘制数据连线
            if (i != 0) {
                pointX = Xpoint + (i - 1) * Xscale + xFirstPointOffset;
                pointY = getDataY(data[i - 1], Ylabel);
                mRoomTempPath.lineTo(pointX, pointY);
            }
            if (i == Xlabel.length - 1) {
                pointX = startX;
                pointY = getDataY(data[i], Ylabel);
                mRoomTempPath.lineTo(pointX, pointY);
            }
        }
        mRoomTempPathMeasure = new PathMeasure(mRoomTempPath, false);
    }

    /**
     * 获取target temp绘线Path数据
     *
     * @param data target temp绘线Path数据
     */
    private void initTargetTempPath(float[] data) {
        mTargetTempPath.reset();
        float pointX;
        float pointY;
        // 横向
        mTargetTempPath.moveTo(Xpoint + xFirstPointOffset, getDataY(data[0], Ylabel));
        for (int i = 0; i < Xlabel.length; i++) {
            float startX = Xpoint + i * Xscale + xFirstPointOffset;
            // 绘制数据连线
            if (i != 0) {
                pointX = Xpoint + (i - 1) * Xscale + xFirstPointOffset;
                pointY = getDataY(data[i - 1], Ylabel);
                mTargetTempPath.lineTo(pointX, pointY);
            }
            if (i == Xlabel.length - 1) {
                pointX = startX;
                pointY = getDataY(data[i], Ylabel);
                mTargetTempPath.lineTo(pointX, pointY);
            }
        }
        mTargetTempPathMeasure = new PathMeasure(mTargetTempPath, false);
    }

    // 绘制矩形图
    private void drawRect(Canvas canvas, float[] data, int dataColor) {
        Paint p = new Paint();
        float left;
        float top;
        float right;
        float bottom;
        float stopY = getDataY(Float.parseFloat(Ylabel[Ylabel.length - 1]), // 灰色线Y轴位置
        Ylabel);
        float rectYScale = (Ypoint - stopY) / 100;
        p.setAntiAlias(true);
        p.setStrokeWidth(dataStrokeWidth);
        p.setColor(dataColor);
        // 横向
        for (int i = 0; i < Xlabel.length; i++) {
            // 绘制柱形图
            if (i != 0) {
                left = Xpoint + (i - 1) * Xscale + xFirstPointOffset + Xscale / 6;
                // 要绘制的rect最终top值
                top = Ypoint - data[i - 1] * rectYScale + lineStrokeWidth;
                // 起点top + (起点top - 终点top) * mRectFration
                // 根据fraction动态更新top值
                rectCurrentTops[i] = Ypoint - (Ypoint - top) * mRectFration;
                right = left + Xscale * 4 / 6;
                bottom = Ypoint;
                // 
                canvas.drawRect(left, rectCurrentTops[i], right, bottom, p);
            // 每次valueAnimator更新时重绘最新top值
            }
        }
    }

    private void drawY1Unit(Canvas canvas, Paint p) {
        int maxYLabelValue = Integer.valueOf(Ylabel[Ylabel.length - 1]);
        p.setTextSize(mYUnitTextSize);
        float textWidth = p.measureText(mY1UnitText);
        canvas.drawText(mY1UnitText, MarginLeft / 2 - textWidth / 2, getDataY(maxYLabelValue, Ylabel) - mYLabelSize - mYLabelSize / 5, p);
    }

    private void drawY2Unit(Canvas canvas, Paint p) {
        int maxYLabel2Value = Integer.valueOf(Ylabel2[Ylabel2.length - 1]);
        p.setTextSize(mYUnitTextSize);
        float textWidth = p.measureText(mY2UnitText);
        canvas.drawText(mY2UnitText, this.getWidth() - MarginRight / 2 - textWidth * 3 / 4, getDataY(maxYLabel2Value, Ylabel2) - mYLabelSize - mYLabelSize / 5, p);
    }

    private void drawXUnit(Canvas canvas, Paint p) {
        p.setTextSize(mXUnitTextSize);
        float textWidth = p.measureText(mXUnitText);
        canvas.drawText(mXUnitText, this.getWidth() / 2 - textWidth / 2, Ypoint + mXlabelSize * 3 + mXlabelSize / 5, p);
    }

    /**
     * 获取data对应绘制Y点值
     */
    private float getDataY(float dataY, String[] Ylabel) {
        float y0 = 0;
        float y1 = 0;
        try {
            y0 = Float.parseFloat(Ylabel[0]);
            y1 = Float.parseFloat(Ylabel[1]);
        } catch (Exception e) {
            return 0;
        }
        try {
            return Ypoint - ((dataY - y0) * Yscale / (y1 - y0));
        } catch (Exception e) {
            return 0;
        }
    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        // LogUtils.error(TAG, "onLayout");
        initParams();
        if (onViewLayoutListener != null) {
            onViewLayoutListener.onLayoutSuccess();
        }
        // 创建一个与该View相同大小的缓冲区
        mCacheBitmap = Bitmap.createBitmap(this.getWidth(), this.getHeight(), Bitmap.Config.ARGB_8888);
        mCacheCanvas = new Canvas();
        // 设置cacheCanvas将会绘制到内存中cacheBitmap上
        mCacheCanvas.setBitmap(mCacheBitmap);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mCacheCanvas.drawColor(Color.BLACK);
        drawGreyXLine(mCacheCanvas, linePaint);
        drawUnit(mCacheCanvas);
        if (powerOnTimeDataArray.length > 1) {
            drawRect(mCacheCanvas, powerOnTimeDataArray, powerTimeLineColor);
        }
        mCacheCanvas.drawPath(mRoomTempPath, roomTempPaint);
        if (roomTempDataArray.length > 1) {
            drawData(mCacheCanvas, roomTempDataArray, roomTempLineColor);
        }
        mCacheCanvas.drawPath(mTargetTempPath, targetTempPaint);
        if (targetTempDataArray.length > 1) {
            drawData(mCacheCanvas, targetTempDataArray, targetTempLineColor);
        }
        drawXLine(mCacheCanvas, linePaint);
        // 将cacheBitmap绘制到该View组件
        canvas.drawBitmap(mCacheBitmap, 0, 0, mBmpPaint);
    }

    /**
     * 开启动画
     */
    private void startAnimation() {
        if (mValueAnimator != null) {
            mValueAnimator.cancel();
        }
        final float targetTempLength = mTargetTempPathMeasure.getLength();
        final float roomTempLength = mRoomTempPathMeasure.getLength();
        mValueAnimator = ValueAnimator.ofFloat(1, 0);
        mValueAnimator.setDuration(ANIM_DURATION);
        // 减速插值器
        mValueAnimator.setInterpolator(new DecelerateInterpolator());
        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float fraction = (Float) animation.getAnimatedValue();
                // 更新mtargetTempEffect
                mtargetTempEffect = new DashPathEffect(new float[] { targetTempLength, targetTempLength }, fraction * targetTempLength);
                targetTempPaint.setPathEffect(mtargetTempEffect);
                // 更新mRoomTempEffect
                mRoomTempEffect = new DashPathEffect(new float[] { roomTempLength, roomTempLength }, fraction * roomTempLength);
                roomTempPaint.setPathEffect(mRoomTempEffect);
                // 更新rect绘制fraction进度
                // fraction是1->0 我们需要的柱形图绘制比例是0->1
                mRectFration = 1 - fraction;
                postInvalidate();
            }
        });
        mValueAnimator.start();
    }

    public interface OnViewLayoutListener {

        void onLayoutSuccess();
    }

    public void setOnViewLayoutListener(OnViewLayoutListener onViewLayoutListener) {
        this.onViewLayoutListener = onViewLayoutListener;
    }

    private OnViewLayoutListener onViewLayoutListener;
}

15 Source : BindNormalActivity.java
with MIT License
from CarGuo

public void init() {
    normalAdapterManager = new BindSuperAdapterManager();
    normalAdapterManager.bind(BindImageModel.clreplaced, BindImageHolder.ID, BindImageHolder.clreplaced).bind(BindTextModel.clreplaced, BindTextHolder.ID, BindTextHolder.clreplaced).bind(BindMutliModel.clreplaced, BindMutliHolder.ID, BindMutliHolder.clreplaced).bind(BindClickModel.clreplaced, BindClickHolder.ID, BindClickHolder.clreplaced).bindEmpty(BindNoDataHolder.NoDataModel.clreplaced, BindNoDataHolder.ID, BindNoDataHolder.clreplaced).setNeedAnimation(true).setOnItemClickListener(new OnItemClickListener() {

        @Override
        public void onItemClick(Context context, int position) {
            Toast.makeText(context, "点击了!! " + position, Toast.LENGTH_SHORT).show();
        }
    });
    adapter = new BindRecyclerAdapter(this, normalAdapterManager, datas);
    recycler.setLayoutManager(new LinearLayoutManager(this));
    // 间隔线
    Paint paint = new Paint();
    paint.setStyle(Paint.Style.STROKE);
    paint.setColor(getResources().getColor(R.color.material_deep_teal_200));
    PathEffect effects = new DashPathEffect(new float[] { 5, 5, 5, 5 }, 1);
    paint.setPathEffect(effects);
    paint.setStrokeWidth(dip2px(this, 5));
    recycler.addItemDecoration(new BindDecorationBuilder(adapter).setPaint(paint).setSpace(dip2px(this, 5)).builder());
    recycler.setAdapter(adapter);
}

15 Source : CustomClickTopicSpan.java
with MIT License
from CarGuo

@Override
public void updateDrawState(TextPaint ds) {
    super.updateDrawState(ds);
    ds.setUnderlineText(true);
    ds.setStyle(Paint.Style.FILL_AND_STROKE);
    PathEffect effects = new DashPathEffect(new float[] { 1, 1 }, 1);
    ds.setPathEffect(effects);
    ds.setStrokeWidth(2);
}

15 Source : CustomClickAtUserSpan.java
with MIT License
from CarGuo

@Override
public void updateDrawState(TextPaint ds) {
    super.updateDrawState(ds);
    ds.setUnderlineText(true);
    // 间隔线
    ds.setStyle(Paint.Style.STROKE);
    PathEffect effects = new DashPathEffect(new float[] { 1, 1 }, 1);
    ds.setPathEffect(effects);
    ds.setStrokeWidth(5);
}

15 Source : WindView.java
with Apache License 2.0
from AhmadNemati

/**
 * Created by َAhmad Nemati on 12/19/2016.
 */
public clreplaced WindView extends View {

    private static final String TAG = WindView.clreplaced.getSimpleName();

    private Rect rect = new Rect();

    private Path path;

    private Matrix matrix;

    private Paint paint;

    private int textColor;

    private String WindDirectionText;

    private long startTime = 0;

    private PathEffect pathEffect;

    private Bitmap smallPoleBitmap;

    private Bitmap bigPoleBitmap;

    private Bitmap smallBladeBitmap;

    private Bitmap bigBladeBitmap;

    private Bitmap trendBitmap;

    private float rotation;

    private int bigPoleX;

    private int smallPoleX;

    private String windText = "Wind";

    private String windName;

    private String windSpeedText;

    private String barometerText = "Barometer";

    private int poleBottomY;

    private int windTextX;

    private int windTextY;

    private float windSpeed;

    private String windSpeedUnit;

    private boolean animationEnable = true;

    private boolean animationBaroMeterEnable = false;

    private float pressurePaddingTop;

    private double senterOfPressureLine;

    private double pressureLineSize;

    private int scale;

    private float barometerTickSpacing;

    private double lineSpace;

    private float pressure;

    private String pressureText;

    private float lineSize;

    private float curSize;

    private int pressureTextY;

    private String pressureUnit;

    private int labelFontSize;

    private int numericFontSize;

    private Typeface typeface;

    private String empty = "--";

    private TrendType trendType = TrendType.UP;

    private int lineColor = Color.WHITE;

    private float lineStrokeWidth = 1f;

    private int barometerColor = Color.WHITE;

    private float barometerStrokeWidth = 2f;

    public WindView(Context context) {
        super(context);
        setupView();
    }

    public WindView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public WindView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public WindView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs);
    }

    public static String getTAG() {
        return TAG;
    }

    private void init(AttributeSet attrs) {
        TypedArray obtainStyledAttributes = getContext().obtainStyledAttributes(attrs, R.styleable.WindView);
        pressure = obtainStyledAttributes.getFloat(R.styleable.WindView_pressure, -1.0f);
        windTextX = obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_windTextX, 242);
        windTextY = obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_windTextY, 44);
        pressureTextY = obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_pressureTextY, 8);
        labelFontSize = obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_labelFontSize, 18);
        numericFontSize = obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_numericFontSize, 14);
        barometerTickSpacing = (float) obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_barometerTickSpacing, 9);
        bigPoleX = obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_bigPoleX, 48);
        smallPoleX = obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_smallPoleX, 98);
        poleBottomY = obtainStyledAttributes.getDimensionPixelSize(R.styleable.WindView_poleBottomY, 118);
        scale = getScaleInPixel(20);
        obtainStyledAttributes.recycle();
        setupView();
    }

    private void setupView() {
        Resources resources = getContext().getResources();
        textColor = resources.getColor(R.color.text_color);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTypeface(getTypeface());
        paint.setStyle(Paint.Style.FILL);
        smallPoleBitmap = BitmapFactory.decodeResource(resources, R.drawable.smallpole);
        bigPoleBitmap = BitmapFactory.decodeResource(resources, R.drawable.bigpole);
        smallBladeBitmap = BitmapFactory.decodeResource(resources, R.drawable.smallblade);
        bigBladeBitmap = BitmapFactory.decodeResource(resources, R.drawable.bigblade);
        matrix = new Matrix();
        WindDirectionText = "";
        lineColor = Color.parseColor("#8bece8e8");
        rotation = 0.0f;
        lineSpace = toPixel(1d);
        pressureLineSize = lineSpace + (barometerTickSpacing);
        senterOfPressureLine = (9d * pressureLineSize) + lineSpace;
        pressurePaddingTop = getPaddingTop();
        pathEffect = new DashPathEffect(new float[] { 4f, 4f }, 0f);
    }

    public void start() {
        animationEnable = true;
        invalidate();
    }

    public void stop() {
        animationEnable = false;
    }

    public void setWindSpeed(float f) {
        windSpeed = f;
        if (windSpeed >= 36.0f && animationEnable) {
            if (smallBladeBitmap != null) {
                smallBladeBitmap.recycle();
            }
            if (bigBladeBitmap != null) {
                bigBladeBitmap.recycle();
            }
            smallBladeBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.blade_s_blur);
            bigBladeBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.blade_big_blur);
        }
        windSpeedText = formatFloat(windSpeed);
        initSpeedUnit();
        invalidate();
    }

    public void setWindDirection(String str) {
        WindDirectionText = str;
        initSpeedUnit();
    }

    private void initSpeedUnit() {
        StringBuilder stringBuilder = new StringBuilder();
        if (windSpeed < 0.0f || windSpeedUnit == null) {
            stringBuilder.append(empty);
        } else {
            stringBuilder.append(" ").append(windSpeedUnit).append(" ").append(WindDirectionText);
        }
        windName = stringBuilder.toString();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        setupPressureLine(false);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        initCanvas(canvas);
    }

    private void initCanvas(Canvas canvas) {
        boolean enable = false;
        if (bigPoleBitmap != null && smallBladeBitmap != null && bigBladeBitmap != null) {
            paint.setColor(textColor);
            paint.setTypeface(typeface);
            canvas.drawBitmap(bigPoleBitmap, bigPoleX, (poleBottomY - bigPoleBitmap.getHeight()), paint);
            canvas.drawBitmap(smallPoleBitmap, smallPoleX, (poleBottomY - smallPoleBitmap.getHeight()), paint);
            if (animationEnable) {
                startTimes();
            }
            int width = bigPoleX + (bigPoleBitmap.getWidth() / 2);
            int height = (poleBottomY - bigPoleBitmap.getHeight()) - 4;
            rect.left = width - (bigBladeBitmap.getWidth() / 2);
            rect.top = height - (bigBladeBitmap.getHeight() / 2);
            rect.bottom = (bigBladeBitmap.getHeight() / 2) + height;
            matrix.reset();
            matrix.setRotate(rotation, (bigBladeBitmap.getWidth()) / 2.0f, (bigBladeBitmap.getHeight()) / 2.0f);
            matrix.postTranslate((width - (bigBladeBitmap.getWidth() / 2)), (height - (bigBladeBitmap.getHeight() / 2)));
            canvas.drawBitmap(bigBladeBitmap, matrix, paint);
            width = smallPoleX + (smallPoleBitmap.getWidth() / 2);
            int height2 = (poleBottomY - smallPoleBitmap.getHeight()) - 4;
            rect.right = (smallBladeBitmap.getWidth() / 2) + width;
            rect.bottom = Math.max(rect.bottom, height + (smallBladeBitmap.getHeight() / 2));
            matrix.reset();
            matrix.setRotate(rotation, (smallBladeBitmap.getWidth()) / 2.0f, (smallBladeBitmap.getHeight()) / 2.0f);
            matrix.postTranslate((width - (smallBladeBitmap.getWidth() / 2)), (height2 - (smallBladeBitmap.getHeight() / 2)));
            canvas.drawBitmap(smallBladeBitmap, matrix, paint);
            drawWind(canvas);
            drawBarometer(canvas);
            if (!animationEnable) {
                curSize = lineSize;
            }
            drawLine(canvas);
            drawPressure(canvas);
            if (trendType == TrendType.DOWN && curSize < lineSize && animationBaroMeterEnable) {
                curSize += 1.0f;
                enable = true;
            } else if (trendType == TrendType.UP && curSize > lineSize && animationBaroMeterEnable) {
                curSize -= 1.0f;
                enable = true;
            } else {
                animationBaroMeterEnable = false;
            }
            if ((animationEnable && windSpeed > 0.0f) || enable) {
                invalidate();
            }
        }
    }

    private void drawLine(Canvas canvas) {
        paint.setColor(lineColor);
        paint.setStrokeWidth(lineStrokeWidth);
        paint.setStyle(Paint.Style.STROKE);
        paint.setPathEffect(pathEffect);
        float width = (float) getWidth();
        if (path == null) {
            path = new Path();
        } else {
            path.reset();
        }
        path.moveTo(10.0f, curSize);
        path.quadTo(width / 2.0f, curSize, width - 20.0f, curSize);
        canvas.drawPath(path, paint);
        paint.setStyle(Paint.Style.FILL);
        paint.setPathEffect(null);
        paint.setColor(textColor);
    }

    private void setupPressureLine(boolean z) {
        int height = getHeight();
        if (height > 0) {
            if ((senterOfPressureLine + (getPaddingTop())) + (getPaddingBottom()) >= (height)) {
                senterOfPressureLine = ((height - getPaddingTop()) - getPaddingBottom());
                pressureLineSize = senterOfPressureLine / 10.0d;
            }
            pressurePaddingTop = (float) ((((height - getPaddingTop()) / 2)) - (senterOfPressureLine / 2.0d));
            float f = (float) (((pressurePaddingTop) + (pressureLineSize * 5.0d)) + lineSpace);
            if (z) {
                lineSize = f;
                curSize = lineSize;
            } else if (trendType == TrendType.DOWN) {
                lineSize = (float) (((pressurePaddingTop) + (pressureLineSize * 5.0d)) + lineSpace);
                if (animationBaroMeterEnable) {
                    curSize = (float) (((pressurePaddingTop) + (pressureLineSize * 7.0d)) + lineSpace);
                } else {
                    curSize = lineSize;
                }
                trendBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.trend_falling);
            } else if (trendType == TrendType.UP) {
                lineSize = (float) (((pressurePaddingTop) + (pressureLineSize * 5.0d)) + lineSpace);
                if (animationBaroMeterEnable) {
                    curSize = (float) (((pressurePaddingTop) + (pressureLineSize * 7.0d)) + lineSpace);
                } else {
                    curSize = lineSize;
                }
                trendBitmap = BitmapFactory.decodeResource(getContext().getResources(), R.drawable.trend_rising);
            } else {
                lineSize = f;
                curSize = lineSize;
                if (trendBitmap != null) {
                    trendBitmap.recycle();
                    trendBitmap = null;
                }
            }
        }
    }

    private void drawWind(Canvas canvas) {
        paint.setTextSize(labelFontSize);
        paint.setStyle(Paint.Style.FILL);
        paint.setPathEffect(null);
        float width = (((smallPoleX) + ((smallBladeBitmap.getWidth()) / 2.0f)) + windTextX);
        canvas.drawText(windText, width, windTextY, paint);
        if (windSpeed < 0.0f) {
            paint.setTextSize(labelFontSize);
            canvas.drawText(windName, width, (windTextY + labelFontSize), paint);
        } else if (!stringValid(windSpeedText)) {
            paint.setTextSize(numericFontSize);
            canvas.drawText(windSpeedText, width, (windTextY + numericFontSize), paint);
            if (!stringValid(windName)) {
                paint.setTextSize(labelFontSize);
                canvas.drawText(windName, width + (((windSpeedText.length() * numericFontSize)) / 2.0f), (windTextY + numericFontSize), paint);
            }
        }
    }

    private void drawPressure(Canvas canvas) {
        float f = curSize + (pressureTextY);
        int width = (getWidth() - 14) - scale;
        paint.setTextSize(labelFontSize);
        float measureText = (width - (paint.measureText(barometerText)));
        f += labelFontSize;
        canvas.drawText(barometerText, measureText, f, paint);
        if (trendBitmap != null) {
            canvas.drawBitmap(trendBitmap, (measureText - (trendBitmap.getWidth())) - 4.0f, f - ((labelFontSize / 2)), paint);
        }
        if (!TextUtils.isEmpty(pressureUnit)) {
            paint.setTextSize((float) labelFontSize);
            measureText = (float) (width - ((int) paint.measureText(pressureUnit)));
            f += (float) numericFontSize;
            canvas.drawText(pressureUnit, measureText, f, paint);
        }
        if (!TextUtils.isEmpty(pressureText)) {
            paint.setTextSize((float) numericFontSize);
            canvas.drawText(pressureText, measureText - ((((paint.measureText(pressureText)) + 4)) + ((paint.measureText(" ")))), f, paint);
        }
    }

    private void startTimes() {
        long nanoTime = System.nanoTime();
        float f = ((float) (nanoTime - startTime)) / 1000000.0f;
        startTime = nanoTime;
        rotation = ((float) ((Math.sqrt((double) windSpeed) * (f)) / 20.0d)) + rotation;
        rotation %= 360.0f;
    }

    private void drawBarometer(Canvas canvas) {
        paint.setStrokeWidth(barometerStrokeWidth);
        paint.setColor(barometerColor);
        paint.setStyle(Paint.Style.FILL);
        int width = getWidth();
        float f = pressurePaddingTop;
        for (int i = 0; i < 10; i++) {
            canvas.drawLine((float) ((width) - toPixel(5d)), f, width, f, paint);
            f = (float) ((f) + (lineSpace + (barometerTickSpacing)));
        }
        paint.setColor(textColor);
    }

    public void animateBaroMeter() {
        if (!animationBaroMeterEnable) {
            animationBaroMeterEnable = true;
            setupPressureLine(false);
            invalidate();
        }
    }

    private int getScaleInPixel(int i) {
        return (int) ((getContext().getResources().getDisplayMetrics().density * (i)) + 0.5f);
    }

    private int dpToPx(int dp) {
        Resources r = getResources();
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics());
    }

    private double toPixel(double d) {
        return (getContext().getResources().getDisplayMetrics().density) * d;
    }

    private String formatFloat(float f) {
        try {
            return NumberFormat.getInstance().format(f);
        } catch (Exception e) {
            return empty;
        }
    }

    private float getscale(float f, int i) {
        return new BigDecimal(Float.toString(f)).setScale(i, 4).floatValue();
    }

    private boolean stringValid(String str) {
        return str == null || str.trim().length() == 0 || str.trim().equalsIgnoreCase("null");
    }

    public TrendType getTrendType() {
        return trendType;
    }

    public void setTrendType(TrendType trendType) {
        this.trendType = trendType;
        setupPressureLine(false);
    }

    public Typeface getTypeface() {
        if (typeface == null)
            return Typeface.DEFAULT;
        return typeface;
    }

    public void setTypeface(Typeface typeface) {
        this.typeface = typeface;
    }

    public int getTextColor() {
        return textColor;
    }

    public void setTextColor(int textColor) {
        this.textColor = textColor;
    }

    public int getLineColor() {
        return lineColor;
    }

    public void setLineColor(int lineColor) {
        this.lineColor = lineColor;
    }

    public float getLineStrokeWidth() {
        return lineStrokeWidth;
    }

    public void setLineStrokeWidth(float lineStrokeWidth) {
        this.lineStrokeWidth = lineStrokeWidth;
    }

    public int getBarometerColor() {
        return barometerColor;
    }

    public void setBarometerColor(int barometerColor) {
        this.barometerColor = barometerColor;
    }

    public float getBarometerStrokeWidth() {
        return barometerStrokeWidth;
    }

    public void setBarometerStrokeWidth(float barometerStrokeWidth) {
        this.barometerStrokeWidth = barometerStrokeWidth;
    }

    public String getWindDirectionText() {
        return WindDirectionText;
    }

    public void setWindDirectionText(String windDirectionText) {
        WindDirectionText = windDirectionText;
    }

    public int getBigPoleX() {
        return bigPoleX;
    }

    public void setBigPoleX(int bigPoleX) {
        this.bigPoleX = bigPoleX;
    }

    public int getSmallPoleX() {
        return smallPoleX;
    }

    public void setSmallPoleX(int smallPoleX) {
        this.smallPoleX = smallPoleX;
    }

    public String getWindText() {
        return windText;
    }

    public void setWindText(String windText) {
        this.windText = windText;
    }

    public String getWindName() {
        return windName;
    }

    public void setWindName(String windName) {
        this.windName = windName;
    }

    public String getWindSpeedText() {
        return windSpeedText;
    }

    public void setWindSpeedText(String windSpeedText) {
        this.windSpeedText = windSpeedText;
    }

    public String getBarometerText() {
        return barometerText;
    }

    public void setBarometerText(String barometerText) {
        this.barometerText = barometerText;
    }

    public int getPoleBottomY() {
        return poleBottomY;
    }

    public void setPoleBottomY(int poleBottomY) {
        this.poleBottomY = poleBottomY;
    }

    public int getWindTextX() {
        return windTextX;
    }

    public void setWindTextX(int windTextX) {
        this.windTextX = windTextX;
    }

    public int getWindTextY() {
        return windTextY;
    }

    public void setWindTextY(int windTextY) {
        this.windTextY = windTextY;
    }

    public String getWindSpeedUnit() {
        return windSpeedUnit;
    }

    public void setWindSpeedUnit(String str) {
        windSpeedUnit = str;
        initSpeedUnit();
    }

    public Rect getRect() {
        return rect;
    }

    public void setRect(Rect rect) {
        this.rect = rect;
    }

    public int getLabelFontSize() {
        return labelFontSize;
    }

    public void setLabelFontSize(int labelFontSize) {
        this.labelFontSize = labelFontSize;
    }

    public int getNumericFontSize() {
        return numericFontSize;
    }

    public void setNumericFontSize(int numericFontSize) {
        this.numericFontSize = numericFontSize;
    }

    public String getPressureUnit() {
        return pressureUnit;
    }

    public void setPressureUnit(String str) {
        pressureUnit = str;
    }

    public int getPressureTextY() {
        return pressureTextY;
    }

    public void setPressureTextY(int pressureTextY) {
        this.pressureTextY = pressureTextY;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float f) {
        pressure = getscale(f, 2);
        if (pressure < 0.0f) {
            pressureText = empty;
        } else {
            pressureText = formatFloat(pressure);
        }
    }

    public float getLineSize() {
        return lineSize;
    }

    public void setLineSize(float lineSize) {
        this.lineSize = lineSize;
    }

    public double getLineSpace() {
        return lineSpace;
    }

    public void setLineSpace(double lineSpace) {
        this.lineSpace = lineSpace;
    }
}

14 Source : CircleProgressView.java
with Apache License 2.0
from xuexiangjys

/**
 * @author xuexiang
 * @since 2019-05-12 12:34
 */
public clreplaced CircleProgressView extends View {

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({ ACCELERATE_DECELERATE_INTERPOLATOR, LINEAR_INTERPOLATOR, ACCELERATE_INTERPOLATOR, DECELERATE_INTERPOLATOR, OVERSHOOT_INTERPOLATOR })
    private @interface AnimateType {
    }

    /**
     * animation types supported
     */
    public static final int ACCELERATE_DECELERATE_INTERPOLATOR = 0;

    public static final int LINEAR_INTERPOLATOR = 1;

    public static final int ACCELERATE_INTERPOLATOR = 2;

    public static final int DECELERATE_INTERPOLATOR = 3;

    public static final int OVERSHOOT_INTERPOLATOR = 4;

    /**
     * the type of animation
     */
    private int mAnimateType = 0;

    /**
     * the progress of start point
     */
    private float mStartProgress = 0;

    /**
     * the progress of end point
     */
    private float mEndProgress = 60;

    /**
     * the color of start progress
     */
    private int mStartColor = getResources().getColor(R.color.xui_config_color_light_orange);

    /**
     * the color of end progress
     */
    private int mEndColor = getResources().getColor(R.color.xui_config_color_dark_orange);

    /**
     * has track of moving or not
     */
    private boolean trackEnabled;

    /**
     * filling the inner space or not
     */
    private boolean fillEnabled;

    /**
     * the stroke width of Track
     */
    private int mTrackWidth;

    /**
     * the stroke width of progress
     */
    private int mProgressWidth;

    /**
     * the size of inner text
     */
    private int mProgressTextSize;

    /**
     * the color of inner text
     */
    private int mProgressTextColor;

    /**
     * the circle of progress broken or not
     */
    private boolean circleBroken;

    /**
     * the color of progress track
     */
    private int mTrackColor = getResources().getColor(R.color.default_pv_track_color);

    /**
     * the duration of progress moving
     */
    private int mProgressDuration = 1200;

    /**
     * show the inner text or not
     */
    private boolean textVisibility;

    /**
     * the animator of progress moving
     */
    private ObjectAnimator progressAnimator;

    /**
     * the progress of moving
     */
    private float moveProgress = 0;

    /**
     * the paint of drawing progress
     */
    private Paint progressPaint;

    /**
     * the paint of drawing track
     */
    private Paint trackPaint;

    /**
     * the gradient of color
     */
    private LinearGradient mShader;

    /**
     * the oval's rect shape
     */
    private RectF mOval;

    private Interpolator mInterpolator;

    private CircleProgressUpdateListener mUpdateListener;

    /**
     * the path of scale zone
     */
    private Path mScaleZonePath;

    /**
     * the width of each scale zone
     */
    private float mScaleZoneWidth;

    /**
     * the length of each scale zone
     */
    private float mScaleZoneLength;

    /**
     * the padding of scale zones
     */
    private int mScaleZonePadding;

    /**
     * open draw the scale zone or not
     */
    private boolean isGraduated = false;

    /**
     * the radius of scale zone corner
     */
    private int mScaleZoneCornerRadius = 0;

    PathEffect pathEffect;

    public CircleProgressView(Context context) {
        this(context, null);
    }

    public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, R.attr.CircleProgressViewStyle);
    }

    public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        obtainAttrs(context, attrs, defStyleAttr);
        init();
    }

    private void obtainAttrs(Context context, AttributeSet attrs, int defStyleAttr) {
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView, defStyleAttr, 0);
        mStartProgress = typedArray.getInt(R.styleable.CircleProgressView_cpv_start_progress, 0);
        mEndProgress = typedArray.getInt(R.styleable.CircleProgressView_cpv_end_progress, 60);
        mStartColor = typedArray.getColor(R.styleable.CircleProgressView_cpv_start_color, getResources().getColor(R.color.xui_config_color_light_orange));
        mEndColor = typedArray.getColor(R.styleable.CircleProgressView_cpv_end_color, getResources().getColor(R.color.xui_config_color_dark_orange));
        fillEnabled = typedArray.getBoolean(R.styleable.CircleProgressView_cpv_isFilled, false);
        trackEnabled = typedArray.getBoolean(R.styleable.CircleProgressView_cpv_isTracked, false);
        circleBroken = typedArray.getBoolean(R.styleable.CircleProgressView_cpv_circle_broken, false);
        mProgressTextColor = typedArray.getColor(R.styleable.CircleProgressView_cpv_progress_textColor, ThemeUtils.resolveColor(getContext(), R.attr.colorAccent));
        mProgressTextSize = typedArray.getDimensionPixelSize(R.styleable.CircleProgressView_cpv_progress_textSize, getResources().getDimensionPixelSize(R.dimen.default_pv_progress_text_size));
        mTrackWidth = typedArray.getDimensionPixelSize(R.styleable.CircleProgressView_cpv_track_width, getResources().getDimensionPixelSize(R.dimen.default_pv_trace_width));
        mProgressWidth = typedArray.getDimensionPixelSize(R.styleable.CircleProgressView_cpv_progress_width, getResources().getDimensionPixelSize(R.dimen.default_pv_trace_width));
        mAnimateType = typedArray.getInt(R.styleable.CircleProgressView_cpv_animate_type, ACCELERATE_DECELERATE_INTERPOLATOR);
        mTrackColor = typedArray.getColor(R.styleable.CircleProgressView_cpv_track_color, getResources().getColor(R.color.default_pv_track_color));
        textVisibility = typedArray.getBoolean(R.styleable.CircleProgressView_cpv_progress_textVisibility, true);
        mProgressDuration = typedArray.getInt(R.styleable.CircleProgressView_cpv_progress_duration, 1200);
        mScaleZoneLength = typedArray.getDimensionPixelSize(R.styleable.CircleProgressView_cpv_scaleZone_length, getResources().getDimensionPixelSize(R.dimen.default_pv_zone_length));
        mScaleZoneWidth = typedArray.getDimensionPixelSize(R.styleable.CircleProgressView_cpv_scaleZone_width, getResources().getDimensionPixelSize(R.dimen.default_pv_zone_width));
        mScaleZonePadding = typedArray.getDimensionPixelSize(R.styleable.CircleProgressView_cpv_scaleZone_padding, getResources().getDimensionPixelSize(R.dimen.default_pv_zone_padding));
        mScaleZoneCornerRadius = typedArray.getDimensionPixelSize(R.styleable.CircleProgressView_cpv_scaleZone_corner_radius, getResources().getDimensionPixelSize(R.dimen.default_pv_zone_corner_radius));
        isGraduated = typedArray.getBoolean(R.styleable.CircleProgressView_cpv_isGraduated, false);
        moveProgress = mStartProgress;
        typedArray.recycle();
    }

    private void init() {
        progressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        progressPaint.setStyle(Paint.Style.STROKE);
        progressPaint.setStrokeCap(Paint.Cap.ROUND);
        progressPaint.setStrokeWidth(mProgressWidth);
        trackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        trackPaint.setStyle(Paint.Style.STROKE);
        trackPaint.setStrokeCap(Paint.Cap.ROUND);
        trackPaint.setStrokeWidth(mTrackWidth);
        mScaleZonePath = new Path();
        drawScaleZones(isGraduated);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawTrack(canvas);
        drawProgress(canvas);
        drawProgressText(canvas);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        updateTheTrack();
        mShader = new LinearGradient(mOval.left - 200, mOval.top - 200, mOval.right + 20, mOval.bottom + 20, mStartColor, mEndColor, Shader.TileMode.CLAMP);
        /**
         * draw the scale zone shape
         */
        /**
         * the shape of scale zone
         */
        RectF mScaleZoneRect = new RectF(0, 0, mScaleZoneWidth, mScaleZoneLength);
        mScaleZonePath.addRoundRect(mScaleZoneRect, mScaleZoneCornerRadius, mScaleZoneCornerRadius, Path.Direction.CW);
    }

    /**
     * draw the track(moving background)
     *
     * @param canvas mCanvas
     */
    private void drawTrack(Canvas canvas) {
        if (trackEnabled) {
            trackPaint.setShader(null);
            trackPaint.setColor(mTrackColor);
            initTrack(canvas, fillEnabled);
        }
    }

    private void drawProgress(Canvas canvas) {
        progressPaint.setShader(mShader);
        updateTheTrack();
        initProgressDrawing(canvas, fillEnabled);
    }

    /**
     * draw the each scale zone, you can set round corner fot it
     *
     * @link
     */
    private void drawScaleZones(boolean isGraduated) {
        if (isGraduated) {
            if (pathEffect == null) {
                pathEffect = new PathDashPathEffect(mScaleZonePath, mScaleZonePadding, 0, PathDashPathEffect.Style.ROTATE);
            }
            progressPaint.setPathEffect(pathEffect);
        } else {
            pathEffect = null;
            progressPaint.setPathEffect(null);
        }
    }

    /**
     * init for track view
     *
     * @param canvas   mCanvas
     * @param isFilled whether filled or not
     */
    private void initTrack(Canvas canvas, boolean isFilled) {
        if (isFilled) {
            trackPaint.setStyle(Paint.Style.FILL);
        } else {
            trackPaint.setStyle(Paint.Style.STROKE);
        }
        if (circleBroken) {
            canvas.drawArc(mOval, 135, 270, isFilled, trackPaint);
        } else {
            canvas.drawArc(mOval, 90, 360, isFilled, trackPaint);
        }
    }

    /**
     * draw the progress text
     *
     * @param canvas mCanvas
     */
    private void drawProgressText(Canvas canvas) {
        if (textVisibility) {
            Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mTextPaint.setStyle(Paint.Style.FILL);
            mTextPaint.setTextSize(mProgressTextSize);
            mTextPaint.setColor(mProgressTextColor);
            mTextPaint.setTextAlign(Paint.Align.CENTER);
            mTextPaint.setTypeface(XUI.getDefaultTypeface());
            String progressText = ((int) moveProgress) + "%";
            float x = (getWidth() + getPaddingLeft() - getPaddingRight()) >> 1;
            float y = (getHeight() + getPaddingTop() - getPaddingBottom() - (mTextPaint.descent() + mTextPaint.ascent())) / 2;
            canvas.drawText(progressText, x, y, mTextPaint);
        }
    }

    /**
     * set progress animate type
     *
     * @param type anim type
     */
    public void setAnimateType(@AnimateType int type) {
        this.mAnimateType = type;
        setObjectAnimatorType(type);
    }

    /**
     * set object animation type by received
     *
     * @param animatorType object anim type
     */
    private void setObjectAnimatorType(int animatorType) {
        switch(animatorType) {
            case ACCELERATE_DECELERATE_INTERPOLATOR:
                if (mInterpolator != null) {
                    mInterpolator = null;
                }
                mInterpolator = new AccelerateDecelerateInterpolator();
                break;
            case LINEAR_INTERPOLATOR:
                if (mInterpolator != null) {
                    mInterpolator = null;
                }
                mInterpolator = new LinearInterpolator();
                break;
            case ACCELERATE_INTERPOLATOR:
                if (mInterpolator != null) {
                    mInterpolator = null;
                    mInterpolator = new AccelerateInterpolator();
                }
                break;
            case DECELERATE_INTERPOLATOR:
                if (mInterpolator != null) {
                    mInterpolator = null;
                }
                mInterpolator = new DecelerateInterpolator();
                break;
            case OVERSHOOT_INTERPOLATOR:
                if (mInterpolator != null) {
                    mInterpolator = null;
                }
                mInterpolator = new OvershootInterpolator();
                break;
            default:
                break;
        }
    }

    /**
     * set move progress
     *
     * @param progress progress of moving
     */
    public void setProgress(float progress) {
        this.moveProgress = progress;
        refreshTheView();
    }

    public float getProgress() {
        return this.moveProgress;
    }

    /**
     * set start progress
     *
     * @param startProgress start progress
     */
    public void setStartProgress(float startProgress) {
        if (startProgress < 0 || startProgress > 100) {
            throw new IllegalArgumentException("Illegal progress value, please change it!");
        }
        this.mStartProgress = startProgress;
        this.moveProgress = mStartProgress;
        refreshTheView();
    }

    /**
     * set end progress
     *
     * @param endProgress end progress
     */
    public void setEndProgress(float endProgress) {
        if (endProgress < 0 || endProgress > 100) {
            throw new IllegalArgumentException("Illegal progress value, please change it!");
        }
        this.mEndProgress = endProgress;
        refreshTheView();
    }

    /**
     * set start color
     *
     * @param startColor start point color
     */
    public void setStartColor(@ColorInt int startColor) {
        this.mStartColor = startColor;
        updateTheTrack();
        mShader = new LinearGradient(mOval.left - 200, mOval.top - 200, mOval.right + 20, mOval.bottom + 20, mStartColor, mEndColor, Shader.TileMode.CLAMP);
        refreshTheView();
    }

    /**
     * set end color
     *
     * @param endColor end point color
     */
    public void setEndColor(@ColorInt int endColor) {
        this.mEndColor = endColor;
        updateTheTrack();
        mShader = new LinearGradient(mOval.left - 200, mOval.top - 200, mOval.right + 20, mOval.bottom + 20, mStartColor, mEndColor, Shader.TileMode.CLAMP);
        refreshTheView();
    }

    /**
     * set the width of progress stroke
     *
     * @param width stroke
     */
    public void setTrackWidth(int width) {
        mTrackWidth = DensityUtils.dp2px(getContext(), width);
        trackPaint.setStrokeWidth(width);
        updateTheTrack();
        refreshTheView();
    }

    /**
     * set the width of progress stroke
     *
     * @param width stroke
     */
    public void setProgressWidth(int width) {
        mProgressWidth = DensityUtils.dp2px(getContext(), width);
        progressPaint.setStrokeWidth(width);
        refreshTheView();
    }

    /**
     * set text size for inner text
     *
     * @param size text size
     */
    public void setProgressTextSize(int size) {
        mProgressTextSize = DensityUtils.sp2px(getContext(), size);
        refreshTheView();
    }

    /**
     * set text color for progress text
     *
     * @param textColor
     */
    public void setProgressTextColor(@ColorInt int textColor) {
        this.mProgressTextColor = textColor;
    }

    /**
     * set duration of progress moving
     *
     * @param duration
     */
    public void setProgressDuration(int duration) {
        this.mProgressDuration = duration;
    }

    /**
     * set track for progress
     *
     * @param trackAble whether track or not
     */
    public void setTrackEnabled(boolean trackAble) {
        this.trackEnabled = trackAble;
        refreshTheView();
    }

    /**
     * set track color for progress background
     *
     * @param color bg color
     */
    public void setTrackColor(@ColorInt int color) {
        this.mTrackColor = color;
        refreshTheView();
    }

    /**
     * set content for progress inner space
     *
     * @param fillEnabled whether filled or not
     */
    public void setFillEnabled(boolean fillEnabled) {
        this.fillEnabled = fillEnabled;
        refreshTheView();
    }

    /**
     * set the broken circle for progress
     *
     * @param isBroken the circle broken or not
     */
    public void setCircleBroken(boolean isBroken) {
        this.circleBroken = isBroken;
        refreshTheView();
    }

    /**
     * set the scale zone type for progress view
     *
     * @param isGraduated have scale zone or not
     */
    public void setGraduatedEnabled(final boolean isGraduated) {
        this.isGraduated = isGraduated;
        post(new Runnable() {

            @Override
            public void run() {
                drawScaleZones(isGraduated);
            }
        });
    }

    /**
     * set the scale zone width for it
     *
     * @param zoneWidth each zone 's width
     */
    public void setScaleZoneWidth(float zoneWidth) {
        this.mScaleZoneWidth = DensityUtils.dp2px(getContext(), zoneWidth);
    }

    /**
     * set the scale zone length for it
     *
     * @param zoneLength each zone 's length
     */
    public void setScaleZoneLength(float zoneLength) {
        this.mScaleZoneLength = DensityUtils.dp2px(getContext(), zoneLength);
    }

    /**
     * set each zone's distance
     *
     * @param zonePadding distance
     */
    public void setScaleZonePadding(int zonePadding) {
        this.mScaleZonePadding = DensityUtils.dp2px(getContext(), zonePadding);
    }

    /**
     * set corner radius for each zone
     *
     * @param cornerRadius round rect zone's corner
     */
    public void setScaleZoneCornerRadius(int cornerRadius) {
        this.mScaleZoneCornerRadius = DensityUtils.dp2px(getContext(), cornerRadius);
    }

    /**
     * set the visibility for progress inner text
     *
     * @param visibility text visible or not
     */
    public void setProgressTextVisibility(boolean visibility) {
        this.textVisibility = visibility;
    }

    /**
     * start the progress's moving
     */
    public void startProgressAnimation() {
        progressAnimator = ObjectAnimator.ofFloat(this, "progress", mStartProgress, mEndProgress);
        progressAnimator.setInterpolator(mInterpolator);
        progressAnimator.setDuration(mProgressDuration);
        progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float progress = (float) animation.getAnimatedValue("progress");
                if (mUpdateListener != null) {
                    mUpdateListener.onCircleProgressUpdate(CircleProgressView.this, progress);
                }
            }
        });
        progressAnimator.addListener(new Animator.AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animator) {
                if (mUpdateListener != null) {
                    mUpdateListener.onCircleProgressStart(CircleProgressView.this);
                }
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                if (mUpdateListener != null) {
                    mUpdateListener.onCircleProgressFinished(CircleProgressView.this);
                }
            }

            @Override
            public void onAnimationCancel(Animator animator) {
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
        progressAnimator.start();
    }

    /**
     * stop the progress moving
     */
    public void stopProgressAnimation() {
        if (progressAnimator != null) {
            progressAnimator.cancel();
            progressAnimator = null;
        }
    }

    /**
     * refresh the layout
     */
    private void refreshTheView() {
        invalidate();
        requestLayout();
    }

    /**
     * update the oval progress track
     */
    private void updateTheTrack() {
        if (mOval != null) {
            mOval = null;
        }
        mOval = new RectF(getPaddingLeft() + mTrackWidth, getPaddingTop() + mTrackWidth, getWidth() - getPaddingRight() - mTrackWidth, getHeight() - getPaddingBottom() - mTrackWidth);
    }

    /**
     * init the circle progress drawing
     *
     * @param canvas   mCanvas
     * @param isFilled filled or not
     */
    private void initProgressDrawing(Canvas canvas, boolean isFilled) {
        if (isFilled) {
            progressPaint.setStyle(Paint.Style.FILL);
        } else {
            progressPaint.setStyle(Paint.Style.STROKE);
        }
        if (circleBroken) {
            canvas.drawArc(mOval, 135 + mStartProgress * 2.7f, (moveProgress - mStartProgress) * 2.7f, isFilled, progressPaint);
        } else {
            canvas.drawArc(mOval, 270 + mStartProgress * 3.6f, (moveProgress - mStartProgress) * 3.6f, isFilled, progressPaint);
        }
    }

    /**
     * 进度条更新监听
     */
    public interface CircleProgressUpdateListener {

        /**
         * 进度条开始更新
         *
         * @param view
         */
        void onCircleProgressStart(View view);

        /**
         * 进度条更新中
         *
         * @param view
         * @param progress
         */
        void onCircleProgressUpdate(View view, float progress);

        /**
         * 进度条更新结束
         *
         * @param view
         */
        void onCircleProgressFinished(View view);
    }

    /**
     * set the progress update listener for progress view
     *
     * @param listener update listener
     */
    public void setProgressViewUpdateListener(CircleProgressUpdateListener listener) {
        this.mUpdateListener = listener;
    }
}

See More Examples