亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android特效之水波紋的實(shí)現(xiàn)

 更新時(shí)間:2016年08月11日 15:41:26   作者:hackware  
今天我們主要講一講如何通過(guò)自定義View(以下簡(jiǎn)稱WaveView)實(shí)現(xiàn) "咻咻咻" 式的水波紋擴(kuò)散效果,感興趣的小伙伴們可以參考學(xué)習(xí)。

前言

水波紋特效,想必大家或多或少見(jiàn)過(guò),在我的印象中,大致有如下幾種:

     支付寶 "咻咻咻" 式

     流量球 "蕩漾" 式

     真實(shí)的水波紋效果,基于Bitmap處理式

話不多說(shuō),先來(lái)看看效果:

填充式水波紋,間距相等

非填充式水波紋,間距相等

非填充式水波紋,間距不斷變大

填充式水波紋,間距不斷變小

想必大家已經(jīng)知道基本的原理了,就是用Canvas來(lái)畫(huà)嘛,但可不是簡(jiǎn)單的畫(huà)哦,請(qǐng)往下看。

分析

這種類型的水波紋,其實(shí)無(wú)非就是畫(huà)圓而已,在給定的矩形中,一個(gè)個(gè)圓由最小半徑擴(kuò)大到最大半徑,伴隨著透明度從1.0變?yōu)?.0。我們假定這種擴(kuò)散是勻速的,則一個(gè)圓從創(chuàng)建(透明度為1.0)到消失(透明度為0.0)的時(shí)長(zhǎng)就是定值,那么某一時(shí)刻某一個(gè)圓的半徑以及透明度完全可以由擴(kuò)散時(shí)間(當(dāng)前時(shí)間 - 創(chuàng)建時(shí)間)決定。

實(shí)現(xiàn)

按照上面的分析,我們寫(xiě)出以下Circle類來(lái)表示一個(gè)圓:

private class Circle {
 private long mCreateTime;

 public Circle() {
 this.mCreateTime = System.currentTimeMillis();
 }

 public int getAlpha() {
 float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mDuration;
 return (int) ((1.0f - percent) * 255);
 }

 public float getCurrentRadius() {
 float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mDuration;
 return mInitialRadius + percent * (mMaxRadius - mInitialRadius);
 }
}

自然而然,在WaveView中,要有一個(gè)List來(lái)保存當(dāng)前正在顯示的圓:

private List<Circle> mCircleList = new ArrayList<Circle>();

我們定義一個(gè)start方法,用來(lái)啟動(dòng)擴(kuò)散:

public void start() {
 if (!mIsRunning) {
 mIsRunning = true;
 mCreateCircle.run();
 }
}

private Runnable mCreateCircle = new Runnable() {
 @Override
 public void run() {
 if (mIsRunning) {
 newCircle();
 postDelayed(mCreateCircle, mSpeed); // 每隔mSpeed毫秒創(chuàng)建一個(gè)圓
 }
 }
};

private void newCircle() {
 long currentTime = System.currentTimeMillis();
 if (currentTime - mLastCreateTime < mSpeed) {
 return;
 }
 Circle circle = new Circle();
 mCircleList.add(circle);
 invalidate();
 mLastCreateTime = currentTime;
}

start方法只是簡(jiǎn)單的創(chuàng)建了一個(gè)圓并添加到了mCircleList中,同時(shí)開(kāi)啟了循環(huán)創(chuàng)建圓的Runnable,然后通知界面刷新,我們?cè)倏纯?code>onDraw方法:

protected void onDraw(Canvas canvas) {
 Iterator<Circle> iterator = mCircleList.iterator();
 while (iterator.hasNext()) {
 Circle circle = iterator.next();
 if (System.currentTimeMillis() - circle.mCreateTime < mDuration) {
 mPaint.setAlpha(circle.getAlpha());
 canvas.drawCircle(getWidth() / 2, getHeight() / 2, circle.getCurrentRadius(), mPaint);
 } else {
 iterator.remove();
 }
 }
 if (mCircleList.size() > 0) {
 postInvalidateDelayed(10);
 }
}

