Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android仿新浪微博雷達掃描效果

Android仿新浪微博雷達掃描效果

編輯:關於Android編程

之前在新浪微博看到一個雷達效果,可以查看圖

先說說這個效果

1.程序默認提示點擊雷達,開始探索

2.當點擊雷達,提示正在探索周邊的人,同時展示雷達掃描效果,即雷達按鈕繞中心旋轉,展現波紋達到掃描效果,

3.當觸摸雷達時,雷達按鈕會縮小,然後手指離開時,雷達按鈕會縮回原位

4.最後如果掃描到周邊的人,卡片顯示周邊人的信息,如果沒有掃描到,則提示未能探索到周邊的人,請稍後再試,同時關閉掃描效果

這裡就不卡片展示周邊人這個效果,畢竟是仿制,我們只需要關注動畫效果,所以做個每兩秒執行掃描效果一周,執行3遍顯示為沒有搜索到周邊的人就行了

說說當中的技術點

1.首先是要熟悉canvas,paint,,其中canvas的畫圓,畫圖片(之所以要熟悉畫圖片,是因為我們有四張圖來顯示成按鈕,這四張圖從新浪微博的app裡獲取,估計它也是這麼干的),畫文字等要熟悉。

2.雷達按鈕繞中心旋轉,這就要涉及到矩陣了,因為雷達按鈕繞中心旋轉,實際上也是對圖片進行旋轉操作,這樣的話Matrix就比較合適了,至於旋轉的角度怎麼得到,用ValueAnimator比較合適,它可以在你設定的時間內,獲取到你設定的兩個值(這裡指旋轉角度,0,到360)之間的速率的變化值,然後刷新View的旋轉角度就可以達到旋轉的效果了

3.雷達按鈕的縮放,原理同旋轉,只不過我們關注的是縮放的比率而已

4.雷達的掃描效果,這個可以具體看看微博的效果,它是首先啟動灰色波紋效果,沒多久白色波紋效果與灰色效果同時抵達,就像波浪,後邊的波浪把前一次波浪沖抵,當到達一定程度的時候顯示灰色線波紋,達到波浪消失的效果,這裡灰色波浪與白色波浪的沖抵效果,我用到了ValueAnimator裡的Interpolator,其中分別為灰色波紋為減速DecelerateInterpolator,白色為AccelerateInterpolator,灰色線波紋為LinearInterpolator,一個減速,一個加速,達到追擊的效果,一個線性,達到逐漸消失的效果

來看看我們的效果圖,請查看附件:

gif錄制效果不是很好,大家會給大家提供鏈接,自行下載查看效果

現在上自定義源碼:

package com.RadarScanView.app;

import android.animation.Animator;

import android.animation.AnimatorListenerAdapter;

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Matrix;

import android.graphics.Paint;

import android.graphics.Rect;

import android.os.Looper;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.view.animation.AccelerateInterpolator;

import android.view.animation.DecelerateInterpolator;

import android.view.animation.LinearInterpolator;

/**

* Created by Administrator on 2015/8/31.

*/

