自定义雷达扫描的实现

最近项目上不忙了,马上也就国庆了,终于有那么一点点的时候可以放松了。

                在gtihub上浏览的时候发现了一个雷达扫描的效果,然后自己学习了下原理,自己动手实践了下。

           

首先实现原理:

(1)基于Matrix 矩阵来实现雷达扫描旋转的问题

(2)基于Android里边渐变的效果来实现扫描的使用不同阶段的颜色透明到扫描颜色的过度

(3)熟练使用矩阵旋转里边的几个方法

Matrix方法中的setRotate()方法会先清除该矩阵,即设为单位矩阵。setTranslate()等方法也是一样的。所以是不能叠加各种效果在一起的。实现不了多效果。所以,如果是想多种效果同时使用的话,用postRotate(), postTranslate()。

下来就可以开始代码的编写了:

package com.example.radarviewdemo;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

/**
 * Created by 郭攀峰 on 2015/8/19.
 */
public class RadarScanView extends View
{
    private static final int DEFAULT_WIDTH = 300;
    private static final int DEFAULT_HEIGHT = 300;

    private int defaultWidth;
    private int defaultHeight;
    private int start;
    private int centerX;
    private int centerY;
    private int radarRadius;
    private int circleColor = Color.parseColor("#f86860");  //圆圈的颜色
    private int radarColor = Color.parseColor("#99f86860"); // 雷达的颜色
    private int tailColor = Color.parseColor("#50f86860");  //扫描的颜色

    private Paint mPaintCircle;
    private Paint mPaintRadar;
    private Matrix matrix;
    private boolean isScan = true;
    private Handler handler = new Handler();
    private Runnable run = new Runnable()
    {
        @Override
        public void run()
        {
        		//通过这个线程来进行刷新雷达的角度 ,这样就让雷达动起来了
            	if (start == 360 || start > 360) {  //这个是要旋转的角度,360度意思是回到了原点
    				start = 0;
    			}
                start += 2;
                Log.e("start_size", start + "");
                matrix = new Matrix();
                matrix.postRotate(start, centerX, centerY);  //旋转
                postInvalidate();     //刷新界面
                handler.postDelayed(run, 10);
        }
    };

    public RadarScanView(Context context)
    {
        super(context);
        init(null, context);
    }

    public RadarScanView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init(attrs, context);
    }

    public RadarScanView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init(attrs, context);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
        //centerX  centerY 使用来确定要绘制的圆的中心点
        centerX = w / 2;
        centerY = h / 2;
        radarRadius = Math.min(w, h);  //半径
    }

    private void init(AttributeSet attrs, Context context)
    {
        if (attrs != null)
        {
            TypedArray ta = context.obtainStyledAttributes(attrs,
                R.styleable.RadarScanView);
            circleColor = ta.getColor(R.styleable.RadarScanView_circleColor, circleColor);
            radarColor = ta.getColor(R.styleable.RadarScanView_radarColor, radarColor);
            tailColor = ta.getColor(R.styleable.RadarScanView_tailColor, tailColor);
            ta.recycle();
        }

        initPaint();
        //得到当前屏幕的像素宽高

        defaultWidth = dip2px(context, DEFAULT_WIDTH);
        defaultHeight = dip2px(context, DEFAULT_HEIGHT);

        matrix = new Matrix();
        handler.post(run);
    }
   /**
    * 设置画笔
    */
    private void initPaint()
    {
        mPaintCircle = new Paint();
        mPaintCircle.setColor(circleColor);
        mPaintCircle.setAntiAlias(true);//抗锯齿
        mPaintCircle.setStyle(Paint.Style.STROKE);//设置实心
        mPaintCircle.setStrokeWidth(2);//画笔宽度

        mPaintRadar = new Paint();
        mPaintRadar.setColor(radarColor);
        mPaintRadar.setAntiAlias(true);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        int resultWidth = 0;
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);

        if (modeWidth == MeasureSpec.EXACTLY)
        {
            resultWidth = sizeWidth;
        }
        else
        {
            resultWidth = defaultWidth;
            if (modeWidth == MeasureSpec.AT_MOST)
            {
                resultWidth = Math.min(resultWidth, sizeWidth);
            }
        }

        int resultHeight = 0;
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        if (modeHeight == MeasureSpec.EXACTLY)
        {
            resultHeight = sizeHeight;
        }
        else
        {
            resultHeight = defaultHeight;
            if (modeHeight == MeasureSpec.AT_MOST)
            {
                resultHeight = Math.min(resultHeight, sizeHeight);
            }
        }

        setMeasuredDimension(resultWidth, resultHeight);
    }

    @Override
    protected void onDraw(Canvas canvas)
    {
        super.onDraw(canvas);

        //分别绘制四个圆
        canvas.drawCircle(centerX, centerY, radarRadius / 7, mPaintCircle);
        canvas.drawCircle(centerX, centerY, radarRadius / 4, mPaintCircle);
        canvas.drawCircle(centerX, centerY, radarRadius / 3, mPaintCircle);
        canvas.drawCircle(centerX, centerY, 3 * radarRadius / 7, mPaintCircle);

        //设置颜色渐变从透明到不透明
        Shader shader = new SweepGradient(centerX, centerY, Color.TRANSPARENT, tailColor);
        mPaintRadar.setShader(shader);
        canvas.concat(matrix);
        canvas.drawCircle(centerX, centerY, 3 * radarRadius / 7, mPaintRadar);
    }

    private int dip2px(Context context, float dipValue)
    {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    private int px2dip(Context context, float pxValue)
    {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (pxValue / scale + 0.5f);
    }

}

  这就是雷达的效果,而里边扫描到的显示的控件下边是实现代码

