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

Android实战简易教程<四十四>(Ripple Effect-为控件增加涟漪效果)

2015-09-26 11:23 701 查看
最近发现了一款可以为控件增加涟漪效果的github项目,可以提升应用的逼格啊,大家不妨引入到自己的项目中。该项目本身是android studio下面编译,我改成了eclipse下可以运行的项目,下面我们来看一下具体的用法吧!

1.RippleView.java:

[java] view
plaincopy

/*

* The MIT License (MIT)

*

* Copyright (c) 2014 Robin Chutaux

*

* Permission is hereby granted, free of charge, to any person obtaining a copy

* of this software and associated documentation files (the "Software"), to deal

* in the Software without restriction, including without limitation the rights

* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell

* copies of the Software, and to permit persons to whom the Software is

* furnished to do so, subject to the following conditions:

*

* The above copyright notice and this permission notice shall be included in

* all copies or substantial portions of the Software.

*

* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,

* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE

* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER

* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,

* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN

* THE SOFTWARE.

*/



package com.example.rippleeffectview;



import com.example.test.R;



import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Bitmap;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.PorterDuff;

import android.graphics.PorterDuffXfermode;

import android.graphics.Rect;

import android.os.Handler;

import android.util.AttributeSet;

import android.view.GestureDetector;

import android.view.MotionEvent;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.Animation;

import android.view.animation.ScaleAnimation;

import android.widget.RelativeLayout;



/**

*

* Date : 10/8/2014

*/

public class RippleView extends RelativeLayout

{

private int WIDTH;

private int HEIGHT;

private int FRAME_RATE = 10;

private int DURATION = 400;

private int PAINT_ALPHA = 90;

private Handler canvasHandler;

private float radiusMax = 0;

private boolean animationRunning = false;

private int timer = 0;

private int timerEmpty = 0;

private int durationEmpty = -1;

private float x = -1;

private float y = -1;

private int zoomDuration;

private float zoomScale;

private ScaleAnimation scaleAnimation;

private Boolean hasToZoom;

private Boolean isCentered;

private Integer rippleType;

private Paint paint;

private Bitmap originBitmap;

private int rippleColor;

private View childView;

private int ripplePadding;

private GestureDetector gestureDetector;

private Runnable runnable = new Runnable()

{

@Override

public void run()

{

invalidate();

}

};



public RippleView(Context context)

{

super(context);

}



public RippleView(Context context, AttributeSet attrs)

{

super(context, attrs);

init(context, attrs);

}



public RippleView(Context context, AttributeSet attrs, int defStyle)

{

super(context, attrs, defStyle);

init(context, attrs);

}



private void init(final Context context, final AttributeSet attrs)

{

if (isInEditMode())

return;



final TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.RippleView);

rippleColor = typedArray.getColor(R.styleable.RippleView_rv_color, getResources().getColor(R.color.rippelColor));

rippleType = typedArray.getInt(R.styleable.RippleView_rv_type, 0);

hasToZoom = typedArray.getBoolean(R.styleable.RippleView_rv_zoom, false);

isCentered = typedArray.getBoolean(R.styleable.RippleView_rv_centered, false);

DURATION = typedArray.getInteger(R.styleable.RippleView_rv_rippleDuration, DURATION);

FRAME_RATE = typedArray.getInteger(R.styleable.RippleView_rv_framerate, FRAME_RATE);

PAINT_ALPHA = typedArray.getInteger(R.styleable.RippleView_rv_alpha, PAINT_ALPHA);

ripplePadding = typedArray.getDimensionPixelSize(R.styleable.RippleView_rv_ripplePadding, 0);

canvasHandler = new Handler();

zoomScale = typedArray.getFloat(R.styleable.RippleView_rv_zoomScale, 1.03f);

zoomDuration = typedArray.getInt(R.styleable.RippleView_rv_zoomDuration, 200);

paint = new Paint();

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.FILL);

paint.setColor(rippleColor);

paint.setAlpha(PAINT_ALPHA);

this.setWillNotDraw(false);



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

{

@Override

public boolean onSingleTapConfirmed(MotionEvent e)

{

return true;

}



@Override

public boolean onSingleTapUp(MotionEvent e)

{

return true;

}

});



this.setDrawingCacheEnabled(true);

}



@Override

public void addView(View child, int index, ViewGroup.LayoutParams params)

{

childView = child;

super.addView(child, index, params);

}



@Override

public void draw(Canvas canvas)

{

super.draw(canvas);

if (animationRunning)

{

if (DURATION <= timer * FRAME_RATE)

{

animationRunning = false;

timer = 0;

durationEmpty = -1;

timerEmpty = 0;

canvas.restore();

invalidate();

return;

}

else

canvasHandler.postDelayed(runnable, FRAME_RATE);



if (timer == 0)

canvas.save();





canvas.drawCircle(x, y, (radiusMax * (((float) timer * FRAME_RATE) / DURATION)), paint);



paint.setColor(getResources().getColor(android.R.color.holo_red_light));



if (rippleType == 1 && originBitmap != null && (((float) timer * FRAME_RATE) / DURATION) > 0.4f)

{

if (durationEmpty == -1)

durationEmpty = DURATION - timer * FRAME_RATE;



timerEmpty++;

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

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

tmpBitmap.recycle();

}



paint.setColor(rippleColor);



if (rippleType == 1)

{

if ((((float) timer * FRAME_RATE) / DURATION) > 0.6f)

paint.setAlpha((int) (PAINT_ALPHA - ((PAINT_ALPHA) * (((float) timerEmpty * FRAME_RATE) / (durationEmpty)))));

else

paint.setAlpha(PAINT_ALPHA);

}

else

paint.setAlpha((int) (PAINT_ALPHA - ((PAINT_ALPHA) * (((float) timer * FRAME_RATE) / DURATION))));



timer++;

}

}



