23

Ich habe festgestellt, dass mit Hilfe von AppCompat Themes Standard-Symbolleiste Symbole durch das Attribut colorControlNormal in meinem Stil getönt werden.Symbolleiste Symbol tönte auf Android

<style name="MyTheme" parent="Theme.AppCompat"> 
    <item name="colorControlNormal">@color/yellow</item> 
</style> 

enter image description here

Wie Sie oben sehen können, jedoch ist es nicht mit allen Symbolen passieren. Ich habe das "Plus" -Zeichen bereitgestellt, das ich von den offiziellen Icons bekommen habe, und es wird nicht getönt (ich habe die "weiße" Version des PNG verwendet). Von dem, was ich von diesem question verstanden habe, tönt System nur Symbole mit nur einem Alpha-Kanal. Ist das wahr?

Wenn ja: Gibt es einen Ort, an dem ich Alpha-definierte, offizielle Materialikonen finden kann? Wenn nicht - und wenn die Symbole in der Symbolleiste alphanumerisch sein müssen, nur um getönt zu sein - wie erwartet Google, dass wir die bereitgestellten Symbole in einer Toolbar verwenden?

Irgendwo im SDK habe ich einige Icons gefunden, die auf _alpha.png enden, und sie werden tatsächlich gut getönt. Allerdings brauche ich die vollständigen Material-Icons, und aus den offiziellen Quellen konnte ich nur white, grey600 und black finden.

Die Anwendung einer ColorFilter zur Laufzeit wäre ein wenig schmerzhaft, und meine eigentliche Toolbar - mit einigen Icons getönt, einige andere nicht - sieht ziemlich schlecht aus.

+1

AppCompat nur färbt seine eigenen Symbole. Vorläufig müssen Sie alle Symbole, die Sie separat von AppCompat bereitstellen, manuell tönen. – alanv

+0

Die verknüpfte Frage gilt auch nur für Benachrichtigungen, nicht für allgemeine Tönung. – alanv

+1

Siehe auch [diese StackO-Post] (http://stackoverflow.com/questions/26780046/menuitem-tinting-on-appcompat-toolbar) für eine gründliche Erklärung. – reVerse

Antwort

4

Ich sehe, dass diese Frage einige Ansichten bekommt, also werde ich eine Antwort für diejenigen posten, die die Kommentare nicht lesen.

Meine Vermutungen in der Frage waren alle falsch und es ist keine Frage der Alphakanäle, zumindest nicht extern. Die Tatsache ist einfach, dass @alanv,

AppCompat tönt nur seine eigenen Symbole. Fürs Erste müssen Sie manuell alle Symbole tönen, die Sie getrennt von AppCompat bereitstellen.

Dies könnte sich in Zukunft ändern, könnte aber auch nicht. Von this answer können Sie auch die Liste der Symbole sehen (sie alle gehören zum internen Ressourcenordner von appcompat, so dass Sie sie nicht ändern können), die automatisch getönt sind und mit welcher Farbe.

Persönlich verwende ich eine colorControlNormal, die schwarz oder weiß (oder ähnliche Farben) ist, und importieren Sie die Symbole mit dieser bestimmten Farbe. Farbige Symbole auf einem farbigen Hintergrund sehen ein wenig schlecht aus. Eine andere Lösung, die ich als angenehm empfinde, ist this class auf github. Sie rufen einfach MenuColorizer.colorMenu(), wenn Sie das Menü erstellen.

+0

Ich denke, Sie sollten sich meine Antwort oben ansehen ... –

19

Hier ist die Lösung, die ich verwende. Rufen Sie nach onPrepareOptionsMenu oder dem entsprechenden Speicherort tintAllIcons auf. Der Grund für mutate() ist, wenn Sie die Symbole an mehreren Stellen verwenden. Ohne Mutate werden sie alle den gleichen Farbton annehmen.

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

Dies wird nicht der Überlauf sorgen, sondern auch für das, können Sie dies tun:

Layout:

<android.support.v7.widget.Toolbar 
    ... 
    android:theme="@style/myToolbarTheme" /> 

Styles:

<style name="myToolbarTheme"> 
     <item name="colorControlNormal">#FF0000</item> 
</style> 

Dies funktioniert ab appcompat v23.1.0.

4

Sie könnten einfach eine benutzerdefinierte Toolbar erstellen, die Ihre Tönungsfarbe beim Aufblasen des Menüs verwendet.

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

} 

nur sicher, dass Sie in Ihrer Aktivität/Fragment-Code aufrufen machen:

toolbar.inflateMenu(R.menu.some_menu); 
toolbar.setOnMenuItemClickListener(someListener); 

keine Reflexion, keine Aussicht Lookup, und nicht so viel Code, nicht wahr?

Und nicht verwenden onCreateOptionsMenu/onOptionsItemSelected, wenn Sie diesen Ansatz verwenden

18

Eine weitere Option ist die neue Unterstützung für Vektor Drawables in der Support-Bibliothek zu verwenden.

Siehe res/xml/ic_search.xml in Blog-Post AppCompat — Age of the vectors

Hinweis der Verweis auf ?attr/colorControlNormal

<vector xmlns:android="..." 
    android:width="24dp" 
    android:height="24dp" 
    android:viewportWidth="24.0" 
    android:viewportHeight="24.0" 
    android:tint="?attr/colorControlNormal"> 
    <path 
     android:pathData="..." 
     android:fillColor="@android:color/white"/> 
</vector> 
+0

Was ist der Unterschied zwischen '' attr/colorControlNormal' bei 'android: tönung' vs' android: fillColor' Attribute? Vielen Dank! –

+0

@SuperThomasLab Das Beispiel stammt aus dem Blog von Chris Banes und zeigt, wie ein getöntes Bild durch einen getönten Vektor ersetzt wird. Beachten Sie, dass die Füllfarbe im Quellbild effektiv fest codiert wurde. Ich weiß nicht, ob in AppCompat jetzt andere Farbdarstellungen unterstützt werden. –

11

ich dies tatsächlich in der Lage war, auf 10 API zu tun (Lebkuchen) und es funktionierte sehr gut.

Bearbeiten: Es 22 auch auf API gearbeitet ...

Hier ist das Endergebnis.

enter image description here

Hinweis: Das Symbol ist eine ziehbar Ressource im ziehbar Ordner (n).

Jetzt ist hier, wie ihre getan:

@Override 
public void onPrepareOptionsMenu(Menu menu) { 
    super.onPrepareOptionsMenu(menu); 

    MenuItem item = menu.findItem(R.id.action_refresh); 
    Drawable icon = getResources().getDrawable(R.drawable.ic_refresh_white_24dp); 
    icon.setColorFilter(getResources().getColor(R.color.colorAccent), PorterDuff.Mode.SRC_IN); 

    item.setIcon(icon); 
} 

An dieser Stelle Sie es zu jeder möglicher Farbe ändern können Sie wollen!

0
@NonNull 
public static Drawable setTintDrawable(@NonNull Drawable drawable, @ColorInt int color) { 
    drawable.clearColorFilter(); 
    drawable.setColorFilter(color, PorterDuff.Mode.SRC_IN); 
    drawable.invalidateSelf(); 
    Drawable wrapDrawable = DrawableCompat.wrap(drawable).mutate(); 
    DrawableCompat.setTint(wrapDrawable, color); 
    return wrapDrawable; 
} 

und auf diese Weise nennen:

MenuItem location = menu.findItem(R.id.action_location); 
DrawableUtils.setTintDrawable(location.getIcon(), Color.WHITE); 

enter image description here