前言
目前写到的项目在加载过程中需要用到像雷达扫描一样的效果,UI小哥(也就是美工)给了一百张各个时间的图片,要我用动画切换图片完成…我觉得作为个程序员,这种效果还是尽量用代码完成,所以就有了这篇博客。
效果图
分析
根据上面的 Gif 可以看出,扫描时雷达的扫描范围为一个圆形,同时有个白色区域一直旋转。雷达搜索的小圆点是随机出现在扫描的圆形范围内的,小圆点的大小随机,透明度逐渐提高,并且出现在雷达扫描线中白色区域扫描后的位置中。
开始之前先要感谢这篇博客的帮助,在看本篇博客之前也可以先看下这篇博客了解下绘制的方法,当然,在下面我也会进行逐步解析……
核心代码
首先根据前面分析的内容,定义小圆点类如下:
public class StarModel {
public float sizePercent;
public int xLocation;
public int yLocation;
public float alpha;
public float twinkleRate;
public int currentLocation;
//此处省略 get set 方法
......
}
其中 sizePercent 为缩放比例,xLocation、yLocation 为小圆点 x、y 坐标,alpha 为透明度,
twinkleRate 为透明度变化的速率。
首先实现小圆点随机在不同位置出现,因为要在顶部半透明圆的白色区域刚刚扫描过的位置出现小圆点,我做了一个处理,把坐标分为四组,分别为:左上、左下、右上、右下。这样可以尽可能的控制小圆点在指定位置显示。
//左上角
private static final float[][] STAR_LOCATION_LEFT_TOP = new float[][]{
{0.2f, 0.3f}, {0.22f, 0.361f}, {0.298f, 0.32f},{0.28f, 0.26f}};
//右下角
private static final float[][] STAR_LOCATION_RIGHT_DOWN = new float[][]{
{0.822f, 0.612f}, {0.722f, 0.76f}, {0.698f, 0.692f},{0.628f, 0.826f}};
//右上角
private static final float[][] STAR_LOCATION_RIGHT_TOP = new float[][]{
{0.612f, 0.3f}, {0.712f, 0.41f}, {0.32f, 0.598f},{0.26f, 0.789f}};
//左下角
private static final float[][] STAR_LOCATION_LEFT_DOWN = new float[][]{
{0.2f, 0.823f}, {0.22f, 0.6791f}, {0.298f, 0.62f},{0.28f, 0.826f}, {0.28f, 0.626f}};
这里的实际上是把视图的宽高分别与上面的值相乘,得到对应坐标。
随机大小通过 Radom 函数来实现,这里的透明度变化速率已经通过代码设置成了固定的值,绘制时通过改变 paint 的 alpha 可以对透明度进行控制
paint.setAlpha((int) (starAlpha * 255));
最上层滚动的半透明圆是通过在线程中不断改变 Matrix 的角度使图片不断旋转,关键代码如下:
//开启线程,不断更新顶部半透明圆的角度
new Thread(){
@Override
public void run() {
super.run();
while (true) {
synchronized (starModels) {
angle = angle % 360;
angle += 6;
if (starModels != null && starModels.size() > 0) {
for (int i = 0; i < starModels.size(); i++) {
resetStarFloat(starModels.get(i));
}
postInvalidate();
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
}.start();
//根据旋转角度 angle 重新绘制最上层半透明圆
matrix.setRotate(angle, mRadarWidth / 2, mRadarHeight / 2);
canvas.drawBitmap(mRadar, matrix, null);
绘制小圆点和顶部的原型图片的代码如下:
private void drawStarDynamic(int count, StarModel starModel, Canvas canvas, Paint paint) {
float starAlpha = starModel.getAlpha();
int xLocation = starModel.getxLocation();
int yLocation = starModel.getyLocation();
float sizePercent = starModel.getSizePercent();
xLocation = (int) (xLocation / sizePercent);
yLocation = (int) (yLocation / sizePercent);
if(xLocation == 0 || yLocation == 0) {
return;
}
Bitmap bitmap;
Rect srcRect;
Rect destRect = new Rect();
if (count % 3 == 0) {
bitmap = mStarOne;
srcRect = mStarOneSrcRect;
destRect.set(xLocation, yLocation,
xLocation + mStarOneWidth, yLocation
+ mStarOneHeight);
} else if (count % 2 == 0) {
bitmap = mStarThree;
srcRect = mStarThreeSrcRect;
destRect.set(xLocation, yLocation, xLocation
+ mStarThreeWidth, yLocation + mStarThreeHeight);
} else {
bitmap = mStarTwo;
srcRect = mStarTwoSrcRect;
destRect.set(xLocation, yLocation, xLocation
+ mStarTwoWidth, yLocation + mStarTwoHeight);
}
paint.setAlpha((int) (starAlpha * 255));
canvas.save();
canvas.scale(sizePercent, sizePercent);
canvas.drawBitmap(bitmap, srcRect, destRect, paint);
canvas.restore();
}
在这里说明下,小圆点需要在白色区域扫过时显示,这张顶部的圆形半透明图片的白线是在右侧水平位置的,根据图片的角度 angle ,可以大概获取到当前白色区域扫描到的位置,根据当前白色区域的位置,更新小圆点的位置就可以基本实现这样的效果了。