自定義View之酷炫的波浪泡沫

海浪


? ? ? ? 這個效果我其實是用兩個自定義View實現(xiàn)的 -_- ?, 波浪是用兩個不斷改變的float值加畫布裁剪實現(xiàn)的 , 泡泡是用float數(shù)組隨機生成不同大小的shape畫的圓,使用三階Bezier曲線和屬性動畫實現(xiàn)。

MainActivity:

public classMainActivityextendsAppCompatActivity {

LoveBezierViewlover;

HandlermHandler=newHandler(){

@Override

public voidhandleMessage(Message msg) {

super.handleMessage(msg);

switch(msg.what){

case20:

lover.addImg();

break;

}

}

};

@Override

protected voidonCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

lover= (LoveBezierView) findViewById(R.id.mylove);

addPaopao();

}

public voidaddPaopao(){

newThread(newRunnable() {

@Override

public voidrun() {

while(true){

SystemClock.sleep(100);

mHandler.sendEmptyMessageDelayed(20,1500);

}

}

}).start();

}

}

WaveView波浪自定義View:

public classWaveViewextendsView{

private intmHeight;

private intmWidth;

private float[]mContentOneYs=null;

private float[]mContentTwoys=null;

private float[]mRestoreOnes=null;

private float[]mRestoreTwos=null;

private static final intSWINGONE=35;

private static final intSWINGTWO=60;//波動幅度

private static final intOFFSETONE=10;

private static final intOFFSETTWO=50;

private final intINIT_BASE_HEIGHT1=200;//距離View頂部的高度

private final intINIT_BASE_HEIGHT2=200;

private intmPosition1=0;//偏移坐標

private intmPosition2=0;

private static final intSTEP1=5;

private static final intSTEP2=8;

privatePaintmPaint1,mPaint2;//畫筆

publicWaveView(Context context) {

this(context,null);

}

publicWaveView(Context context, AttributeSet attrs) {

this(context, attrs,0);

}

publicWaveView(Context context, AttributeSet attrs,intdefStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private voidinit() {//初始化畫筆

mPaint1=newPaint(Paint.ANTI_ALIAS_FLAG);

mPaint1.setColor(Color.parseColor("#33CCFF"));

mPaint1.setStrokeWidth(4);

mPaint1.setAlpha(85);

mPaint2=newPaint(Paint.ANTI_ALIAS_FLAG);

mPaint2.setColor(Color.parseColor("#99FFFF"));//代碼設置顏色

mPaint2.setStrokeWidth(4);

mPaint2.setAlpha(155);

}

@Override

protected voidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override

protected voidonSizeChanged(intw,inth,intoldw,intoldh) {

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

if(w !=0|| h !=0|| w != oldw || h != oldh) {

mWidth= w;

mHeight= h;

calculatePoints();

}

}

@Override

protected voidonDraw(Canvas canvas) {

super.onDraw(canvas);

canvas.save();

Path path =newPath();

path.addArc(0,(mHeight/2)-350,mWidth,(mHeight/2)+350,0,360);

canvas.clipPath(path);

changeRestorePosition();

for(inti =0; i

final intx = i;

final floaty1 =mRestoreOnes[i];

final floaty2 =mRestoreTwos[i];

canvas.drawLine(x, y2, x,mHeight,mPaint2);

canvas.drawLine(x, y1, x,mHeight,mPaint1);

}

invalidate();

}

private voidcalculatePoints() {

mContentOneYs=new float[mWidth];

mContentTwoys=new float[mWidth];

mRestoreOnes=new float[mWidth];

mRestoreTwos=new float[mWidth];

for(inti =0; i

mContentOneYs[i] = getYPosition(i,SWINGONE,OFFSETONE,INIT_BASE_HEIGHT1);

mContentTwoys[i] = getYPosition(i,SWINGTWO,OFFSETTWO,INIT_BASE_HEIGHT2);

}

}

private voidchangeRestorePosition() {

//偏移坐標的方法窜锯,根據(jù)響應的步長設置每次的偏移起始點

if(mWidth!=0) {

mPosition1= (mPosition1+STEP1) %mWidth;

System.arraycopy(mContentOneYs,mPosition1,mRestoreOnes,0,mWidth-mPosition1);

System.arraycopy(mContentOneYs,0,mRestoreOnes,mWidth-mPosition1,mPosition1);

mPosition2= (mPosition2+STEP2) %mWidth;

System.arraycopy(mContentTwoys,mPosition2,mRestoreTwos,0,mWidth-mPosition2);

System.arraycopy(mContentTwoys,0,mRestoreTwos,mWidth-mPosition2,mPosition2);

}

}

private floatgetYPosition(intx,intswing,intoffset,intbaseHeight) {

floatcycle = (float) (2* Math.PI) /mWidth;

return(float) Math.sin(cycle * x + offset) * swing + baseHeight;

}

}

LoveBezierView泡沫上升效果:

public classLoveBezierViewextendsRelativeLayout{

privateDrawable[]drawables;//圖片集合

private intdWidth,dHeight;//泡泡寬高

privateLayoutParamslayoutParams;//泡泡寬高及位置

private intmWidth,mHeight;

privateRandomrandom=newRandom();

intwhats=1;

publicLoveBezierView(Context context) {

super(context);

init();

}

publicLoveBezierView(Context context, AttributeSet attrs) {

super(context, attrs);

init();

}

publicLoveBezierView(Context context, AttributeSet attrs,intdefStyleAttr) {

super(context, attrs, defStyleAttr);

init();

}

private voidinit() {

drawables=newDrawable[3];//泡泡的數(shù)組

drawables[0] = ContextCompat.getDrawable(getContext(), R.drawable.yuan);

drawables[1] = ContextCompat.getDrawable(getContext(), R.drawable.yuan2);

drawables[2] = ContextCompat.getDrawable(getContext(), R.drawable.yuan3);

}

@Override

protected voidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

mWidth= getMeasuredWidth();

mHeight= getMeasuredHeight();

}

/*@Override? ? 兩種測量方法

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

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

mWidth = w;

mHeight = h;

}*/

public voidaddImg(){

ImageView imageView =newImageView(getContext());

intwhat =random.nextInt(3);

imageView.setBackground(drawables[what]);

dWidth=drawables[what].getIntrinsicWidth();

dHeight=drawables[what].getIntrinsicHeight();

layoutParams=newLayoutParams(dWidth,dHeight);//泡泡寬高

/* layoutParams.addRule(ALIGN_PARENT_LEFT , TRUE);? ? //水平居中

layoutParams.addRule(ALIGN_PARENT_BOTTOM, TRUE);? //在父控件底部*/

imageView.setLayoutParams(layoutParams);

addView(imageView);

AnimatorSet animator = getBezierAnimator(imageView);

animator.addListener(newAnimatorLinstener(imageView));

animator.start();

}

privateAnimatorSet getBezierAnimator(ImageView imageView) {

Estimator evaluator =newEstimator(getPoint(2), getPoint(1));//隨機兩個拐點

ValueAnimator valueAnimator = ValueAnimator.ofObject(evaluator, getPointF(1), getPointF(2));

valueAnimator.setDuration(5000);

valueAnimator.addUpdateListener(newValueUpdateLinstener(imageView));

valueAnimator.setTarget(imageView);

ObjectAnimator ob = ObjectAnimator.ofFloat(imageView,"alpha",0.1f,1.0f);

ob.setDuration(2000);

AnimatorSet a =newAnimatorSet();

a.playTogether(valueAnimator,ob);

returna;

}

privatePointF getPoint(intscale) {

PointF pointF =newPointF();//選擇Y軸的兩個拐點

pointF.x=random.nextInt((mWidth));

pointF.y=random.nextInt((mHeight-100)) / scale;

returnpointF;

}

private classAnimatorLinstenerextendsAnimatorListenerAdapter {

privateImageViewimageView;

publicAnimatorLinstener(ImageView imageView) {

this.imageView= imageView;

}

@Override

public voidonAnimationEnd(Animator animation) {

removeView(imageView);

}

}

privatePointF getPointF(inti) {

PointF pointF =newPointF();

if(i ==1){

pointF.set(random.nextInt(mWidth-18),mHeight-dHeight-30);//在底部X軸隨機出現(xiàn)

}else{

pointF.set(random.nextInt(getWidth()),0);

}

returnpointF;

}

private classValueUpdateLinstenerimplementsValueAnimator.AnimatorUpdateListener {

privateImageViewimageView;

publicValueUpdateLinstener(ImageView imageView) {

this.imageView= imageView;

}

@Override

public voidonAnimationUpdate(ValueAnimator valueAnimator) {

PointF pointF = (PointF) valueAnimator.getAnimatedValue();

imageView.setX(pointF.x);

imageView.setY(pointF.y);

//? ? ? ? ? ? Log.e("TAG", valueAnimator.getAnimatedFraction()+"=========");

imageView.setAlpha(1- valueAnimator.getAnimatedFraction());

}

}

}