onDraw方法遍歷了每一個(gè)Circle,判斷Circle的擴(kuò)散時(shí)間是否超過(guò)了設(shè)定的擴(kuò)散時(shí)間,如果是則移除,如果不是,則計(jì)算Circle當(dāng)前的透明度和半徑并繪制出來(lái)。我們添加了一個(gè)延時(shí)刷新來(lái)不斷重繪界面,以達(dá)到連續(xù)的波紋擴(kuò)散效果。

現(xiàn)在運(yùn)行程序,應(yīng)該能看到圖2中的效果了,不過(guò)有點(diǎn)別扭,按常識(shí),水波的間距是越來(lái)越大的,如何做到呢?

技巧

要讓水波紋的半徑非勻速變大,我們只能去修改Circle.getCurrentRadius()方法了。我們?cè)俅慰纯催@個(gè)方法:

public float getCurrentRadius() {
 float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mDuration;
 return mInitialRadius + percent * (mMaxRadius - mInitialRadius);
}

percent表示Circle當(dāng)前擴(kuò)散時(shí)間和總擴(kuò)散時(shí)間的一個(gè)百分比,考慮到當(dāng)前擴(kuò)散時(shí)間超過(guò)總擴(kuò)散時(shí)間時(shí)Circle會(huì)被移除,因此percent的實(shí)際區(qū)間為[0, 1],看到[0, 1],我不知道大家想到的是什么,我首先想到的就是差值器(Interpolator),我們可以通過(guò)定義差值器來(lái)實(shí)現(xiàn)對(duì)Circle半徑變化的控制!

我們修改代碼:

private Interpolator mInterpolator = new LinearInterpolator();

public void setInterpolator(Interpolator interpolator) {
 mInterpolator = interpolator;
 if (mInterpolator == null) {
 mInterpolator = new LinearInterpolator();
 }
}

private class Circle {
 private long mCreateTime;

 public Circle() {
 this.mCreateTime = System.currentTimeMillis();
 }

 public int getAlpha() {
 float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mDuration;
 return (int) ((1.0f - mInterpolator.getInterpolation(percent)) * 255);
 }

 public float getCurrentRadius() {
 float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mDuration;
 return mInitialRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mInitialRadius);
 }
}

這樣,外部使用WaveView時(shí),只需調(diào)用setInterpolator()來(lái)定義不同的插值器即可實(shí)現(xiàn)不同的效果。

圖3效果的代碼:

mWaveView = (WaveView) findViewById(R.id.wave_view);
mWaveView.setDuration(5000);
mWaveView.setStyle(Paint.Style.STROKE);
mWaveView.setSpeed(400);
mWaveView.setColor(Color.parseColor("#ff0000"));
mWaveView.setInterpolator(new AccelerateInterpolator(1.2f));
mWaveView.start();

圖4效果的代碼:

mWaveView = (WaveView) findViewById(R.id.wave_view);
mWaveView.setDuration(5000);
mWaveView.setStyle(Paint.Style.FILL);
mWaveView.setColor(Color.parseColor("#ff0000"));
mWaveView.setInterpolator(new LinearOutSlowInInterpolator());
mWaveView.start();

附上WaveView的所有代碼:

/**
 * 水波紋特效
 * Created by hackware on 2016/6/17.
 */
public class WaveView extends View {
 private float mInitialRadius; // 初始波紋半徑
 private float mMaxRadiusRate = 0.85f; // 如果沒(méi)有設(shè)置mMaxRadius,可mMaxRadius = 最小長(zhǎng)度 * mMaxRadiusRate;
 private float mMaxRadius; // 最大波紋半徑
 private long mDuration = 2000; // 一個(gè)波紋從創(chuàng)建到消失的持續(xù)時(shí)間
 private int mSpeed = 500; // 波紋的創(chuàng)建速度,每500ms創(chuàng)建一個(gè)
 private Interpolator mInterpolator = new LinearInterpolator();

