Android 5.0 Material Design is implemented by clicking any View, androidmaterial

Source: Internet
Author: User

Android 5.0 Material Design is implemented by clicking any View, androidmaterial
For more information, see [Mr. Simple blog ]. I am participating in the blog star. Click here to vote for me. Thank you ~
Preface

Since the advent of Android 5.0, its UI style has been widely praised, simple and dynamic. However, due to busy work, I have not paid much attention to Android 5.0. A few days ago, some of the handsome guys from zhimingbo Director Yu Gang (blog address) asked about the effect of water waves when clicking any View in Android 5.0 Material Design. Gang Ge said that water waves have been achieved, however, it may take some time to open the source. I just wrote the ripple effect of sonic payment yesterday, so today I made it according to the Implementation ideas provided by gang Ge, so I got my article today. The results may not be very good. One is self-learning, and the other is to share ideas.

From the current implementation perspective, there are two main implementation ideas: the first is custom View, such as inheriting the Button, and dynamically drawing a background in the onDraw of the Button, then, the background size and color are changed to achieve the dynamic effect. This implementation is quite limited and you can customize a type of View. Only such View can produce ripple effects; the other is custom layout. There is only one view in the layout, and the background is drawn in the same way, and then the animation has limitations, that is, only one view can be placed in one layout, only this view can produce water waves!

The reality is that we need all views to produce ripple effects when clicking. The problem arises. How can we achieve this?

Code Implementation

In fact, everyone's Implementation ideas are similar, which is a problem of applicability and complexity.

My idea is to customize a layout. When you touch the layout, you can use the coordinates of the touch point to find the corresponding sub-view, after finding this view, we crop an area in the dispatchDraw function of the layout, and draw a ripple effect in this area, so that the radius of the background layer increases gradually and the transparency decreases gradually. In this way, when you click a view, a background layer gradually becomes larger and lighter, regardless of the view! After the effect is complete, clear the background layer.

Run the Code directly.

