Android_水瓶loading和圆环loading

来源:互联网 发布:安利云服务软件 编辑:程序博客网 时间:2024/05/02 19:36

自定义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

1 0
原创粉丝点击