android自定義view粒子效果之雨(not surfaceview)
首先宣告的是,粒子效果不一定是用surfaceview來實現的,只要可以繪製和更新繪製既可以做到很多精彩的畫面。
簡單的說一下自定義view吧,其實就是繼承View,然後生成幾個構造方法,這樣就是一個簡單的自定義view。
但是它什麼也做不了,什麼也不顯示,很多人都知道,覆蓋onDraw(Canvas)方法,沒錯public class MyView extends View{ public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); } public MyView(Context context) { super(context); } }
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//做自己想做的事情(繪製)
}
這樣,一個可以顯示自己繪製的view已經完成一半了,為什麼說一半,因為還不會動,但是這會有很多邏輯,而這些邏輯不應該出現在主執行緒中,所以用Handler來做這部分事情,開啟一個處理邏輯的執行緒通過Handler來更新繪製。
private Runnable run = new Runnable() { public void run() { long curTime = 0; while (true) { curTime = System.currentTimeMillis(); //此處加入邏輯 mHandler.sendEmptyMessage(0); curTime = System.currentTimeMillis() - curTime; try { if(curTime < 30){ Thread.sleep(30 - curTime); } } catch (InterruptedException e) { break; } } } }; private void logic(){ //此處加入邏輯處理 } private Handler mHandler = new Handler() { public void handleMessage(android.os.Message msg) { invalidate(); }; };
好吧,這樣基本上一個自定義view的框架就出來了。
鋪墊好了後面就會好理解了,繪製和動畫基本上都是在onDraw裡面和logic裡面完成,其他的粒子效果也是。
粒子效果在我看來,其實就是具有相同屬性的物件集合運動,說白了,就是一個列表裡面有多個物件,每個物件自己都在動,放在一起,就出現了粒子效果。再簡單點說,只要定義一個類,這個類有繪製和運動就可以了,然後例項化多個,放在列表裡面,繪製的時候遍歷每個元素就可以了。
所以要在自定義view中加入一個ArrayList就可以了,然後在onDraw和logic裡面遍歷list裡面的每個元素。說到這裡了,其實核心也出來了,粒子效果最終追述到的根源,還是單個元素的定製。
那麼粒子效果有大家想象的那麼難嗎,其實沒有,起碼我寫的幾個都是在100行程式碼左右(單個元素),那麼,來看看下雨的效果怎麼實現的吧。
如果在手機上看,會很清楚和流暢,因為我用視訊錄製轉換成gif,這樣解析度就小了很多,而且幀率也變了。
單個雨點實際上就是一條線,線的大小可以根據自己的喜好定製隨機範圍。那麼需要定義一些基本的變數。顯示的寬,高,隨機數。
/**
* 顯示區域的寬度
*/
protected int width;
/**
* 顯示區域的高度
*/
protected int height;
/**
* 效果元素的隨機物件
*/
protected Random rand;
上面的寬高是通過View的getWidth()和getHeight()來傳遞的。rand也是在構造的時候就已經例項化了。
public EffectItem(int width, int height){
this.width = width;
this.height = height;
rand =new Random();
}
上面的EffectItem其實就是Rain,只不過我把它抽離出來了,方便以後其他粒子複用,但是不影響閱讀,把它看成Rain就可以了。繪製的區域出來了,那麼繪製的線呢?這就通過rand來生成,先看看系統繪製直線的方法:
public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
native_drawLine(mNativeCanvas, startX, startY, stopX, stopY, paint.mNativePaint);
}
需要起始x,y和終點x,y。系統有個Rect的類,它有left, top, right, bottom。所以可以使用這個類來輔助。
<span style="white-space:pre"> </span>int x = rand.nextInt(width);
int y = rand.nextInt(height);
int w = rand.nextInt(size / 2);
int h = rand.nextInt(size);
w = w > h ? h : w;
point.left = x;
point.top = y;
point.right = x - w;
point.bottom = y + h;
size的值可以自己定,我定的是50畫素,這樣一條線段的座標就出來了,只要draw裡面使用就可以了
public void draw(Canvas canvas){
canvas.drawLine(point.left, point.top, point.right, point.bottom, paint);
}
還記得我前面說的嗎,每個元素都會在自定義的View裡面的onDraw(Canvas)裡面遍歷繪製,所以不用途擔心這裡面的draw不起作用。ok,繪製線出來了,但是,你會發現這個線不動,因為沒有邏輯讓它動起來。
那麼該怎麼動呢,對,用速度,要讓它往下落,那麼y的座標就一直在變,所有y方向有有個速度,但是你又會發現,一個斜槓在往下掉,不符合自然規律,應該讓它按照它的角度和方向落下,聽的好難啊啊,其實就2行程式碼,上面程式碼你會很奇怪有個w,h,這次有用了,稍微在紙上畫畫,你會發現這條線段是按照一定規律,即一個係數(是幾不重要),只要x方向乘以w和y方向乘以h就可以了,所以如果定義速度的話就好辦多了。
private void reset(){
int x = rand.nextInt(width);
int y = rand.nextInt(height);
int w = rand.nextInt(size / 2);
int h = rand.nextInt(size);
w = w > h ? h : w;
point.left = x;
point.top = y;
point.right = x - w;
point.bottom = y + h;
int speedX = w;
int speedY = h;
speedX = speedX == 0 ? 1 : speedX;
speedY = speedY == 0 ? 1 : speedY;
speedX = speedX > speedY ? speedY : speedX;
speed.x = -speedX;
speed.y = speedY;
}
上面就是生成一個雨點的方法,speed是個Point的物件,這樣可以表示x和y方向上的速度。
生成和繪製都有了,就差運動了
public void move(){
point.left += speed.x;
point.top += speed.y;
point.right = point.right + speed.x;
point.bottom = point.bottom + speed.y;
if(point.left < 0 || point.left > width || point.bottom > height){
reset();
}
speed.y += rand.nextBoolean() ? 1 : 0;
}
上面就是運動的方法,就是簡單的把位置變換了下,但是當出繪製區域的時候,會重新生成一個雨點,所以,螢幕上實際上就是固定數目的雨點的不停的變換位置。最後的y方向的速度是不定時的將y方向加入加速度,這樣就會有重力似的效果。每個元素move方法其實就是在自定義View中的logic中被遍歷的。
到此位置,一個雨點的生成,繪製,運動都完成了,只要加入到list中然後在View裡面遍歷就基本完成了。一個雨點完整的程式碼如下:
public class RainPoint extends EffectItem{
private Paint paint = new Paint();
private final int size = 50; //長度在0-50畫素
private Rect point; //雨點
private Point speed; //雨點x,y方向速度
public RainPoint(int width, int height){
super(width, height);
point = new Rect();
speed = new Point();
paint.setColor(0xffffffff);
reset();
}
public void draw(Canvas canvas){
canvas.drawLine(point.left, point.top, point.right, point.bottom, paint);
}
public void move(){
point.left += speed.x;
point.top += speed.y;
point.right = point.right + speed.x;
point.bottom = point.bottom + speed.y;
if(point.left < 0 || point.left > width || point.bottom > height){
reset();
}
speed.y += rand.nextBoolean() ? 1 : 0;
}
private void reset(){
int x = rand.nextInt(width);
int y = rand.nextInt(height);
int w = rand.nextInt(size / 2);
int h = rand.nextInt(size);
w = w > h ? h : w;
point.left = x;
point.top = y;
point.right = x - w;
point.bottom = y + h;
int speedX = w;
int speedY = h;
speedX = speedX == 0 ? 1 : speedX;
speedY = speedY == 0 ? 1 : speedY;
speedX = speedX > speedY ? speedY : speedX;
speed.x = -speedX;
speed.y = speedY;
}
}
而EffectItem程式碼如下:
<pre name="code" class="java">public abstract class EffectItem implements EffectBase{
/**
* 顯示區域的寬度
*/
protected int width;
/**
* 顯示區域的高度
*/
protected int height;
/**
* 效果元素的隨機物件
*/
protected Random rand;
public EffectItem(int width, int height){
this.width = width;
this.height = height;
rand =new Random();
}
}
而EffectBase介面定義了兩個方法:public interface EffectBase {
/**
* 繪製效果
* @param canvas
*/
public void draw(Canvas canvas);
/**
* 效果元素變化
*/
public void move();
}
這樣,一個粒子的完整過程就出來了,而後面其它的粒子也是按照這個模型就行設計的。剩下的就是在list裡面加入多個例項了,然後按部就班的在onDraw裡面遍歷每個元素的draw方法,在logic裡面遍歷move方法。
<span style="white-space:pre"> </span><span style="color:#ff0000;">最重要的是,因為這是自定義View,可以像使用其他View一樣,放到佈局裡面,所以豐富它,可以有無限的遐想展示空間。</span>
下面我再貼出我豐富的幾個豐富的效果,後面會說到怎麼實現。
變化雨點顏色(在xml中定義屬性就可以了)
每個雨點都隨機顏色(在xml中定義屬性就可以了)
還可以進行區域clip哦
好了,如果誰有好的想法也可以共享一下哦,看看如果能實現,看看效果。詳細程式碼:https://github.com/xianfeng99/Particle
github上面的程式碼可能沒有及時更新。
相關推薦
android自定義view粒子效果之雨(not surfaceview)
首先宣告的是,粒子效果不一定是用surfaceview來實現的,只要可以繪製和更新繪製既可以做到很多精彩的畫面。 簡單的說一下自定義view吧,其實就是繼承View,然後生成幾個構造方法,這樣就是一個簡單的自定義view。 public class MyView exte
【Android自定義View實戰】之自定義評價打分控制元件RatingBar,可以自定義星星大小和間距
在Android開發中,我們經常會用到對商家或者商品的評價,運用星星進行打分。然而在Android系統中自帶的打分控制元件,RatingBar特別不好用,間距和大小無法改變。所以,我就自定義了一個特別好用的打分控制元件。在專案中可以直接使用,特別簡
【Android自定義View實戰】之自定義超簡單SearchView搜尋框
package cn.bluemobi.dylan.searchview; import android.content.Context; import android.text.Editable; import android.text.TextWatcher; import android.util.A
Android 自定義View動畫效果進階
RectF oval = new RectF(x, y, x1, y1); paint.setColor(Color.WHITE);//設定圓環的顏色 paint.setStyle(Paint.Style.STROKE);//設定空心 paint.setAntiAlias(true);//消除鋸齒 pain
Android自定義View--翻書控制元件(一)
0.前言 最近重看了一遍封神演義,感覺QQ閱讀那個翻書的效果挺好的,準備做一個。上週五下午用了兩個小時只寫了一部分功能,以後有時間再完善 1.分析 先看效果圖 這個空間,說簡單也簡單,說難也難,簡單就在於這個效果主要就是依賴canvas的clippath才見到部分canvas,難就難在裁
Android 自定義 HorizontalScrollView 打造再多圖片(控制元件)也不怕 OOM 的橫向滑動效果
自從Gallery被谷歌廢棄以後,Google推薦使用ViewPager和HorizontalScrollView來實現Gallery的效果。的確HorizontalScrollView可以實現Gallery的效果,但是HorizontalScrollView存在一個很大的問
Android自定義View ——畫弧線詳解(Rectf放入用法)
好久沒有寫部落格了。最近想寫一個關於Android的介面,類似於遙控器按鈕形狀,就是類似於下面這張圖片,但是我想設計的使上下左右四個按鈕不是連在一起的,他們之間是有間隔的。在設計的途中關於畫弧線這個函式,我一直沒有理解,所以就這部分進行了一些測試,大家看過這張圖片之後就明白
Android 自定義View練習:雷達圖(比重)繪製
code: package com.louisgeek.louiscustomviewstudy; import android.content.Context; import android.content.res.Resources; import
android 自定義dialog並實現失去焦點(背景透明)的功能
前言:由於在專案中需要用到更新顯示動畫的需求,所以想到了dialog,自定義dialog不難,網上教程很多,但是在實現dialog背景透明的需求時,遇到了一點問題,網上的一些方法在我的機器上並沒有實現,只能曲折中找到了另一個方法實現。雖然有點麻煩,但畢竟效果不錯。 此方法寫
Android 自定義視訊錄製終極解決方案(翻轉問題)
Android 自定義視訊錄製翻轉問題終極解決方案 自定義視訊錄製 使用系統可用播放器 前後攝像和視訊反轉問題 總結 自定義視訊錄製 mediarecorder = new MediaRecorder();// 建立mediarecorde
android自定義View之3D索引效果
效果圖: 我的小霸王太卡了。 最近工作比較忙,今天搞了一下午才搞出來這個效果,這種效果有很多種實現方式,最常見的應該是用貝塞爾曲線實現的。今天我們來看另一種不同的實現方式,只需要用到 canvas.scale(),有沒有很好奇是怎麼實現的呢。 首先來說一下思路,只要有了思
android 自定義view之側滑效果
效果圖: 看網上的都是兩個view拼接,預設右側的不顯示,水平移動的時候把右側的view顯示出來。但是看最新版QQ上的效果不是這樣的,但給人的感覺卻很好,所以獻醜來一發比較高仿的。 知識點: 1、ViewDragHelper 的用法; 2、滑動衝突的解決; 3、自定
Android自定義View之水波紋顯示進度效果
@Override protected void onDraw(Canvas canvas) { if (null != backgroundBitmap) { canvas.drawBitmap(createImage(), 0, 0, null);
Android 自定義View之TextView跑馬燈效果
public class MarqueeView extends SurfaceView implements SurfaceHolder.Callback{ public Context mContext; private float mTextSize = 100; //字型大小
Android自定義View之ListView實現時間軸效果:我只是個送快遞的。
先上效果圖: 實現時間軸的原理 listview的基本使用,相信大家都很熟悉。先在layout下新建一個xml佈局檔案,對應一個子項的listView的顯示內容。在上面的圖我們可以看到,每一項都是 有3個 textview控制元件
Android自定義View之點選效果
最近在做新版本,各種UI效果都需要自定義,而自定義View點選效果問題一直困擾著我。各種找資料也沒有找到自己想要的東西,可能是我關鍵字打的不對吧。最後在檢視TextView的原始碼時解決了我的問題,由於原始碼功能太多,不易查詢,特此提取記錄。 UI效果
Android自定義View之使用Path繪製手勢軌跡和水波效果
先看下效果圖: 繪製軌跡 繪製手指的軌跡主要是攔截View的onTouchEvent()方法,並根據手指的軌跡繪製path。path中有兩種可以實現的方法 1、Path.lineTo(x,y)方法 public class MoveP
Android -- 自定義view實現keep歡迎頁倒計時效果
super onfinish -m use new getc awt ttr alt 1,最近打開keep的app的時候,發現它的歡迎頁面的倒計時效果還不錯,所以打算自己來寫寫,然後就有了這篇文章。 2,還是老規矩,先看一下我們今天實現的效果 相較於我們常見的倒計時
Android自定義View效果目錄
class 重寫 自定義 textview 居中 url 冒泡 and 雷達圖 1、絢麗的loading動效的實現 2、Android自定義View:進度條+冒泡文本 3、Android雷達圖(蜘蛛網圖) 4、Android文本閃爍 5、Android繪制圓形進度條 6、重
Android自定義View——實現水波紋效果類似剩余流量球
string 三個點 pre ber block span 初始化 move 理解 最近突然手癢就想搞個貝塞爾曲線做個水波紋效果玩玩,終於功夫不負有心人最後實現了想要的效果,一起來看下吧: 效果圖鎮樓 一:先一步一步來分解一下實現的過程 需要繪制一個正弦曲線(sin