public class RadarScanView extends View {

//默認掃描圖標

private Bitmap mIconScanBitmap;

//掃描時圖標

private Bitmap mIconScaningBitmap;

//白色掃描圖

private Bitmap mScanBitmap;

//黑色掃描背景

private Bitmap mScanBackgroundBitmap;

//掃描按鈕區域

private Rect mButtonArea = new Rect();

//縮放矩陣

private Matrix mScaleMatrix = new Matrix();

//旋轉矩陣

private Matrix mRotateMatrix = new Matrix();

//掃描圖標旋轉動畫

private ValueAnimator mRotateAnimator = new ValueAnimator();

//手指點擊時白色掃描圖片縮小動畫

private ValueAnimator mScaleMinAnimator = new ValueAnimator();

//手指放開時白色掃描圖片放大動畫

private ValueAnimator mScaleMaxAnimator = new ValueAnimator();

//掃描波紋灰色線動畫

private ValueAnimator mOutGrayAnimator = new ValueAnimator();

//掃描波紋白色動畫

private ValueAnimator mInnerWhiteAnimator = new ValueAnimator();

//掃描波紋灰色動畫

private ValueAnimator mBlackAnimator = new ValueAnimator();

//畫筆

private Paint mOutGrayPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

private Paint mInnerWhitePaint = new Paint(Paint.ANTI_ALIAS_FLAG);

private Paint mBlackPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

//掃描圖標旋轉角度

private float mRotateDegree;

//縮放比例,默認1:1

private float mScaleRatio = 1;

//設定自定義View半徑

private int mRadius;

//掃描波紋灰色線半徑

private float mOutGrayRadius = 0;

//掃描波紋白色部分半徑

private float mInnerWhiteRadius = 0;

//掃描波紋灰色部分半徑

private float mBlackRadius = 0;

//默認掃描文字提示

private String mTipText = "點擊雷達,開始探索";

//測量掃描文字提示邊界

private Rect mTextBound = new Rect();

//是否點擊按鈕,默認沒有點擊

private boolean isButtonClick = false;

public RadarScanView(Context context) {

this(context, null);

}

public RadarScanView(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}

public RadarScanView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

//加載圖片

mIconScanBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.radar_button_icon_scan);

mIconScaningBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.radar_button_icon_scaning);

mScanBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.radar_button_scan);

mScanBackgroundBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.radar_button_scan_background);

//初始化畫筆

initViewPaint();

}

private void initViewPaint() {

mOutGrayPaint.setStrokeWidth(4f);

mOutGrayPaint.setColor(Color.rgb(228, 228, 228));

mOutGrayPaint.setDither(true);

mOutGrayPaint.setStyle(Paint.Style.STROKE);

mInnerWhitePaint.setStrokeWidth(1f);

mInnerWhitePaint.setColor(Color.rgb(241, 241, 241));

mInnerWhitePaint.setDither(true);

mInnerWhitePaint.setStyle(Paint.Style.FILL);

mBlackPaint.setStrokeWidth(1f);

mBlackPaint.setColor(Color.rgb(228, 228, 228));

mBlackPaint.setDither(true);

mBlackPaint.setStyle(Paint.Style.FILL);

mTextPaint.setTextSize(37f);

mTextPaint.setColor(Color.rgb(185, 185, 185));

mTextPaint.setDither(true);

mTextPaint.setStyle(Paint.Style.FILL);

}

@Override

public boolean onTouchEvent(MotionEvent event) {

switch (event.getActionMasked()) {

case MotionEvent.ACTION_DOWN:

//當按鈕只有在圖片即按鈕區域內則認定為點擊,不作點擊

isButtonClick = false;

if (mButtonArea.contains((int) event.getX(), (int) event.getY())) {//手指按下,執行縮小動畫

if (!mScaleMinAnimator.isRunning() && !mScaleMaxAnimator.isRunning() && !mRotateAnimator.isRunning()) {//如果動畫正在執行則不執行動畫

isButtonClick = true;

//點擊了按鈕,啟動白色圖片縮小動畫

mScaleMinAnimator.start();

}

}

break;

case MotionEvent.ACTION_CANCEL:

break;

case MotionEvent.ACTION_MOVE:

break;

case MotionEvent.ACTION_UP:

if (isButtonClick) {

//當點擊了按鈕,啟動白色圖片放大動畫與掃描圖片旋轉動畫

if (!mScaleMaxAnimator.isRunning()) {//如果動畫正在執行則不執行動畫

mScaleMaxAnimator.start();

}

if (!mRotateAnimator.isRunning()) {//如果動畫正在執行則不執行動畫

mRotateAnimator.start();

}

}

break;

}

return true;

}

