Jak zaimplementować DrawerArrowToggle z biblioteki appcompat v7 21 na Androida


97

Teraz, gdy pojawił się Android 5.0, zastanawiałem się, jak zaimplementować animowane ikony paska akcji.

Ta biblioteka tutaj implementuje ją dobrze, ale skoro biblioteka appcompat v7 ma ją, jak można ją zaimplementować?

Biblioteka odwołuje się do niego w plikach themes.xml

 <item name="drawerArrowStyle">@style/Widget.AppCompat.DrawerArrowToggle</item>

W tym stylu

 <style name="Base.V7.Theme.AppCompat" parent="Platform.AppCompat">

AKTUALIZACJA

Zaimplementowałem to za pomocą DrawerToggle w wersji 7. Jednak nie mogę tego stylizować. Proszę pomóż

Znalazłem jego styl w pliku v7 styles_base.xml

<style name="Base.Widget.AppCompat.DrawerArrowToggle" parent="">
    <item name="color">?android:attr/textColorSecondary</item>
    <item name="thickness">2dp</item>
    <item name="barSize">18dp</item>
    <item name="gapBetweenBars">3dp</item>
    <item name="topBottomBarArrowSize">11.31dp</item>
    <item name="middleBarArrowSize">16dp</item>
    <item name="drawableSize">24dp</item>
    <item name="spinBars">true</item>
</style>

Dodałem to do moich stylów i nie działało. Dodano również do mojego attr.xml

<declare-styleable name="DrawerArrowToggle">
    <!-- The drawing color for the bars -->
    <attr name="color" format="color"/>
    <!-- Whether bars should rotate or not during transition -->
    <attr name="spinBars" format="boolean"/>
    <!-- The total size of the drawable -->
    <attr name="drawableSize" format="dimension"/>
    <!-- The max gap between the bars when they are parallel to each other -->
    <attr name="gapBetweenBars" format="dimension"/>
    <!-- The size of the top and bottom bars when they merge to the middle bar to form an arrow -->
    <attr name="topBottomBarArrowSize" format="dimension"/>
    <!-- The size of the middle bar when top and bottom bars merge into middle bar to form an arrow -->
    <attr name="middleBarArrowSize" format="dimension"/>
    <!-- The size of the bars when they are parallel to each other -->
    <attr name="barSize" format="dimension"/>
    <!-- The thickness (stroke size) for the bar paint -->
    <attr name="thickness" format="dimension"/>
</declare-styleable>

Ale zawiesza się i wyświetla błąd typu koloru, gdy to robi. Czego mi brakuje?

Odpowiedzi:


243

Po pierwsze, powinieneś wiedzieć, że teraz android.support.v4.app.ActionBarDrawerTogglejest przestarzały.

Musisz to zastąpić android.support.v7.app.ActionBarDrawerToggle.

Oto mój przykład i używam nowego, Toolbaraby zastąpić ActionBar.

MainActivity.java

public class MainActivity extends ActionBarActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(mToolbar);
    DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(
        this,  mDrawerLayout, mToolbar,
        R.string.navigation_drawer_open, R.string.navigation_drawer_close
    );
    mDrawerLayout.setDrawerListener(mDrawerToggle);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setHomeButtonEnabled(true);
    mDrawerToggle.syncState();
}

style.xml

<style name="AppTheme" parent="Theme.AppCompat.Light">
    <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
</style>

<style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
    <item name="spinBars">true</item>
    <item name="color">@android:color/white</item>
</style>

Możesz przeczytać dokumenty na AndroidDocument # DrawerArrowToggle_spinBars

Ten atrybut jest kluczem do implementacji animacji przejścia od menu do strzałki.

public static int DrawerArrowToggle_spinBars

Określa, czy słupki mają się obracać podczas przejścia.
Musi być wartością logiczną, „prawda” lub „fałsz”.

Tak, to ten zestaw: <item name="spinBars">true</item>.

Następnie można zaprezentować animację.

Mam nadzieję, że to może ci pomóc.


12
Wystąpiły problemy z wyświetlaniem ikony hamburgera. dzwonienie mDrawerToggle.syncState();naprawiło to.
aheuermann

1
dla mnie getSupportActionBar () zwraca null .. co może być tego przyczyną?
Ramesh_D,

2
Android Studio mówi Cannot resolve method setSupportActionBar(android.widget.Toolbar). Próbowałem też z android.support.v7.toolbar. Czy ktoś wie, dlaczego tak się dzieje?
pez

1
Użyłem setSupportActionBar(mToolbar);i zdefiniowałem, <item name="spinBars">true</item>ale animacja nie działa
SweetWisher,

2
Powinien używać ActionBarDrawerToggle (Activity, DrawerLayout, int, int), jeśli ustawiasz Toolbar jako ActionBar swojego działania.
Peter Zhao

24

