drawable动画以及CounterView计数

照例:效果图

###具体实现

  • 布局

                <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/aat_blue"
        android:orientation="vertical">
    
    <RelativeLayout
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center_horizontal">

        <ImageView
            android:id="@+id/imageview"
            android:layout_width="200dp"
            android:layout_height="200dp"
            android:background="@drawable/score" />

        <com.github.premnirmal.textcounter.CounterView
            android:id="@+id/value_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:layout_marginBottom="20dp"
            android:layout_marginTop="90dp"
            android:text="0"
            android:textColor="#ffffff"
            android:textSize="80sp" />
    </RelativeLayout>

    <Button
        android:id="@+id/tv_change_value"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp"
        android:text="改变数值" />

</LinearLayout>

ImageView 的background 是个蓝色背景图片

com.github.premnirmal.textcounter.CounterView 这个类 从github找的,可以自行search

  • 我这里是在fragment中的。大家自己随意

        /**
     * 描述:
     * 作者:Marc on 2016/7/22 10:03
     * 邮箱:aliali_ha@yeah.net
     */
    public class FragmentThree extends BaseFragment {
        ImageView imageView;
        CounterView valueTv;
        Button btn;
        CircularProgressDrawable drawable;
        Animator currentAnimation;
    
        @Override
        public void fetchData() {
            getmLoadingPager().loadData();
        }
    
        @Override
        protected View initSuccess() {
            View view = View.inflate(UIUtils.getContext(), R.layout.test_drawable, null);
            imageView = (ImageView) view.findViewById(R.id.imageview);
            valueTv = (CounterView) view.findViewById(R.id.value_tv);
            view.findViewById(R.id.tv_change_value).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Random random = new Random();
                    int score = random.nextInt(150);
                    valueTv.setStartValue(0);
                    valueTv.setEndValue(score);
                    valueTv.setIncrement(1);
                    valueTv.start();
                    startRingAnim(score);
                }
            });
    
            initViews();
    
            return view;
        }
    
    private void initViews() {
        drawable = new CircularProgressDrawable.Builder()
                .setRingWidth(ScreenUtils.dip2px(UIUtils.getContext(),10))
                .setRingWidth(ScreenUtils.dip2px(UIUtils.getContext(),9))
                .setOutlineColor(
                        getResources().getColor(android.R.color.transparent))
                .setRingColor(getResources().getColor(android.R.color.white))//外圈白色
                .setCenterColor(
                        getResources().getColor(android.R.color.transparent))
                .create();

        imageView.setImageDrawable(drawable);

        Typeface tf = Typeface.createFromAsset(getActivity().getAssets(),
                "Uni_Sans_Light.otf");
        valueTv.setTypeface(tf);
        valueTv.setAutoFormat(false);
        valueTv.setFormatter(new Formatter() {
            @Override
            public String format(String prefix, String suffix, float value) {
                return prefix
                        + NumberFormat.getNumberInstance(Locale.US).format(
                        value) + suffix;
            }
        });
        valueTv.setAutoStart(false);
    }

    @Override
    protected LoadingPager.LoadResult initData() {
        SystemClock.sleep(2000);
        return LoadingPager.LoadResult.SUCCESS;
    }

    /**
     * 开始圆圈动画
     *
     * @param score
     */
    private void startRingAnim(int score) {
        currentAnimation = prepareStyle2Animation(score);
        currentAnimation.start();
    }

    /**
     * 圆框动画
     *
     * @param duration
     * @return
     */
    private Animator prepareStyle2Animation(long duration) {
        AnimatorSet animation = new AnimatorSet();
        float progress = (duration / 150f) * 0.727f;

        ObjectAnimator progressAnimation = ObjectAnimator.ofFloat(drawable,
                CircularProgressDrawable.PROGRESS_PROPERTY, 0.f, -progress);
        progressAnimation.setDuration(duration * 20);
        progressAnimation
                .setInterpolator(new AccelerateDecelerateInterpolator());

        animation.play(progressAnimation);

        return animation;
    }
}

这个类是我自己写的子类。取消fragment预加载。然后增加getLoading加载状态