@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(1.0f, zoomScale, 1.0f, zoomScale, w / 2, h / 2);

scaleAnimation.setDuration(zoomDuration);

scaleAnimation.setRepeatMode(Animation.REVERSE);

scaleAnimation.setRepeatCount(1);

}



@Override

public boolean onTouchEvent(MotionEvent event)

{

if (gestureDetector.onTouchEvent(event) && !animationRunning)

{

if (hasToZoom)

this.startAnimation(scaleAnimation);



radiusMax = Math.max(WIDTH, HEIGHT);



if (rippleType != 2)

radiusMax /= 2;



radiusMax -= ripplePadding;



if (isCentered || rippleType == 1)

{

this.x = getMeasuredWidth() / 2;

this.y = getMeasuredHeight() / 2;

}

else

{

this.x = event.getX();

this.y = event.getY();

}



animationRunning = true;



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

originBitmap = getDrawingCache(true);



invalidate();

this.performClick();

}



childView.onTouchEvent(event);

return true;

}



@Override

public boolean onInterceptTouchEvent(MotionEvent event)

{

return true;

}



private Bitmap getCircleBitmap(final int radius) {

final Bitmap output = Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);

final Canvas canvas = new Canvas(output);

final Paint paint = new Paint();

final Rect rect = new Rect((int)(x - radius), (int)(y - radius), (int)(x + radius), (int)(y + radius));



paint.setAntiAlias(true);

canvas.drawARGB(0, 0, 0, 0);

canvas.drawCircle(x, y, radius, paint);



paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

canvas.drawBitmap(originBitmap, rect, rect, paint);



return output;

}

}

2.MainActivity.java:

[java] view
plaincopy

package com.example.test;



import com.example.rippleeffectview.RippleView;



import android.os.Bundle;

import android.support.v7.app.ActionBarActivity;

import android.view.Menu;

import android.view.MenuItem;



public class MainActivity extends ActionBarActivity {



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

final RippleView rippleView = (RippleView) findViewById(R.id.more);

}



@Override

public boolean onCreateOptionsMenu(Menu menu) {

// Inflate the menu; this adds items to the action bar if it is present.

getMenuInflater().inflate(R.menu.main, menu);

return true;

}



@Override

public boolean onOptionsItemSelected(MenuItem item) {

// Handle action bar item clicks here. The action bar will

// automatically handle clicks on the Home/Up button, so long

// as you specify a parent activity in AndroidManifest.xml.

int id = item.getItemId();

if (id == R.id.action_settings) {

return true;

}

return super.onOptionsItemSelected(item);

}

}

3.布局文件应该是需要注意的地方:

[html] view
plaincopy

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:ripple="http://schemas.android.com/apk/res-auto"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent" >



<com.example.rippleeffectview.RippleView

android:id="@+id/more"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_margin="5dp"

ripple:rv_centered="true"

ripple:rv_type="rectangle" >



<Button

android:layout_width="match_parent"

android:layout_height="80dp"

android:background="@color/switch_thumb_normal_material_dark"

android:text="I like Color" />

</com.example.rippleeffectview.RippleView>



</RelativeLayout>

需要注意的地方如下图:

ripple:rv_centered="true"表示涟漪出现在中间位置;

ripple:rv_type="rectangle"表示涟漪的形状-长方形;

此外还有:

ripple:rv_type="doubleRipple"表示双涟漪;

ripple:rv_zoom="true"表示控件有缩放效果

ripple:rv_color="#000000"表示涟漪的颜色为黑色

还有其他属性在这里:

[html] view
plaincopy

<resources>

<declare-styleable name="RippleView">

<attr name="rv_alpha" format="integer" />

<attr name="rv_framerate" format="integer"/>

<attr name="rv_rippleDuration" format="integer"/>

<attr name="rv_zoomDuration" format="integer" />

<attr name="rv_color" format="color" />

<attr name="rv_centered" format="boolean" />

<attr name="rv_type" format="enum">

<enum name="simpleRipple" value="0"/>

<enum name="doubleRipple" value="1"/>

<enum name="rectangle" value="2" />

</attr>

<attr name="rv_ripplePadding" format="dimension" />

<attr name="rv_zoom" format="boolean" />

<attr name="rv_zoomScale" format="float" />



</declare-styleable>

</resources>

大家可以自行测试效果。

运行效果如下:








下面讨论一下如何将项目引入到自己的工程中:

复制上面箭头指向的三个文件到自己的项目中,按照上面例子所示的方法把控件包起来即可使用,非常方便,不懂的地方可以留言,谢谢!

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