您的位置:首页 > 移动开发 > Android开发

安卓学习笔记---Android源码解析--Material Design之水波纹点击效果RippleEffect使用

2016-09-12 14:53 661 查看
今天老板跟我说,能不能加一个点击效果,要不然用户不知道他是否已经点击了,我说好的,刚开始我是使用的selector添加效果的,UI看了之后说好丑啊,能不能改的好看点啊,哎,,,果然好难啊,咋滴都得好看呐

,于是就另找方法吧

我记得以前看过那个点击之后显示水波纹的效果感觉很酷炫啊,我觉得我要是加上的话,感觉会不会好点,哈哈,说干就干。

这个好像是5.0添加的特性,当我看到这篇文章,眼前一亮:

转载文章地址:
http://blog.csdn.net//lyhhj/article/details/48505041
Android5.0已经出了好久了,但是目前市场上的App好像没有多少用5.0上面的一些效果,依旧延续着之前的控件使用,但是既然新的东西已经出来了,就必定会淘汰旧的不好的,所以我们要与时俱进。其中Material Design真的很不错,其中有好多酷炫的动画,Android5.0的SwipeRefreshLayout会取代之前的PullToRefreshListView、RecyclerView,CardView也会取代ListView、MaterialEdittext也会取代Edittex以及一些FloatButton等等,以后会逐一介绍的。今天我们看一下RippleEffect水波纹点击效果,先上图:



大家可以看到按钮或者布局点击的时候会有水波涟漪的效果,很不错,用到你的app上一定会很高大上的。

下面我们分析一下源码,然后再看怎么使用,因为我觉得如果你光会用但是不了解怎么实现的你最多也就算个码农,所以我们要尝试着读懂源码,然后再尝试着自己定义view
首先在init()方法中初始化一些组件和styles,并设置相应的属性包括设置画布的抗锯齿标志、画图的实心空心、透明度颜色的设置。

[java] view
plain copy

<span style="font-size:14px;"><span style="white-space: pre;"> </span>paint = new Paint();

paint.setAntiAlias(true); //设置画布抗锯齿标志

paint.setStyle(Paint.Style.FILL); //设置画图实心

paint.setColor(rippleColor); //设置画图颜色

paint.setAlpha(rippleAlpha); //设置透明度

this.setWillNotDraw(false); //设置将不绘画</span>

然后创建手势,因为我们的点击有可能为长点击,我们用手势来做一些操作

[java] view
plain copy

<span style="font-size:14px;"><span style="white-space:pre"> </span>/**

* 创建新的手势

*/

gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {

@Override

public void onLongPress(MotionEvent event) {

super.onLongPress(event);

animateRipple(event); //创建动画

sendClickEvent(true); //发送长点击事件

}

@Override

public boolean onSingleTapConfirmed(MotionEvent e) {

return true;

}

@Override

public boolean onSingleTapUp(MotionEvent e) {

return true;

}

});

this.setDrawingCacheEnabled(true); //更新cache,提高绘图速度

this.setClickable(true);</span>

接下来重写OnDraw()方法

[java] view
plain copy

<span style="font-size:14px;">@Override

public void draw(Canvas canvas) {

super.draw(canvas);

if (animationRunning) {

if (rippleDuration <= timer * frameRate) {

animationRunning = false;

timer = 0;

durationEmpty = -1;

timerEmpty = 0;

canvas.restore();

invalidate();

if (onCompletionListener != null) onCompletionListener.onComplete(this);

return;

} else

canvasHandler.postDelayed(runnable, frameRate);

if (timer == 0)

canvas.save();

canvas.drawCircle(x, y, (radiusMax * (((float) timer * frameRate) / rippleDuration)), paint); //画圆的半径

paint.setColor(Color.parseColor("#ffff4444")); //设置颜色

if (rippleType == 1 && originBitmap != null && (((float) timer * frameRate) / rippleDuration) > 0.4f) {

if (durationEmpty == -1)

durationEmpty = rippleDuration - timer * frameRate;

timerEmpty++;

//创建圆的bitmap

final Bitmap tmpBitmap = getCircleBitmap((int) ((radiusMax) * (((float) timerEmpty * frameRate) / (durationEmpty))));

canvas.drawBitmap(tmpBitmap, 0, 0, paint);

tmpBitmap.recycle();

}

paint.setColor(rippleColor);

if (rippleType == 1) {

if ((((float) timer * frameRate) / rippleDuration) > 2f)

paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timerEmpty * frameRate) / (durationEmpty)))));

else

paint.setAlpha(rippleAlpha);

}

else

paint.setAlpha((int) (rippleAlpha - ((rippleAlpha) * (((float) timer * frameRate) / rippleDuration))));

timer++;

}

}</span>

这里面包括我们设置圆的颜色、半径大小,透明度(透明度是根据距离的增长而越来越透明的)

最重要的核心部分也就是创建动画了:

[java] view
plain copy

<span style="font-size:18px;"> </span><span style="font-size:14px;">/**

* Create Ripple animation centered at x, y

*

* @param x Horizontal position of the ripple center

* @param y Vertical position of the ripple center

*/

private void createAnimation(final float x, final float y) {

if (this.isEnabled() && !animationRunning) {

if (hasToZoom)

this.startAnimation(scaleAnimation);

radiusMax = Math.max(WIDTH, HEIGHT);

if (rippleType != 2)

radiusMax /= 1;

radiusMax -= ripplePadding;

if (isCentered || rippleType == 1) {

this.x = getMeasuredWidth() ;

this.y = getMeasuredHeight() ;

} else {

this.x = x;

this.y = y;

}

animationRunning = true;

if (rippleType == 1 && originBitmap == null)

originBitmap = getDrawingCache(true);

invalidate();

}

}</span>

