Android BottomNavigationView Eine Registerkarte mit verschiedenen nicht ausgewählten / ausgewählten Farben


8

Ich versuche, ein Design wie dieses zusammenzubringen.

Geben Sie hier die Bildbeschreibung ein

Beachten Sie, dass der "ausgewählte Farbton der Registerkarte" blau ist, das Symbol der mittleren Registerkarte jedoch immer der grüne Kreis mit der weißen Uhr in der Mitte sein sollte.

Ich habe eine Reihe von Dingen ausprobiert. Versuchen Sie zunächst, dies programmgesteuert mithilfe einer XML-Ressource mit Ebenenliste zu tun, die über den grünen Kreis und die Uhr-PNG-Ressource verfügt, was überhaupt nicht funktioniert hat. Dann habe ich gerade den Designer gebeten, mir das vollständige Symbol (Uhr und grüner Kreis) zu geben, aber jetzt stoße ich auf dieses Problem.

(Nicht ausgewählt)

Geben Sie hier die Bildbeschreibung ein

(Ausgewählt)

Geben Sie hier die Bildbeschreibung ein

Ich finde nicht die richtigen Begriffe, nach denen ich bei Google suchen kann, um dies zu beheben.

Am Ende muss die ausgewählte Registerkartenfarbe blau sein, aber das mittlere Registerkartensymbol muss immer das tatsächliche Symbol ohne zusätzliche Farbe sein (im Wesentlichen muss es genau wie die PNG-Datei aussehen).

PS: Ich verwende Xamarin.Forms, FreshMvvm und den FreshTabbedFONavigationContainer. Über den Renderer habe ich jedoch direkten Zugriff auf BottomNavigationView und alle anderen nativen Android-Komponenten. Die Lösung muss also keine Xamarin-Lösung sein. Eine Java / Kotlin-Lösung würde auch funktionieren und ich kann sie einfach in Xamarin konvertieren.

======================

EDITIERT:

======================

Ich bin mit dem unten stehenden Andres Castro- Code viel weiter gekommen , habe aber immer noch das gleiche Problem wie zuvor. Mit dem folgenden Code von Andres habe ich wieder FontAwesome für die Symbole verwendet (was hervorragend funktioniert). Dabei musste ich jedoch ein verwenden LayerDrawable, um das Symbol für die mittlere Registerkarte des Kreises / Symbols zu erstellen.

Das ist es also, was ich bisher habe.

Nicht ausgewähltes zentrales Symbol

Geben Sie hier die Bildbeschreibung ein

Ausgewähltes zentrales Symbol

Geben Sie hier die Bildbeschreibung ein

Wie Sie sehen können, ist das mittlere Symbol bei Nichtauswahl immer noch grau und bei Auswahl blau (die richtigen ausgewählten / nicht ausgewählten Farben der anderen 4 Symbole).

Hier ist der Code, den ich bisher für das mittlere Symbol habe.

UpdateTabbedIcons

private void UpdateTabbedIcons()
{
    for (var i = 0; i < Element.Children.Count; i++) {
        var tab = _bottomNavigationView.Menu.GetItem(i);

        var element = Element.Children[i];
        if (element is NavigationPage navigationPage) {
            //if the child page is a navigation page get its root page
            element = navigationPage.RootPage;
        }

        UpdateTabIcon(tab, element);
    }
}

UpdateTabIcon

public void UpdateTabIcon(IMenuItem menuItem, Page page)
{
    var icon = page?.Icon;
    if (icon == null) return;

    var drawable = new IconDrawable(Context, icon, "fa-regular-pro-400.ttf");

    var element = Element.CurrentPage;
    if (element is NavigationPage navigationPage) {
        //if the child page is a navigation page get its root page
        element = navigationPage.RootPage;
    }

    if (page is DoNowTabPage) { //Page for center icon
        drawable.Color(Helpers.Resources.White.ToAndroid());
        var finalDrawable = GetCombinedDrawable(drawable);
        menuItem.SetIcon(finalDrawable);
        return;
    } else if (element == page) {
        drawable.Color(BarSelectedItemColor.ToAndroid());
    } else {
        drawable.Color(BarItemColor.ToAndroid());
    }

    menuItem.SetIcon(drawable);
}

