android 圆角 水波纹_android 5.0 水波纹 实现

RippleView是一个自定义视图,用于在Android上实现圆角水波纹效果。它支持设置颜色、动画时长、帧率、透明度等属性,并提供了长按和点击事件的处理。通过GestureDetector监听触摸事件,触发水波纹动画,同时可选择是否伴随缩放动画。
摘要由CSDN通过智能技术生成

public class RippleView extendsRelativeLayout {private intWIDTH;private intHEIGHT;private int frameRate = 10;private int rippleDuration = 400;private int rippleAlpha = 90;privateHandler 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 intzoomDuration;private floatzoomScale;privateScaleAnimation scaleAnimation;privateBoolean hasToZoom;privateBoolean isCentered;privateInteger rippleType;privatePaint paint;privateBitmap originBitmap;private intrippleColor;private intripplePadding;privateGestureDetector gestureDetector;private final Runnable runnable = newRunnable() {

@Overridepublic voidrun() {

invalidate();

}

};privateOnRippleCompleteListener onCompletionListener;publicRippleView(Context context) {super(context);

}publicRippleView(Context context, AttributeSet attrs) {super(context, attrs);

init(context, attrs);

}public RippleView(Context context, AttributeSet attrs, intdefStyle) {super(context, attrs, defStyle);

init(context, attrs);

}/*** Method that initializes all fields and sets listeners

*

*@paramcontext Context used to create this view

*@paramattrs Attribute used to initialize fields*/

private void init(final Context context, finalAttributeSet 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);

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

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

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

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

canvasHandler= newHandler();

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

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

typedArray.recycle();

paint= newPaint();

paint.setAntiAlias(true);

paint.setStyle(Paint.Style.FILL);

paint.setColor(rippleColor);

paint.setAlpha(rippleAlpha);this.setWillNotDraw(false);

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

@Overridepublic voidonLongPress(MotionEvent event) {super.onLongPress(event);

animateRipple(event);

sendClickEvent(true);

}

@Overridepublic booleanonSingleTapConfirmed(MotionEvent e) {return true;

}

@Overridepublic booleanonSingleTapUp(MotionEvent e) {return true;

}

});this.setDrawingCacheEnabled(true);this.setClickable(true);

}

@Overridepublic voiddraw(Canvas canvas) {super.draw(canvas);if(animationRunning) {

canvas.save();if (rippleDuration <= timer *frameRate) {

animationRunning= false;

timer= 0;

durationEmpty= -1;

timerEmpty= 0;//There is problem on Android M where canvas.restore() seems to be called automatically//For now, don't call canvas.restore() manually on Android M (API 23)

if(Build.VERSION.SDK_INT != 23) {

canvas.restore();

}

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

}elsecanvasHandler.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++;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) > 0.6f)

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

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

timer++;

}

}

@Overrideprotected void onSizeChanged(int w, int h, int oldw, intoldh) {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);

}/*** Launch Ripple animation for the current view with a MotionEvent

*

*@paramevent MotionEvent registered by the Ripple gesture listener*/

public voidanimateRipple(MotionEvent event) {

createAnimation(event.getX(), event.getY());

}/*** Launch Ripple animation for the current view centered at x and y position

*

*@paramx Horizontal position of the ripple center

*@paramy Vertical position of the ripple center*/

public void animateRipple(final float x, final floaty) {

createAnimation(x, y);

}/*** Create Ripple animation centered at x, y

*

*@paramx Horizontal position of the ripple center

*@paramy Vertical position of the ripple center*/

private void createAnimation(final float x, final floaty) {if (this.isEnabled() && !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 =x;this.y =y;

}

animationRunning= true;if (rippleType == 1 && originBitmap == null)

originBitmap= getDrawingCache(true);

invalidate();

}

}