Jeśli korzystasz z biblioteki pomocy technicznej DrawerLayout, zgodnie z sugestią zawartą w szkoleniu dotyczącym tworzenia szuflady nawigacji , możesz skorzystać z nowo dodanej obsługi android.support. v7 .app.ActionBarDrawerToggle (uwaga: inna niż obecnie przestarzała android.support. v4 .app.ActionBarDrawerToggle ):

pokazuje ikonę hamburgera, gdy szuflada jest zamknięta, i strzałkę, gdy szuflada jest otwarta. Animuje się między tymi dwoma stanami, gdy szuflada się otwiera.

Chociaż szkolenie nie zostało zaktualizowane w celu uwzględnienia przestarzałej / nowej klasy, powinieneś być w stanie używać go prawie dokładnie tego samego kodu - jedyną różnicą w jego implementacji jest konstruktor.


Używam wersji 4 w mojej aplikacji bc nie muszę obsługiwać urządzeń przed api 15. Więc gdybym chciał, aby to zadziałało, musiałbym użyć przełącznika szuflady paska akcji w wersji 7? Gdybym to zrobił, czy nie musiałbym konwertować wszystkich moich stylów na AppCompat i fragmentować działania na działania na pasku akcji i tak dalej? Czy mogę zaimplementować tylko przełącznik szuflady z wersji 7. Obecnie używam wersji 7 do wyświetlania kart. Czy powinienem używać wersji 4, jeśli nie obsługuję interfejsu API poniżej 15? I chyba potrzebuję wersji 7 do widoków kart.
Bignadad

Cała kompatybilność biblioteki obsługi dla projektowania materiałów jest zaimplementowana w wersji 7-appcompat i jest zalecana, jeśli chcesz obsługiwać te style na urządzeniach <5.0. AppCompat jest zbudowany w oparciu o i wymaga wersji 4, więc to naprawdę ważne, jeśli w ogóle chcesz używać AppCompat. Jeśli już używasz FragmentActivity, jesteś już całkiem blisko - różnica w stylizacji jest teraz dość niewielka (głównie zastąpienie atrybutu android: atrybuty atrybutami bez przestrzeni nazw).
ianhanniballake

Zaktualizowałem pytanie, jeśli nie masz nic przeciwko temu
Bignadad

To naprawdę osobna kwestia dotycząca stylizacji. Proponuję przesłać tę część jako całość innego pytania (zachęcam do dodania komentarza z linkiem do niego).
ianhanniballake

1
@mraviator - tak: zmień XML, a następnie utwórz i dołącz v7 ActionBarDrawerToggle. Odpowiedź kanoniczną od producenta AppCompat posiada pełną przykład w jaki sposób powinna być skonstruowana XML.
ianhanniballake

17

Stworzyłem małą aplikację, która miała podobną funkcjonalność

Główna aktywność

public class MyActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my);

        DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
        android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
        ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(
                this,
                drawerLayout,
                toolbar,
                R.string.open,
                R.string.close
        )

        {
            public void onDrawerClosed(View view)
            {
                super.onDrawerClosed(view);
                invalidateOptionsMenu();
                syncState();
            }

            public void onDrawerOpened(View drawerView)
            {
                super.onDrawerOpened(drawerView);
                invalidateOptionsMenu();
                syncState();
            }
        };
        drawerLayout.setDrawerListener(actionBarDrawerToggle);

        //Set the custom toolbar
        if (toolbar != null){
            setSupportActionBar(toolbar);
        }

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);

        actionBarDrawerToggle.syncState();
    }
}

Mój kod XML tego działania

<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MyActivity"
    android:id="@+id/drawer"
    >

    <!-- The main content view -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
        <include layout="@layout/toolbar_custom"/>
    </FrameLayout>
    <!-- The navigation drawer -->
    <ListView
        android:layout_marginTop="?attr/actionBarSize"
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#457C50"/>


</android.support.v4.widget.DrawerLayout>

Mój niestandardowy pasek narzędzi XML

<?xml version="1.0" encoding="utf-8"?>

<android.support.v7.widget.Toolbar
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/toolbar"
    android:background="?attr/colorPrimaryDark">
    <TextView android:text="U titel"
        android:textAppearance="@android:style/TextAppearance.Theme"
        android:textColor="@android:color/white"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</android.support.v7.widget.Toolbar>

Mój styl motywu

<resources>
    <style name="AppTheme" parent="Base.Theme.AppCompat"/>

    <style name="AppTheme.Base" parent="Theme.AppCompat">
        <item name="colorPrimary">@color/primary</item>
        <item name="colorPrimaryDark">@color/primaryDarker</item>
        <item name="android:windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="drawerArrowStyle">@style/DrawerArrowStyle</item>
    </style>

    <style name="DrawerArrowStyle" parent="Widget.AppCompat.DrawerArrowToggle">
        <item name="spinBars">true</item>
        <item name="color">@android:color/white</item>
    </style>

    <color name="primary">#457C50</color>
    <color name="primaryDarker">#580C0C</color>
</resources>

