ripples color android xml android-5.0-lollipop material-design rippledrawable

color - rippledrawable android



Efecto Ripple de Android-Comentarios táctiles para botones-Uso de XML (7)

Estaba investigando el efecto dominó, ya que era algo que quería aplicar a unos pocos botones en mi aplicación y que pasó por su publicación. Si bien su pregunta es buscar una respuesta sobre cómo agregar el efecto dominó usando XML que en realidad era algo que estaba tratando de evitar, cuando intente agregar ese atributo verá que requiere v21.

Si su objetivo es inferior a v21, ese nuevo botón de ampliación de clase (o ImageButton, etc.) evitará las quejas del compilador.

Como no había ninguna explicación sobre cómo implementar la clase personalizada anterior, pensé en completarla. Todo lo que necesitas hacer es crear la nueva clase y luego en el XML cambiar "Botón" a "the.package.name.MyButton".

De:

<Button android:id="@+id/Button" android:layout_width="wrap_content" android:layout_height="wrap_content" />

A:

<the.package.name.MyButton android:id="@+id/Button" android:layout_width="wrap_content" android:layout_height="wrap_content" />

Eso es. Ahora su botón cuando se presiona tendrá una onda contenida dentro de sus límites.

Me gusta este enfoque. Solo deseo que la onda se extienda más allá de los límites. Para un botón pequeño, este efecto dominó realmente resalta cuán cuadrado o rectangular es realmente el botón. Visualmente sería más satisfactorio si la onda continuara hasta que alcanzara su radio completo.

Estoy tratando de comprender cómo implementar el "Efecto Ripple - Touch Feedback" para botones y otras vistas. Miré las preguntas relacionadas con el efecto Ripple touch en SO y obtuve una idea de ello. Pude obtener el efecto de onda con este código de Java.

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 > 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); } }

Pero, quiero usar el enfoque XML. ¿Cómo logro esto? He visto this y this , pero todavía no me siento cómodo con los estilos, así que me resulta difícil lograr el efecto dominó.

Tengo un botón con el siguiente código XML:

<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" />

¿Cómo obtengo efecto dominó para este botón? Si alguien puede guiarme, estaré agradecido.

[EDITAR] Agregar ripple.xml y background.xml, como se menciona en uno de los enlaces de arriba. Creé una carpeta drawable-v21 en res y agregué los archivos a continuación allí.

ripple.xml

<?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="@android:color/black" > <item android:drawable="@drawable/background"> </item> </ripple>

background.xml

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" > <solid android:color="@android:color/darker_gray" /> </shape>

Agregué la ondulación como fondo para mi botón, aquí está el xml para mi botón ahora ...

<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" />

Cuando ejecuto la aplicación, obtengo una ResourceNotFoundException. Aquí está la traza del logcat.

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 <unknown> 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


La mejor manera de usar esto en Android: primer plano , porque también te permite usar tu propio fondo.

android: foreground = "? android: attr / seleccionableItemBackground"

Ejemplo:

<android.support.v7.widget.AppCompatButton android:layout_width="match_parent" android:layout_height="wrap_content" android:foreground="?android:attr/selectableItemBackground" android:background="@color/button.normal" android:textColor="@color/white"/>


Leve adición a la respuesta anterior: tenga en cuenta que el color de la máscara no se utiliza de ninguna manera.

También puedes hacer cosas más complicadas con ondas. Por ejemplo, si desea un borde en su botón de ondulación, puede usarlo como una lista de capas.

<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?android:colorControlHighlight"> <!-- Note: <ripple> acts like a layer-list --> <item android:id="@android:id/mask"> <shape android:shape="oval"> <!-- This color is not displayed in any way --> <solid android:color="@android:color/black" /> </shape> </item> <!-- This is the border --> <item> <shape android:shape="rectangle"> <corners android:radius="3dp"/> <!-- Use your border color in place of #f00 --> <stroke android:width="1dp" android:color="#f00"/> </shape> </item> </ripple>

Tenga en cuenta que el elemento con id @android:id/mask solo se usa para mostrar dónde se detendrá el efecto @android:id/mask . Si quieres que cubra todo el botón, puedes cambiar el android:shape para que sea rectangle . ¡Puedes imaginar hacer muchas más cosas interesantes con esto también!

También asegúrese de tener una copia de seguridad dibujable para dispositivos que aún no son 21 o la aplicación se bloqueará en dispositivos viejos.


Para lollipop (API> 21) haga que el archivo como btn_ripple_effect.xml sea dibujable y coloque debajo del código

<?xml version="1.0" encoding="utf-8"?> <ripple xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:color="?android:colorAccent" tools:targetApi="lollipop"> <item android:drawable="@color/cancel_btn_clr" /> <!-- default --> <item android:id="@android:id/mask"> <shape android:shape="rectangle"> <solid android:color="?android:colorAccent" /> </shape> </item> </ripple>

Para pre lollipop (API <21) crea un archivo como btn_ripple_effect.xml en la carpeta drawable-v21 y pon el código siguiente

<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape> <solid android:color="@color/colorAccent"></solid> </shape> </item> <item> <shape> <solid android:color="@color/cancel_btn_clr"></solid> </shape> </item> </selector>


Puede agregar los datos clickable como true y de background o de background como atributos de atributo de atributo ?attr/selectableItemBackground atributo ?attr/selectableItemBackground a la vista:

<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button" android:clickable="true" android:background="?attr/selectableItemBackground" android:textColor="@android:color/white"/>

Si en el caso de que su vista ya tenga un background lleno de algo, podría llenar su foreground con selectableItemBackground

<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Button" android:clickable="true" android:foreground="?attr/selectableItemBackground" android:background="@color/colorPrimary" android:textColor="@android:color/white"/>


Puedes hacer algo como esto:

<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@drawable/ripple" />

Donde el ripple.xml es:

<ripple xmlns:android="http://schemas.android.com/apk/res/android" android:color="?android:colorControlHighlight"> <item android:id="@android:id/mask"> <shape android:shape="oval"> <solid android:color="?android:colorAccent" /> </shape> </item> </ripple>


Simplemente ponga ?attr/selectableItemBackground en el fondo del botón para la API 21+, como a continuación:

<Button android:layout_width="match_parent" android:layout_height="70dp" android:background="?attr/selectableItemBackground" android:text="Button" />