我们可以在这里面设置圆的最大半径,最大半径越大,我们得到的水波涟漪效果越快,越小,得到的水波涟漪效果越慢,也就是radiusMax /=1,这句代码。

那我们的动画怎么设置呢?当然用ScaleAnimation动画了

[java] view
plain copy

<span style="font-size:14px;">@Override

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

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

WIDTH = w;

HEIGHT = h;

scaleAnimation = new ScaleAnimation(2.0f, zoomScale, 2.0f, zoomScale, w / 2, h / 2);

scaleAnimation.setDuration(zoomDuration);

scaleAnimation.setRepeatMode(Animation.REVERSE);

scaleAnimation.setRepeatCount(1);

}</span>

它的参数如下:

ScaleAnimation(float fromX, float toX, float fromY, float toY,int pivotXType, float pivotXValue, int pivotYType, float pivotYValue)

参数说明:

float fromX 动画起始时 X坐标上的伸缩尺寸

float toX 动画结束时 X坐标上的伸缩尺寸

float fromY 动画起始时Y坐标上的伸缩尺寸

float toY 动画结束时Y坐标上的伸缩尺寸

int pivotXType 动画在X轴相对于物件位置类型

float pivotXValue 动画相对于物件的X坐标的开始位置

int pivotYType 动画在Y轴相对于物件位置类型

float pivotYValue 动画相对于物件的Y坐标的开始位置

好了,这样差不多就完成了我们的水波涟漪效果了。。。。

看一下怎么用吧?

如果你的开发IDE是Android Studio那么我们可以把github上的库集成到我们的项目中,

[java] view
plain copy

<span style="font-size:14px;">dependencies {

compile 'com.github.traex.rippleeffect:library:1.2.3'

} </span>

在我们的布局中引用RippleEffect就OK了

[java] view
plain copy

<span style="font-size:14px;"><com.Hankkin.library.RippleView

android:id="@+id/more"

android:layout_width="?android:actionBarSize"

android:layout_height="?android:actionBarSize"

android:layout_toLeftOf="@+id/more2"

android:layout_margin="5dp"

ripple:rv_centered="true">

<ImageView

android:layout_width="?android:actionBarSize"

android:layout_height="?android:actionBarSize"

android:src="@android:drawable/ic_menu_edit"

android:layout_centerInParent="true"

android:padding="10dp"

android:background="@android:color/holo_blue_dark"/>

</com.Hankkin.library.RippleView> </span>

当然你也可以把库中的RippleView直接拷到我们的项目里面,还可以该里面的动画快慢速度等,注意也要把库里面的styles,attrs拷进来,放到自己的项目里面,就可以自己改一些配置了。

——————————————————————————————————————————————————————————————————————————————————————————————————————

下面再和大家说一下比较重要的一点吧,这个网上的demo都没有说,是我自己用的时候发现的

也就是我们的点击事件,这时候如果你还用普通的OnClickListener()是不行的,因为动画还没有结束,就直接startIntent()跳转界面了,如果你的界面没有finish()掉的话,返回的时候动画会继续执行完。

那么怎么破呢?

我们就需要给我们的RippleView设置监听事件而不是我们的控件设置监听事件了,因为我们的RippleView中有这样一个接口:

[java] view
plain copy

<span style="font-size:14px;">public interface OnRippleCompleteListener {

void onComplete(RippleView rippleView);

} </span>

也就是动画完成的事件

[java] view
plain copy

<span style="font-size:14px;">RippleView view = (RippleView) findViewById(R.id.reView);

view.setOnRippleCompleteListener(new RippleView.OnRippleCompleteListener() {

@Override

public void onComplete(RippleView rippleView) {

Intent intent = new Intent(getApplicationContext(),HelloActivity.class);

startActivity(intent);

}

}); </span>

这样我们就实现了动画完成之后才来实现界面跳转了

小伙伴们,快试一下吧。

当然我们的ListView的item点击也可以实现这样的效果,因为我们的RippleView中是支持Listview点击的

[java] view
plain copy

/**

* Send a click event if parent view is a Listview instance

* 若为Listview发送点击事件

* @param isLongClick Is the event a long click ?

*/

private void sendClickEvent(final Boolean isLongClick) {

if (getParent() instanceof AdapterView) {

final AdapterView adapterView = (AdapterView) getParent();

final int position = adapterView.getPositionForView(this);

final long id = adapterView.getItemIdAtPosition(position);

if (isLongClick) {

if (adapterView.getOnItemLongClickListener() != null)

adapterView.getOnItemLongClickListener().onItemLongClick(adapterView, this, position, id);

} else {

if (adapterView.getOnItemClickListener() != null)

adapterView.getOnItemClickListener().onItemClick(adapterView, this, position, id);

}

}

}

这里先提一下,以后会详细说怎么用的.....

github地址:
https://github.com/traex/RippleEffect
博主讲的很透彻啊,果断使用到自己的项目中去了,看了看效果,感觉效果还不错呢


虽然博主已经提供资源地址,我自己还是上传到了自己的资源上,好方便下载吗,嘿嘿,感谢哦。

下载地址:

点击打开链接
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