效果圖
先上效果圖
實現(xiàn)
WaveView的屬性
- Wate Level(水位) - 波浪靜止時水面距離底部的高度
- Amplitude(振幅) - 波浪垂直振動時偏離水面的最大距離
- Wave Length(波長) - 一個完整的波浪的水平長度
- Wave Shift(偏移) - 波浪相對于初始位置的水平偏移
實現(xiàn)思路
設(shè)想我們有一個畫好波形的圖片宝冕,那么我們只需要用這張圖片填充(X軸方向重復(fù)扁掸,Y軸方向延伸)整個View撼班,然后水平移動圖片,就可以得到波浪效果了宋列。
所以要做的事很簡單:繪制一個波形圖,填充到View里,移動波形圖。
1. 繪制初始波形
private void createShader() {
...
Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
// Draw default waves into the bitmap
// y=Asin(ωx+φ)+h
float waveX1 = 0;
final float wave2Shift = mDefaultWaveLength / 4;
final float endX = getWidth();
final float endY = getHeight();
...
while (waveX1 < endX) {
double wx = waveX1 * mDefaultAngularFrequency;
int startY = (int) (mDefaultWaterLevel + mDefaultAmplitude * Math.sin(wx));
// draw bottom wave with the alpha 40
canvas.drawLine(waveX1, startY, waveX1, endY, wavePaint1);
// draw top wave with the alpha 60
float waveX2 = (waveX1 + wave2Shift) % endX;
canvas.drawLine(waveX2, startY, waveX2, endY, wavePaint2);
waveX1++;
}
// use the bitamp to create the shader
mWaveShader = new BitmapShader(bitmap, Shader.TileMode.REPEAT, Shader.TileMode.CLAMP);
mViewPaint.setShader(mWaveShader);
}
首先一個長寬恰等于WaveView的Bitmap:Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888)
政模。
在Bitmap中使用默認的屬性繪制出初始波形。初始波形的屬性:Wate Level(水位)為WaveView高度的1/2沿腰;Amplitude(振幅)為WaveView高度的1/20览徒;Wave Length(波長)等于WaveView的寬度。
繪制好的初始波形是下面這個樣子:
代碼第 9 ~ 27 行進行初始波形的繪制颂龙。波形由wave1和wave2兩個波組成习蓬,wave2就是wave1向左偏移1/4的wave length纽什,所以不需要重復(fù)計算。
最后把這個Bitmap設(shè)置成為Paint的Shader躲叼。設(shè)置Shader相當于設(shè)定畫筆的形狀芦缰,使用設(shè)置了Shader的Paint繪制圖形時,實際上是在使用Bitmap填充繪制的區(qū)域枫慷。X軸的填充方式為TileMode.REPEAT
让蕾,即重復(fù)填充;Y軸的填充方式為TileMode.CLAMP
或听,即使用邊緣的色值延伸填充探孝。
2. 調(diào)整Bitmap的大小并填充到WaveView
有了初始波形,當WaveView的屬性改變時誉裆,只需要對初始波形進行相應(yīng)的拉伸/壓縮和位移就可以得到用戶想要的波形顿颅。
// sacle shader according to mWaveLengthRatio and mAmplitudeRatio
// this decides the size(mWaveLengthRatio for width, mAmplitudeRatio for height) of waves
mShaderMatrix.setScale(
mWaveLengthRatio / DEFAULT_WAVE_LENGTH_RATIO,
mAmplitudeRatio / DEFAULT_AMPLITUDE_RATIO,
0,
mDefaultWaterLevel);
// translate shader according to mWaveShiftRatio and mWaterLevelRatio this decides the start position(mWaveShiftRatio for x, mWaterLevelRatio for
// this decides the start position(mWaveShiftRatio for x, mWaterLevelRatio for y) of waves
mShaderMatrix.postTranslate(
mWaveShiftRatio * getWidth(),
(DEFAULT_WATER_LEVEL_RATIO - mWaterLevelRatio) * getHeight());
// assign matrix to invalidate the shader
mWaveShader.setLocalMatrix(mShaderMatrix);
float radius = getWidth() / 2f
- (mBorderPaint == null ? 0f : mBorderPaint.getStrokeWidth());
canvas.drawCircle(getWidth() / 2f, getHeight() / 2f, radius, mViewPaint);
代碼 3 ~ 6 行對Shader進行拉伸/壓縮,10 ~ 12 行對Shader進行水平/豎直平移足丢。
代碼 17 ~ 19 行用Shader填充成想要的形狀粱腻。
3. 動畫
// horizontal animation.
// wave waves infinitely.
ObjectAnimator waveShiftAnim = ObjectAnimator.ofFloat(
mWaveView, "waveShiftRatio", 0f, 1f);
waveShiftAnim.setRepeatCount(ValueAnimator.INFINITE);
waveShiftAnim.setDuration(1000);
waveShiftAnim.setInterpolator(new LinearInterpolator());
animators.add(waveShiftAnim);
// vertical animation.
// water level increases from 0 to center of WaveView
ObjectAnimator waterLevelAnim = ObjectAnimator.ofFloat(
mWaveView, "waterLevelRatio", 0f, 0.5f);
waterLevelAnim.setDuration(10000);
waterLevelAnim.setInterpolator(new DecelerateInterpolator());
animators.add(waterLevelAnim);
// amplitude animation.
// wave grows big then grows small, repeatedly
ObjectAnimator amplitudeAnim = ObjectAnimator.ofFloat(
mWaveView, "amplitudeRatio", 0f, 0.05f);
amplitudeAnim.setRepeatCount(ValueAnimator.INFINITE);
amplitudeAnim.setRepeatMode(ValueAnimator.REVERSE);
amplitudeAnim.setDuration(5000);
amplitudeAnim.setInterpolator(new LinearInterpolator());
animators.add(amplitudeAnim);
代碼 3 ~ 8 行讓波形一直向右移動,效果就是波形一直在波動斩跌。
代碼 12 ~ 16 行讓水位從0逐漸漲到WaveView高度的一半绍些。
代碼 20 ~ 26 行波浪的大小從大變小,再從小變大耀鸦。
源代碼
代碼在github:WaveView
打個廣告
美團平臺及酒旅事業(yè)群招人啦柬批,歡迎加入我們!
我可以幫忙內(nèi)推揭糕,簡歷請發(fā)到我郵箱gelitenight@gmail.com
【美團網(wǎng)】高級Android開發(fā)工程師
工作內(nèi)容: 負責美團酒店萝快、旅游產(chǎn)品 Android 客戶端的設(shè)計、開發(fā)與改進著角。
- 3年以上工作經(jīng)驗揪漩,2年以上Android開發(fā)經(jīng)驗;
- 熟悉Android系統(tǒng)吏口,熟悉Android軟件的開發(fā)奄容、測試、分發(fā)流程产徊;
- 良好的編程風格昂勒,扎實的編程基礎(chǔ)和數(shù)據(jù)結(jié)構(gòu)算法基礎(chǔ);
- 熟悉移動網(wǎng)絡(luò)的特性舟铜,對網(wǎng)絡(luò)編程和常用網(wǎng)絡(luò)協(xié)議有較深刻理解和經(jīng)驗戈盈;
- 有一定的架構(gòu)設(shè)計能力,良好的編碼能力,編寫文檔能力塘娶;
- 熱愛互聯(lián)網(wǎng)和新技術(shù)归斤,具有極強的快速學(xué)習(xí)能力;
- 有以下特征優(yōu)先考慮:
- 有開源作品或技術(shù)博客(需原創(chuàng)技術(shù)文章)刁岸;
- 熟悉Socket編程脏里。
北京、上海虹曙、廈門迫横、成都都有職位,更多職位請見職位列表酝碳。
本文遵循“署名-非商業(yè)性使用-相同方式共享”的創(chuàng)作共同協(xié)議矾踱,歡迎轉(zhuǎn)載,轉(zhuǎn)載時請注明作者和出處击敌。
作者: gelitenight
出處: http://gelitenight.github.io/wave-view/