Android click Button watermark Effect
First, let's take a look at what I want to introduce to you, such:
VcLwo7/K18/examples/templates + ajrL/PtqjKx7vhy/templates + examples/templates + templates/qOssqK21MrCvP69 + NDQz + templates/templates + dTatcS + 2 NDOx/templates + 2 NDOx/samples/qGjPGJyIC8 + samples/tbQ1dKz9rG7teO797XEdmlld6GjPC9wPg0KPHByZSBjbGFzcz0 = "brush: java; ">Public View findTargetView (float x, float y, View anchorView) {ArrayList TouchablesView = anchorView. getTouchables (); View targetView = null; for (View child: touchablesView) {RectF rectF = getViewRectF (child); if (rectF. contains (x, y) & child. isClickable () {// This indicates that targetView = child; break;} return targetView;} is found in the clicked view ;}
Find the rectangular area of the view, because the ripple is to be drawn to the Area:
public RectF getViewRectF(View view) { int[] location = new int[2]; view.getLocationOnScreen(location); int childLeft = location[0]; int childTop = location[1]; int childRight = childLeft + view.getMeasuredWidth(); int childBottom = childTop + view.getMeasuredHeight(); return new RectF(childLeft, childTop, childRight, childBottom); }
After finding the rectangle area, this area is the place where the ripple is to be drawn. As mentioned above, the ripple is actually a ring. To draw a circle, you need to know the coordinates of the center and the radius of the circle, the coordinates of the center must be x and y at the time of down, but how can we calculate the radius appropriately? As you can see, if the width of the view is greater than the height, click the lower-left or lower-right corner of the view, and the radius is basically equal to the width of the view. Click the upper or lower part of the view, the radius is between 0 and the view height. For details about the calculation method, see:
The radius calculation method is as follows:
Float left = circleCenterX-targetTouchRectF. left; float right = targetTouchRectF. right-circleCenterX; float top = circleCenterY-targetTouchRectF. top; float bottom = targetTouchRectF. bottom-circleCenterY; // The maximum calculated value is the radius rawRadius = Math. max (bottom, Math. max (Math. max (left, right), top ));
The radius is calculated. Although the center of the circle is x and y at the time of down, you still need to pay attention to the following points, the x and y coordinates of the circle center provided when the ring is drawn are relative to layout in this article. Therefore, some processing is required when calculating y:
/*** Obtain the center coordinate of the ring */public float [] getCircleCenterPostion (float x, float y) {int [] location = new int [2]; float [] mDownPositon = new float [2]; getLocationOnScreen (location); mDownPositon [0] = x; mDownPositon [1] = y-location [1]; return mDownPositon ;}
After calculating the coordinates and radius of the center of the circle, you can write down and draw the circular ripple. Where is this ripple suitable? A friend immediately said that it must have been drawn in the onDraw method. Congratulations, in my opinion, you are wrong. In our layout, there are a lot of childviews, while layout is a viewGroup, viewGroup draws its own background first, then draws itself, and then draws childview. If the ripple is drawn in onDraw, that means that the childView drawn after the childview will cover our ripple, so we should draw the ripple after the childview painting is complete, so as to ensure that childView is at the top layer.
Override the dispatchDraw method:
@ Override protected void dispatchDraw (Canvas canvas) {super. dispatchDraw (canvas);/*** draw the ripple after the child element is drawn */if (mTargetTouchView! = Null) {RectF clipRectF = clipRectF (mTargetTouchView); canvas. save (); // in order not to allow the circle to be drawn to exceed the range canvas. clipRect (clipRectF); if (drawedRadius <rawRadius) {drawedRadius + = rawRadius/drawingRadiusDegrees; canvas. drawCircle (mDownPositon [0], mDownPositon [1], drawedRadius, mHalfTransPaint); postInvalidateDelayed (INVALID_DURATION);} else {canvas. drawCircle (mDownPositon [0], mDownPositon [1], rawRadius, mTransPaint); post (delayedRunnable);} canvas. restore ();}}
As you can see in the distribution drawing event, ripple is a piece of drawing, such:
The ripple of this segment is implemented by creating rings one by one. Therefore, when a ring is not drawn, the next ring needs to be drawn in a delayed manner.
The above ripple effect is basically complete, but there are click events, such as 360 mobile guard or Baidu mobile guard. After the ripple effect is played, it will respond to the click event, therefore, we also need to initiate a delayed response to this click event.
In the up event, record the event of the event and return true, indicating to consume the event. After the ring is drawn, use the view to distribute the event:
If (ev. getAction () = MotionEvent. ACTION_UP) {// method to be executed in up after the ripple is drawn. // if (drawedRadius = 0) {// return false; //} // long totalTime = (long) (INVALID_DURATION * (drawingRadiusDegrees + 5); // the end time of the ripple. // long time = (long) (totalTime-drawedRadius * totalTime/rawRadius); delayedRunnable. event = ev; return true;} class postUpEventDelayed implements Runnable {private MotionEvent event; @ Override p Ublic void run () {if (mTargetTouchView! = Null & mTargetTouchView. isClickable () & event! = Null) {mTargetTouchView. dispatchTouchEvent (event); // distribution }}}
In the dispatchDraw method, determine whether to post (delayedRunnable) if the painting is complete; execute the childView event delay distribution.