GetCombinedDrawable

private Drawable GetCombinedDrawable(IconDrawable iconDrawable)
{
    var displayMetrics = Resources.DisplayMetrics;

    GradientDrawable circleDrawable = new GradientDrawable();
    circleDrawable.SetColor(Helpers.Resources.Green.ToAndroid());
    circleDrawable.SetShape(ShapeType.Oval);
    circleDrawable.SetSize((int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 500, displayMetrics), (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 500, displayMetrics));
    circleDrawable.Alpha = 1;

    var inset = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 140, displayMetrics);
    var bottomInset = (int)TypedValue.ApplyDimension(ComplexUnitType.Dip, 40, displayMetrics);
    LayerDrawable finalDrawable = new LayerDrawable(new Drawable[] { circleDrawable, iconDrawable });
    finalDrawable.SetLayerHeight(1, iconDrawable.IntrinsicHeight);
    finalDrawable.SetLayerWidth(1, iconDrawable.IntrinsicWidth);
    finalDrawable.SetLayerInset(1, inset, inset, inset, inset + bottomInset);
    finalDrawable.SetLayerInsetBottom(0, bottomInset);
    finalDrawable.ClearColorFilter();

    return finalDrawable;
}

Wie Sie in der Abbildung sehen können GradientDrawable, die ich für den Kreis erstelle, setze ich die Farbe auf meine grüne Farbe (ich habe eine benutzerdefinierte Klasse namens Ressourcen ... das ist nicht die Android- ResourcesKlasse).

Da stecke ich also fest. Ich stelle den Kreis auf eine grüne Farbe ein, aber sobald er in der BottomNavigationView angezeigt wird, stimmt seine Farbe immer mit den nicht ausgewählten / ausgewählten Farben der anderen Symbole überein.

In der Hoffnung, diese letzte Ausgabe zu überwinden. Vielen Dank für jede Hilfe.


Eine einfache Lösung besteht darin, ein leeres Element dazwischen zu verwenden und eine separate Bildansicht mit dem grünen Bild über der BottomNavigationView zu platzieren.
Shivam Yadav

1
Warum ändern Sie den ausgewählten Farbton nicht programmgesteuert in Abhängigkeit vom Index der unteren Navigationsansicht?
Saamer

1
@ Saamer Dein Kommentar schien so einfach haha. Kannst du es als Antwort posten, damit ich das Kopfgeld vergeben kann? Dies ist der Code, den ich verwendet habe ..._bottomNavigationView.ItemIconTintList = null;
Ryan Alford

Es hat bei dir funktioniert? BottomNavigationView ist schmerzlich schwieriger als die iOS-Implementierung. Ich habe einige Nachforschungen angestellt, um festzustellen, ob das, was Sie gefragt haben, möglich ist, und als ich es dann in Android native sah, habe ich mir überlegt, wie ich es erreichen kann.
Saamer

1
Ja, es hat funktioniert. Ich bin mir nicht sicher, aber es scheint, als würde meine Änderung ALLE Farbtöne für Elementsymbole zurücksetzen, aber das tut es nicht. Alle anderen Registerkarten funktionieren weiterhin, da ich sie jedes Mal manuell einstelle und die Mitte grün ist, wenn sie ausgewählt und nicht ausgewählt ist.
Ryan Alford

Antworten:


1

BottomNavigationView ist schmerzlich schwieriger als die iOS-Implementierung. Ich habe einige Nachforschungen angestellt, um festzustellen, ob das, was Sie gefragt haben, möglich ist, und als ich es dann in Android native sah, habe ich mir überlegt, wie ich es erreichen kann.

