您的位置:首页 > 产品设计 > UI/UE

Android UI 之自定义RadarView——高仿微信雷达扫描

2015-12-07 17:40 579 查看
最近看了一个视频讲了一种微信雷达扫描的实现方案,借鉴了一下,自己也写一个玩玩,与大家分享一下。基本想出来三种解决方案,根据不同需求情况选择即可。





方案一实现思路(通用):

1.自定义view

2.重写onDraw()方法

3.画四个无锯齿空心圆

4.画以最大圆为半径的实心渐变圆

5.创建矩阵,旋转画布,重绘,并用Handler实现循环

package com.ml512.radarview;

import com.ml512.radardemo.R;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
/**
* 2015/12/06 22:49
* @author ITjianghuxiaoxiong
* http://blog.csdn.net/itjianghuxiaoxiong */
@SuppressLint("DrawAllocation")
public class RadarView extends View {
private int w, h;// 获取控件宽高
private Paint mPaintLine;// 画雷达圆线
private Paint mPaintSolid;// 画雷达渐变实心圆
private Matrix matrix;
private int degrees;
private Handler mHandler = new Handler();
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
degrees++;
matrix.postRotate(degrees, w / 2, h / 2);//旋转矩阵
RadarView.this.invalidate();// 重绘
mHandler.postDelayed(mRunnable, 55);
}
};

public RadarView(Context context) {
this(context, null);
}

public RadarView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

public RadarView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setBackgroundResource(R.drawable.radar_bg);//雷达的背景图片(紫色满天星,可以在微信APP中直接找到图片资源)
initPaint();
mHandler.postDelayed(mRunnable,500);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
w = getMeasuredWidth();//获取view的宽度
h = getMeasuredHeight();//获取view的高度
}

/**
* 初始化画笔
*/
private void initPaint() {
mPaintLine = new Paint();
mPaintLine.setColor(Color.parseColor("#CCA1A1A1"));// 设置画笔
mPaintLine.setStrokeWidth(1);// 设置画笔宽度
mPaintLine.setAntiAlias(true);// 消除锯齿
mPaintLine.setStyle(Style.STROKE);// 设置空心

mPaintSolid = new Paint();
mPaintSolid.setAntiAlias(true);// 消除锯齿
mPaintSolid.setStyle(Style.FILL);//实心圆
matrix = new Matrix();//创建组件
}

@Override
protected void onDraw(Canvas canvas) {
//四个空心圆
canvas.drawCircle(w / 2, h / 2, w / 6, mPaintLine);
canvas.drawCircle(w / 2, h / 2, 5 * w / 14, mPaintLine);
canvas.drawCircle(w / 2, h / 2, 12 * w / 20, mPaintLine);
canvas.drawCircle(w / 2, h / 2, 9 * w / 11, mPaintLine);

//渐变
Shader mShader = new SweepGradient(w / 2, h / 2, Color.TRANSPARENT, Color.parseColor("#33FFFFFF"));
mPaintSolid.setShader(mShader);
canvas.setMatrix(matrix);
canvas.drawCircle(w / 2, h / 2, 9 * w / 11, mPaintSolid);
matrix.reset();//重置矩阵,避免累加,越转越快
super.onDraw(canvas);
}

}


本以为微信也是这么实现的,结果发现透明还是照微信差一点点,继续看微信apk解压的资源文件发现,原来连四个空心圆+实心渐变圆是一张图片,害的我还画了半天调比例。所以就有下面的第二种方案。

方案二实现思路(适用于最大圆直径小于屏幕宽度的情况):

1.四个空心圆+实心圆为一张图片

2.普通ImageView+xml旋转动画





旋转动画:

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

<rotate
android:duration="10000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="-1"
android:toDegrees="359"/>

</set>


repeatCount设置成-1保证循环转动,从0度转到359,duration时长10秒,绕中心点旋转。

加载动画:

// 加载动画
Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.radar_rotate_anim);
LinearInterpolator lin = new LinearInterpolator();// 匀速旋转
rotateAnim.setInterpolator(lin);
ImageView radarImage = (ImageView) findViewById(R.id.image_radar);
radarImage.startAnimation(rotateAnim);

ImageView正常布局就行了,这样就齐活了,就可以用了,但是有个问题,不方便设置让最大的圆直径超过屏幕宽度,可以设置 android:scaleType="centerCrop",但是虽然超出了屏幕,布局效果也微信一至了,但是问题就来了,超出后旋转,图片是长方形的,圆图被截取了,所以这种用法适用于最大圆直径小于屏幕宽度的情况。所以虽然简单但美中不足,于是设想将两种方案结合起来,方案三就诞生了。

方案三实现思路(通用):

1.四个空心圆+实心圆为一张图片

2.自定义ImageView

3.利用方案一的方法用矩阵让image转起来

package com.ml512.radarview;

import com.ml512.radardemo.R;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.os.Handler;
import android.util.AttributeSet;
import android.widget.ImageView;
/**
* 2015/12/06 22:49
* @author ITjianghuxiaoxiong
* http://blog.csdn.net/itjianghuxiaoxiong */
@SuppressLint("DrawAllocation")
public class RadarImageView extends ImageView {
private int w, h;// 获取控件宽高
private Matrix matrix;
private int degrees;
private Handler mHandler = new Handler();
private Runnable mRunnable = new Runnable() {
@Override
public void run() {
degrees++;
matrix.postRotate(degrees, w / 2, h / 2);
RadarImageView.this.invalidate();// 重绘
mHandler.postDelayed(mRunnable, 50);
}
};

public RadarImageView(Context context) {
this(context, null);
}

public RadarImageView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}

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

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
w = getMeasuredWidth();//获取view的宽度
h = getMeasuredHeight();//获取view的高度
}

/**
* 初始化
*/
private void init() {
setBackgroundResource(R.drawable.radar_bg);
matrix = new Matrix();
mHandler.postDelayed(mRunnable,500);
}

@Override
protected void onDraw(Canvas canvas) {
canvas.setMatrix(matrix);
super.onDraw(canvas);
matrix.reset();
}

}
布局引用:

<com.ml512.radarview.RadarImageView
android:id="@+id/image_radar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:padding="15dp"
android:src="@drawable/wx_radar_imgae"/>


很简单吧,好了,以上就是三种实现方案了,根据自己的实际需要选择吧,同时如果有更好的解决方法,也欢迎交流~

Demo源码http://download.csdn.net/detail/itjianghuxiaoxiong/9331925
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: