android實(shí)現(xiàn)貝塞爾曲線之波浪效果
本文實(shí)例為大家分享了android實(shí)現(xiàn)貝塞爾曲線之波浪效果的具體代碼,供大家參考,具體內(nèi)容如下
1 前言
為了給我以前的博客填坑,這章講解貝塞爾曲線的幾個(gè)常用的應(yīng)用:
1.波浪效果
2.qq聊天列表上的沾粘體效果
3.翻書頁效果
4.彈性球效果
大家如果把這些看懂并掌握,以后做和貝塞爾曲線相關(guān)的效果應(yīng)該都能信手拈來!
2 波浪效果

原理分析:
其實(shí)這個(gè)效果應(yīng)用了2個(gè)階的貝塞爾曲線來完成的,先看一下原理分析圖:

有上面的圖可以看出:在屏幕的左面畫出了1.5個(gè)波長,在屏幕中畫出1個(gè)波長,然后讓它循環(huán)的向右移動,這個(gè)就會出現(xiàn)波浪效果,這里有幾點(diǎn)需要注意:
1.為什么是1.5個(gè)波長而不是1個(gè)波長呢?
理論上1個(gè)波長就夠了,但是實(shí)際運(yùn)行出來的效果會出現(xiàn)不協(xié)調(diào),所以經(jīng)過調(diào)試,我又加了0.5個(gè)波長
2.那條綠線是干什么用的?
在波浪線以下的所有空間都要填充成一個(gè)顏色,所以path必須是封閉的區(qū)間,只有這個(gè)才能填充。代碼中我會具體的解釋
我們在編碼的時(shí)候只需要計(jì)算最左面半個(gè)波長的坐標(biāo),其他的用for循環(huán)搞定。
好了我們看一下代碼:
public class WaveView extends View {
? ? private int ?width = 0;
? ? private int height = 0;
? ? private int baseLine = 0;// 基線,用于控制水位上漲的,這里是寫死了沒動,你可以不斷的設(shè)置改變。
? ? private Paint mPaint;
? ? private int waveHeight = 100;// 波浪的最高度
? ? private int waveWidth ?;//波長
? ? private float offset =0f;//偏移量
? ? public WaveView(Context context, AttributeSet attrs) {
? ? ? ? super(context, attrs);
? ? ? ? initView();
? ? }
? ? /**
? ? ?* 不斷的更新偏移量,并且循環(huán)。
? ? ?*/
? ? private void updateXControl(){
? ? ? ? //設(shè)置一個(gè)波長的偏移
? ? ? ? ValueAnimator mAnimator = ValueAnimator.ofFloat(0,waveWidth);
? ? ? ? mAnimator.setInterpolator(new LinearInterpolator());
? ? ? ? mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
? ? ? ? ? ? @Override
? ? ? ? ? ? public void onAnimationUpdate(ValueAnimator animation) {
? ? ? ? ? ? ? ? float animatorValue = (float)animation.getAnimatedValue() ;
? ? ? ? ? ? ? ? offset = animatorValue;//不斷的設(shè)置偏移量,并重畫
? ? ? ? ? ? ? ? postInvalidate();
? ? ? ? ? ? }
? ? ? ? });
? ? ? ? mAnimator.setDuration(1000);
? ? ? ? mAnimator.setRepeatCount(ValueAnimator.INFINITE);
? ? ? ? mAnimator.start();
? ? }
? ? @Override
? ? protected void onDraw(Canvas canvas) {
? ? ? ? super.onDraw(canvas);
? ? ? ? canvas.drawPath(getPath(),mPaint);
? ? }
? ? //初始化paint,沒什么可說的。
? ? private void initView(){
? ? ? ? mPaint = new Paint();
? ? ? ? mPaint.setColor(Color.RED);
? ? ? ? mPaint.setStyle(Paint.Style.FILL);
? ? }
? ? @Override
? ? protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
? ? ? ? super.onLayout(changed, left, top, right, bottom);
? ? ? ? width = getMeasuredWidth();//獲取屏幕寬度
? ? ? ? height = getMeasuredHeight();//獲取屏幕高度
? ? ? ? waveWidth = width;
? ? ? ? baseLine = height/2;
? ? ? ? updateXControl();
? ? }
? ? /**
? ? ?* 核心代碼,計(jì)算path
? ? ?* @return
? ? ?*/
? ? private Path ?getPath(){
? ? ? ? int itemWidth = waveWidth/2;//半個(gè)波長
? ? ? ? Path mPath = new Path();
? ? ? ? mPath.moveTo(-itemWidth * 3, baseLine);//起始坐標(biāo)
? ? ? ? //核心的代碼就是這里
? ? ? ? for (int i = -3; i < 2; i++) {
? ? ? ? ? ? int startX = i * itemWidth;
? ? ? ? ? ? mPath.quadTo(
? ? ? ? ? ? ? ? ? ? startX + itemWidth/2 + offset,//控制點(diǎn)的X,(起始點(diǎn)X + itemWidth/2 + offset)
? ? ? ? ? ? ? ? ? ? getWaveHeigh( i ),//控制點(diǎn)的Y
? ? ? ? ? ? ? ? ? ? startX + itemWidth + offset,//結(jié)束點(diǎn)的X
? ? ? ? ? ? ? ? ? ? baseLine//結(jié)束點(diǎn)的Y
? ? ? ? ? ? );//只需要處理完半個(gè)波長,剩下的有for循環(huán)自已就添加了。
? ? ? ? }
? ? ? ? //下面這三句話很重要,它是形成了一封閉區(qū)間,讓曲線以下的面積填充一種顏色,大家可以把這3句話注釋了看看效果。
? ? ? ? mPath.lineTo(width,height);
? ? ? ? mPath.lineTo(0,height);
? ? ? ? mPath.close();
? ? ? ? return ?mPath;
? ? }
? ? //奇數(shù)峰值是正的,偶數(shù)峰值是負(fù)數(shù)
? ? private int getWaveHeigh(int num){
? ? ? ? if(num % 2 == 0){
? ? ? ? ? ? return baseLine + waveHeight;
? ? ? ? }
? ? ? ? return baseLine - waveHeight;
? ? }
}核心的代碼在 getPath()方法中,其實(shí)這個(gè)坐標(biāo)是有規(guī)律的:
先找到最左面的半個(gè)波長,設(shè)置貝塞爾曲線坐標(biāo),
然后用for循環(huán),不斷的設(shè)置,
這個(gè)規(guī)律大家體會,我這里簡單提一下。
3 qq聊天列表上的沾粘體效果
先看一個(gè)效果圖:

這個(gè)做起來小有點(diǎn)復(fù)雜。具體思路如下:
1.畫兩個(gè)圓,一個(gè)黏連小球固定在一個(gè)點(diǎn)上,一個(gè)氣泡小球跟隨手指的滑動改變坐標(biāo)。隨著兩個(gè)圓間距越來越大,黏連小球半徑越來越小。
2.當(dāng)間距小于一定值,松開手指氣泡小球會恢復(fù)原來位置;
3.當(dāng)間距超過一定值之后,黏連小球消失,氣泡小球繼續(xù)跟隨手指移動,此時(shí)手指松開,氣泡小球消失~
結(jié)尾
本來想把上面的全部弄在一篇博客呢,現(xiàn)在看來不太可能,一篇一篇的來吧。核心就是貝塞爾曲線的應(yīng)用,大家如何理解了貝塞爾曲線,這些都不難。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android ListView與ScrollView沖突的解決方法總結(jié)
這篇文章主要介紹了Android ListView與ScrollView沖突的解決方法總結(jié)的相關(guān)資料,需要的朋友可以參考下2017-04-04
使用Android studio查看Kotlin的字節(jié)碼教程
這篇文章主要介紹了使用Android studio查看Kotlin的字節(jié)碼教程,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03
Android自定義processor實(shí)現(xiàn)bindView功能的實(shí)例
下面小編就為大家分享一篇Android自定義processor實(shí)現(xiàn)bindView功能的實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-12-12
Android組件Glide實(shí)現(xiàn)圖片平滑滾動效果
這篇文章主要介紹了Android組件Glide實(shí)現(xiàn)圖片平滑滾動效果的相關(guān)資料,具有一定的參考價(jià)值,需要的朋友可以參考下2016-07-07
Android App中使用RatingBar實(shí)現(xiàn)星級打分功能的教程
這篇文章主要介紹了Android App中使用RatingBar實(shí)現(xiàn)星級打分功能的教程,文中舉了一個(gè)使用SeekBar與RatingBar制作的應(yīng)用內(nèi)打分條的功能,非常簡單,需要的朋友可以參考下2016-04-04
Android判斷和監(jiān)聽底座狀態(tài)和類型的方法介紹
這篇文章主要介紹了Android判斷和監(jiān)聽底座狀態(tài)和類型的方法介紹,例如判斷當(dāng)前底座狀態(tài)、判斷插入底座類型、監(jiān)控充電充電狀態(tài)等,需要的朋友可以參考下2014-06-06

