FruitLoadView 一个自定义view可用来做加载view

闲暇时自己做得一个自定义view,后续如果还有时间的话再去增强功能。

Github地址:https://github.com/X-FAN/FruitLoadView 欢迎star

效果图 博客上的图片文件不能太大,github效果图要清晰些,大家将就下

2016.8.5: 新增fruitDrawableArray属性,可以在跳动中变换

源码还是比较简单的

public class FruitLoadView extends View {
    private final String TAG = "Fruit";
    private int mWidth;
    private int mHeight;
    private int mOvalW;
    private int mOvalH;
    private int mStartHeight;
    private int mFruitHeight;
    private int mFruitWidth;
    private int mIndex = 1;
    private int mLength;
    private boolean mIsDraw = false;
    private boolean mIsMutliMode = false;
    private boolean mIsHasChanged = false;//是否已经变换过在达到最高前
    private float mMinScale;
    private float mAnimatedValue = 1.0f;
    private List<Drawable> mFruitDrawables;

    private Drawable mFruitDrawable;
    private ValueAnimator mScaleLargerAnimator;
    private Paint mPaint;
    private RectF mOvalRectF;


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


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

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


    private void init(Context context, AttributeSet attrs) {
        if (attrs == null) {
            return;
        }
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FruitLoadView);
        handleMultiDrawable(a);
        if (!mIsMutliMode) {
            mFruitDrawable = a.getDrawable(R.styleable.FruitLoadView_fruitDrawable);
            if (mFruitDrawable == null) {
                throw new NullPointerException("fruit drawable is null");
            }
        }
        int shadowColor = a.getColor(R.styleable.FruitLoadView_shadowColor, 0xFFE6E6E6);
        int animatorDuration = a.getInt(R.styleable.FruitLoadView_animatorDuration, 1000);
        int maxHeight = a.getDimensionPixelSize(R.styleable.FruitLoadView_maxHeight, 100);
        int fruitHeight = a.getDimensionPixelSize(R.styleable.FruitLoadView_fruitHeight, -1);
        int fruitWidth = a.getDimensionPixelSize(R.styleable.FruitLoadView_fruitWidth, -1);
        if (fruitHeight > 0) {
            mFruitHeight = fruitHeight;
        } else {
            mFruitHeight = mFruitDrawable.getIntrinsicHeight();
        }
        if (fruitWidth > 0) {
            mFruitWidth = fruitWidth;
        } else {
            mFruitWidth = mFruitDrawable.getIntrinsicWidth();
        }
        mOvalW = mFruitWidth / 2;
        mOvalH = (int) (mFruitHeight * 0.5) / 2;
        mStartHeight = mFruitHeight + maxHeight;
        mMinScale = (float) mFruitHeight / (float) mStartHeight;
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setColor(shadowColor);
        mOvalRectF = new RectF();
        initAnimator(animatorDuration);
        a.recycle();
    }

    /**
     * 处理多个drawable的情况
     *
     * @param a
     */
    private void handleMultiDrawable(TypedArray a) {
        int resId = a.getResourceId(R.styleable.FruitLoadView_fruitDrawableArray, -1);
        if (resId != -1) {
            Resources resources = getResources();
            TypedArray typedArray = resources.obtainTypedArray(resId);
            mFruitDrawables = new ArrayList<>();
            for (int i = 0; i < typedArray.length(); i++) {
                Drawable drawable = typedArray.getDrawable(i);
                mFruitDrawables.add(drawable);
            }
            if (!mFruitDrawables.isEmpty()) {
                mIsMutliMode = true;
                mFruitDrawable = mFruitDrawables.get(0);
                mLength = mFruitDrawables.size();
            }
            typedArray.recycle();
        }
    }


    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mIsDraw) {
            canvas.translate(mWidth / 2, mHeight / 2);// 将画布坐标原点移动到中心位置
            canvas.save();
            canvas.drawOval(mOvalRectF, mPaint);
            mFruitDrawable.setBounds(-mOvalW, (int) (-mStartHeight * mAnimatedValue), mOvalW, (int) (-(mStartHeight * mAnimatedValue - mFruitHeight)));
            mFruitDrawable.draw(canvas);
            canvas.restore();
        }

    }


    private void initAnimator(long duration) {
        mScaleLargerAnimator = ValueAnimator.ofFloat(1.0f, mMinScale, 1.0f).setDuration(duration);
        mScaleLargerAnimator.setInterpolator(new DecelerateInterpolator());
        mScaleLargerAnimator.setRepeatCount(ValueAnimator.INFINITE);
        mScaleLargerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimatedValue = (float) animation.getAnimatedValue();
                if (mAnimatedValue > 0.9f) {//认为达到最高点
                    mIsHasChanged = false;
                }
                mOvalRectF.set(-mOvalW * mAnimatedValue, -mOvalH * mAnimatedValue, mOvalW * mAnimatedValue, mOvalH * mAnimatedValue);
                changeDrawable();
                invalidate();
            }
        });
        mScaleLargerAnimator.start();
    }

    /**
     * 变更需要绘制的drawable
     */
    private void changeDrawable() {
        //差值小于0.05f即认为在最低点
        if (mIsMutliMode && !mIsHasChanged && (mAnimatedValue - mMinScale) < 0.05f) {
            mFruitDrawable = mFruitDrawables.get(mIndex);
            if (mIndex < mLength - 1) {
                mIndex++;
            } else {
                mIndex = 0;
            }
            mIsHasChanged = true;
        }
    }


    /**
     * 是否正在展示
     *
     * @return
     */
    public boolean isShowing() {
        return mIsDraw;
    }

    /**
     * 展示
     */
    public void showLoading() {
        mIsDraw = true;
        mScaleLargerAnimator.start();
    }

    /**
     * 消失
     */
    public void hideLoading() {
        mIsDraw = false;
        mScaleLargerAnimator.cancel();
        mScaleLargerAnimator.end();
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏向治洪

android自定义xmls文件属性

在使用到自定义View的xml布局文件中需要加入xmlns:前缀=http://schemas.android.com/apk/res/你的自定义View所在...

21450
来自专栏程序员叨叨叨

【Android】手把手教你上滑解锁的效果

最近,公司开发的APP中要实现类似上滑解锁效果的推荐页,捣腾了两天,基本实现了效果,附效果图如上。接下来和大家聊聊如何实现这样的效果。

60320
来自专栏Winter漫聊技术

Android水波动画帮助类,一行代码实现View显示/隐藏/startActivity特效(0.3.1)

So,你可以如下compile该library了,也可以把这个类CircularAnim拷贝到项目里去。

12520
来自专栏计算机编程

点击显示更多文本自定义控件

写在前面的话: 在正常项目流程中,我们很多情况下会碰到点击显示更多文本,这样可以利于页面变化加载,点击显示更多可能会非常常用,现在博主利用自己的闲暇时间来一点一...

17030
来自专栏李蔚蓬的专栏

Material Design 实战 之第四弹 —— 卡片布局

首先这里准备用CardView来填充主题内容, CardView是用于实现卡片式布局效果的重要控件,由appcompat-v7库提供。 实际上,CardVi...

16210
来自专栏项勇

笔记11 | 动态设置TextView的字体大小

23460
来自专栏androidBlog

仿网易新闻的顶部导航指示器

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/details...

17110
来自专栏Android开发小工

自定义View基础(二)View的滑动

在移动设备上,滑动基本是基础特性。不管是用的最多的下拉刷新还是ViewPager,他们的基础都是滑动。View的滑动实现方法也是绚丽的自定义View的基础知识。

7720
来自专栏向治洪

仿支付宝手势密码

这篇来分享一下绘制手势密码的实现(主要是设置手势密码、校验手势密码): 一、大致界面介绍: ? ?                        图1  ...

30470
来自专栏Android小菜鸡

沉浸式状态栏的封装使用

  随着用户要求的不断提高,Android版本的不断升级,沉浸式状态栏似乎已经成为了每个App的必备功能。   首先要实现它我们得先理解他,状态栏不同于标题栏...

31610

扫码关注云+社区

领取腾讯云代金券