package com.example.radarviewdemo;
import android.animation.ObjectAnimator;
import android.animation.TypeEvaluator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.animation.LinearInterpolator;
import android.widget.TextView;

/**
 * Created by 10129302 on 15-2-12.
 */
public class RippleView extends TextView
{

    private static final String tag = RippleView.class.getSimpleName();

    private static final int DEFAULT_RIPPLE_COLOR = Color.rgb(0x33, 0x99, 0xcc);
    /**
     * 波纹的颜色
     */
    private int mRippleColor = DEFAULT_RIPPLE_COLOR;
    /**
     * 默认的波纹的最小值
     */
    private int mMinSize = 200;
    /**
     * 波纹动画效果是否正在进行
     */
    private boolean animationRunning = false;

    private int currentProgress = 0;
    /**
     * 动画中波纹的个数
     */
    private int mRippleNum = 4;
    /**
     * //无限长的数值,使动画不停止
     */
    private int mTotalTime = 1000 * 1000;

    public static final int MODE_IN = 1;
    public static final int MODE_OUT = 2;

    private int mode = MODE_OUT;

    private int mPeriod = 30;
    private int mCenterX;
    private int mCenterY;
    private int mRadius;
    private Paint mPaint;
    private ObjectAnimator mAnimator;

    public RippleView(Context context)
    {
        super(context);
        initPaint();
        initAnimation();
    }