 private List<Circle> mCircleList = new ArrayList<Circle>();
 private boolean mIsRunning;

 private boolean mMaxRadiusSet;

 private Paint mPaint;
 private long mLastCreateTime;

 private Runnable mCreateCircle = new Runnable() {
 @Override
 public void run() {
 if (mIsRunning) {
 newCircle();
 postDelayed(mCreateCircle, mSpeed);
 }
 }
 };

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

 public WaveView(Context context, AttributeSet attrs) {
 super(context, attrs);
 mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 setStyle(Paint.Style.FILL);
 }

 public void setStyle(Paint.Style style) {
 mPaint.setStyle(style);
 }

 @Override
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 if (!mMaxRadiusSet) {
 mMaxRadius = Math.min(w, h) * mMaxRadiusRate / 2.0f;
 }
 }

 public void setMaxRadiusRate(float maxRadiusRate) {
 this.mMaxRadiusRate = maxRadiusRate;
 }

 public void setColor(int color) {
 mPaint.setColor(color);
 }

 /**
 * 開(kāi)始
 */
 public void start() {
 if (!mIsRunning) {
 mIsRunning = true;
 mCreateCircle.run();
 }
 }

 /**
 * 停止
 */
 public void stop() {
 mIsRunning = false;
 }

 protected void onDraw(Canvas canvas) {
 Iterator<Circle> iterator = mCircleList.iterator();
 while (iterator.hasNext()) {
 Circle circle = iterator.next();
 if (System.currentTimeMillis() - circle.mCreateTime < mDuration) {
 mPaint.setAlpha(circle.getAlpha());
 canvas.drawCircle(getWidth() / 2, getHeight() / 2, circle.getCurrentRadius(), mPaint);
 } else {
 iterator.remove();
 }
 }
 if (mCircleList.size() > 0) {
 postInvalidateDelayed(10);
 }
 }

 public void setInitialRadius(float radius) {
 mInitialRadius = radius;
 }

 public void setDuration(long duration) {
 this.mDuration = duration;
 }

 public void setMaxRadius(float maxRadius) {
 this.mMaxRadius = maxRadius;
 mMaxRadiusSet = true;
 }

 public void setSpeed(int speed) {
 mSpeed = speed;
 }

 private void newCircle() {
 long currentTime = System.currentTimeMillis();
 if (currentTime - mLastCreateTime < mSpeed) {
 return;
 }
 Circle circle = new Circle();
 mCircleList.add(circle);
 invalidate();
 mLastCreateTime = currentTime;
 }

 private class Circle {
 private long mCreateTime;

 public Circle() {
 this.mCreateTime = System.currentTimeMillis();
 }

 public int getAlpha() {
 float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mDuration;
 return (int) ((1.0f - mInterpolator.getInterpolation(percent)) * 255);
 }

 public float getCurrentRadius() {
 float percent = (System.currentTimeMillis() - mCreateTime) * 1.0f / mDuration;
 return mInitialRadius + mInterpolator.getInterpolation(percent) * (mMaxRadius - mInitialRadius);
 }
 }

 public void setInterpolator(Interpolator interpolator) {
 mInterpolator = interpolator;
 if (mInterpolator == null) {
 mInterpolator = new LinearInterpolator();
 }
 }
}

總結(jié)

想必大家看完這篇文章會(huì)覺(jué)得原來(lái)插值器還可以這么用。其實(shí),有些時(shí)候我們使用系統(tǒng)提供的API,往往過(guò)于局限其中,有時(shí)候換個(gè)思路,說(shuō)不定會(huì)得到奇妙的效果。以上就是在Android實(shí)現(xiàn)水波紋特效的全部?jī)?nèi)容,希望對(duì)大家開(kāi)發(fā)Android有所幫助。
。

