Android 自定义控件之三点循环缩放

这里写图片描述

效果图如上,就是三点循环的变大、变小

package com.example.dotdemo;

import java.util.ArrayList;
import java.util.List;


import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.animation.AccelerateDecelerateInterpolator;

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@SuppressLint("NewApi")
public class DilatingDotsProgressBar extends View {
    public static final String TAG = DilatingDotsProgressBar.class.getSimpleName();
    public static final double START_DELAY_FACTOR = 0.35;
    private static final float DEFAULT_GROWTH_MULTIPLIER = 1.75f;
    private static final int MIN_SHOW_TIME = 500; // ms
    private static final int MIN_DELAY = 500; // ms
    private int mDotColor;
    private int mAnimationDuration;
    private int mWidthBetweenDotCenters;
    private int mNumberDots;
    private float mDotRadius;
    private float mDotScaleMultiplier;
    private float mDotMaxRadius;
    private float mHorizontalSpacing;
    private long mStartTime = -1;
    private boolean mShouldAnimate;
    private boolean mDismissed = false;
    private ArrayList<DilatingDotDrawable> mDrawables = new ArrayList<DilatingDotDrawable>();
    private final List<Animator> mAnimations = new ArrayList<Animator>();
    /** delayed runnable to stop the progress */
    private final Runnable mDelayedHide = new Runnable() {
        @Override
        public void run() {
            mStartTime = -1;
            setVisibility(View.GONE);
            stopAnimations();
        }
    };
    /** delayed runnable to start the progress */
    private final Runnable mDelayedShow = new Runnable() {
        @Override
        public void run() {
            if (!mDismissed) {
                mStartTime = System.currentTimeMillis();
                setVisibility(View.VISIBLE);
                startAnimations();
            }
        }
    };

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

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

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

    private void init(AttributeSet attrs) {
        TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.DilatingDotsProgressBar);
        mNumberDots = a.getInt(R.styleable.DilatingDotsProgressBar_dd_numDots, 3);
        mDotRadius = a.getDimension(R.styleable.DilatingDotsProgressBar_android_radius, 8);
        mDotColor = a.getColor(R.styleable.DilatingDotsProgressBar_android_color, 0xff9c27b0);
        mDotScaleMultiplier = a.getFloat(R.styleable.DilatingDotsProgressBar_dd_scaleMultiplier, DEFAULT_GROWTH_MULTIPLIER);
        mAnimationDuration = a.getInt(R.styleable.DilatingDotsProgressBar_dd_animationDuration, 300);
        mHorizontalSpacing = a.getDimension(R.styleable.DilatingDotsProgressBar_dd_horizontalSpacing, 12);
        boolean isShow = a.getBoolean(R.styleable.DilatingDotsProgressBar_dd_show_now, false);
        a.recycle();

        mShouldAnimate = false;
        calculateMaxRadius();
        calculateWidthBetweenDotCenters();

        initDots();
        updateDots();