然后就是在布局中將兩個自定義View組合秀睛,寫成一個自定義View的畫太卡,onDraw最好不要有太復雜的運算差牛。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末以政,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子项郊,更是在濱河造成了極大的恐慌,老刑警劉巖斟赚,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件着降,死亡現(xiàn)場離奇詭異,居然都是意外死亡拗军,警方通過查閱死者的電腦和手機任洞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來发侵,“玉大人交掏,你說我怎么就攤上這事∪婿” “怎么了盅弛?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我挪鹏,道長见秽,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任讨盒,我火速辦了婚禮解取,結果婚禮上,老公的妹妹穿的比我還像新娘返顺。我一直安慰自己禀苦,他們只是感情好,可當我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布遂鹊。 她就那樣靜靜地躺著伦忠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪稿辙。 梳的紋絲不亂的頭發(fā)上昆码,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音邻储,去河邊找鬼赋咽。 笑死,一個胖子當著我的面吹牛吨娜,可吹牛的內容都是我干的脓匿。 我是一名探鬼主播,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼宦赠,長吁一口氣:“原來是場噩夢啊……” “哼陪毡!你這毒婦竟也來了颗圣?” 一聲冷哼從身側響起芬迄,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤磷支,失蹤者是張志新(化名)和其女友劉穎础芍,沒想到半個月后抽莱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耳奕,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡僧著,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年既绩,在試婚紗的時候發(fā)現(xiàn)自己被綠了身辨。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丐谋。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖煌珊,靈堂內的尸體忽然破棺而出号俐,到底是詐尸還是另有隱情,我是刑警寧澤定庵,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布吏饿,位于F島的核電站踪危,受9級特大地震影響,放射性物質發(fā)生泄漏找岖。R本人自食惡果不足惜陨倡,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望许布。 院中可真熱鬧兴革,春花似錦、人聲如沸蜜唾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽袁余。三九已至擎勘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間颖榜,已是汗流浹背棚饵。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掩完,地道東北人噪漾。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像且蓬,于是被迫代替她去往敵國和親欣硼。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,724評論 2 354

推薦閱讀更多精彩內容