相關(guān)文章

  • android加密參數(shù)定位實(shí)現(xiàn)方法

    android加密參數(shù)定位實(shí)現(xiàn)方法

    這篇文章主要介紹了android加密參數(shù)定位方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04
  • Android實(shí)現(xiàn)弧形菜單效果

    Android實(shí)現(xiàn)弧形菜單效果

    本文主要介紹了Android實(shí)現(xiàn)弧形菜單效果的示例代碼。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-03-03
  • Android Sqlite命令詳解(基本命令)

    Android Sqlite命令詳解(基本命令)

    這篇文章主要介紹了Android Sqlite命令詳解(基本命令)的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • Android自定義短信倒計(jì)時(shí)view流程分析

    Android自定義短信倒計(jì)時(shí)view流程分析

    倒計(jì)時(shí)實(shí)現(xiàn)有三種方式 而這個(gè)自定義view是通過(guò)handler實(shí)現(xiàn)的。本文通過(guò)實(shí)例代碼給大家介紹Android自定義短信倒計(jì)時(shí)view流程,,需要的朋友可以參考下
    2020-03-03
  • Android自定義ProgressDialog進(jìn)度等待框

    Android自定義ProgressDialog進(jìn)度等待框

    這篇文章主要介紹了Android自定義ProgressDialog進(jìn)度等待框,通過(guò)本文大家可以嘗試?yán)肁ndroid自定義ProgressDialog,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-01-01
  • Flutter 使用fluro的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)進(jìn)行頁(yè)面切換

    Flutter 使用fluro的轉(zhuǎn)場(chǎng)動(dòng)畫(huà)進(jìn)行頁(yè)面切換

    在實(shí)際應(yīng)用中,我們常常會(huì)對(duì)不同的頁(yè)面采取不同的轉(zhuǎn)場(chǎng)動(dòng)畫(huà),以提高頁(yè)面切換過(guò)程中的用戶體驗(yàn)。例如,微信的掃碼后在手機(jī)上確認(rèn)登錄頁(yè)面就是從底部彈出的,而大部分頁(yè)面的跳轉(zhuǎn)都是從右向左滑入。通過(guò)這種形式區(qū)分不同的轉(zhuǎn)場(chǎng)場(chǎng)景,從而給用戶更多的趣味性以提高用戶體驗(yàn)。
    2021-06-06
  • android 照相功能的簡(jiǎn)單實(shí)例

    android 照相功能的簡(jiǎn)單實(shí)例

    android 照相功能的簡(jiǎn)單實(shí)例,需要的朋友可以參考一下
    2013-06-06
  • Android多線程斷點(diǎn)續(xù)傳下載示例詳解

    Android多線程斷點(diǎn)續(xù)傳下載示例詳解

    這篇文章主要為大家詳細(xì)介紹了Android多線程斷點(diǎn)續(xù)傳下載示例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-11-11
  • Android Retrofit實(shí)現(xiàn)多圖片/文件、圖文上傳功能

    Android Retrofit實(shí)現(xiàn)多圖片/文件、圖文上傳功能

    Retrofit是Square開(kāi)發(fā)的一個(gè)Android和Java的REST客戶端庫(kù)。這個(gè)庫(kù)非常簡(jiǎn)單并且具有很多特性,相比其他的網(wǎng)絡(luò)庫(kù),更容易讓初學(xué)者快速掌握
    2017-03-03
  • Android App開(kāi)發(fā)中Gradle構(gòu)建過(guò)程的配置方法

    Android App開(kāi)發(fā)中Gradle構(gòu)建過(guò)程的配置方法

    這篇文章主要介紹了Android App開(kāi)發(fā)中Gradle構(gòu)建過(guò)程的配置方法,包括在Gradle中配置manifest的方法,需要的朋友可以參考下
    2016-06-06

最新評(píng)論