private void initScaleMinAnimator() {

mScaleMinAnimator.setFloatValues(mRadius, mRadius * 0.87f);

mScaleMinAnimator.setDuration(500);

mScaleMinAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mScaleRatio = ((Float) animation.getAnimatedValue()) / mRadius;

invalidateView();

}

});

}

private void initScaleMaxAnimator() {

mScaleMaxAnimator.setFloatValues(mRadius * 0.87f, mRadius);

mScaleMaxAnimator.setDuration(500);

mScaleMaxAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mScaleRatio = ((Float) animation.getAnimatedValue()) / mRadius;

invalidateView();

}

});

}

private void initRoateAnimator() {

mRotateAnimator.setFloatValues(0, 360);

mRotateAnimator.setDuration(2000);

//重復三次,模仿正在掃描

mRotateAnimator.setRepeatCount(3);

mRotateAnimator.setInterpolator(new LinearInterpolator());

mRotateAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mRotateDegree = (Float) animation.getAnimatedValue();

invalidateView();

}

});

mRotateAnimator.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationStart(Animator animation) {

super.onAnimationStart(animation);

mTipText = "正在探索周邊的人...";

//旋轉動畫啟動後啟動掃描波紋動畫

mOutGrayAnimator.start();

mInnerWhiteAnimator.start();

mBlackAnimator.start();

}

@Override

public void onAnimationEnd(Animator animation) {

super.onAnimationEnd(animation);

//取消掃描波紋動畫

mOutGrayAnimator.cancel();

mInnerWhiteAnimator.cancel();

mBlackAnimator.cancel();

//重置界面要素

mOutGrayRadius = 0;

mInnerWhiteRadius = 0;

mBlackRadius = 0;

mTipText = "未能探索到周邊的人,請稍後再試";

invalidateView();

}

});

}

private void initOutGrayAnimator() {

mOutGrayAnimator.setFloatValues(mBlackRadius, getMeasuredWidth() / 2);

mOutGrayAnimator.setDuration(1000);

mOutGrayAnimator.setRepeatCount(-1);

mOutGrayAnimator.setInterpolator(new LinearInterpolator());

mOutGrayAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mOutGrayRadius = (Float) animation.getAnimatedValue();

}

});

}

private void initInnerWhiteAnimator() {

mInnerWhiteAnimator.setFloatValues(0, getMeasuredWidth() / 3);

mInnerWhiteAnimator.setDuration(1000);

mInnerWhiteAnimator.setRepeatCount(-1);

mInnerWhiteAnimator.setInterpolator(new AccelerateInterpolator());

mInnerWhiteAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mInnerWhiteRadius = (Float) animation.getAnimatedValue();

}

});

}

private void initBlackAnimator() {

mBlackAnimator.setFloatValues(0, getMeasuredWidth() / 3);

mBlackAnimator.setDuration(1000);

mBlackAnimator.setRepeatCount(-1);

mBlackAnimator.setInterpolator(new DecelerateInterpolator());

mBlackAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

mBlackRadius = (Float) animation.getAnimatedValue();

}

});

}

@Override

protected void onSizeChanged(int w, int h, int oldw, int oldh) {

super.onSizeChanged(w, h, oldw, oldh);

//掃描按鈕區域,取自掃描灰色背景圖片區域即可

mButtonArea.set(getMeasuredWidth() / 2 - mScanBackgroundBitmap.getWidth() / 2, getMeasuredHeight() / 2 - mScanBackgroundBitmap.getHeight() / 2, getMeasuredWidth() / 2 +

mScanBackgroundBitmap

.getWidth() / 2, getMeasuredHeight() / 2 + mScanBackgroundBitmap.getHeight() / 2);

//View半徑,取自View寬高最小者

mRadius = mScanBitmap.getWidth() / 2 > mScanBitmap.getHeight() / 2 ? mScanBitmap.getHeight() / 2 : mScanBitmap.getWidth() / 2;

//初始化動畫

initScaleMinAnimator();

initScaleMaxAnimator();

initRoateAnimator();

initBlackAnimator();

initInnerWhiteAnimator();

initOutGrayAnimator();

}

