国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 系統(tǒng) > Android > 正文

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

2019-12-12 05:42:46
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

前言

水波紋特效,想必大家或多或少見(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有所幫助。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 乳山市| 乌兰浩特市| 喀什市| 赤壁市| 环江| 烟台市| 彭泽县| 冀州市| 阳山县| 丰县| 鹿邑县| 林周县| 辛集市| 海阳市| 天长市| 曲阜市| 柯坪县| 盐源县| 平邑县| 石家庄市| 和静县| 桐城市| 黄石市| 菏泽市| 海门市| 楚雄市| 保亭| 建湖县| 英山县| 繁峙县| 湖州市| 湾仔区| 韶关市| 凤城市| 湘潭县| 井冈山市| 静安区| 万山特区| 凤凰县| 桐庐县| 麟游县|