写点什么

Android 自定义 View 之 LeavesLoading,移动开发工程师考试

用户头像
Android架构
关注
发布于: 刚刚

leaf.startTime = currentTime + new Random().nextInt((int)mLeafFloatTime);leaf.x = mProgressLen;leaf.y = getLeafLocationY(leaf);}}


要想让 Leaf 飘动轨迹为正弦函数,关键在于确定 Leaf 的 Y 轴坐标:


/**


  • 获取叶子的 Y 轴坐标

  • @param leaf 叶子

  • @return 经过计算的叶子 Y 轴坐标*/private float getLeafLocationY(Leaf leaf){float w = (float) (Math.PI * 2 / mProgressLen);//角频率 float A;//计算振幅值 switch (leaf.type){case LITTLE:A = mLeafLen/3;break;case MIDDLE:A = mLeaf


《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
浏览器打开:qq.cn.hn/FTe 免费领取
复制代码


Len*2/3;break;default:A = mLeafLen;break;}// (mHeight-mLeafLen)/2 是为了让 Leaf 的 Y 轴起始位置居中 return (float) (A * Math.sin(w * leaf.x + leaf.n)+(mHeight-mLeafLen)/2);}

3.3 叶子飘动时自旋转

这里就涉及到了 Leaf 的绘制,其实 Gif 中的叶子和风扇都可以使用 Canves 直接绘制图案,但是这样就会有两个问题:


  1. 难画:想要画出满意图形,并且还要旋转、缩放、平移可要下一番功夫。

  2. 灵活性低:如果想换其他样式又得重新设计绘制过程。


因此这里采用 Canves.drawBitmap() 的方式绘制,直接使用已有的图片作为叶子和风扇,同时利用 Canves.drawBitmap() 的一个重载的方法可以很方便的实现旋转、缩放、平移:


void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) ;


就是通过这里的 Matrix 矩阵,它内部封装了 postScale()postTranslatepostRotate() 等方法,可以帮助我们快速的对 Bitmap 进行旋转、缩放、平移还有其他操作。使用时要记得配合 Canves 的 save()restore() 使用,否则达不到想要的效果。


对这方面不熟的朋友可以看看 HenCoder 的自定义 View 教学 1-4


绘制 Leaf 的方法:


private void drawLeaves(Canvas canvas){long currentTime = System.currentTimeMillis();for (Leaf leaf : mLeafList) {if (currentTime > leaf.startTime && leaf.startTime != 0){// 获取 leaf 当前的坐标 getLeafLocation(leaf,currentTime);canvas.save();Matrix matrix = new Matrix();// 缩放 自适应 View 的大小 float scaleX = (float) mLeafLen / mLeafBitmapWidth;float scaleY = (float) mLeafLen / mLeafBitmapHeight;matrix.postScale(scaleX,scaleY);// 位移 float transX = leaf.x;float transY = leaf.y;matrix.postTranslate(transX,transY);// 旋转// 计算旋转因子 float rotateFraction = ((currentTime - leaf.startTime) % mLeafRotateTime)/(float)mLeafRotateTime;float rotate;switch (leaf.rotateDir){case CLOCKWISE://顺时针 rotate = rotateFraction * 360 + leaf.rotateAngle;break;default://逆时针 rotate = -rotateFraction * 360 + leaf.rotateAngle;break;}// 旋转中心选择 Leaf 的中心坐标 matrix.postRotate(rotate,transX + mLeafLen / 2,transY + mLeafLen / 2);canvas.drawBitmap(mLeafBitmap,matrix,mBitmapPaint);canvas.restore();}}

3.4 Loading == 100% 出现动画

增加一个判断字段 isLoadingCompleted ,在 onDraw() 中选择对应绘制策略。


isLoadingCompleted 在 setProgress() 中根据 progress 设置:


/**


  • 设置进度(自动刷新)

  • @param progress 0-100*/public void setProgress(int progress){if (progress < 0){mProgress = 0;}else if (progress > 100){mProgress = 100;}else {mProgress = progress;}if (progress == 100){isLoadingCompleted = true;}else {isLoadingCompleted = false;}// 255 不透明 mCompletedFanPaint.setAlpha(255);postInvalidate();}


LeavesLoading.onDraw() 部分实现:


@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);......if (isLoadingCompleted){//绘制加载完成特效 drawCompleted(canvas);}else {//绘制扇叶 drawFan(canvas,mFanLen,mBitmapPaint);}//刷新 postInvalidate();}


drawCompleted() 实现:

private void drawCompleted(Canvas canvas) {// 每次绘制风扇透明度递减 10int alpha = mCompletedFanPaint.getAlpha() - 10;if (alpha <= 0){alpha = 0;}mCompletedFanPaint.setAlpha(alpha);// 文字透明度刚好与风扇相反 mCompletedTextPaint.setAlpha(255-alpha);// 计算透明因子 float fraction = alpha / 255f;// 叶片大小 和 文字大小 也是相反变化的 float fanLen = fraction * mFanLen;float textSize = (1 - fraction) * mCompletedTextSize;mCompletedTextPaint.setTextSize(textSize);//测量文字占用空间 Rect bounds = new Rect();mCompletedTextPaint.getTextBounds(LOADING_COMPLETED,0,LOADING_COMPLETED.length(),bounds);// 与 drawLeaf() 相似,不再赘述 drawFan(canvas, (int) fanLen, mCompletedFanPaint);//画文字 canvas.drawText(LOADING_COMPLETED,0,LOADING_COMPLETED.length(),mFanCx-bounds.width()/2f,mFanCy+bounds.height()/2f,mCompletedTextPaint);}流程:计算风扇和文字透明度 -> 计算风扇和文字大小以及文字占用空间 -> 绘制 ,注释写得比较清楚就不赘述了。4. 结束

文章中如有出现任何错误,欢迎大家到评论区留言指正。如果觉得 LeavesLoading 对您有任何帮助,希望可以在 GitHub 得到您的 Star !Thanks:

用户头像

Android架构

关注

还未添加个人签名 2021.10.31 加入

还未添加个人简介

评论

发布
暂无评论
Android 自定义 View 之 LeavesLoading,移动开发工程师考试