Cuando utilizo elementos de diseño de la AppCompatbiblioteca para los Toolbarelementos de mi menú, el teñido funciona como se esperaba. Me gusta esto:
<item
    android:id="@+id/action_clear"
    android:icon="@drawable/abc_ic_clear_mtrl_alpha"  <-- from AppCompat
    android:title="@string/clear" />
Pero si utilizo mis propios dibujables o incluso copio los dibujables de la AppCompatbiblioteca a mi propio proyecto, no se teñirá en absoluto.
<item
    android:id="@+id/action_clear"
    android:icon="@drawable/abc_ic_clear_mtrl_alpha_copy"  <-- copy from AppCompat
    android:title="@string/clear" />
¿Hay alguna magia especial en el AppCompat Toolbarque solo tiñe los dibujables de esa biblioteca? ¿Alguna forma de hacer que esto funcione con mis propios diseños?
Ejecutando esto en un dispositivo API de nivel 19 con compileSdkVersion = 21y targetSdkVersion = 21, y también usando todo, desdeAppCompat
abc_ic_clear_mtrl_alpha_copyes una copia exacta del abc_ic_clear_mtrl_alphapng deAppCompat
Editar:
El tinte se basa en el valor que he establecido android:textColorPrimaryen mi tema.
Por ejemplo <item name="android:textColorPrimary">#00FF00</item>, me daría un color de tinte verde.
Capturas de pantalla
El teñido funciona como se esperaba con dibujable de AppCompat

El tinte no funciona con dibujable copiado de AppCompat


Respuestas:
Porque si echas un vistazo al código fuente de TintManager en AppCompat, verás:
Lo que básicamente significa que tienen ResourceIds particulares en la lista blanca para ser teñidos.
Pero supongo que siempre puedes ver cómo tiñen esas imágenes y hacen lo mismo. Es tan fácil como configurar ColorFilter en un dibujable.
fuente
Después de la nueva biblioteca de soporte v22.1, puede usar algo similar a esto:
fuente
setColorFilter()es preferible.Establecer un
ColorFilter(tinte) en aMenuItemes simple. Aquí hay un ejemplo:El código anterior es muy útil si desea admitir diferentes temas y no desea tener copias adicionales solo por el color o la transparencia.
Haga clic aquí para que una clase de ayuda establezca
ColorFiltertodos los elementos de diseño de un menú, incluido el icono de desbordamiento.En
onCreateOptionsMenu(Menu menu)solo llamarMenuColorizer.colorMenu(this, menu, color);después de inflar su menú y listo; sus iconos están teñidos.fuente
app:iconTintEl atributo se implementaSupportMenuInflaterdesde la biblioteca de soporte (al menos en 28.0.0).Probado con éxito con API 15 y superior.
Archivo de recursos del menú:
(En este caso,
?attr/appIconColorEnabledera un atributo de color personalizado en los temas de la aplicación y los recursos del icono eran elementos de diseño vectoriales).fuente
android:iconTintyandroid:iconTintModeno funciona, pero prefijar con enapp:lugar deandroid:funciona como un encanto (en mis propios elementos de diseño vectoriales, API> = 21)SupportMenuInflaterno se aplicará ninguna lógica personalizada si el menú no es un meSupportMenugustaMenuBuilder, simplemente vuelve a la normalidadMenuInflater.AppCompatActivity.startSupportActionMode(callback)y las implementaciones de soporte apropiadas deandroidx.appcompatse pasarán a la devolución de llamada.Personalmente preferí este enfoque desde este enlace.
Cree un diseño XML con lo siguiente:
y haga referencia a este elemento de dibujo desde su menú:
fuente
bitmap. Hay otras formas de colorear vectores. Quizás alguien podría añadir vector de coloración aquí también ...La mayoría de las soluciones en este hilo usan una API más nueva, o usan la reflexión, o usan la búsqueda de vista intensiva para llegar al inflado
MenuItem.Sin embargo, hay un enfoque más elegante para hacer eso. Necesita una barra de herramientas personalizada, ya que su caso de uso de "aplicar tinte personalizado" no funciona bien con la API de estilo / tematización pública.
Solo asegúrese de llamar a su código de Actividad / Fragmento:
Sin reflejo, sin búsqueda de vistas y sin tanto código, ¿eh?
Y ahora puedes ignorar lo ridículo
onCreateOptionsMenu/onOptionsItemSelected.fuente
Menu#getItem()complejidad es O (1) en la barra de herramientas, porque los elementos se almacenan en ArrayList. Que es diferente delView#findViewByIdrecorrido (al que me referí como búsqueda de vista en mi respuesta), cuya complejidad está lejos de ser constante :-)Aquí está la solución que utilizo; puede llamarlo después de onPrepareOptionsMenu () o el lugar equivalente. El motivo de mutate () es si utiliza los iconos en más de una ubicación; sin el mutado, todos adquirirán el mismo tono.
Esto no se encargará del desbordamiento, pero para eso, puede hacer esto:
Diseño:
Estilos:
Esto funciona a partir de appcompat v23.1.0.
fuente