    public RippleView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        initPaint();
        initAnimation();
    }

    public RippleView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        initPaint();
        initAnimation();
    }

    private void initPaint()
    {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setColor(mRippleColor);
    }

    private void initAnimation()
    {
        mAnimator = ObjectAnimator.ofInt(this, "currentProgress", 0, 100);
        mAnimator.setRepeatCount(ObjectAnimator.INFINITE);
        mAnimator.setRepeatMode(ObjectAnimator.RESTART);
        mAnimator.setInterpolator(new LinearInterpolator());
        mAnimator.setEvaluator(mProgressEvaluator);
        mAnimator.setDuration(mTotalTime);
    }

    public void setMode(int mode)
    {
        this.mode = mode;
    }

    public void startRippleAnimation()
    {
        if (!animationRunning)
        {
            mAnimator.start();
            animationRunning = true;
        }
    }

    public void stopRippleAnimation()
    {
        if (animationRunning)
        {
            mAnimator.end();
            animationRunning = false;
        }
    }

    public boolean isRippleAnimationRunning()
    {
        return animationRunning;
    }

    public int getCurrentProgress()
    {
        return currentProgress;
    }

    public void setCurrentProgress(int currentProgress)
    {
        this.currentProgress = currentProgress;
        this.invalidate();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh)
    {
        super.onSizeChanged(w, h, oldw, oldh);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
    {
        //super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int resultWidth = 0;
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        if (modeWidth == MeasureSpec.EXACTLY)
        {
            resultWidth = sizeWidth;
        }
        else
        {
            resultWidth = mMinSize;
            if (modeWidth == MeasureSpec.AT_MOST)
            {
                resultWidth = Math.min(resultWidth, sizeWidth);
            }
        }

        int resultHeight = 0;
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        if (modeHeight == MeasureSpec.EXACTLY)
        {
            resultHeight = sizeHeight;
        }
        else
        {
            resultHeight = mMinSize;
            if (modeHeight == MeasureSpec.AT_MOST)
            {
                resultHeight = Math.min(resultHeight, sizeHeight);
            }
        }

        mCenterX = resultWidth / 2;
        mCenterY = resultHeight / 2;
        mRadius = Math.max(resultWidth, resultHeight) / 2;

        Log.d(tag, "ripple out view radius = " + mRadius + "; width =" + resultWidth
            + "; height = " + resultHeight);

        setMeasuredDimension(resultWidth, resultHeight);
    }

    @Override
    public void onDraw(Canvas canvas)
    {
        for (int i = 0; i < mRippleNum; i++)
        {
            int progress = (currentProgress + i * 100 / (mRippleNum)) % 100;
            if (mode == 1)
                progress = 100 - progress;

            mPaint.setAlpha(255 - 255 * progress / 100);
            canvas.drawCircle(mCenterX, mCenterY, mRadius * progress / 100, mPaint);
        }
        super.onDraw(canvas);
    }

    @Override
    protected void onDetachedFromWindow()
    {
        super.onDetachedFromWindow();
        if (isRippleAnimationRunning())
            stopRippleAnimation();
    }

    /**
     * 自定义估值器
     */
    private TypeEvaluator mProgressEvaluator = new TypeEvaluator()
    {

        @Override
        public Object evaluate(float fraction, Object startValue, Object endValue)
        {
            fraction = (fraction * mTotalTime / mPeriod) % 100;
            return fraction;
        }
    };

}

下边就是扫描到的自定义效果RandomTextView

<span style="font-family: Arial;">package com.example.radarviewdemo;</span>
import java.util.LinkedList;
import java.util.Random;
import java.util.Vector;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;