Um Ihre letzte Herausforderung zu implementieren, müssten Sie den ausgewählten Farbton jedes Mal programmgesteuert ändern, abhängig vom Index der unteren Navigationsansicht.


2

Da Sie Zugriff auf die untere Navigationsansicht haben, können Sie Ihre untere Symbolleiste bei jedem Seitenwechsel einfach neu zeichnen. Wir haben etwas Ähnliches gemacht und keine Leistungsprobleme festgestellt.

Sie möchten zuerst die Seitenänderungen überwachen, indem Sie die darin enthaltenen Seitenänderungen abonnieren OnElementChanged

Element.CurrentPageChanged += ElementOnCurrentPageChanged;

Dann ElementOnCurrentPageChangedkönnen Sie im Inneren jede Seite durchlaufen und den Menüpunkt für diese Seite erhalten

private void UpdateTabbedIcons()
{
    for (var i = 0; i < Element.Children.Count; i++)
    {
        var tab = _bottomNavigationView.Menu.GetItem(i);

        var element = Element.Children[i];
        if (element is NavigationPage navigationPage)
        {
            //if the child page is a navigation page get its root page
            element = navigationPage.RootPage;
        }

        UpdateTabIcon(tab, element);
    }
}

In unserem Fall haben wir Schriftsymbole verwendet, also haben wir die Symbole gezeichnet und jedes Mal die Farben festgelegt.

public void UpdateTabIcon(IMenuItem menuItem, Page page)
{
    var icon = page?.Icon?.File;
    if (icon == null) return;

    var drawable = new IconDrawable(Context, "FontAwesome.ttf", icon).SizeDp(20);

    var element = Element.CurrentPage;
    if (element is NavigationPage navigationPage)
    {
        //if the child page is a navigation page get its root page
        element = navigationPage.RootPage;
    }

    if (element == page)
    {
        drawable.Color(BarSelectedItemColor.ToAndroid());
    }
    else
    {
        drawable.Color(BarItemColor.ToAndroid());
    }

    menuItem.SetIcon(drawable);
}

Wir mussten auch OnAttachedToWindow überschreiben, um sicherzustellen, dass die Symbole neu gezeichnet wurden, wenn wir aus verschiedenen Zuständen zur App zurückkehrten.

protected override void OnAttachedToWindow()
{
    UpdateTabbedIcons();

    base.OnAttachedToWindow();
}

Sie müssen dies an Ihren Anwendungsfall anpassen, aber ich denke, diese Methode sollte das erreichen, wonach Sie suchen.


Genial. Ich werde es heute Abend versuchen. Wenn Sie Arbeitscode haben, der FontAwesome (oder andere vektorgrafische Schriftarten) für BottomNavigationView verwendet, sollten Sie wirklich irgendwo einen Blog-Beitrag verfassen. Ich konnte kein Beispiel finden und meine Versuche würden das Symbol niemals zeigen.
Ryan Alford

1

Sie können SVG-Bilder verwenden und Ihr eigenes Farbattribut erstellen sowie einen zeichnbaren Selektor für das mittlere Symbol sowie andere Symbole für die untere Navigationsansicht erstellen.

in der Datei colours.xml

    <color name="color_bottom_selected">#44C8F5</color>
 <color name="color_bottom_unselected">#c0c0c0</color>

in der Datei attrs.xml

   <attr name="color_bottom_unselected" format="color" />
    <attr name="color_bottom_selected" format="color" />

in der SVG-Bilddatei

Ersetzen Sie den fest codierten Farbwert durch Ihr Attribut

android:fillColor="#fff" to android:fillColor="?attr/color_bottom_unselected"

und vergessen Sie nicht, den Selektor zeichnbar zu machen


1

Versuchen Sie, den Farbtonmodus DST zu verwenden , bei dem der Farbton einfach ignoriert wird.

