Ich habe nach einer Methode gesucht, um die Farbe des Überlaufmenüsymbols in Android programmgesteuert zu ändern.
Die einzige Option, die ich gefunden habe, besteht darin, das Symbol dauerhaft zu ändern, indem Sie einen benutzerdefinierten Stil hinzufügen. Das Problem ist, dass wir dies in naher Zukunft während der Nutzung unserer App ändern müssen.
Unsere App ist eine Erweiterung einer Reihe von Online-Plattformen und daher kann ein Benutzer die Web-URL seiner Plattform eingeben. Diese haben ihre eigenen Stile und werden von einem API-Aufruf an die App abgerufen.
Diese könnten mich auffordern, die Farbe des Symbols zu ändern …
Derzeit ändere ich andere Symbole in der Actionbar wie folgt:
if (ib != null){
Drawable resIcon = getResources().getDrawable(R.drawable.navigation_refresh);
resIcon.mutate().setColorFilter(StyleClass.getColor("color_navigation_icon_overlay"), PorterDuff.Mode.SRC_ATOP);
ib.setIcon(resIcon);
}
Im Moment muss ich die Stile verwenden.

Nebenniere
Sie können das Überlaufsymbol tatsächlich mit einem kleinen Trick programmgesteuert ändern. Hier ist ein Beispiel:
Erstellen Sie einen Stil für das Überlaufmenü und übergeben Sie eine Inhaltsbeschreibung
<style name="Widget.ActionButton.Overflow" parent="@android:style/Widget.Holo.ActionButton.Overflow">
<item name="android:contentDescription">@string/accessibility_overflow</item>
</style>
<style name="Your.Theme" parent="@android:style/Theme.Holo.Light.DarkActionBar">
<item name="android:actionOverflowButtonStyle">@style/Widget.ActionButton.Overflow</item>
</style>
Ruf jetzt an ViewGroup.findViewsWithText
und geben Sie Ihre Inhaltsbeschreibung ein. Also so etwas wie:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// The content description used to locate the overflow button
final String overflowDesc = getString(R.string.accessibility_overflow);
// The top-level window
final ViewGroup decor = (ViewGroup) getWindow().getDecorView();
// Wait a moment to ensure the overflow button can be located
decor.postDelayed(new Runnable() {
@Override
public void run() {
// The List that contains the matching views
final ArrayList<View> outViews = new ArrayList<>();
// Traverse the view-hierarchy and locate the overflow button
decor.findViewsWithText(outViews, overflowDesc,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
// Guard against any errors
if (outViews.isEmpty()) {
return;
}
// Do something with the view
final ImageButton overflow = (ImageButton) outViews.get(0);
overflow.setImageResource(R.drawable.ic_action_overflow_round_red);
}
}, 1000);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Add a dummy item to the overflow menu
menu.add("Overflow");
return super.onCreateOptionsMenu(menu);
}
View.findViewsWithText
wurde in API-Ebene 14 hinzugefügt, daher müssen Sie Ihre eigene Kompatibilitätsmethode verwenden:
static void findViewsWithText(List<View> outViews, ViewGroup parent, String targetDescription) {
if (parent == null || TextUtils.isEmpty(targetDescription)) {
return;
}
final int count = parent.getChildCount();
for (int i = 0; i < count; i++) {
final View child = parent.getChildAt(i);
final CharSequence desc = child.getContentDescription();
if (!TextUtils.isEmpty(desc) && targetDescription.equals(desc.toString())) {
outViews.add(child);
} else if (child instanceof ViewGroup && child.getVisibility() == View.VISIBLE) {
findViewsWithText(outViews, (ViewGroup) child, targetDescription);
}
}
}
Ergebnisse


michalbrz
Die Antwort von Adneal ist großartig und ich habe sie bis vor kurzem verwendet. Aber dann wollte ich, dass meine App Materialdesign nutzt und damit Theme.AppCompat.*
Stil und android.support.v7.widget.Toolbar
.
Ja, es funktionierte nicht mehr und ich versuchte, es durch Einstellung zu beheben Your.Theme
‘s Eltern zu @style/Widget.AppCompat.ActionButton.Overflow
. Mit richtiger Einstellung hat es funktioniert contentDescription
aber dann scheiterte es beim Casting an ImageButton
. Es stellte sich heraus in neusten (version 23) android.support.v7
Klasse OverflowMenuButton
erstreckt sich von AppCompatImageView
. Das Ändern der Casting-Klasse reichte aus, damit es mit der Toolbar auf Nexus 5 mit Lollipop funktioniert.
Dann habe ich es auf Galaxy S4 mit KitKat ausgeführt und egal was ich versucht habe, ich konnte keine Überläufe einstellen contentDescription
zu meinem benutzerdefinierten Wert. Aber in AppCompat-Stile Ich habe festgestellt, dass es bereits einen Standardwert hat:
<item name="android:contentDescription">@string/abc_action_menu_overflow_description</item>
Warum also nicht verwenden? Auch durch Hannes Idee (in den Kommentaren) habe ich Listener implementiert, um eine zufällige Zeit für die Verzögerung loszuwerden postDelayed
. Und da sich das Überlaufsymbol bereits in der AppCompat-Bibliothek befindet, würde ich es auch verwenden – ich wende einen Farbfilter an, sodass ich keine eigenen Symbolressourcen benötige.
Mein Code basiert auf Adneals Arbeit mit Verbesserungen von Android Lollipop:
public static void setOverflowButtonColor(final Activity activity) {
final String overflowDescription = activity.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<View>();
decorView.findViewsWithText(outViews, overflowDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
AppCompatImageView overflow=(AppCompatImageView) outViews.get(0);
overflow.setColorFilter(Color.CYAN);
removeOnGlobalLayoutListener(decorView,this);
}
});
}
und gemäß einer anderen StackOverflow-Antwort:
public static void removeOnGlobalLayoutListener(View v, ViewTreeObserver.OnGlobalLayoutListener listener) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) {
v.getViewTreeObserver().removeGlobalOnLayoutListener(listener);
}
else {
v.getViewTreeObserver().removeOnGlobalLayoutListener(listener);
}
}
natürlich statt Color.CYAN
Sie können Ihre eigene Farbe verwenden – activity.getResources().getColor(R.color.black);
BEARBEITEN: Unterstützung für die neueste AppCompat-Bibliothek (23) hinzugefügt, die AppCompatImageView verwendet. Für AppCompat 22 sollten Sie die Überlaufschaltfläche in TintImageView umwandeln

