title: Android L's Ripple Effect - Touch Feedback for Buttons - Using XML
body: <p>I am trying to understand how to implement the "Ripple Effect - Touch Feedback" for buttons and other views. I looked at the questions related to Ripple touch effect on SO and got some insight into it. I was able to successfully get the ripple effect using this java code.</p>
  
  <pre><code>import android.animation.ObjectAnimator;
  import android.content.Context;
  import android.graphics.Canvas;
  import android.graphics.Color;
  import android.graphics.Paint;
  import android.graphics.Path;
  import android.graphics.RadialGradient;
  import android.graphics.Region;
  import android.graphics.Shader;
  import android.support.annotation.NonNull;
  import android.util.AttributeSet;
  import android.view.MotionEvent;
  import android.view.animation.AccelerateInterpolator;
  import android.widget.Button;
  
  public class MyButton extends Button {
  
      private float mDownX;
      private float mDownY;
  
      private float mRadius;
  
      private Paint mPaint;
  
      public MyButton(final Context context) {
          super(context);
          init();
      }
  
      public MyButton(final Context context, final AttributeSet attrs) {
          super(context, attrs);
          init();
      }
  
      public MyButton(final Context context, final AttributeSet attrs,
              final int defStyle) {
          super(context, attrs, defStyle);
          init();
      }
  
      private void init() {
          mPaint = new Paint();
          mPaint.setAlpha(100);
      }
  
      @Override
      public boolean onTouchEvent(@NonNull final MotionEvent event) {
          if (event.getActionMasked() == MotionEvent.ACTION_UP) {
              mDownX = event.getX();
              mDownY = event.getY();
  
              ObjectAnimator animator = ObjectAnimator.ofFloat(this, "radius", 0,
                      getWidth() * 3.0f);
              animator.setInterpolator(new AccelerateInterpolator());
              animator.setDuration(400);
              animator.start();
          }
          return super.onTouchEvent(event);
      }
  
      public void setRadius(final float radius) {
          mRadius = radius;
          if (mRadius &gt; 0) {
              RadialGradient radialGradient = new RadialGradient(mDownX, mDownY,
                      mRadius * 3, Color.TRANSPARENT, Color.BLACK,
                      Shader.TileMode.MIRROR);
              mPaint.setShader(radialGradient);
          }
          invalidate();
      }
  
      private Path mPath = new Path();
      private Path mPath2 = new Path();
  
      @Override
      protected void onDraw(@NonNull final Canvas canvas) {
          super.onDraw(canvas);
  
          mPath2.reset();
          mPath2.addCircle(mDownX, mDownY, mRadius, Path.Direction.CW);
  
          canvas.clipPath(mPath2);
  
          mPath.reset();
          mPath.addCircle(mDownX, mDownY, mRadius / 3, Path.Direction.CW);
  
          canvas.clipPath(mPath, Region.Op.DIFFERENCE);
  
          canvas.drawCircle(mDownX, mDownY, mRadius, mPaint);
      }
  }
  </code></pre>
  
  <p>But, i want to use XML approach. How do i achieve this? I have looked at <a href="https://stackoverflow.com/questions/24527402/android-l-ripple-touch-effect-on-shape">this</a> and <a href="https://stackoverflow.com/questions/24480425/android-l-fab-button-shadow/24498041#24498041">this</a>, but i am not yet that comfortable with styles, so i am finding it difficult to achieve the ripple effect.</p>
  
  <p>I have a button with the following XML code:</p>
  
  <pre><code> &lt;Button
              android:id="@+id/button_email"
              android:layout_width="0dip"
              android:layout_height="wrap_content"
              android:layout_weight="0.50"
              android:gravity="center"
              android:text="@string/email" /&gt;
  </code></pre>
  
  <p>How do i get ripple effect for this button. If someone can guide me, I will be thankful.</p>
  
  <p>[EDIT] Adding ripple.xml and background.xml, as mentioned in one of the links above. I have created a drawable-v21 folder in res and added the below files there.</p>
  
  <p>ripple.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;ripple xmlns:android="http://schemas.android.com/apk/res/android"
      android:color="@android:color/black" &gt;
      &lt;item android:drawable="@drawable/background"&gt;
      &lt;/item&gt;
  &lt;/ripple&gt;
  </code></pre>
  
  <p>background.xml</p>
  
  <pre><code>&lt;?xml version="1.0" encoding="utf-8"?&gt;
  &lt;shape xmlns:android="http://schemas.android.com/apk/res/android" &gt;
      &lt;solid android:color="@android:color/darker_gray" /&gt;
  &lt;/shape&gt;
  </code></pre>
  
  <p>I added the ripple as background for my button, here is the xml for my button now..</p>
  
  <pre><code>&lt;Button
      android:id="@+id/button_email"
      android:layout_width="0dip"
      android:layout_height="wrap_content"
      android:layout_weight="0.50"
      android:gravity="center"
      android:background="@drawable/ripple"
      android:text="@string/email" /&gt;
  </code></pre>
  
  <p>When i run the application i get a ResourceNotFoundException. Here is the logcat trace..</p>
  
  <pre><code>07-21 17:03:39.043: E/AndroidRuntime(15710): FATAL EXCEPTION: main
  07-21 17:03:39.043: E/AndroidRuntime(15710): Process: com.xx.xxx, PID: 15710
  07-21 17:03:39.043: E/AndroidRuntime(15710): android.view.InflateException: Binary XML file line #60: Error inflating class &lt;unknown&gt;
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.createView(LayoutInflater.java:620)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.android.internal.policy.impl.PhoneLayoutInflater.onCreateView(PhoneLayoutInflater.java:56)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.onCreateView(LayoutInflater.java:669)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:694)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.rInflate(LayoutInflater.java:758)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.xx.xxx.BusinessAdapter.onCreateViewHolder(BusinessAdapter.java:106)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.xx.xxx.BusinessAdapter.onCreateViewHolder(BusinessAdapter.java:1)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.RecyclerView$Adapter.createViewHolder(RecyclerView.java:2915)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:2511)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.LinearLayoutManager$RenderState.next(LinearLayoutManager.java:1425)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.LinearLayoutManager.fill(LinearLayoutManager.java:999)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:524)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.RecyclerView.dispatchLayout(RecyclerView.java:1461)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.support.v7.widget.RecyclerView.onLayout(RecyclerView.java:1600)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.android.internal.widget.ActionBarOverlayLayout.onLayout(ActionBarOverlayLayout.java:374)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.layoutChildren(FrameLayout.java:453)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.widget.FrameLayout.onLayout(FrameLayout.java:388)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.View.layout(View.java:14817)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewGroup.layout(ViewGroup.java:4631)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewRootImpl.performLayout(ViewRootImpl.java:1983)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1740)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:996)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:5600)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:761)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.Choreographer.doCallbacks(Choreographer.java:574)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.Choreographer.doFrame(Choreographer.java:544)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:747)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.os.Handler.handleCallback(Handler.java:733)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.os.Handler.dispatchMessage(Handler.java:95)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.os.Looper.loop(Looper.java:136)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.app.ActivityThread.main(ActivityThread.java:5001)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at java.lang.reflect.Method.invokeNative(Native Method)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at java.lang.reflect.Method.invoke(Method.java:515)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at dalvik.system.NativeStart.main(Native Method)
  07-21 17:03:39.043: E/AndroidRuntime(15710): Caused by: java.lang.reflect.InvocationTargetException
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at java.lang.reflect.Constructor.constructNative(Native Method)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    at android.view.LayoutInflater.createView(LayoutInflater.java:594)
  07-21 17:03:39.043: E/AndroidRuntime(15710):    ... 50 more
  07-21 17:03:39.043: E/AndroidRuntime(15710): Caused by: android.content.res.Resources$NotFoundException: Resource is not a Drawable (color or path): TypedValue{t=0x1/d=0x7f020075 a=-1 r=0x
  </code></pre>