Fügen Sie diese Zeile Ihrer Methode hinzu GetCombinedDrawable()

circleDrawable.setTintMode(PorterDuff.Mode.DST);

Wenn dies nicht funktioniert, versuchen Sie Folgendes:

finalDrawable.ClearColorFilter();
finalDrawable.setTintMode(PorterDuff.Mode.DST);

Ich habe tatsächlich alle PorterDuff.Mode-Optionen ausprobiert, aber keine hat funktioniert.
Ryan Alford

0

Ich kann Ihnen dabei helfen:

public class HomeMenuTabLayout extends TabLayout {

public static final int HOME_MENU_TABLAYOUT_COUNT = 5;

public static final int HOME_MENU_LIVE_INDEX = 0;
public static final int HOME_MENU_TEAM_INDEX = 1;
public static final int HOME_MENU_ADS_INDEX = 2;
public static final int HOME_MENU_WALLET_INDEX = 3;
public static final int HOME_MENU_POST_INDEX = 4;

public int selectedIndex = 0;
private TextView unread;

public HomeMenuTabLayout(Context context) {
    super(context);
    initItems(context);
}

public HomeMenuTabLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
    initItems(context);
}

public HomeMenuTabLayout(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initItems(context);
}

public void initItems(Context context) {
    for (int i = 0; i < HOME_MENU_TABLAYOUT_COUNT; i++) {
        addTab(newTab());
    }

    for (int i = 0; i < HOME_MENU_TABLAYOUT_COUNT; i++) {
        TabLayout.Tab tab = this.getTabAt(i);
        tab.setCustomView(getTabView(context, i, false));
    }
}

public void setTagIndex(Context context, int index) {
    getTabView(context, selectedIndex, false);
    selectedIndex = index;
    getTabView(context, selectedIndex, true);
}

private View getTabView(Context context, int index, boolean selected) {
    View v = null;
    TabLayout.Tab tab = this.getTabAt(index);
    if (tab != null) {
        v = tab.getCustomView();
        if (v == null) {
            v = LayoutInflater.from(context).inflate(R.layout.activity_main_tab_layout, null);
        }
    }

    if (v == null) {
        return null;
    }

    ImageView img = v.findViewById(R.id.tablayout_image);
    int color = 0;
    int color2 = 0;
    if (selected) {
        color = getResources().getColor(R.color.corn_flower_blue);
        color2 = getResources().getColor(R.color.dark_sky_blue_three);
        TmlyUtils.displayViewWithZoom(img);
    } else {
        color = getResources().getColor(R.color.battleship_grey_dark);
        color2 = getResources().getColor(R.color.battleship_grey_dark);
    }

    switch (index) {
        case HOME_MENU_ADS_INDEX:
            Bitmap offers = StyleKit.imageOfTabbarSearchActive(color, color2);
            img.setImageBitmap(offers);
            break;
        case HOME_MENU_LIVE_INDEX:

            Bitmap live = StyleKit.imageOfTabbarHomeActive(color, color2);
            img.setImageBitmap(live);
            unread = v.findViewById(R.id.tablayout_unread);
            break;
        case HOME_MENU_TEAM_INDEX:
            Bitmap team = StyleKit.imageOfTabbarSocialActive(color, color2);
            img.setImageBitmap(team);
            break;
        case HOME_MENU_WALLET_INDEX:
            Bitmap wallet = StyleKit.imageOfTabbarCaddyActive(color, color2);
            img.setImageBitmap(wallet);
            break;
        case HOME_MENU_POST_INDEX:
            Bitmap chat = StyleKit.imageOfTabbarPlusActive(getResources().getColor(R.color.white), getResources().getColor(R.color.white));
            img.setImageBitmap(chat);
            View cirle = v.findViewById(R.id.tablayout_circle);
            cirle.setVisibility(View.VISIBLE);
            break;
        default:
            break;
    }
    return v;
}
}