public class RandomTextView extends FrameLayout
    implements
        ViewTreeObserver.OnGlobalLayoutListener
{

    private static final String tag = RandomTextView.class.getSimpleName();

    private static final int MAX = 5;
    private static final int IDX_X = 0;
    private static final int IDX_Y = 1;
    private static final int IDX_TXT_LENGTH = 2;
    private static final int IDX_DIS_Y = 3;
    private static final int TEXT_SIZE = 12;

    private Random random;
    private Vector<String> vecKeywords;
    private int width;
    private int height;
    private int mode = RippleView.MODE_OUT;
    private int fontColor = 0xff0000ff;
    private int shadowColor = 0xdd696969;

    public interface OnRippleViewClickListener
    {
        void onRippleViewClicked(View view);
    }

    private OnRippleViewClickListener onRippleOutViewClickListener;

    public RandomTextView(Context context)
    {
        super(context);
        init(null, context);
    }

    public RandomTextView(Context context, AttributeSet attrs)
    {
        super(context, attrs);
        init(attrs, context);
    }

    public RandomTextView(Context context, AttributeSet attrs, int defStyleAttr)
    {
        super(context, attrs, defStyleAttr);
        init(attrs, context);
    }

    public void setMode(int mode)
    {
        this.mode = mode;
    }

    public void setOnRippleViewClickListener(OnRippleViewClickListener listener)
    {
        onRippleOutViewClickListener = listener;
    }

    /**
     * 添加RippleOutView的内容
     *
     * @param keyword
     */
    public void addKeyWord(String keyword)
    {
        if (vecKeywords.size() < MAX)
        {
            if (!vecKeywords.contains(keyword))
                vecKeywords.add(keyword);
        }
    }

    public Vector<String> getKeyWords()
    {
        return vecKeywords;
    }

    public void removeKeyWord(String keyword)
    {
        if (vecKeywords.contains(keyword))
        {
            vecKeywords.remove(keyword);
        }
    }

    private void init(AttributeSet attrs, Context context)
    {
        random = new Random();
        vecKeywords = new Vector<String>(MAX);
        getViewTreeObserver().addOnGlobalLayoutListener(this);

    }

    @Override
    public void onGlobalLayout()
    {
        int tmpW = getWidth();
        int tmpH = getHeight();
        if (width != tmpW || height != tmpH)
        {
            width = tmpW;
            height = tmpH;
            Log.d(tag, "RandomTextView width = " + width + "; height = " + height);
        }
    }

    public void show()
    {
        this.removeAllViews();

        if (width > 0 && height > 0 && vecKeywords != null && vecKeywords.size() > 0)
        {
            //找到中心点
            int xCenter = width >> 1;
            int yCenter = height >> 1;
            //关键字的个数。
            int size = vecKeywords.size();
            int xItem = width / (size + 1);
            int yItem = height / (size + 1);
            LinkedList<Integer> listX = new LinkedList<Integer>();
            LinkedList<Integer> listY = new LinkedList<Integer>();
            for (int i = 0; i < size; i++)
            {
                // 准备随机候选数,分别对应x/y轴位置
                listX.add(i * xItem);
                listY.add(i * yItem + (yItem >> 2));
            }
            LinkedList<RippleView> listTxtTop = new LinkedList<RippleView>();
            LinkedList<RippleView> listTxtBottom = new LinkedList<RippleView>();

            for (int i = 0; i < size; i++)
            {
                String keyword = vecKeywords.get(i);
                // 随机颜色
                int ranColor = fontColor;
                // 随机位置,糙值
                int xy[] = randomXY(random, listX, listY, xItem);

                int txtSize = TEXT_SIZE;
                // 实例化RippleOutView
                final RippleView txt = new RippleView(getContext());
                if (mode == RippleView.MODE_IN)
                {
                    txt.setMode(RippleView.MODE_IN);
                }
                else
                {
                    txt.setMode(RippleView.MODE_OUT);
                }

                txt.setOnClickListener(new OnClickListener()
                {
                    @Override
                    public void onClick(View view)
                    {
                        if (onRippleOutViewClickListener != null)
                            onRippleOutViewClickListener.onRippleViewClicked(view);
                    }
                });
                txt.setText(keyword);
                txt.setTextColor(ranColor);
                txt.setTextSize(TypedValue.COMPLEX_UNIT_SP, txtSize);
                txt.setShadowLayer(1, 1, 1, shadowColor);
                txt.setGravity(Gravity.CENTER);
                txt.startRippleAnimation();

                // 获取文本长度
                //Paint paint = txt.getPaint();
                int strWidth = /* (int) Math.ceil(paint.measureText(keyword)) */txt
                        .getMeasuredWidth();
                xy[IDX_TXT_LENGTH] = strWidth;
                // 第一次修正:修正x坐标
                if (xy[IDX_X] + strWidth > width - (xItem/* >> 1 */))
                {
                    int baseX = width - strWidth;
                    // 减少文本右边缘一样的概率
                    xy[IDX_X] = baseX - xItem + random.nextInt(xItem >> 1);
                }
                else if (xy[IDX_X] == 0)
                {
                    // 减少文本左边缘一样的概率
                    xy[IDX_X] = Math.max(random.nextInt(xItem), xItem / 3);
                }
                xy[IDX_DIS_Y] = Math.abs(xy[IDX_Y] - yCenter);
                txt.setTag(xy);
                if (xy[IDX_Y] > yCenter)
                {
                    listTxtBottom.add(txt);
                }
                else
                {
                    listTxtTop.add(txt);
                }
            }

            attach2Screen(listTxtTop, xCenter, yCenter, yItem);
            attach2Screen(listTxtBottom, xCenter, yCenter, yItem);
        }
    }

    /** 修正RippleOutView的Y坐标将将其添加到容器上。 */
    private void attach2Screen(LinkedList<RippleView> listTxt, int xCenter, int yCenter,
            int yItem)
    {
        int size = listTxt.size();
        sortXYList(listTxt, size);
        for (int i = 0; i < size; i++)
        {
            RippleView txt = listTxt.get(i);
            int[] iXY = (int[]) txt.getTag();
            // 第二次修正:修正y坐标
            int yDistance = iXY[IDX_Y] - yCenter;
            // 对于最靠近中心点的,其值不会大于yItem<br/>
            // 对于可以一路下降到中心点的,则该值也是其应调整的大小<br/>
            int yMove = Math.abs(yDistance);
            inner : for (int k = i - 1; k >= 0; k--)
            {
                int[] kXY = (int[]) listTxt.get(k).getTag();
                int startX = kXY[IDX_X];
                int endX = startX + kXY[IDX_TXT_LENGTH];
                // y轴以中心点为分隔线,在同一侧
                if (yDistance * (kXY[IDX_Y] - yCenter) > 0)
                {
                    if (isXMixed(startX, endX, iXY[IDX_X], iXY[IDX_X]
                        + iXY[IDX_TXT_LENGTH]))
                    {
                        int tmpMove = Math.abs(iXY[IDX_Y] - kXY[IDX_Y]);
                        if (tmpMove > yItem)
                        {
                            yMove = tmpMove;
                        }
                        else if (yMove > 0)
                        {
                            // 取消默认值。
                            yMove = 0;
                        }
                        break inner;
                    }
                }
            }

            if (yMove > yItem)
            {
                int maxMove = yMove - yItem;
                int randomMove = random.nextInt(maxMove);
                int realMove = Math.max(randomMove, maxMove >> 1) * yDistance
                    / Math.abs(yDistance);
                iXY[IDX_Y] = iXY[IDX_Y] - realMove;
                iXY[IDX_DIS_Y] = Math.abs(iXY[IDX_Y] - yCenter);
                // 已经调整过前i个需要再次排序
                sortXYList(listTxt, i + 1);
            }
            FrameLayout.LayoutParams layParams = new FrameLayout.LayoutParams(
            /* FrameLayout.LayoutParams.WRAP_CONTENT */200,
            /* FrameLayout.LayoutParams.WRAP_CONTENT */200);
            layParams.gravity = Gravity.LEFT | Gravity.TOP;
            layParams.leftMargin = iXY[IDX_X];
            layParams.topMargin = iXY[IDX_Y];
            addView(txt, layParams);
        }
    }

    private int[] randomXY(Random ran, LinkedList<Integer> listX,
            LinkedList<Integer> listY, int xItem)
    {
        int[] arr = new int[4];
        arr[IDX_X] = listX.remove(ran.nextInt(listX.size()));
        arr[IDX_Y] = listY.remove(ran.nextInt(listY.size()));
        return arr;
    }

    /** A线段与B线段所代表的直线在X轴映射上是否有交集。 */
    private boolean isXMixed(int startA, int endA, int startB, int endB)
    {
        boolean result = false;
        if (startB >= startA && startB <= endA)
        {
            result = true;
        }
        else if (endB >= startA && endB <= endA)
        {
            result = true;
        }
        else if (startA >= startB && startA <= endB)
        {
            result = true;
        }
        else if (endA >= startB && endA <= endB)
        {
            result = true;
        }
        return result;
    }

    /**
     * 根据与中心点的距离由近到远进行冒泡排序。
     *
     * @param endIdx 起始位置。
     * @param listTxt 待排序的数组。
     *
     */
    private void sortXYList(LinkedList<RippleView> listTxt, int endIdx)
    {
        for (int i = 0; i < endIdx; i++)
        {
            for (int k = i + 1; k < endIdx; k++)
            {
                if (((int[]) listTxt.get(k).getTag())[IDX_DIS_Y] < ((int[]) listTxt
                        .get(i).getTag())[IDX_DIS_Y])
                {
                    RippleView iTmp = listTxt.get(i);
                    RippleView kTmp = listTxt.get(k);
                    listTxt.set(i, kTmp);
                    listTxt.set(k, iTmp);
                }
            }
        }
    }
}

