RadarView 雷达图

前言

目前写到的项目在加载过程中需要用到像雷达扫描一样的效果,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 ,可以大概获取到当前白色区域扫描到的位置,根据当前白色区域的位置,更新小圆点的位置就可以基本实现这样的效果了。

最后,项目 Github 地址 ,欢迎 Star ^-^