Dies ist ein benutzerdefiniertes TabLayout. Sie können sehen, dass ich die TabLayout-Klasse erweitere. Wenn das TabLayout erstellt wird, rufe ich die initItems-Methode auf, die addTab hinzufügt, und lege eine benutzerdefinierte Ansicht dafür fest.

Das getTabView gibt die aufgeblasene Ansicht zurück, wie Sie damit sehen können

 LayoutInflater.from(context).inflate(R.layout.activity_main_tab_layout, null);

Wenn du es brauchst

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="@dimen/tab_bar_height">

    <ImageView
        android:id="@+id/tablayout_circle"
        android:layout_width="@dimen/tab_bar_height"
        android:layout_height="@dimen/tab_bar_height"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:background="@drawable/circle_blue_gradient"
        android:visibility="gone"
        tools:visibility="visible" />

    <ImageView
        android:id="@+id/tablayout_image"
        android:layout_width="@dimen/tab_bar_icon_favorite_height"
        android:layout_height="@dimen/tab_bar_icon_favorite_height"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true" />

</RelativeLayout>

Nach dem Aufblasen der Ansicht können Sie Ihr Ansichtselement mit erhalten

  ImageView img = v.findViewById(R.id.tablayout_image);

Sie können überprüfen, ob die Ansicht mit dem ausgewählten Booleschen Wert ausgewählt ist. In Ihrem Fall müssen Sie den Farbschalter ignorieren, wenn der Index der zentrale ist.

Nur eine Sache, wenn Sie auf ein TabLayout-Symbol klicken, vergessen Sie nicht, das aufzurufen

setTagIndex();

Wenn Sie dies nicht tun, wird das Bild nicht neu gezeichnet


0

Lösung

Gradle:

implementation 'com.github.armcha:SpaceNavigationView:1.6.0'

Layout:

<com.luseen.spacenavigation.SpaceNavigationView
        android:id="@+id/space"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentBottom="true"
        app:active_item_color="@color/color_trans"
        app:centre_button_color="@color/black"
        app:inactive_item_color="@color/color_trans"
        app:space_background_color="@color/white"
        app:space_item_icon_only_size="24dp"
        app:space_item_icon_size="@dimen/space_item_icon_default_size"
        app:space_item_text_size="@dimen/space_item_text_default_size" />

Raumnavigationselemente hinzufügen.

 spaceNavigationView = (SpaceNavigationView) findViewById(R.id.space);
 spaceNavigationView.initWithSaveInstanceState(savedInstanceState);

       /*Space navigation View*/
        spaceNavigationView.initWithSaveInstanceState(savedInstanceState);

        spaceNavigationView.addSpaceItem(new SpaceItem(0, "Templates", R.drawable.ic_color_template_tab, getResources().getColor(R.color.color_yellow)));
        spaceNavigationView.addSpaceItem(new SpaceItem(1, "Explore", R.drawable.ic_category_tab, getResources().getColor(R.color.color_bg)));
        spaceNavigationView.addSpaceItem(new SpaceItem(2, "Tools", R.drawable.ic_tools_tab, getResources().getColor(R.color.color_bg)));
        spaceNavigationView.addSpaceItem(new SpaceItem(3, "My Work", R.drawable.ic_my_work_tab, getResources().getColor(R.color.color_bg)));


        spaceNavigationView.setCentreButtonIconColorFilterEnabled(true);
        spaceNavigationView.setCentreButtonIcon(R.drawable.ic_create2_tab);
        spaceNavigationView.setInActiveCentreButtonIconColor(ContextCompat.getColor(this, R.color.white));
        spaceNavigationView.setActiveCentreButtonBackgroundColor(ContextCompat.getColor(this, R.color.color_yellow));
        spaceNavigationView.setCentreButtonColor(ContextCompat.getColor(this, R.color.black));
        spaceNavigationView.setCentreButtonRippleColor(ContextCompat.getColor(this, R.color.color_yellow));
        spaceNavigationView.setCentreButtonSelectable(true);

        spaceNavigationView.setSpaceBackgroundColor(ContextCompat.getColor(this, R.color.obaudiopicker_white));
    //  spaceNavigationView.setCentreButtonSelected(2, R.drawable.ic_color_template_tab, getResources().getColor(R.color.color_yellow));
        spaceNavigationView.setInActiveSpaceItemColor(ContextCompat.getColor(this, R.color.color_bg));