/** The MIT License (MIT) ** Copyright (c) 2015 bboyfeiyu@gmail.com (mr. simple) ** 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 limit * 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 encoded 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 MERCHANTABILITY, * fitness for a particle 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 org. simple; import android. content. context; import Ndroid. content. res. typedArray; import android. graphics. canvas; import android. graphics. color; import android. graphics. paint; import android. graphics. point; import android. graphics. rectF; import android. util. attributeSet; import android. util. log; import android. view. motionEvent; import android. view. view; import android. view. viewGroup; import android. widget. relativeLayout; import org. simple. materiallayout. R ;/** * MaterialLayout is the layout that simulates the ripple effect of the View clicked in Android 5.0. It is different from other views that simulate the Material * design effect, all subviews in the MaterialLayout layout will produce ripple effects when clicked, rather than a specific View. ** @ author mrsimple */public class MaterialLayout extends RelativeLayout {private static final int DEFAULT_RADIUS = 10; private static final int DEFAULT_FRAME_RATE = 10; private static final int DEFAULT_DURATION = 200; private static final int DEFAULT_ALPHA = 255; private static final float DEFAULT_SCALE = 0.8f; private static final int DEFAULT_ALPHA_STEP = 5;/*** animation frame rate */private int mFrameRate = DEFAULT_FRAME_RATE; /* gradient animation duration */private int mDuration = DEFAULT_DURATION;/*/private Paint mPaint = new Paint (); /*** center Point of the clicked view */private Point mCenterPoint = null;/*** Rect of the view */private RectF mTargetRectf; /*** start circle background radius */private int MRadius = DEFAULT_RADIUS;/*** maximum radius */private int mMaxRadius = DEFAULT_RADIUS;/*** gradient background Color */private int mCirclelColor = Color. LTGRAY;/*** increase in radius of each re-painting */private int mRadiusStep = 1;/*** Save the alpha value set by the user */private int mBackupAlpha; /*** the circle radius is used for the zoom ratio of the clicked view. The default value is 0.8 */private float mCircleScale = DEFAULT_SCALE;/*** the alpha value of the color, (0,255) */private int mColorAlpha = DEFAULT_ALPHA;/*** each time an animation is run Ha gradient decrease value */private int mAlphaStep = DEFAULT_ALPHA_STEP;/*** @ param context */public MaterialLayout (Context context) {this (context, null );} public MaterialLayout (Context context, AttributeSet attrs) {super (context, attrs); init (context, attrs);} public MaterialLayout (Context context, AttributeSet attrs, int defStyle) {super (context, attrs, defStyle); init (context, attrs);} private void in It (Context context, AttributeSet attrs) {if (isInEditMode () {return;} if (attrs! = Null) {initTypedArray (context, attrs);} initPaint (); this. setWillNotDraw (false); this. setDrawingCacheEnabled (true);} private void initTypedArray (Context context, AttributeSet attrs) {final TypedArray typedArray = context. obtainStyledAttributes (attrs, R. styleable. materialLayout); mCirclelColor = typedArray. getColor (R. styleable. materialLayout_color, Color. LTGRAY); mDuration = typedArray. getInte Ger (R. styleable. materialLayout_duration, DEFAULT_DURATION); mFrameRate = typedArray. getInteger (R. styleable. materialLayout_framerate, DEFAULT_FRAME_RATE); mColorAlpha = typedArray. getInteger (R. styleable. materialLayout_alpha, DEFAULT_ALPHA); mCircleScale = typedArray. getFloat (R. styleable. materialLayout_scale, DEFAULT_SCALE); typedArray. recycle ();} private void initPaint () {mPaint. setAntiAlias (tru E); mPaint. setStyle (Paint. style. FILL); mPaint. setColor (mCirclelColor); mPaint. setAlpha (mColorAlpha); // backup the alpha attribute to reset mBackupAlpha = mColorAlpha when the animation is complete ;} /*** indicates whether the clicked coordinate point is inside the View ** @ param touchView * @ param x coordinate clicked * @ param y coordinate clicked * @ return if the clicked coordinates are in this view, true is returned, otherwise, false */private boolean isInFrame (View touchView, float x, float y) {int left = touchView is returned. getLeft (); int top = touchView. getT Op (); int right = touchView. getRight (); int bottom = touchView. getBottom (); return x >=left & x <= right & y> = top & y <= bottom ;} /*** obtain the left ** @ param View target view ** @ return center */private Point getViewCenterPoint (View) {int left = view. getLeft (); int top = view. getTop (); int right = view. getRight (); int bottom = view. getBottom (); mTargetRectf = new RectF (left, top, right, bot Tom); mCenterPoint = new Point (right + left)/2, (top + bottom)/2); return mCenterPoint;} private View findTargetView (ViewGroup viewGroup, float x, float y) {int childCount = viewGroup. getChildCount (); // iteratively finds the target View to be clicked for (int I = 0; I <childCount; I ++) {View childdview = viewGroup. getChildAt (I); // if it is a ViewGroup, go deep into the subview if (childView instanceof ViewGroup) {findTargetView (viewGroup, x, y );} Else if (isInFrame (childView, x, y) {// otherwise, judge whether the point is returned childView;} return null ;} private boolean isAnimEnd () {return mRadius> = mMaxRadius;} private void calculateMaxRadius (View view) {// retrieves the longest edge of the View, int maxLength = Math. max (view. getWidth (), view. getHeight (); // calculate the radius of the Ripple circle. mMaxRadius = (int) (maxLength/2) * mCircleScale); int redrawCount = mDuration/mFrameRate ;// Calculate the value-added mRadiusStep = (mMaxRadius-DEFAULT_RADIUS)/redrawCount for each animation radius; // calculate the value of mAlphaStep = (mColorAlpha-100)/redrawCount for each alpha decrease ;} @ Override public boolean onInterceptTouchEvent (MotionEvent event) {Log. d (VIEW_LOG_TAG, "touch:" + this); if (event. getAction () = MotionEvent. ACTION_DOWN) {View touchView = findTargetView (this, event. getX (), event. getY (); if (touchView! = Null) {mCenterPoint = getViewCenterPoint (touchView); // calculate the related data calculateMaxRadius (touchView); // re-paint the view invalidate () ;}} return super. onInterceptTouchEvent (event);} @ Override protected void dispatchDraw (Canvas canvas) {super. dispatchDraw (canvas); // draw the Circle drawRippleIfNecessary (canvas);} private void drawRippleIfNecessary (Canvas canvas) {if (isFoundTouchedSubView () {// calculate the new mRadi radius and alpha Value Us + = mRadiusStep; mColorAlpha-= mAlphaStep; // crop an area, which is the area of the clicked View. clipRect is used to obtain this area, so that the painting operation can only be performed within this area range. // even if the drawn content is greater than this area, the painting content greater than this area is invisible. this ensures that the background layer can only be drawn in the area canvas of the clicked view. clipRect (mTargetRectf); mPaint. setAlpha (mColorAlpha); // draw the background circle, that is, canvas. drawCircle (mCenterPoint. x, mCenterPoint. y, mRadius, mPaint);} if (isAnimEnd () {reset ();} else {invalidateDelayed () ;}/ *** send the re-painting message */priva Te void invalidateDelayed () {this. postDelayed (new Runnable () {@ Override public void run () {invalidate () ;}}, mFrameRate );} /*** determine whether to find the clicked subview ** @ return */private boolean isFoundTouchedSubView () {return mCenterPoint! = Null & mTargetRectf! = Null;} private void reset () {mCenterPoint = null; mTargetRectf = null; mRadius = DEFAULT_RADIUS; mColorAlpha = mBackupAlpha; invalidate ();}}

Custom Attributes, attrs. xml

<?xml version="1.0" encoding="utf-8"?><resources>    <declare-styleable name="MaterialLayout">        <attr name="alpha" format="integer" />        <attr name="alpha_step" format="integer" />        <attr name="framerate" format="integer" />        <attr name="duration" format="integer" />        <attr name="color" format="color" />        <attr name="scale" format="float" />    </declare-styleable></resources>


Use the example to reference the MaterialLayout project or use the code and attrs. copy the xml file to your project and add the MaterialLayout layout to your layout xml file. Note that you should not forget to reference the namespace of the custom attribute MaterialLayout, that is, the xmlns below: ml. Replace com. example. materialdemo with your package name.
<org.simple.MaterialLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:ml="http://schemas.android.com/apk/res/com.example.materialdemo"    android:id="@+id/layout"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:layout_margin="5dp"    android:background="#f0f0f0"    android:gravity="center"    ml:duration="200"    ml:alpha="200"    ml:scale="1.2"    ml:color="#FFD306" >    <Button        android:id="@+id/my_button"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:background="#33CC99"        android:padding="10dp"        android:text="@string/click"        android:textSize="20sp" />    <ImageView        android:id="@+id/my_imageview1"        android:layout_width="100dp"        android:layout_height="100dp"        android:layout_below="@id/my_button"        android:layout_marginTop="30dp"        android:background="#33CC99"        android:contentDescription="@string/app_name"        android:padding="10dp"        android:src="@drawable/ic_launcher" /></org.simple.MaterialLayout>


This gif was recorded with a DOT card, and it looks good on the real machine. You can clone a copy of the code on github to check the results. If you don't think it works, don't try it. Give your github address and I am willing to learn your excellent implementation. We also look forward to the early implementation of the open source code.

Github Repository

Click here to fork.


I am participating in the blog star. Now that you have seen this,Click here to vote for meThank you ~

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.