color - icon tint android
TeƱido de MenuItem en la barra de herramientas de AppCompat (6)
Cuando uso los elementos extraíbles de la biblioteca de AppCompat
para los elementos del menú de la Toolbar
, el tinte 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 elementos extraíbles o incluso copio los elementos extraíbles de la biblioteca de AppCompat
en mi propio proyecto, no se tiñerá 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 la AppCompat
Toolbar
AppCompat
que solo AppCompat
los AppCompat
extraíbles de esa biblioteca? ¿Hay alguna manera de hacer que esto funcione con mis propios objetos descartables?
Ejecutando esto en el dispositivo API Nivel 19 con compileSdkVersion = 21
y targetSdkVersion = 21
, y también usando todo desde AppCompat
abc_ic_clear_mtrl_alpha_copy
es una copia exacta de abc_ic_clear_mtrl_alpha
png de AppCompat
Editar:
El tinte se basa en el valor que he establecido para android:textColorPrimary
en mi tema.
Por ejemplo, <item name="android:textColorPrimary">#00FF00</item>
me daría un color de tinte verde.
Capturas de pantalla
Tinte de trabajo como se esperaba con drawable de AppCompat
Tinte no funciona con Drawable copiado de AppCompat
Aquí está la solución que uso; puede llamarlo después de onPrepareOptionsMenu () o el lugar equivalente. El motivo de mutate () es si usa los íconos en más de una ubicación; sin el mutado, todos tomarán el mismo tono.
public class MenuTintUtils {
public static void tintAllIcons(Menu menu, final int color) {
for (int i = 0; i < menu.size(); ++i) {
final MenuItem item = menu.getItem(i);
tintMenuItemIcon(color, item);
tintShareIconIfPresent(color, item);
}
}
private static void tintMenuItemIcon(int color, MenuItem item) {
final Drawable drawable = item.getIcon();
if (drawable != null) {
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
item.setIcon(drawable);
}
}
private static void tintShareIconIfPresent(int color, MenuItem item) {
if (item.getActionView() != null) {
final View actionView = item.getActionView();
final View expandActivitiesButton = actionView.findViewById(R.id.expand_activities_button);
if (expandActivitiesButton != null) {
final ImageView image = (ImageView) expandActivitiesButton.findViewById(R.id.image);
if (image != null) {
final Drawable drawable = image.getDrawable();
final Drawable wrapped = DrawableCompat.wrap(drawable);
drawable.mutate();
DrawableCompat.setTint(wrapped, color);
image.setImageDrawable(drawable);
}
}
}
}
}
Esto no se ocupará del desbordamiento, pero para eso, puede hacer esto:
Diseño:
<android.support.v7.widget.Toolbar
...
android:theme="@style/myToolbarTheme" />
Estilos:
<style name="myToolbarTheme">
<item name="colorControlNormal">#FF0000</item>
</style>
Esto funciona a partir de appcompat v23.1.0.
Después de la nueva biblioteca de soporte v22.1, puede usar algo similar a esto:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_home, menu);
Drawable drawable = menu.findItem(R.id.action_clear).getIcon();
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable, ContextCompat.getColor(this,R.color.textColorPrimary));
menu.findItem(R.id.action_clear).setIcon(drawable);
return true;
}
Establecer un ColorFilter
(tinte) en un MenuItem
es simple. Aquí hay un ejemplo:
Drawable drawable = menuItem.getIcon();
if (drawable != null) {
// If we don''t mutate the drawable, then all drawable''s with this id will have a color
// filter applied to it.
drawable.mutate();
drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
drawable.setAlpha(alpha);
}
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 ver una clase de ayudante para establecer un ColorFilter
en todos los ColorFilter
de un menú, incluido el icono de desbordamiento.
En onCreateOptionsMenu(Menu menu)
simplemente llame a MenuColorizer.colorMenu(this, menu, color);
después de inflar tu menú y listo; tus íconos están teñidos
La mayoría de las soluciones en este subproceso usan una API más nueva, o usan reflexión, o usan una búsqueda intensiva de vista para llegar al elemento de MenuItem
inflado.
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.
public class MyToolbar extends Toolbar {
... some constructors, extracting mAccentColor from AttrSet, etc
@Override
public void inflateMenu(@MenuRes int resId) {
super.inflateMenu(resId);
Menu menu = getMenu();
for (int i = 0; i < menu.size(); i++) {
MenuItem item = menu.getItem(i);
Drawable icon = item.getIcon();
if (icon != null) {
item.setIcon(applyTint(icon));
}
}
}
void applyTint(Drawable icon){
icon.setColorFilter(
new PorterDuffColorFilter(mAccentColor, PorterDuff.Mode.SRC_IN)
);
}
}
Solo asegúrate de llamar tu código de Actividad / Fragmento:
toolbar.inflateMenu(R.menu.some_menu);
toolbar.setOnMenuItemClickListener(someListener);
Sin reflexión, sin búsqueda de vistas, y no tanto código, ¿eh?
Y ahora puedes ignorar el ridículo onCreateOptionsMenu/onOptionsItemSelected
.
Personalmente prefiero este enfoque desde este link
Crea un diseño XML con lo siguiente:
<?xml version="1.0" encoding="utf-8"?>
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/ic_action_something"
android:tint="@color/color_action_icons_tint"/>
y referencia este dibujable de tu menú:
<item
android:id="@+id/option_menu_item_something"
android:icon="@drawable/ic_action_something_tined"
Porque si echas un vistazo al código fuente de TintManager en AppCompat, verás:
/**
* Drawables which should be tinted with the value of {@code R.attr.colorControlNormal},
* using the default mode.
*/
private static final int[] TINT_COLOR_CONTROL_NORMAL = {
R.drawable.abc_ic_ab_back_mtrl_am_alpha,
R.drawable.abc_ic_go_search_api_mtrl_alpha,
R.drawable.abc_ic_search_api_mtrl_alpha,
R.drawable.abc_ic_commit_search_api_mtrl_alpha,
R.drawable.abc_ic_clear_mtrl_alpha,
R.drawable.abc_ic_menu_share_mtrl_alpha,
R.drawable.abc_ic_menu_copy_mtrl_am_alpha,
R.drawable.abc_ic_menu_cut_mtrl_alpha,
R.drawable.abc_ic_menu_selectall_mtrl_alpha,
R.drawable.abc_ic_menu_paste_mtrl_am_alpha,
R.drawable.abc_ic_menu_moreoverflow_mtrl_alpha,
R.drawable.abc_ic_voice_search_api_mtrl_alpha,
R.drawable.abc_textfield_search_default_mtrl_alpha,
R.drawable.abc_textfield_default_mtrl_alpha
};
/**
* Drawables which should be tinted with the value of {@code R.attr.colorControlActivated},
* using the default mode.
*/
private static final int[] TINT_COLOR_CONTROL_ACTIVATED = {
R.drawable.abc_textfield_activated_mtrl_alpha,
R.drawable.abc_textfield_search_activated_mtrl_alpha,
R.drawable.abc_cab_background_top_mtrl_alpha
};
/**
* Drawables which should be tinted with the value of {@code android.R.attr.colorBackground},
* using the {@link android.graphics.PorterDuff.Mode#MULTIPLY} mode.
*/
private static final int[] TINT_COLOR_BACKGROUND_MULTIPLY = {
R.drawable.abc_popup_background_mtrl_mult,
R.drawable.abc_cab_background_internal_bg,
R.drawable.abc_menu_hardkey_panel_mtrl_mult
};
/**
* Drawables which should be tinted using a state list containing values of
* {@code R.attr.colorControlNormal} and {@code R.attr.colorControlActivated}
*/
private static final int[] TINT_COLOR_CONTROL_STATE_LIST = {
R.drawable.abc_edit_text_material,
R.drawable.abc_tab_indicator_material,
R.drawable.abc_textfield_search_material,
R.drawable.abc_spinner_mtrl_am_alpha,
R.drawable.abc_btn_check_material,
R.drawable.abc_btn_radio_material
};
/**
* Drawables which contain other drawables which should be tinted. The child drawable IDs
* should be defined in one of the arrays above.
*/
private static final int[] CONTAINERS_WITH_TINT_CHILDREN = {
R.drawable.abc_cab_background_top_material
};
Lo que significa que tienen ID de recursos particulares en la lista blanca para ser tintados.
Pero supongo que siempre se puede ver cómo están polarizando esas imágenes y hacer lo mismo. Es tan fácil como configurar el ColorFilter en un dibujo.