web-dev-qa-db-fra.com

Masquage de la barre d'action sur RecyclerView/ListView onScroll

Dans mon application, j'ai eu une activité avec une sorte de barre d'actions en haut et la liste en dessous. Ce que je veux faire, c’est faire défiler la liste en haut, pour qu’elle se cache, puis, lorsque la liste est défilée vers le bas, elle devrait défiler avec la liste, comme si elle était juste au-dessus du bord supérieur de l’écran. Comment puis-je obtenir cette fonctionnalité?

45
Graykos

Mise à jour le 03/06/2015:

Google prend maintenant cela en charge avec la variable CoordinatorLayout.

<Android.support.design.widget.CoordinatorLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:app="http://schemas.Android.com/apk/res-auto"
    Android:id="@+id/main_content"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent">

    <Android.support.design.widget.AppBarLayout
        Android:id="@+id/appbar"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content"
        Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">

        <Android.support.v7.widget.Toolbar
            Android:id="@+id/toolbar"
            Android:layout_width="match_parent"
            Android:layout_height="?attr/actionBarSize"
            Android:background="?attr/colorPrimary"
            app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways" />

        <Android.support.design.widget.TabLayout
            Android:id="@+id/tabs"
            Android:layout_width="match_parent"
            Android:layout_height="wrap_content" />

    </Android.support.design.widget.AppBarLayout>

    <Android.support.v4.view.ViewPager
        Android:id="@+id/viewpager"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

    <Android.support.design.widget.FloatingActionButton
        Android:id="@+id/fab"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_gravity="end|bottom"
        Android:layout_margin="@dimen/fab_margin"
        Android:src="@drawable/ic_done" />

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

Source:https://github.com/chrisbanes/cheesesquare/blob/master/app/src/main/res/layout/include_list_viewpager.xml

Documenté ici:https://developer.Android.com/reference/Android/support/design/widget/AppBarLayout.html

Réponse originale:

Exemple similaire aux applications Google Play Music et Umano:

https://github.com/umano/AndroidSlidingUpPanel

Regardez le code dans ce référentiel. Lorsque vous faites glisser le panneau vers le haut, la barre d’action se glisse également vers le haut.

De la démo:

   getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);

   SlidingUpPanelLayout layout = (SlidingUpPanelLayout) findViewById(R.id.sliding_layout);
    layout.setShadowDrawable(getResources().getDrawable(R.drawable.above_shadow));
    layout.setAnchorPoint(0.3f);
    layout.setPanelSlideListener(new PanelSlideListener() {
        @Override
        public void onPanelSlide(View panel, float slideOffset) {
            Log.i(TAG, "onPanelSlide, offset " + slideOffset);
            if (slideOffset < 0.2) {
                if (getActionBar().isShowing()) {
                    getActionBar().hide();
                }
            } else {
                if (!getActionBar().isShowing()) {
                    getActionBar().show();
                }
            }
        }

        @Override
        public void onPanelExpanded(View panel) {
            Log.i(TAG, "onPanelExpanded");

        }

        @Override
        public void onPanelCollapsed(View panel) {
            Log.i(TAG, "onPanelCollapsed");

        }

        @Override
        public void onPanelAnchored(View panel) {
            Log.i(TAG, "onPanelAnchored");

        }
    });

Téléchargez l'exemple ici:

https://play.google.com/store/apps/details?id=com.sothree.umano

enter image description here

ListView - sans bibliothèques:

Je voulais récemment la même fonctionnalité et cela fonctionne parfaitement pour moi:

Au fur et à mesure que l'utilisateur fait défiler l'écran vers le haut, la barre Action est masquée afin de permettre à l'utilisateur de travailler avec tout l'écran.

Lorsque l'utilisateur fait défiler l'écran vers le bas et s'en va, la barre d'actions reviendra.

getWindow().requestFeature(Window.FEATURE_ACTION_BAR_OVERLAY);

listView.setOnScrollListener(new OnScrollListener() {
    int mLastFirstVisibleItem = 0;

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {   }           

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {    
        if (view.getId() == listView.getId()) {
            final int currentFirstVisibleItem = listView.getFirstVisiblePosition();

            if (currentFirstVisibleItem > mLastFirstVisibleItem) {
                // getSherlockActivity().getSupportActionBar().hide();
                getSupportActionBar().hide();
            } else if (currentFirstVisibleItem < mLastFirstVisibleItem) {
                // getSherlockActivity().getSupportActionBar().show();
                getSupportActionBar().show();
            }

            mLastFirstVisibleItem = currentFirstVisibleItem;
        }               
    }
});

RecyclerView - sans bibliothèques

    this.mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
        int mLastFirstVisibleItem = 0;

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            final int currentFirstVisibleItem = mLinearLayoutManager.findFirstVisibleItemPosition();

            if (currentFirstVisibleItem > this.mLastFirstVisibleItem) {
                MainActivity.this.getSupportActionBar().hide();
            } else if (currentFirstVisibleItem < this.mLastFirstVisibleItem) {
                MainActivity.this.getSupportActionBar().show();
            }

            this.mLastFirstVisibleItem = currentFirstVisibleItem;
        }
    });