Moje style w values-v21

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="AppTheme" parent="AppTheme.Base">
        <item name="android:windowContentTransitions">true</item>
        <item name="android:windowAllowEnterTransitionOverlap">true</item>
        <item name="android:windowAllowReturnTransitionOverlap">true</item>
        <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
        <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
    </style>
</resources>

1
Działa idealnie, ale nie chcę używać tytułu, więc jak sobie z tym poradzić? Ponieważ jeśli użyję Theme.AppCompat.Light.NoActionBar , z pewnością da mi to NULL w getSupportActionBar
SweetWisher ツ

Użyłem powyższego kodu. Mam wyjątek: to działanie ma już pasek akcji dostarczany przez wystrój okna w linii setsupportactionbar (pasek narzędzi). Użyłem getSupportActionBar (). Hide (); Przed setContentView (R.layout.activity_main); Teraz działa.
Thirumalvalavan

setSupportActionBar (pasek narzędzi); również skomentował.
Thirumalvalavan

9

Aby odpowiedzieć na zaktualizowaną część pytania: aby nadać styl ikonie / strzałce szuflady, masz dwie możliwości:

Stylizuj samą strzałkę

Aby to zrobić, nadpisz drawerArrowStylew swoim motywie w następujący sposób:

<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    <item name="drawerArrowStyle">@style/MyTheme.DrawerArrowToggle</item>
</style>
<style name="MyTheme.DrawerArrowToggle" parent="Widget.AppCompat.DrawerArrowToggle">
    <item name="color">@android:color/holo_purple</item>
    <!-- ^ this will make the icon purple -->
</style>

To prawdopodobnie nie jest to, czego chcesz , ponieważ sam ActionBar powinien mieć spójną stylizację ze strzałką, więc najprawdopodobniej chcesz wybrać opcję drugą:

Motyw dla ActionBar / Toolbar

Zastąp atrybut android:actionBarTheme( actionBarThemedla appcompat) globalnego motywu aplikacji własnym motywem (z którego prawdopodobnie powinieneś pochodzić ThemeOverlay.Material.ActionBar/ThemeOverlay.AppCompat.ActionBar) w następujący sposób:

<style name="AppBaseTheme" parent="Theme.AppCompat.Light">
    <item name="actionBarTheme">@style/MyTheme.ActionBar</item>
</style>
<style name="MyTheme.ActionBar" parent="ThemeOverlay.AppCompat.ActionBar">
    <item name="android:textColorPrimary">@android:color/white</item>
    <!-- ^ this will make text and arrow white -->
    <!-- you can also override drawerArrowStyle here -->
</style>

Ważną uwagą jest to, że gdy używasz niestandardowego układu z Toolbarimplementacją ActionBar zamiast standardowej (np. Jeśli używasz kombinacji DrawerLayout- NavigationView- w Toolbarcelu uzyskania efektu szuflady w stylu materiału, gdzie jest widoczny pod półprzezroczystym actionBarThemepaskiem stanu), atrybut oczywiście nie jest pobierane automatycznie (ponieważ AppCompatActivitydomyślnie ma się tym zająć ActionBar), więc Toolbarnie zapomnij zastosować motywu ręcznie:

<!--inside your custom layout with DrawerLayout
and NavigationView or whatever -->
<android.support.v7.widget.Toolbar
        ...
        app:theme="?actionBarTheme">

- rozwiąże to do wartości domyślnej AppCompat ThemeOverlay.AppCompat.ActionBarlub do nadpisania, jeśli ustawisz atrybut w wyprowadzonym motywie.

PS mały komentarz na temat drawerArrowStyleprzesłonięcia i spinBarsatrybutu - który, jak sugeruje wiele źródeł, powinien być ustawiony, trueaby uzyskać animację szuflady / strzałki. Chodzi o to, spinBarsże true domyślnie w AppCompat (sprawdź Base.Widget.AppCompat.DrawerArrowToggle.Commonstyl), nie musisz actionBarThemew ogóle nadpisywać, aby animacja działała. Otrzymasz animację, nawet jeśli ją przesłonisz i ustawisz atrybut na false, to po prostu inna, mniej kręta animacja. Ważną rzeczą jest użycie ActionBarDrawerToggle, to przyciąga fantazyjne animowane rysowanie.


2

Chcę trochę poprawić powyższy kod

    public class MainActivity extends ActionBarActivity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
        DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(
            this,  mDrawerLayout, mToolbar,
            R.string.navigation_drawer_open, R.string.navigation_drawer_close
        );
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
    }

a wszystkie inne rzeczy pozostaną takie same ...

Dla tych, którzy mają problem z Drawerlayoutnakładaniem paska narzędzi

dodaj android:layout_marginTop="?attr/actionBarSize"do głównego układu zawartości szuflady


jak używasz, getSupportActionBar()gdy po prostu przedłużasz Activity?
wzieba

po prostu nie możesz, musisz przedłużyć odActionBarActivity
Nitin Misra,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.