@Override

protected void onDraw(Canvas canvas) {

//繪制波紋

canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, mBlackRadius, mBlackPaint);

canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, mInnerWhiteRadius, mInnerWhitePaint);

canvas.drawCircle(getMeasuredWidth() / 2, getMeasuredHeight() / 2, mOutGrayRadius, mOutGrayPaint);

//繪制背景

Bitmap mScanBgBitmap = getScanBackgroundBitmap();

if (mScanBgBitmap != null) {

canvas.drawBitmap(mScanBgBitmap, getMeasuredWidth() / 2 - mScanBgBitmap.getWidth() / 2, getMeasuredHeight() / 2 - mScanBgBitmap.getHeight() / 2, new Paint(Paint

.ANTI_ALIAS_FLAG));

}

//繪制按鈕背景

Bitmap mButtonBgBitmap = getButtonBackgroundBitmap();

canvas.drawBitmap(mButtonBgBitmap, getMeasuredWidth() / 2 - mButtonBgBitmap.getWidth() / 2, getMeasuredHeight() / 2 - mButtonBgBitmap.getHeight() / 2, new Paint(Paint.ANTI_ALIAS_FLAG));

//繪制掃描圖片

Bitmap mScanBitmap = getScanBitmap();

canvas.drawBitmap(mScanBitmap, getMeasuredWidth() / 2 - mScanBitmap.getWidth() / 2, getMeasuredHeight() / 2 - mScanBitmap.getHeight() / 2, new Paint(Paint.ANTI_ALIAS_FLAG));

//繪制文本提示

mTextPaint.getTextBounds(mTipText, 0, mTipText.length(), mTextBound);

//此處50為文本與按鈕之間間隔,可以自己設定

canvas.drawText(mTipText, getMeasuredWidth() / 2 - mTextBound.width() / 2, getMeasuredHeight() / 2 + mScanBackgroundBitmap.getHeight() / 2 + mTextBound.height() + 50, mTextPaint);

}

//繪制白色按鈕背景,根據縮放矩陣與縮放比例,復制圖片達到手指點擊與手指放開時按鈕的縮小與放大效果

private Bitmap getButtonBackgroundBitmap() {

mScaleMatrix.reset();

mScaleMatrix.postScale(mScaleRatio, mScaleRatio);

return Bitmap.createBitmap(mScanBitmap, 0, 0, mScanBitmap.getWidth(), mScanBitmap.getHeight(), mScaleMatrix, true);

}

//判斷是否正在執行旋轉動畫,如果正在執行動畫,則取消灰色白淨

private Bitmap getScanBackgroundBitmap() {

if (mRotateAnimator.isRunning()) {

return null;

}

return mScanBackgroundBitmap;

}

//判斷是否正在執行動畫,如果正在執行,根據旋轉矩陣,與旋轉的角度復制掃描圖標,則實現圖標不斷旋轉,如果未執行,則返回未掃描圖片

private Bitmap getScanBitmap() {

if (mRotateAnimator.isRunning()) {

mRotateMatrix.reset();

mRotateMatrix.postRotate(mRotateDegree, mIconScaningBitmap.getWidth() / 2, mIconScaningBitmap.getHeight() / 2);

return Bitmap.createBitmap(mIconScaningBitmap, 0, 0, mIconScaningBitmap.getWidth(), mIconScaningBitmap.getHeight(), mRotateMatrix, true);

}

return mIconScanBitmap;

}

//刷新View

public void invalidateView() {

if (Looper.getMainLooper() == Looper.myLooper()) {

invalidate();

} else {

postInvalidate();

}

}

}

就整體感覺而言,個人感覺不是很好,不斷刷新View對內存,CPU的性能有很高的要求,如果大家有好的思路,請大家共享一下,一起學習吧

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved