English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
This article introduces how to implement the following effects by using a custom View and property animation
The implementation idea is quite simple:
First, let's take a look at the part of drawing a semi-transparent circle
public class ClickCircleView extends View { private Bitmap bitmap; private Paint paint; private Canvas canvas; private boolean isSpreadFlag = false;//Mark whether the emission is completed public boolean isSpreadFlag() { return isSpreadFlag; } public void setIsSpreadFlag(boolean isSpreadFlag) { this.isSpreadFlag = isSpreadFlag; } public ClickCircleView(Context context, int width, int height, int screenWidth, int screenHeight) { super(context); bitmap = Bitmap.createBitmap(screenWidth, screenHeight, Bitmap.Config.ARGB_8888); // Set the width and height of the bitmap canvas = new Canvas(); canvas.setBitmap(bitmap); paint = new Paint(Paint.DITHER_FLAG); paint.setAntiAlias(true); paint.setColor(Color.WHITE); paint.setStyle(Paint.Style.FILL); paint.setAlpha(50); canvas.drawCircle(screenWidth / 2, screenHeight / 2, width / 2 + 10, paint); invalidate(); } @Override protected void onDraw(Canvas canvas) { canvas.drawBitmap(bitmap, 0, 0, null); } }
As can be seen, the relevant properties are set on the brush, then directly call the canvas's drawCircle() method to draw a semi-transparent circle, and finally call the invalidate() method to refresh the View
It is necessary to override the parent class's onDraw() method, otherwise the custom View cannot take effect
We set a flag isSpreadFlag, which is used to mark whether the expansion animation is completed
Then we implement two animation effects
Click expansion animation
<set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:duration="1000" android:propertyName="scaleY" android:valueFrom="1.0" android:valueTo="1.8" android:valueType="floatType" /> <objectAnimator android:duration="1000" android:propertyName="scaleX" android:valueFrom="1.0" android:valueTo="1.8" android:valueType="floatType" /> </set>
It's very simple, just change the scale value to increase to1.8times
Non-click expansion and contraction animation
<set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together"> <objectAnimator android:duration="1000" android:propertyName="scaleX" android:valueFrom="1.0" android:valueTo="1.2" android:valueType="floatType" /> <objectAnimator android:duration="1000" android:propertyName="scaleY" android:valueFrom="1.0" android:valueTo="1.2" android:valueType="floatType" /> <objectAnimator android:duration="1000" android:propertyName="scaleX" android:startOffset="1000" android:valueFrom="1.2" android:valueTo="1.0" android:valueType="floatType" /> <objectAnimator android:duration="1000" android:propertyName="scaleY" android:startOffset="1000" android:valueFrom="1.2" android:valueTo="1.0" android:valueType="floatType" /> </set>
Similar to the previous animation, the startOffset parameter can be used to control the running order of the Animation, such as Android:startOffset=""10"00" indicates the animation delay of the property setting1Second execution
Then it is the part of executing animation and logic with threads
Animation part when not clicked
mXiuyixiuButton.post(new Runnable() { @Override public void run() { clickCircleView = new ClickCircleView(CustomView1.this, mXiuyixiuButton.getWidth() , mXiuyixiuButton.getHeight(), mXiuyixiuLayout.getMeasuredWidth(), mXiuyixiuLayout.getMeasuredHeight()); clickCircleView.setVisibility(View.VISIBLE); mXiuyixiuLayout.addView(clickCircleView); mXiuyixiuLayout.postInvalidate(); // Load animation final Animator anim = AnimatorInflater.loadAnimator(CustomView1.this, R.animator.circle_scale_animator); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { if (anim != null) { anim.start();//Loop animation execution } } }); anim.setTarget(clickCircleView); anim.start(); } });
After initializing clickCircleView, add this view to the parent layout, then load the animation and set it to loop, and finally use postInvalidate() to refresh the view in the child thread
Animation part when clicked
mXiuyixiuButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { clickCircleView.setVisibility(View.GONE);//Launch the circle, hiding the loop animation View final ClickCircleView item = new ClickCircleView(CustomView1.this, mXiuyixiuButton.getWidth() , mXiuyixiuButton.getHeight(), mXiuyixiuLayout.getWidth(), mXiuyixiuLayout.getHeight()); Animator spreadAnim = AnimatorInflater.loadAnimator(CustomView1.this, R.animator.circle_spread_animator); spreadAnim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { item.setIsSpreadFlag(true);//Mark after the animation is completed } }); spreadAnim.setTarget(item); spreadAnim.start(); clickCircleViewList.add(item); mXiuyixiuLayout.addView(item); mXiuyixiuLayout.invalidate(); handler.post(circleViewRunnable); } });
Hide the non-click animation, initialize the ClickCircleView, add the view to the List, and then add it to the parent layout. After that, load the animation, add the isSpreadFlag mark at the end of the animation, and finally call the invalidate() method to refresh the view and start the thread.
Thread part
private Runnable circleViewRunnable = new Runnable() { public void run() { for (int i = 0; i < clickCircleViewList.size(); i++) { if (clickCircleViewList.get(i).isSpreadFlag()) { mXiuyixiuLayout.removeView(clickCircleViewList.get(i)); clickCircleViewList.remove(i); mXiuyixiuLayout.postInvalidate(); } } if (clickCircleViewList.size() <= 0) { clickCircleView.setVisibility(View.VISIBLE); } handler.postDelayed(this, 100); } };
Traverse the list, remove the view with the isSpreadFlag marker from the list and the parent layout, and refresh the view. Finally, if the list is empty, the animation is displayed when not clicked
Remember to remove the thread in onDestroy() at the end
@Override protected void onDestroy() { super.onDestroy(); handler.removeCallbacks(circleViewRunnable); }
Using custom View with property animation to achieve this effect has a high degree of coupling. However, compared with using custom View completely, this method is more smooth. Most of the code is implemented based on the code from other blogs, but if you just use it without summarizing, it will not become your own knowledge. Therefore, this blog was written.
Reference: Several ways to implement Alipay's Xiu Xiu with android
That's all for this article. I hope it will be helpful to everyone's learning and also hope everyone will support the Yelling Tutorial more.
Declaration: The content of this article is from the network, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, does not edit the content manually, and does not assume relevant legal liability. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (When sending an email, please replace # with @ for reporting, and provide relevant evidence. Once verified, this site will immediately delete the suspected infringing content.)