Lorne Laliberte
Ab Support 23.1 hat die Toolbar nun getOverflowIcon() und setOverflowIcon() Methoden, damit wir das viel einfacher machen können:
public static void setOverflowButtonColor(final Toolbar toolbar, final int color) {
Drawable drawable = toolbar.getOverflowIcon();
if(drawable != null) {
drawable = DrawableCompat.wrap(drawable);
DrawableCompat.setTint(drawable.mutate(), color);
toolbar.setOverflowIcon(drawable);
}
}
Es gibt viel bessere Lösung. Sie können dies programmgesteuert in der Laufzeit tun
toolbar.overflowIcon?.setColorFilter(colorInt, PorterDuff.Mode.SRC_ATOP)
Viola!
Es gibt die weniger hackige Lösung zum Ändern des Überlaufsymbols. Es gibt ein Beispiel zum Ändern der Farbe des Überlaufsymbols, aber Sie können es anpassen, um das Bild zu ändern:
private void setOverflowIconColor(int color) {
Drawable overflowIcon = toolbar.getOverflowIcon();
if (overflowIcon != null) {
Drawable newIcon = overflowIcon.mutate();
newIcon.setColorFilter(color, PorterDuff.Mode.MULTIPLY);
toolbar.setOverflowIcon(newIcon);
}
}

Atul O Holic
Basierend auf der Antwort von @michalbrz habe ich das Symbol unten verwendet, um das Symbol selbst zu ändern. 🙂
public static void setOverflowButtonColor(final Activity activity) {
final String overflowDescription = activity.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<View>();
decorView.findViewsWithText(outViews, overflowDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
TintImageView overflow = (TintImageView) outViews.get(0);
//overflow.setColorFilter(Color.CYAN); //changes color
overflow.setImageResource(R.drawable.dots);
removeOnGlobalLayoutListener(decorView, this);
}
});

MiguelHincapieC
Verwenden appcompat-v7:23.0.1 keiner von @adneal oder @michalbrz hat bei mir funktioniert. Ich musste 2 Codezeilen der Antwort von @michalbrz ändern, damit es funktioniert.
Ich füge eine Antwort hinzu, weil beide aktuellen Antworten für jemanden nützlich sein können, aber wenn Sie die letzte appcompat-Version wie ich verwenden, sollten Sie diese basierend auf @michalbrz verwenden:
private static void setOverflowButtonColor(final AppCompatActivity activity, final PorterDuffColorFilter colorFilter) {
final String overflowDescription = activity.getString(R.string.abc_action_menu_overflow_description);
final ViewGroup decorView = (ViewGroup) activity.getWindow().getDecorView();
final ViewTreeObserver viewTreeObserver = decorView.getViewTreeObserver();
viewTreeObserver.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
final ArrayList<View> outViews = new ArrayList<>();
decorView.findViewsWithText(outViews, overflowDescription,
View.FIND_VIEWS_WITH_CONTENT_DESCRIPTION);
if (outViews.isEmpty()) {
return;
}
ActionMenuItemView overflow = (ActionMenuItemView)outViews.get(0);
overflow.getCompoundDrawables()[0].setColorFilter(colorFilter);
removeOnGlobalLayoutListener(decorView,this);
}
});
}
Mit michalbrz-Code bekam ich diesen Fehler:
java.lang.ClassCastException: android.support.v7.internal.view.menu.ActionMenuItemView cannot be cast to android.support.v7.internal.widget.TintImageView
Also, nachdem ich ein wenig gegraben habe ActionMenuItemView
‘s Code habe ich herausgefunden, wie man das drawable des Symbols erhält (indem ich in setIcon()
), dann habe ich einfach Casting zu geändert ActionMenuItemView
angewandter Farbfilter nach links ziehbar erhalten getCompoundDrawables()
und Voila! Es klappt!
.
7842700cookie-checkProgrammgesteuertes Ändern des Symbols für das Android-Überlaufmenüyes
Ich glaube, der einzige Weg ist ein benutzerdefinierter Stil. Ich glaube nicht, dass Sie es programmgesteuert ändern können.
– Robby Pond
26. Februar 14 um 16:13 Uhr
Ich habe irgendwie das gleiche Gefühl, hoffe nur, dass ich falsch liege.
– Mathijs Segers
26. Februar 14 um 20:01 Uhr