Verwenden Sie initWithSaveInstanceState(savedInstanceState)und, override onSaveInstanceStatewenn Sie die ausgewählte Artikelposition und das ausgewählte Abzeichen bei der Gerätedrehung beibehalten möchten

@Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        spaceNavigationView.onSaveInstanceState(outState);
        Log.i(TAG, "onSaveInstanceState: ");
    }

OnClick Listener einstellen

spaceNavigationView.setSpaceOnClickListener(new SpaceOnClickListener() {
            @Override
            public void onCentreButtonClick() {
                setDefaultIcon();
                new Handler().post(new Runnable() {
                    @Override
                    public void run() {
                        spaceNavigationView.setActiveCentreButtonIconColor(ContextCompat.getColor(NEWBusinessCardMainActivity.this, R.color.black));

                    }
                });
                changeCurrentFragmentTo(Constants.ITEM_CREATE);
            }

            @Override
            public void onItemClick(final int itemIndex, String itemName) {
                Log.d("onItemClick ", "" + itemIndex + " " + itemName);
                switch (itemIndex) {
                    case 0:
                        setDefaultIcon();
                        new Handler().post(new Runnable() {
                            @Override
                            public void run() {
                                spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_template_tab);
                                spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_yellow));
                            }
                        });
                        changeCurrentFragmentTo(Constants.ITEM_TEMPLATE);
                        break;
                    case 1:
                        setDefaultIcon();
                        new Handler().post(new Runnable() {
                            @Override
                            public void run() {
                                spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_category_tab);
                                spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_category));

                            }
                        });
                        changeCurrentFragmentTo(Constants.ITEM_CATEGORY);
                        break;
                    case 2:
                        setDefaultIcon();
                        new Handler().post(new Runnable() {
                            @Override
                            public void run() {
                                spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_tool_tab);
                                spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_tools));

                            }
                        });
                        changeCurrentFragmentTo(Constants.ITEM_TOOLS);
                        break;
                    case 3:
                        setDefaultIcon();
                        new Handler().post(new Runnable() {
                            @Override
                            public void run() {
                                spaceNavigationView.changeItemIconAtPosition(itemIndex, R.drawable.ic_color_my_work_tab);
                                spaceNavigationView.changeItemTextColorAtPosition(itemIndex, getResources().getColor(R.color.color_mywork));

                            }
                        });
                        changeCurrentFragmentTo(Constants.ITEM_MY_WORK);
                        break;
                }
            }

            @Override
            public void onItemReselected(int itemIndex, String itemName) {
   //        Toast.makeText(MainActivity.this, itemIndex + " " + itemName, Toast.LENGTH_SHORT).show();

            }
        });

setDefaultIcon ()

private void setDefaultIcon() {
        spaceNavigationView.changeItemIconAtPosition(0, R.drawable.ic_template_tab, getResources().getColor(R.color.color_bg));
        spaceNavigationView.changeItemIconAtPosition(1, R.drawable.ic_category_tab, getResources().getColor(R.color.color_bg));
        spaceNavigationView.changeItemIconAtPosition(2, R.drawable.ic_tools_tab, getResources().getColor(R.color.color_bg));
        spaceNavigationView.changeItemIconAtPosition(3, R.drawable.ic_my_work_tab, getResources().getColor(R.color.color_bg));


    }

Beispiel:

Geben Sie hier die Bildbeschreibung ein

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.