实例介绍
参照:http://blog.csdn.net/Poison_H/article/details/43735445。点击手机屏幕实现水波效果,如下图:
【核心代码】
public class WaterWaveView extends SurfaceView implements SurfaceHolder.Callback { // 背景图的宽度和高度 private int backWidth; private int backHeight; /** * buf1 和 buf2是波能缓冲区,分别代表了每个点的前一时刻和后一时刻的波幅数据 */ private short[] buf1; private short[] buf2; private int[] bitmap1; private int[] bitmap2; private Bitmap bgImage = null; // 是否第一次加载 private boolean firstLoad = false; WavingThread wavingThread = new WavingThread(); // 显示一个surface的抽象接口,使你可以控制surface的大小和格式, 以及在surface上编辑像素,和监视surace的改变 SurfaceHolder mSurfaceHolder = null; private int doubleWidth; private int fiveWidth; // 持续时间 private int loopTime; private int bitmapLen; public WaterWaveView(Context context) { super(context); mSurfaceHolder = getHolder(); mSurfaceHolder.addCallback(this); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { if (!firstLoad) { // 背景图 bgImage = BitmapFactory.decodeResource(this.getResources(), R.drawable.bg); bgImage = Bitmap.createScaledBitmap(bgImage, w, h, false);// 缩放而已 backWidth = bgImage.getWidth(); backHeight = bgImage.getHeight(); buf2 = new short[backWidth * backHeight]; buf1 = new short[backWidth * backHeight]; bitmap2 = new int[backWidth * backHeight]; bitmap1 = new int[backWidth * backHeight]; // 将bgImage的像素拷贝到bitmap1数组中,用于渲染。。。 bgImage.getPixels(bitmap1, 0, backWidth, 0, 0, backWidth, backHeight); bgImage.getPixels(bitmap2, 0, backWidth, 0, 0, backWidth, backHeight); for (int i = 0; i < backWidth * backHeight; i) { buf2[i] = 0; buf1[i] = 0; } doubleWidth = backWidth << 1; fiveWidth = 5 * backWidth; loopTime = ((backHeight - 4) * backWidth) >> 1; bitmapLen = backWidth * backHeight - 1; firstLoad = true; } } class WavingThread extends Thread { boolean running = true; public void setRunning(boolean running) { this.running = running; } @Override public void run() { Canvas c = null; while (running) { c = mSurfaceHolder.lockCanvas(); makeRipple(); doDraw(c); mSurfaceHolder.unlockCanvasAndPost(c); } } } /******************************************************* * 计算波能数据缓冲区 *******************************************************/ private void makeRipple() { int k = fiveWidth; int xoff = 0, yoff = 0; int cp = 0; int tarClr = 0; int i = fiveWidth; while (i < loopTime) { // 波能扩散 buf2[k] = (short) (((buf1[k - 2] buf1[k 2] buf1[k - doubleWidth] buf1[k doubleWidth]) >> 1) - buf2[k]); // 波能衰减 buf2[k] = (short) (buf2[k] - (buf2[k] >> 5)); // 求出该点的左上的那个点xoff,yoff cp = k - doubleWidth - 2; xoff = buf2[cp - 2] - buf2[cp 2]; yoff = buf2[cp - doubleWidth] - buf2[k - 2]; tarClr = k yoff * doubleWidth xoff; if (tarClr > bitmapLen || tarClr < 0) { k = 2; continue; } // 复制象素 bitmap2[k] = bitmap1[tarClr]; k = 2; i; } short[] tmpBuf = buf2; buf2 = buf1; buf1 = tmpBuf; } /***************************************************** * 增加波源 x坐标 y坐标 波源半径 波源能量 *****************************************************/ private void touchWater(int x, int y, int stonesize, int stoneweight) { // 判断坐标是否在屏幕范围内 if (x stonesize > backWidth) { return; } if (y stonesize > backHeight) { return; } if (x - stonesize < 0) { return; } if (y - stonesize < 0) { return; } // 产生波源,填充前导波能缓冲池 int endStoneX = x stonesize; int endStoneY = y stonesize; int squaSize = stonesize * stonesize; int posy = y - stonesize; int posx = x - stonesize; for (posy = y - stonesize; posy < endStoneY; posy) { for (posx = x - stonesize; posx < endStoneX; posx) { if ((posx - x) * (posx - x) (posy - y) * (posy - y) < squaSize) { buf1[backWidth * posy posx] = (short) -stoneweight; } } } } /***************************************************** * 增加波源 x坐标 y坐标 波源半径 波源能量 *****************************************************/ private void trickWater(int x, int y, int stonesize, int stoneweight) { // 判断坐标是否在屏幕范围内 if (x stonesize > backWidth) { return; } if (y stonesize > backHeight) { return; } if (x - stonesize < 0) { return; } if (y - stonesize < 0) { return; } // 产生波源,填充波能缓冲池 int endStoneX = x stonesize; int endStoneY = y stonesize; int posy = y - stonesize; int posx = x - stonesize; for (posy = y - stonesize; posy < endStoneY; posy) { for (posx = x - stonesize; posx < endStoneX; posx) { if (posy >= 0 && posy < backHeight && posx >= 0 && posx < backWidth) { buf1[backWidth * posy posx] = (short) -stoneweight; } } } } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN) { // 设置波源半径和波源能量 touchWater((int) event.getX(), (int) event.getY(), 200, 300); } else if (event.getAction() == MotionEvent.ACTION_MOVE) { trickWater((int) event.getX(), (int) event.getY(), 200, 300); } return true; } protected void doDraw(Canvas canvas) { /** * Parameters: 1.colors 2.offset 3.stride 4.x 5. y 6.width 7.height * 8.hasAlpha 9. paint */ //绘制 canvas.drawBitmap(bitmap2, 0, backWidth, 0, 0, backWidth, backHeight, false, null); } @Override public void surfaceCreated(SurfaceHolder holder) { wavingThread.setRunning(true); wavingThread.start(); } @Override public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; wavingThread.setRunning(false); // 非暴力关闭线程,直到此次该线程运行结束之前,主线程停止运行,以防止Surface被重新激活 while (retry) { try { wavingThread.join(); // 阻塞current // Thread(当前执行线程)直到被调用线程(thread)完成。 retry = false; } catch (InterruptedException e) { } } } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // TODO Auto-generated method stub } }
waterWaveView = new WaterWaveView(this); setContentView(waterWaveView);
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明
网友评论
我要评论