Jak zaimplementować niestandardowy zwijany pasek narzędzi w systemie Android?

80

Korzystanie z tego samouczka do implementacji wzorca elastycznej przestrzeni (tego ze zwijanym paskiem narzędzi).

Staram się osiągnąć podobny efekt jak w działaniu Lollipop Contacts , które na początku wchodząc w działanie, widoki to tylko część nagłówka obrazka:

wprowadź opis obrazu tutaj

Następnie użytkownik może przewinąć układ pod obrazem, aby odsłonić więcej, aż osiągnie maksimum:

wprowadź opis obrazu tutaj

W mojej aplikacji nie mogę tego zrobić.

Dzieje się tak, że po wejściu do działania nagłówek obrazu jest prezentowany w maksymalnym rozmiarze, w rozmiarze AppBarLayout, tak jak w powyższym układzie, w przeciwieństwie do działania Lollipop Contacts , gdzie pokazuje tylko część obrazu.

To jest kod, który ustawia wysokość AppBarLayout (chcę, aby szerokość ekranu była maksymalną wysokością):

int widthPx = getResources().getDisplayMetrics().widthPixels;
AppBarLayout appbar = (AppBarLayout)findViewById(R.id.appbar);
appbar.setLayoutParams(new CoordinatorLayout.LayoutParams(CoordinatorLayout.LayoutParams.MATCH_PARENT, widthPx));

I to jest kod, który ustawia RecyclerView. Próbowałem z scrollToPosition, sądziłem, że podniesie to widok RecyclerView w górę, ale nie ma to żadnego wpływu:

mRecyclerView = (RecyclerView) findViewById(R.id.activity_profile_bottom_recyclerview);

    mRecyclerView.setHasFixedSize(true);

    // use a linear layout manager
    mLayoutManager = new LinearLayoutManager(this);

    mRecyclerView.setLayoutManager(mLayoutManager);

    // specify an adapter (see also next example)
    if(mAdapter == null){
        mAdapter = new ProfileAdapter(this, user, inEditMode);
        mRecyclerView.setAdapter(mAdapter);
    }

    mRecyclerView.scrollToPosition(mAdapter.getItemCount() - 1); // itemCount is 4

To jest układ XML:

<android.support.v4.widget.DrawerLayout 
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/activity_profile"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">

<android.support.design.widget.CoordinatorLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">
    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        android:layout_width="match_parent"
        android:layout_height="0dp" // set programatically
        android:fitsSystemWindows="true"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
        <android.support.design.widget.CollapsingToolbarLayout
            android:id="@+id/collapsing_toolbar"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:fitsSystemWindows="true"
            app:contentScrim="?attr/colorPrimary"
            app:expandedTitleMarginBottom="32dp"
            app:expandedTitleMarginEnd="64dp"
            app:expandedTitleMarginStart="48dp"
            app:layout_scrollFlags="scroll|exitUntilCollapsed">
            <ImageView
                android:id="@+id/header"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@drawable/header"
                android:fitsSystemWindows="true"
                android:scaleType="centerCrop"
                app:layout_collapseMode="parallax" />
            <android.support.v7.widget.Toolbar
                android:id="@+id/anim_toolbar"
                android:layout_width="match_parent"
                android:layout_height="?attr/actionBarSize"
                app:layout_collapseMode="pin"
                app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
        </android.support.design.widget.CollapsingToolbarLayout>
    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/activity_profile_bottom_recyclerview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" /> 

    </android.support.design.widget.CoordinatorLayout>

    <include layout="@layout/navigation_view"/>
</android.support.v4.widget.DrawerLayout>

Uwaga: Jeśli ręcznie przewinie się w dół, RecyclerView zejdzie w dół i ujawni więcej obrazu, po prostu nie będzie działać przez kod.

Myślę, że scrollToPosition nie jest rozwiązaniem, czy ktoś ma jakiś pomysł?

Zastanawiałem się nad użyciem flagi enterAlwaysCollapsed być może, jak wspomniano tutaj w sekcji CoordinatorLayout i Appbar z minHeight:

enterAlwaysCollapsed: Kiedy twój widok zadeklarował minHeight i użyjesz tej flagi, twój widok wejdzie tylko na swojej minimalnej wysokości (tj. „zwinięty”), a ponownie rozwinie się do pełnej wysokości, gdy przewijany widok osiągnie szczyt.

Dlatego ustawiłem flagę scroll | enterAlwaysCollapsed na moim pasku narzędzi i minHeight w moim RecyclerView, co nie działało. Następnie próbowałem przenieść minHeight do innych układów, takich jak AppBarLayout, nic nie działało. Czasami po prostu zmniejszał obraz bez całego widoku.

Jjang
źródło
2
Dzięki @karaokyo, to faktycznie zadziałało. Wciąż próbuję dowiedzieć się, czy są też inne rozwiązania.
Jjang,
@karaokyo, czy mógłbyś to sprawdzić? stackoverflow.com/questions/33069081/…
Jjang
Użyłbym MotionLayout do zrobienia tego. Zobacz przykłady na https://github.com/android/views-widgets-samples/tree/master/ConstraintLayoutExamples
Lin Lin

Odpowiedzi:

1

AppBarComponentZapewnia metodę o nazwie .setExpanded(boolean expanded), który pozwala, aby rozwinąć AppBarComponent.

Pamiętaj jednak, że ta metoda polega na tym, że ten układ jest bezpośrednim dzieckiem pliku CoordinatorLayout.

Możesz przeczytać to, aby uzyskać więcej informacji.

Jeśli chcesz animować do niestandardowego przesunięcia, spróbuj użyć tej setTopAndBottomOffset(int)metody.

CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) appBar.getLayoutParams();
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
if (behavior != null) {
    ValueAnimator valueAnimator = ValueAnimator.ofInt();
    valueAnimator.setInterpolator(new DecelerateInterpolator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            behavior.setTopAndBottomOffset((Integer) animation.getAnimatedValue());
            appBar.requestLayout();
        }
    });
    valueAnimator.setIntValues(0, -900);
    valueAnimator.setDuration(400);
    valueAnimator.start();
}
Lukas
źródło