Android点击屏幕出现水波纹效果
2015-02-11 16:28
369 查看
在http://blog.csdn.net/poison_h/article/details/43635955这篇文章,介绍了如何给按钮设置水波纹效果。
可能有人会想到可不可以点击背景的时候也出现水波纹效果呢?其实当时我也是这样想的。没有想到Google下,还真的找到了,又一次站在了巨人的肩上。虽然是站在巨人的肩上,但是也要自己懂得才行,要转变自己得知识才是最棒的
好了,先看下效果图:
![](https://oscdn.geek-share.com/Uploads/Images/Content/202011/18/524f35cd93a8e5cf711fa2ae29c34dc6)
1.首先我们需要重写SurfaceView:
SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。
surface是纵深排序(Z-ordered)的,这表明它总在自己所在窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内 的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者
surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
你可以通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口。
surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意:
1> 所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。
2> 由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。
(1)、第一步在onSizeChanged()方法中,设置背景图片,并且根据背景图片设置两个波能缓冲区大小,并初始化。
2.计算波能数据缓冲区
3.最后分别对move和down事件分别进行填充不同的波能缓冲池
详细代码:
最后在我MainActivity中调用:
可能有人会想到可不可以点击背景的时候也出现水波纹效果呢?其实当时我也是这样想的。没有想到Google下,还真的找到了,又一次站在了巨人的肩上。虽然是站在巨人的肩上,但是也要自己懂得才行,要转变自己得知识才是最棒的
好了,先看下效果图:
1.首先我们需要重写SurfaceView:
SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸。Surfaceview控制这个Surface的绘制位置。
surface是纵深排序(Z-ordered)的,这表明它总在自己所在窗口的后面。surfaceview提供了一个可见区域,只有在这个可见区域内 的surface部分内容才可见,可见区域外的部分不可见。surface的排版显示受到视图层级关系的影响,它的兄弟视图结点会在顶端显示。这意味者
surface的内容会被它的兄弟视图遮挡,这一特性可以用来放置遮盖物(overlays)(例如,文本和按钮等控件)。注意,如果surface上面 有透明控件,那么它的每次变化都会引起框架重新计算它和顶层控件的透明效果,这会影响性能。
你可以通过SurfaceHolder接口访问这个surface,getHolder()方法可以得到这个接口。
surfaceview变得可见时,surface被创建;surfaceview隐藏前,surface被销毁。这样能节省资源。如果你要查看 surface被创建和销毁的时机,可以重载surfaceCreated(SurfaceHolder)和 surfaceDestroyed(SurfaceHolder)。
surfaceview的核心在于提供了两个线程:UI线程和渲染线程。这里应注意:
1> 所有SurfaceView和SurfaceHolder.Callback的方法都应该在UI线程里调用,一般来说就是应用程序主线程。渲染线程所要访问的各种变量应该作同步处理。
2> 由于surface可能被销毁,它只在SurfaceHolder.Callback.surfaceCreated()和 SurfaceHolder.Callback.surfaceDestroyed()之间有效,所以要确保渲染线程访问的是合法有效的surface。
(1)、第一步在onSizeChanged()方法中,设置背景图片,并且根据背景图片设置两个波能缓冲区大小,并初始化。
// 背景图 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; }
2.计算波能数据缓冲区
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; }
3.最后分别对move和down事件分别进行填充不同的波能缓冲池
// 产生波源,填充前导波能缓冲池 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; } } }
详细代码:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
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(), 4, 160);
} else if (event.getAction() == MotionEvent.ACTION_MOVE)
{
trickWater((int) event.getX(), (int) event.getY(), 2, 64);
}
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
}
}
最后在我MainActivity中调用:
waterWaveView = new WaterWaveView(this); setContentView(waterWaveView);
相关文章推荐
- Android L 水波纹点击效果
- android 控件点击波纹效果
- android 点击水波纹效果
- Android 水波纹点击效果(Ripple Effect)
- Android riple material 点击水波纹效果
- android简单仿android5.0点击波纹效果
- android如何实现按钮的点击水波纹效果:
- Android 设置主题实现点击波纹效果
- Android 水波纹点击效果(Ripple Effect)
- Android中5.0实现点击水波纹效果
- Android仿相册点击屏幕出现标题和底部菜单
- Android源码解析--Material Design之水波纹点击效果RippleEffect使用
- Android 水波纹点击效果(Ripple Effect)
- Android 水波纹点击效果(Ripple Effect)
- Android 设置主题实现点击波纹效果
- Android 之实用小代码-获取屏幕尺寸、判断是否是平板、文字颜色、点击效果、计算字宽等。
- android RadioButton 点击时候出现点击声音的效果
- Android Material适配 为控件设置指定背景色和点击波纹效果
- android 按钮点击效果实现 在studio下出现的错误
- Android特效专辑(十)——点击水波纹效果实现,逻辑清晰实现简单