CircularProgressDrawable 的代码如下

                public class CircularProgressDrawable extends Drawable {
    /**
     * Factor to convert the factor to paint the arc.
     * <p/>
     * In this way the developer can use a more user-friendly [0..1f] progress
     */
    public static final int PROGRESS_FACTOR = -360;
    /**
     * Property Inner Circle Scale.
     * <p/>
     * The inner ring is supposed to defaults stay 3/4 radius off the outer ring at (75% scale), but this
     * property can make it grow or shrink via this equation: OuterRadius * Scale.
     * <p/>
     * A 100% scale will make the inner circle to be the same radius as the outer ring.
     */
    public static final String CIRCLE_SCALE_PROPERTY = "circleScale";
    /**
     * Property Progress of the outer circle.
     * <p/>
     * The progress of the circle. If {@link #setIndeterminate(boolean) indeterminate flag} is set
     * to FALSE, this property will be used to indicate the completion of the outer circle [0..1f].
     * <p/>
     * If set to TRUE, the drawable will activate the loading mode, where the drawable will
     * show a 90º arc which will be spinning around the outer circle as much as progress goes.
     */
    public static final String PROGRESS_PROPERTY = "progress";
    /**
     * Property Ring color.
     * <p/>
     * Changes the ring filling color
     */
    public static final String RING_COLOR_PROPERTY = "ringColor";
    /**
     * Property circle color.
     * <p/>
     * Changes the inner circle color
     */
    public static final String CIRCLE_COLOR_PROPERTY = "centerColor";
    /**
     * Property outline color.
     * <p/>
     * Changes the outline of the ring color.
     */
    public static final String OUTLINE_COLOR_PROPERTY = "outlineColor";
    /**
     * Logger Tag for Logging purposes.
     */
    public static final String TAG = "CircularProgressDrawable";
    /**
     * Paint object to draw the element.
     */
    private final Paint paint;
    /**
     * Ring progress.
     */
    protected float progress;
    /**
     * Color for the empty outer ring.
     */
    protected int outlineColor;
    /**
     * Color for the completed ring.
     */
    protected int ringColor;
    /**
     * Color for the inner circle.
     */
    protected int centerColor;
    /**
     * Rectangle where the filling ring will be drawn into.
     */
    protected final RectF arcElements;
    /**
     * Width of the filling ring.
     */
    protected final int ringWidth;
    /**
     * Scale of the inner circle. It will affect the inner circle size on this equation:
     * ([Biggest length of the Drawable] / 2) - (ringWidth / 2) * scale.
     */
    protected float circleScale;
    /**
     * Set if it is an indeterminate
     */
    protected boolean indeterminate;

    /**
     * Creates a new CouponDrawable.
     *
     * @param ringWidth    Width of the filled ring
     * @param circleScale  Scale difference between the outer ring and the inner circle
     * @param outlineColor Color for the outline color
     * @param ringColor    Color for the filled ring
     * @param centerColor  Color for the center element
     */
    CircularProgressDrawable(int ringWidth, float circleScale, int outlineColor, int ringColor, int centerColor) {
        this.progress = 0;
        this.outlineColor = outlineColor;
        this.ringColor = ringColor;
        this.centerColor = centerColor;
        this.paint = new Paint();
        this.paint.setAntiAlias(true);
        this.ringWidth = ringWidth;
        this.arcElements = new RectF();
        this.circleScale = circleScale;
        this.indeterminate = false;
    }

    @Override
    public void draw(Canvas canvas) {
        final Rect bounds = getBounds();

        // Calculations on the different components sizes
        int size = Math.min(bounds.height(), bounds.width());
        float outerRadius = (size / 2) - (ringWidth / 2);
        float innerRadius = outerRadius * circleScale;
        float offsetX = (bounds.width() - outerRadius * 2) / 2;
        float offsetY = (bounds.height() - outerRadius * 2) / 2;

        // Outline Circle
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(1);
        paint.setColor(outlineColor);
        canvas.drawCircle(bounds.centerX(), bounds.centerY(), outerRadius, paint);

        // Inner circle
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(centerColor);
        canvas.drawCircle(bounds.centerX(), bounds.centerY(), innerRadius, paint);

        int halfRingWidth = ringWidth / 2;
        float arcX0 = offsetX + halfRingWidth;
        float arcY0 = offsetY + halfRingWidth;
        float arcX = offsetX + outerRadius * 2 - halfRingWidth;
        float arcY = offsetY + outerRadius * 2 - halfRingWidth;

        // Outer Circle
        paint.setColor(ringColor);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(ringWidth);
        paint.setStrokeCap(Paint.Cap.ROUND);
        arcElements.set(arcX0 - 7, arcY0 - 7, arcX + 7, arcY + 7);
        if (indeterminate) {
            canvas.drawArc(arcElements, progress, 50, false, paint);
        } else {
            canvas.drawArc(arcElements, 139, progress, false, paint);
        }
    }

    @Override
    public void setAlpha(int alpha) {
        paint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        paint.setColorFilter(cf);
    }

    @Override
    public int getOpacity() {
        return 1 - paint.getAlpha();
    }


    /**
     * Returns the progress of the outer ring.
     * <p/>
     * Will output a correct value only when the indeterminate mode is set to FALSE.
     *
     * @return Progress of the outer ring.
     */
    public float getProgress() {
        return progress / PROGRESS_FACTOR;
    }

    /**
     * Sets the progress [0..1f]
     *
     * @param progress Sets the progress
     */
    public void setProgress(float progress) {
        if (indeterminate) {
            this.progress = progress;
        } else {
            this.progress = PROGRESS_FACTOR * progress;
        }
        invalidateSelf();
    }

    /**
     * Returns the inner circle scale.
     *
     * @return Inner circle scale in float multiplier.
     */
    public float getCircleScale() {
        return circleScale;
    }

    /**
     * Sets the inner circle scale.
     *
     * @param circleScale Inner circle scale.
     */
    public void setCircleScale(float circleScale) {
        this.circleScale = circleScale;
        invalidateSelf();
    }

    /**
     * Get the indeterminate status of the Drawable
     *
     * @return TRUE if the Drawable is in indeterminate mode or FALSE if it is in progress mode.
     */
    public boolean isIndeterminate() {
        return indeterminate;
    }

    /**
     * Sets the indeterminate parameter.
     * <p/>
     * The indeterminate parameter will change the behavior of the Drawable. If the indeterminate
     * mode is set to FALSE, the outer ring will be able to be filled by using {@link #setProgress(float) setProgress}.
     * <p/>
     * Otherwise the drawable will enter "loading mode" and a 90º arc will be able to be spinned around
     * the inner circle.
     * <p/>
     * <b>By default, indeterminate mode is set to FALSE.</b>
     *
     * @param indeterminate TRUE to activate loading mode. FALSE to activate progress mode.
     */
    public void setIndeterminate(boolean indeterminate) {
        this.indeterminate = indeterminate;
    }

    /**
     * Gets the outline color.
     *
     * @return Outline color of the empty ring.
     */
    public int getOutlineColor() {
        return outlineColor;
    }

    /**
     * Gets the filled ring color.
     *
     * @return Returns the filled ring color.
     */
    public int getRingColor() {
        return ringColor;
    }

    /**
     * Gets the color of the inner circle.
     *
     * @return Inner circle color.
     */
    public int getCenterColor() {
        return centerColor;
    }

    /**
     * Sets the empty progress outline color.
     *
     * @param outlineColor Outline color in #AARRGGBB format.
     */
    public void setOutlineColor(int outlineColor) {
        this.outlineColor = outlineColor;
        invalidateSelf();
    }

    /**
     * Sets the progress ring  color.
     *
     * @param ringColor Ring color in #AARRGGBB format.
     */
    public void setRingColor(int ringColor) {
        this.ringColor = ringColor;
        invalidateSelf();
    }

    /**
     * Sets the inner circle color.
     *
     * @param centerColor Inner circle color in #AARRGGBB format.
     */
    public void setCenterColor(int centerColor) {
        this.centerColor = centerColor;
        invalidateSelf();
    }

    /**
     * Helper class to manage the creation of a CircularProgressDrawable
     *
     * @author Saul Diaz <sefford@gmail.com>
     */
    public static class Builder {

        /**
         * Witdh of the stroke of the filled ring
         */
        int ringWidth;
        /**
         * Color of the outline of the empty ring in #AARRGGBB mode.
         */
        int outlineColor;
        /**
         * Color of the filled ring in #AARRGGBB mode.
         */
        int ringColor;
        /**
         * Color of the inner circle in #AARRGGBB mode.
         */
        int centerColor;
        /**
         * Scale between the outer ring and the inner circle
         */
        float circleScale = 0.75f;

        /**
         * Sets the ring width.
         *
         * @param ringWidth Default ring width
         * @return This builder
         */
        public Builder setRingWidth(int ringWidth) {
            this.ringWidth = ringWidth;
            return this;
        }

        /**
         * Sets the default empty outer ring outline color.
         *
         * @param outlineColor Outline color in #AARRGGBB format.
         * @return
         */
        public Builder setOutlineColor(int outlineColor) {
            this.outlineColor = outlineColor;
            return this;
        }

        /**
         * Sets the progress ring color.
         *
         * @param ringColor Ring color in #AARRGGBB format.
         * @returns This Builder
         */
        public Builder setRingColor(int ringColor) {
            this.ringColor = ringColor;
            return this;
        }


        /**
         * Sets the inner circle color.
         *
         * @param centerColor Inner circle color in #AARRGGBB format.
         * @return This builder
         */
        public Builder setCenterColor(int centerColor) {
            this.centerColor = centerColor;
            return this;
        }

        /**
         * Sets the inner circle scale. Defaults to 0.75.
         *
         * @param circleScale Inner circle scale.
         * @return This builder
         */
        public Builder setInnerCircleScale(float circleScale) {
            this.circleScale = circleScale;
            return this;
        }

        /**
         * Creates a new CircularProgressDrawable with the requested parameters
         *
         * @return New CircularProgressDrawableInstance
         */
        public CircularProgressDrawable create() {
            return new CircularProgressDrawable(ringWidth, circleScale, outlineColor, ringColor, centerColor);
        }

    }
}

没错 ,看到这么多英文注释。确实是github找的。能实现效果就好