        if (isShow) {
            showNow();
        }
    }

    @Override
    protected void onSizeChanged(final int w, final int h, final int oldw, final int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        if (computeMaxHeight() != h || w != computeMaxWidth()) {
            updateDots();
        }
    }

    @Override
    public void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        removeCallbacks();
    }

    private void removeCallbacks() {
        removeCallbacks(mDelayedHide);
        removeCallbacks(mDelayedShow);
    }

    public void reset() {
        hideNow();
    }

    /**
     * Hide the progress view if it is visible. The progress view will not be
     * hidden until it has been shown for at least a minimum show time. If the
     * progress view was not yet visible, cancels showing the progress view.
     */
    public void hide() {
        hide(MIN_SHOW_TIME);
    }

    public void hide(int delay) {
        mDismissed = true;
        removeCallbacks(mDelayedShow);
        long diff = System.currentTimeMillis() - mStartTime;
        if ((diff >= delay) || (mStartTime == -1)) {
            mDelayedHide.run();
        } else {
            if ((delay - diff) <= 0) {
                mDelayedHide.run();
            } else {
                postDelayed(mDelayedHide, delay - diff);
            }
        }
    }

    /**
     * Show the progress view after waiting for a minimum delay. If
     * during that time, hide() is called, the view is never made visible.
     */
    @SuppressWarnings ("unused")
    public void show() {
        show(MIN_DELAY);
    }

    @SuppressWarnings ("unused")
    public void showNow() {
        show(0);
    }

    @SuppressWarnings ("unused")
    public void hideNow() {
        hide(0);
    }

    public void show(int delay) {
        mStartTime = -1;
        mDismissed = false;
        removeCallbacks(mDelayedHide);

        if (delay == 0) {
            mDelayedShow.run();
        } else {
            postDelayed(mDelayedShow, delay);
        }
    }

    @Override
    protected void onDraw(Canvas canvas) {
        if (shouldAnimate()) {
            for (DilatingDotDrawable dot : mDrawables) {
                dot.draw(canvas);
            }
        }
    }

    @Override
    protected boolean verifyDrawable(final Drawable who) {
        if (shouldAnimate()) {
            return mDrawables.contains(who);
        }
        return super.verifyDrawable(who);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension((int) computeMaxWidth(), (int) computeMaxHeight());
    }

    private float computeMaxHeight() {
        return mDotMaxRadius * 2;
    }

    private float computeMaxWidth() {
        return computeWidth() + ((mDotMaxRadius - mDotRadius) * 2);
    }

    private float computeWidth() {
        return (((mDotRadius * 2) + mHorizontalSpacing) * mDrawables.size()) - mHorizontalSpacing;
    }

    private void calculateMaxRadius() {
        mDotMaxRadius = mDotRadius * mDotScaleMultiplier;
    }

    private void calculateWidthBetweenDotCenters() {
        mWidthBetweenDotCenters = (int) (mDotRadius * 2) + (int) mHorizontalSpacing;
    }

    @SuppressLint("NewApi")
    private void initDots() {
        mDrawables.clear();
        mAnimations.clear();

        Log.i("lcf", "mAnimationDuration = "+mAnimationDuration );

        for (int i = 1; i <= mNumberDots; i++) {
            final DilatingDotDrawable dot = new DilatingDotDrawable(mDotColor, mDotRadius, mDotMaxRadius);
            dot.setCallback(this);
            mDrawables.add(dot);

            ValueAnimator growAnimator = ObjectAnimator.ofFloat(dot, "radius", mDotRadius, mDotMaxRadius, mDotRadius);
            growAnimator.setDuration(mAnimationDuration);
            growAnimator.setInterpolator(new AccelerateDecelerateInterpolator());

            if (i == mNumberDots) {
                growAnimator.addListener(new AnimatorListenerAdapter() {
                    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
                    @Override
                    public void onAnimationEnd(Animator animation) {
                        if (shouldAnimate()) {
                            startAnimations();//注意这个地方,是从新开始启动动画
                        }
                    }
                });
            }


            growAnimator.setStartDelay((i - 1) * (int) (START_DELAY_FACTOR * mAnimationDuration));

            mAnimations.add(growAnimator);
        }
    }

    @SuppressLint("NewApi")
    private void updateDots() {
        if (mDotRadius <= 0) {
            mDotRadius = getHeight() / 2 / mDotScaleMultiplier;
        }

        int left = (int) (mDotMaxRadius - mDotRadius);
        int right = (int) (left + mDotRadius * 2) + 2;
        int top = 0;
        int bottom = (int) (mDotMaxRadius * 2) + 2;

        for (int i = 0; i < mDrawables.size(); i++) {
            final DilatingDotDrawable dot = mDrawables.get(i);
            dot.setRadius(mDotRadius);
            dot.setBounds(left, top, right, bottom);
            ValueAnimator growAnimator = (ValueAnimator) mAnimations.get(i);
            growAnimator.setFloatValues(mDotRadius, mDotRadius * mDotScaleMultiplier, mDotRadius);

            left += mWidthBetweenDotCenters;
            right += mWidthBetweenDotCenters;
        }
    }

    protected void startAnimations() {
        mShouldAnimate = true;
        for (Animator anim : mAnimations) {
            anim.start();
        }
    }

    protected void stopAnimations() {
        mShouldAnimate = false;
        removeCallbacks();
        for (Animator anim : mAnimations) {
            anim.cancel();
        }
    }

    protected boolean shouldAnimate() {
        return mShouldAnimate;
    }

    // -------------------------------
    // ------ Getters & Setters ------
    // -------------------------------

    public void setDotRadius(float radius) {
        reset();
        mDotRadius = radius;
        calculateMaxRadius();
        calculateWidthBetweenDotCenters();
        setupDots();
    }

    public void setDotSpacing(float horizontalSpacing) {
        reset();
        mHorizontalSpacing = horizontalSpacing;
        calculateWidthBetweenDotCenters();
        setupDots();
    }

    public void setGrowthSpeed(int growthSpeed) {
        reset();
        mAnimationDuration = growthSpeed;
        setupDots();
    }

    public void setNumberOfDots(int numDots) {
        reset();
        mNumberDots = numDots;
        setupDots();
    }

    public void setDotScaleMultpiplier(float multplier) {
        reset();
        mDotScaleMultiplier = multplier;
        calculateMaxRadius();
        setupDots();
    }

    public void setDotColor(int color) {
        mDotColor = color;
        for (DilatingDotDrawable dot : mDrawables) {
            dot.setColor(mDotColor);
        }
    }

    private void setupDots() {
        initDots();
        updateDots();
        showNow();
    }

    public int getDotGrowthSpeed() {
        return mAnimationDuration;
    }

    public float getDotRadius() {
        return mDotRadius;
    }

    public float getHorizontalSpacing() {
        return mHorizontalSpacing;
    }

    public int getNumberOfDots() {
        return mNumberDots;
    }

    public float getDotScaleMultiplier() {
        return mDotScaleMultiplier;
    }
}