然后就是Demo:http://download.csdn.net/detail/u012808234/9146709

           

                   

时间: 2024-09-22 12:50:17

自定义雷达扫描的实现的相关文章

Android仿微信、QQ附近好友雷达扫描效果_Android

1.概述 最近一直到在带实习生,因为人比较多,所以很长一段时间没有更新博客了,今天更新一篇雷达扫描附近好友效果,以后尽量每周更新一篇,先看一下效果: 2.实现 1.效果分析 效果分为两个部分,一个是上半部分的自定义RadarView,还有就是下半部分的ViewPager,至于怎么做到缩放和背景虚化的效果大家可以去看看LazyViewPager这里不详细介绍,这里主要实现扫描效果部分. 2.扫描效果实现 2.1自定义RadarView在onDraw()方法中画六个圆圈,至于圆圈的半径是多少我们需要

Android雷达扫描动态界面制作_Android

先看看效果图: 源码: package com.zihao.radar; import android.app.Activity; import android.os.Bundle; import android.view.Window; import android.view.WindowManager; import com.zihao.radar.view.RadarView; public class MainActivity extends Activity { private Rad

Android编程简单实现雷达扫描效果_Android

本文实例讲述了Android编程简单实现雷达扫描效果.分享给大家供大家参考,具体如下: 在eoe看到有一篇关于雷达扫描的文章,然后看了下,很简单,但是觉得还有很多可以优化的地方,下面贴出来 package com.example.wave; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Matrix; im

WPF 自定义雷达图开发实例教程_C#教程

自定义雷达图表如下: 1.创建UserControl,名为"RadarChartControl" 前台: <UserControl x:Class="WpfApplication2.RadarChartControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/win

Android动画之雷达扫描效果

我们首先看一下效果图,有个整体的印象 好了,为了便于理解,这里就按照动画所见内容依次展开来说 准备 这里决定采用canvas(画布)和paint(画笔)实现了这个简单动画控件. 由图片可以看到有两条交叉的十字线.几个圆圈和一些白点,那么首先定义一下所需的画笔,画布及一些数据 setBackgroundColor(Color.TRANSPARENT); //宽度=5,抗锯齿,描边效果的白色画笔 mPaintLine = new Paint(); mPaintLine.setStrokeWidth(

Android仿微信雷达扫描效果的实现方法

本文主要给大家介绍的是关于Android实现微信雷达扫描效果的相关内容,分享出来供大家参考学习,下面来看看详细的介绍: 废话不多说 先上图(用AS录制的 转换工具不是很好 所以看得效果不是很好) 效果图 示例代码 Activity 代码 public class ShapeDrawableActivity extends AppCompatActivity { private ImageView ivLightbeam; private ObjectAnimator radarScanAnim;

PS制作雷达扫描动画

  效果图: 新建个250*200的画布.填充灰色做背景--用椭圆工具画个#bacce5的正圆. 图层样式 现在看起来像个椭圆的饼饼. 咬下去吧!画个颜色是#00387d的蓝色圆圆,要比刚刚的那个饼小一圈-- 继续图层样式-- 把刚刚的那个蓝圆圆复制一层,然后清除掉图层样式,其实我们只是想要一个和蓝圆圆一样大的另一个圆而已. 把清除了图层样式的那个圆的填充设置为0, 图层样式--现在看起来是这样-- 现在画个这个形状像上面白色的东东, 不要问我怎么画,自己想办法--把那个白色的东东设置填充为0%

Android仿微信雷达辐射搜索好友(逻辑清晰实现简单)_Android

不知不觉这个春节也已经过完了,遗憾家里没网,没能及时给大家送上祝福,今天回到深圳,明天就要上班了,小伙伴们是不是和我一样呢?今天讲的是一个大家都见过的动画,雷达搜索好友嘛,原理也十分的简单,你看完我的分析,也会觉得很简单了,国际惯例,无图无真相,我们先看看效果图,对了,真 测试机送人了,所讲这段时间应该一直用模拟器显示吧! 仿微信雷达扫描,仿安卓微信.云播雷达扫描动画效果点击中间的黑色圆圈开始扫描动画,再次点击复位,需要这种效果的朋友可以自己下载看一下. 效果图如下所示: 这个界面相信大家都认识

Android仿微信雷达辐射搜索好友(逻辑清晰实现简单)

不知不觉这个春节也已经过完了,遗憾家里没网,没能及时给大家送上祝福,今天回到深圳,明天就要上班了,小伙伴们是不是和我一样呢?今天讲的是一个大家都见过的动画,雷达搜索好友嘛,原理也十分的简单,你看完我的分析,也会觉得很简单了,国际惯例,无图无真相,我们先看看效果图,对了,真 测试机送人了,所讲这段时间应该一直用模拟器显示吧! 仿微信雷达扫描,仿安卓微信.云播雷达扫描动画效果点击中间的黑色圆圈开始扫描动画,再次点击复位,需要这种效果的朋友可以自己下载看一下. 效果图如下所示: 这个界面相信大家都认识