Android_水瓶loading和圆环loading


自定义Loading套路

一般自定义loading都是重写dialog,修改dialog内部的contentview,
先看下效果图,

这里写图片描述

demo里面包含了两个小loading,今天的目标就是实现这个两个小玩意,

  • 描写自定义类,继承dialog,
  • 在oncreat中设置外面传递过来的自定义view,
  • 在builder属性中,给外面的dialog设置属性
  • 这里我们模仿Android系统的做法用建造者模式来配置属性

下面看下dialog的代码,

public class ATWaterDialog extends Dialog {
// 提供配置dialog的一些属性
    private Context mContext;
    private int mLoadingViewLayout;
    private String mLoadingDesc;
    private boolean mCancelable;
    private boolean mOutsideCancelable;
    private TextView mTextView;

// 因为我们要用建造者模式,构造函数需要私有化
    private ATWaterDialog(Context context) {
        this(context, 0);
    }
// 提供接受建造者的,构造函数,不对外公开,给builder用的
    private ATWaterDialog(Builder builder) {
        this(builder.mContext, 0);
        mContext = builder.mContext;
        mLoadingViewLayout = builder.mLoadingViewLayout;
        mLoadingDesc = builder.mLoadingDesc;
        mCancelable = builder.mCancelable;
        mOutsideCancelable = builder.mOutsideCancelable;
    }

    private ATWaterDialog(Context context, int themeResId) {
        super(context, R.style.Translucent_NoTitle);
    }

下面是建造者的代码

    public static class Builder {
        private Context mContext;
        private int mLoadingViewLayout;
        private String mLoadingDesc;
        private boolean mCancelable;
        private boolean mOutsideCancelable;

// 构造函数中传入必传参数,这里我们dialog需要拿到context和外面的view布局
        public Builder(Context context, int loadingViewLayout) {
            mContext = context;
            mLoadingViewLayout = loadingViewLayout;
        }

        public Builder loadingDesc(String loadingDesc) {
            this.mLoadingDesc = loadingDesc;
            return this;
        }

        public Builder cancelable(boolean cancelable) {
            this.mCancelable = cancelable;
            return this;
        }

        public Builder outsideCancelable(boolean outsideCancelable) {
            this.mOutsideCancelable = outsideCancelable;
            return this;
        }
// 建造者用dialog接受他自己的方法,构造出来一个dialog
        public ATWaterDialog build() {
            return new ATWaterDialog(this);
        }
    }

下面就是给dialog设置样子,就是我们外面传递过来的layout

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 这里很简单就是在dialog onCreate中设置布局填充dialog
        setContentView(mLoadingViewLayout);
        mTextView = (TextView) findViewById(R.id.tv_gif_oading_desc);
        if (null != mTextView) {
            mTextView.setText(mLoadingDesc);
        }
        setCancelable(mCancelable);
        setCanceledOnTouchOutside(mOutsideCancelable);
    }

最后使用的我们的dialog

//有没有很简单像造房子一样,建造各种门,床,窗户,最后show就行了
  atWaterDialog = new ATWaterDialog.Builder(this, R.layout.dialog_water_loading)
                .cancelable(true)
                .outsideCancelable(true)
                .loadingDesc("我擦,加载....")
                .build();

所以自定义dialog的时候,其实还是自定义view,


下面我们看下水瓶子的View如何实现

自定义view的过程都老生常谈的话题了,套路就不写了,

  • 自定义属性
  • 获取属性
  • 测量
  • 绘制

这里用的一个知识点就是画笔的绘制模式,那张景点的图大家都不陌生我就不copy了,我们把外面传递过来的水瓶子bitmap绘制到画布上,

在绘制之前,先把画布用橡皮擦,擦成透明的,然后把水瓶画上去,
这个时候就是一个透明的画布上面有一个空瓶子,

这时候我们绘制水流,用贝塞尔曲线绘制path,

然后画笔的图层模式设置成SRC_IN,就是绘制的水波和瓶子相交的时候,我们取上层,这样就留下了瓶子样式的水流,并且根据水波的Y值一直变动

    private void drawTargetBitmap() {
        path.reset();
        bg.eraseColor(getResources().getColor(android.R.color.transparent));
        // 当控制点的x坐标大于或等于终点x坐标时更改标识值
        if (controlX >= defW) {
            isIncrease = false;
        }
        // 当控制点的x坐标小于或等于起点x坐标时更改标识值
        else if (controlX <= 0) {
            isIncrease = true;
        }

        // 根据标识值判断当前的控制点x坐标是该加还是减
        controlX = isIncrease ? controlX + 10 : controlX - 10;
        if (controlY >= 0) {
            // 波浪上移
            controlY -= 1;
            waveY -= 1;
        } else {
            // 超出则重置位置
            waveY = WAVEY_SCALE * defH;
            controlY = CONTROLY_SCALE * defH;
        }

        // 贝塞尔曲线的生成
        path.moveTo(0, waveY);
        // 两个控制点通过controlX,controlY生成
        path.cubicTo(controlX / 2, waveY - (controlY - waveY), (controlX + defW) / 2, controlY, defW, waveY);
        // 与下下边界闭合
        path.lineTo(defW, defH);
        path.lineTo(0, defH);
        // 进行闭合
        path.close();
        mCanvas.drawBitmap(mBitmap, 0, 0, paint);
        paint.setXfermode(porterDuffXfermode);
        mCanvas.drawPath(path, paint);
        paint.setXfermode(null);
    }

然后在onDraw里面,把我们绘制的水流画布放到系统的canvas里面

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawTargetBitmap();
        //这里直接把我们自己创建的bitmap放到系统的canvas里面,因为变化都在这里
        canvas.drawBitmap(bg, getPaddingLeft(), getPaddingTop(), null);
        if (isReflesh) {
            invalidate();
        }
    }

主要的就是画笔模式的使用,和一个path的使用


圆环的view就更简单了,

  • 提供自定义属性圆环宽度
  • 距离view的外边距距离
  • 绘制圆环

    OK完成了


圆环的知识点就一个画笔的阴影模式,以及如何让绘制的圆环动起来

  • 阴影模式
// 这里有四种模式有兴趣的可以看下源代码继承结构树
        circlePaint.setShader(new SweepGradient(viewWidth, viewHeight, doughnutColors, null));
  • 圆环的旋转,这里因为我们背景是圆角矩形,圆形都是我们绘制了,
  • 所以我们作用动画的时候不能给view设置,因为那样圆形的矩形也会旋转,
  • 所以我们在绘制圆角背景后,旋转画布,然后绘制圆环这样圆环就东西来了—哈哈

代码如下:

//绘制背景
   canvas.drawRoundRect(rectBg, circleCorner, circleCorner, bgPaint);
   //旋转画布
        canvas.rotate(rotateDegree, viewWidth / 2, viewHeight / 2);
        //绘制圆环
        canvas.drawArc(oval, 90, 360, false, circlePaint);

属性动画提供画布旋转的偏移量

    private void getValAniamtion() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.F);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator valueAnimator) {
                rotateDegree = 360 * Float.valueOf(valueAnimator.getAnimatedValue().toString());
                invalidate();
            }
        });
        valueAnimator.setDuration(800);
        valueAnimator.setInterpolator(new LinearInterpolator());
        valueAnimator.setRepeatMode(ValueAnimator.RESTART);
        valueAnimator.setRepeatCount(ValueAnimator.INFINITE);
        valueAnimator.start();
    }

到此我们的dialog就自定义完毕了,荆轲刺秦王_end


源码下载地址,多多star谢谢https://github.com/GuoFeilong/ATLoading

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值