package com.example.dotdemo;

import android.annotation.SuppressLint;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;

@SuppressLint("Override")
public class    extends Drawable {
    private static final String TAG = DilatingDotDrawable.class.getSimpleName();
    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    private float radius;
    private float maxRadius;
    final Rect mDirtyBounds = new Rect(0, 0, 0, 0);

    public DilatingDotDrawable(final int color, final float radius, final float maxRadius) {
        mPaint.setColor(color);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeJoin(Paint.Join.ROUND);

        this.radius = radius;
        setMaxRadius(maxRadius);
    }

    @Override
    public void draw(Canvas canvas) {
        final Rect bounds = getBounds();
        canvas.drawCircle(bounds.centerX(), bounds.centerY(), radius - 1, mPaint);
    }

    @Override
    public void setAlpha(int alpha) {
        if (alpha != mPaint.getAlpha()) {
            mPaint.setAlpha(alpha);
            invalidateSelf();
        }
    }

    @Override
    public void setColorFilter(ColorFilter colorFilter) {
        mPaint.setColorFilter(colorFilter);
        invalidateSelf();
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

    public void setColor(int color) {
        mPaint.setColor(color);
        invalidateSelf();
    }

    public void setRadius(float radius) {
        this.radius = radius;
        invalidateSelf();
    }

    public float getRadius() {
        return radius;
    }

    @Override
    public int getIntrinsicWidth() {
        return (int) (maxRadius * 2) + 2;
    }

    @Override
    public int getIntrinsicHeight() {
        return (int) (maxRadius * 2) + 2;
    }

    public void setMaxRadius(final float maxRadius) {
        this.maxRadius = maxRadius;
        mDirtyBounds.bottom = (int) (maxRadius * 2) + 2;
        mDirtyBounds.right = (int) (maxRadius * 2) + 2;
    }

    public Rect getDirtyBounds() {
        return mDirtyBounds;
    }

    @Override
    protected void onBoundsChange(final Rect bounds) {
        super.onBoundsChange(bounds);
        mDirtyBounds.offsetTo(bounds.left, bounds.top);
    }
}


http://download.csdn.net/detail/luo446718254/9605616

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值