android - Ocultando ActionBar en RecyclerView/ListView onScroll
collapsingtoolbarlayout scroll flags (7)
En mi aplicación obtuve una actividad con algún tipo de barra de acciones en la parte superior y la vista de lista debajo. Lo que quiero hacer es desplazarlo hacia ARRIBA con la lista, de modo que se oculta y luego, cuando la lista se está desplazando hacia abajo, debería desplazarse hacia abajo con la lista, como si estuviera justo sobre el borde superior de la pantalla. ¿Cómo puedo lograr esta funcionalidad?
Actualizado el 3/06/2015:
Google ahora admite esto usando 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>
Documentado aquí: https://developer.android.com/reference/android/support/design/widget/AppBarLayout.html
Respuesta Original:
Ejemplo similar a las aplicaciones de Google Play Music y Umano:
https://github.com/umano/AndroidSlidingUpPanel
Eche un vistazo al código en este repositorio. A medida que desliza el panel hacia arriba, la Barra de acciones también se desliza hacia arriba.
De la demostración :
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");
}
});
Descargue el ejemplo aquí:
https://play.google.com/store/apps/details?id=com.sothree.umano
ListView - sin bibliotecas:
Hace poco quería la misma funcionalidad y esto funciona perfectamente para mí:
A medida que el usuario se desplaza hacia arriba, la barra de acciones se ocultará para darle al usuario toda la pantalla para trabajar con ella.
A medida que el usuario se desplaza hacia abajo y suelta, la ActionBar volverá.
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 - sin bibliotecas
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;
}
});
¡Avíseme si necesita más ayuda!
Creo que va a funcionar 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;
}
}
}
});
Estoy seguro de que no es la mejor solución. Pero aún no he encontrado uno mejor. Espero que sea útil.
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;
}
}
});
Experimenta el parpadeo ya que al ocultar / mostrar la barra de acciones, se muestra el espacio disponible para los cambios en el diseño del contenido, lo que provoca una retransmisión. Con esto, también cambia el índice de la posición del primer elemento visible (puede verificarlo al cerrar sesión mLastFirstVisibleItem y currentFirstVisibleItem .
Puede hacer frente al parpadeo dejando que ActionBar superponga su diseño de contenido. Para habilitar el modo de superposición para la barra de acciones, debe crear un tema personalizado que amplíe un tema existente de la barra de acciones y establezca la propiedad android: windowActionBarOverlay en verdadero .
Con esto puedes eliminar el parpadeo pero la barra de acción superpondrá el contenido de tu lista. Una solución fácil para esto es establecer el relleno superior de listview (o el diseño raíz) a la altura de la barra de acción.
<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" />
Desafortunadamente, esto dará como resultado un relleno constante en la parte superior. Un refinamiento de esta solución es agregar una vista de encabezado a la vista de lista que tiene la altura de ? Android: attr / actionBarSize (y eliminar el conjunto de relleno superior anteriormente)
Lo que está buscando se llama patrón de retorno rápido , aplicado a la barra de acción. La aplicación Google IO 2014 usa exactamente eso. Lo uso en una de mis aplicaciones, puede verificar el código fuente de esa aplicación de Google para ver cómo lo obtuvieron. La clase BaseActivity es donde tienes lo que necesitas, lee el código y extrae solo esa funcionalidad específica. ¡Disfruta la codificación! :)
Si está utilizando un CoordinatorLayout, este es el truco.
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways" />
La app:layout_scrollFlags="scroll|enterAlways"
hará que nuestra barra de herramientas se desplace fuera de la pantalla cuando el usuario se desplace por la lista y tan pronto como comience a desplazarse, la barra de herramientas volverá a aparecer.
Tengo un pensamiento que es una buena idea.
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;