@Overridepublic booleanonTouchEvent(MotionEvent event) {if(gestureDetector.onTouchEvent(event)) {

animateRipple(event);

sendClickEvent(false);

}return super.onTouchEvent(event);

}

@Overridepublic booleanonInterceptTouchEvent(MotionEvent event) {this.onTouchEvent(event);return super.onInterceptTouchEvent(event);

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

*

*@paramisLongClick Is the event a long click ?*/

private void sendClickEvent(finalBoolean isLongClick) {if (getParent() instanceofAdapterView) {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);

}

}

}private Bitmap getCircleBitmap(final intradius) {final Bitmap output =Bitmap.createBitmap(originBitmap.getWidth(), originBitmap.getHeight(), Bitmap.Config.ARGB_8888);final Canvas canvas = newCanvas(output);final Paint paint = newPaint();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);returnoutput;

}/*** Set Ripple color, default is #FFFFFF

*

*@paramrippleColor New color resource*/

public void setRippleColor(intrippleColor) {this.rippleColor =getResources().getColor(rippleColor);

}public intgetRippleColor() {returnrippleColor;

}publicRippleType getRippleType()

{returnRippleType.values()[rippleType];

}/*** Set Ripple type, default is RippleType.SIMPLE

*

*@paramrippleType New Ripple type for next animation*/

public void setRippleType(finalRippleType rippleType)

{this.rippleType =rippleType.ordinal();

}publicBoolean isCentered()

{returnisCentered;

}/*** Set if ripple animation has to be centered in its parent view or not, default is False

*

*@paramisCentered*/

public void setCentered(finalBoolean isCentered)

{this.isCentered =isCentered;

}public intgetRipplePadding()

{returnripplePadding;

}/*** Set Ripple padding if you want to avoid some graphic glitch

*

*@paramripplePadding New Ripple padding in pixel, default is 0px*/

public void setRipplePadding(intripplePadding)

{this.ripplePadding =ripplePadding;

}publicBoolean isZooming()

{returnhasToZoom;

}/*** At the end of Ripple effect, the child views has to zoom

*

*@paramhasToZoom Do the child views have to zoom ? default is False*/

public voidsetZooming(Boolean hasToZoom)

{this.hasToZoom =hasToZoom;

}public floatgetZoomScale()

{returnzoomScale;

}/*** Scale of the end animation

*

*@paramzoomScale Value of scale animation, default is 1.03f*/

public void setZoomScale(floatzoomScale)

{this.zoomScale =zoomScale;

}public intgetZoomDuration()

{returnzoomDuration;

}/*** Duration of the ending animation in ms

*

*@paramzoomDuration Duration, default is 200ms*/

public void setZoomDuration(intzoomDuration)

{this.zoomDuration =zoomDuration;

}public intgetRippleDuration()

{returnrippleDuration;

}/*** Duration of the Ripple animation in ms

*

*@paramrippleDuration Duration, default is 400ms*/

public void setRippleDuration(intrippleDuration)

{this.rippleDuration =rippleDuration;

}public intgetFrameRate()

{returnframeRate;

}/*** Set framerate for Ripple animation

*

*@paramframeRate New framerate value, default is 10*/

public void setFrameRate(intframeRate)

{this.frameRate =frameRate;

}public intgetRippleAlpha()

{returnrippleAlpha;

}/*** Set alpha for ripple effect color

*

*@paramrippleAlpha Alpha value between 0 and 255, default is 90*/

public void setRippleAlpha(intrippleAlpha)

{this.rippleAlpha =rippleAlpha;

}public voidsetOnRippleCompleteListener(OnRippleCompleteListener listener) {this.onCompletionListener =listener;

}/*** Defines a callback called at the end of the Ripple effect*/

public interfaceOnRippleCompleteListener {voidonComplete(RippleView rippleView);

}public enumRippleType {

SIMPLE(0),

DOUBLE(1),

RECTANGLE(2);inttype;

RippleType(inttype)

{this.type =type;

}

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值