Faites-moi savoir si vous avez besoin de plus d'aide!

76
Jared Burrows

Vous constatez le scintillement car en masquant/affichant le ActionBar l’espace disponible pour vos modifications de présentation du contenu, ce qui provoque un relais. Avec cela, l'index de la position du premier élément visible change également (vous pouvez le vérifier en déconnectant mLastFirstVisibleItem et currentFirstVisibleItem

Vous pouvez faire face au scintillement en laissant la barre d’action recouvrir la présentation de votre contenu. Pour activer le mode superposition pour la barre d'action, vous devez créer un thème personnalisé qui étend un thème de barre d'action existant et définissez la propriété Android: windowActionBarOverlay sur true.

Avec cela, vous pouvez éliminer le scintillement, mais la barre d'action superposera le contenu de votre liste. Une solution simple consiste à définir le remplissage supérieur de la liste (ou de la présentation racine) à la hauteur de la barre d'actions.

<ListView xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@Android:id/list"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:paddingTop="?android:attr/actionBarSize" />

Malheureusement, cela se traduira par un remplissage constant au sommet. Un raffinement de cette solution consiste à ajouter une vue en-tête à la vue liste qui a la hauteur de ? Android: attr/actionBarSize (et supprimer le remplissage supérieur défini précédemment).

10
ne'mi

Ce que vous recherchez s'appelle Modèle de retour rapide , appliqué à la barre d’action. Google IO 2014 app utilise exactement cela. Je l'utilise dans l'une de mes applications. Vous pouvez consulter le code source de cette application Google pour voir comment il l'a obtenu. La classe BaseActivity est l'endroit où vous avez ce dont vous avez besoin, lisez le code et extrayez cette fonctionnalité spécifique. Profitez de la programmation! :)

8
Diego Palomar

Je suis sûr que ce n'est pas la meilleure solution. Mais je n'en ai pas encore trouvé de meilleur. J'espère que ça vous sera utile.

    static boolean scroll_down;
    ...
    mRecyclerView.setOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
                if (scroll_down) {
                    actionBar.hide();
                } else {
                    actionBar.show();
                }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            if (dy > 70) {
                //scroll down
                scroll_down = true;

            } else if (dy < -5) {
                //scroll up
                scroll_down = false;
            }
        }
    });
3
Alexey

Je pense que c'est une bonne idée.

listView.setOnScrollListener(new OnScrollListener() {
    int mLastFirstVisibleItem = 0;

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
      switch (scrollState) {
            case OnScrollListener.SCROLL_STATE_FLING:
                if (view.getId()==lv_searchresult_results.getId()){
                final int currentFirstVisibleItem=lv_searchresult_results.getFirstVisiblePosition();
                    if(currentFirstVisibleItem>mLastFirstVisibleItem){

                    ObjectAnimator.ofFloat(toolbar, "translationY", -toolbar.getHeight()).start();
                    else if(currentFirstVisibleItem<(mLastFirstVisibleItem)){

                    ObjectAnimator.ofFloat(toolbar, "translationY", 0).start();
                    }
                    mLastFirstVisibleItem= currentFirstVisibleItem;
                }

                if(lv_searchresult_results.getLastVisiblePosition() == myAdapter.getListMap().size()){ 
                    if(myAdapter.getListMap().size() < allRows&&!upLoading){

                    }
                }
                break;
            case OnScrollListener.SCROLL_STATE_IDLE:

                if (view.getFirstVisiblePosition()<=1){
                    ObjectAnimator.ofFloat(toolbar, "translationY", 0).start();

                }
                    if(lv_searchresult_results.getLastVisiblePosition() == myAdapter.getListMap().size()){
                    if(myAdapter.getListMap().size() < allRows&&!upLoading){


                    }
                }
                break;
1
康寿伟

Je pense que cela fonctionnera bien .....

listView.setOnScrollListener(new OnScrollListener() {
            int mLastFirstVisibleItem = listView.getLastVisiblePosition();
            boolean isScrolling = false;

            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if(scrollState == 0)
                    isScrolling = false;
                else if(scrollState == 1)
                    isScrolling = true;
                else if(scrollState == 2)
                    isScrolling = true;     
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {    
                if (view.getId() == myTeamListView.getId()) {

                    if(isScrolling) {
                    final int currentFirstVisibleItem = myTeamListView.getLastVisiblePosition();

                    if (currentFirstVisibleItem > mLastFirstVisibleItem) {                      
                        ((AppCompatActivity)getActivity()).getSupportActionBar().hide();
                    } else if (currentFirstVisibleItem < mLastFirstVisibleItem) {                       
                        ((AppCompatActivity)getActivity()).getSupportActionBar().show();                    
                    }
                    mLastFirstVisibleItem = currentFirstVisibleItem;
                    }
                }
            }
        });
0
Lalit Sharma