Android UI 之自定義RadarView——高仿微信雷達掃描
阿新 • • 發佈:2019-02-12
最近看了一個視訊講了一種微信雷達掃描的實現方案,借鑑了一下,自己也寫一個玩玩,與大家分享一下。基本想出來三種解決方案,根據不同需求情況選擇即可。
方案一實現思路(通用):
1.自定義view
2.重寫onDraw()方法
3.畫四個無鋸齒空心圓
4.畫以最大圓為半徑的實心漸變圓
5.建立矩陣,旋轉畫布,重繪,並用Handler實現迴圈
[java] view plain copy print?- 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")
- publicclass RadarView extends View {
- privateint w, h;// 獲取控制元件寬高
- private Paint mPaintLine;// 畫雷達圓線
- private Paint mPaintSolid;
- private Matrix matrix;
- privateint degrees;
- private Handler mHandler = new Handler();
- private Runnable mRunnable = new Runnable() {
- @Override
- publicvoid 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
- protectedvoid onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- w = getMeasuredWidth();//獲取view的寬度
- h = getMeasuredHeight();//獲取view的高度
- }
- /**
- * 初始化畫筆
- */
- privatevoid 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
- protectedvoid 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);
- }
- }
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旋轉動畫
旋轉動畫:
[html] view plain copy print?- <?xmlversion="1.0"encoding="utf-8"?>
- <setxmlns: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>
<?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秒,繞中心點旋轉。
載入動畫:
[java] view plain copy print?- // 載入動畫
- 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);
// 載入動畫
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轉起來 [java] view plain copy print?- 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")
- publicclass RadarImageView extends ImageView {
- privateint w, h;// 獲取控制元件寬高
- private Matrix matrix;
- privateint degrees;
- private Handler mHandler = new Handler();
- private Runnable mRunnable = new Runnable() {
- @Override
- publicvoid 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
- protectedvoid onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- w = getMeasuredWidth();//獲取view的寬度
- h = getMeasuredHeight();//獲取view的高度
- }
- /**
- * 初始化
- */
- privatevoid init() {
- setBackgroundResource(R.drawable.radar_bg);
- matrix = new Matrix();
- mHandler.postDelayed(mRunnable,500);
- }
- @Override
- protectedvoid onDraw(Canvas canvas) {
- canvas.setMatrix(matrix);
- super.onDraw(canvas);
- matrix.reset();
- }
- }
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();
}
}
佈局引用:
[html]
view plain
copy
print?
- <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"/>
<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