在 RecyclerView/ListView onScroll 上隐藏 ActionBar
Posted
技术标签:
【中文标题】在 RecyclerView/ListView onScroll 上隐藏 ActionBar【英文标题】:Hiding the ActionBar on RecyclerView/ListView onScroll 【发布时间】:2012-11-13 14:25:10 【问题描述】:在我的应用程序中,我有一个活动,顶部有某种操作栏,下面是列表视图。我想要做的 - 是用列表向上滚动它,所以它隐藏,然后,当列表向下滚动时 - 它应该随着列表向下滚动,就像它只是在屏幕上边框上方一样。我怎样才能实现这个功能?
【问题讨论】:
***.com/questions/11494300/… @Graykos,你能选择一个正确的答案吗? 【参考方案1】:2015 年 6 月 3 日更新:
Google 现在使用 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_
android:layout_>
<android.support.design.widget.AppBarLayout
android:id="@+id/appbar"
android:layout_
android:layout_
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_
android:layout_
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_
android:layout_ />
</android.support.design.widget.AppBarLayout>
<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_
android:layout_
app:layout_behavior="@string/appbar_scrolling_view_behavior" />
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab"
android:layout_
android:layout_
android:layout_gravity="end|bottom"
android:layout_margin="@dimen/fab_margin"
android:src="@drawable/ic_done" />
</android.support.design.widget.CoordinatorLayout>
来源: https://github.com/chrisbanes/cheesesquare/blob/master/app/src/main/res/layout/include_list_viewpager.xml
在此记录: https://developer.android.com/reference/android/support/design/widget/AppBarLayout.html
原答案:
类似于 Google Play 音乐和 Umano 应用的示例:
https://github.com/umano/AndroidSlidingUpPanel
查看此存储库中的代码。当您向上滑动面板时,ActionBar 也会向上滑动。
来自演示:
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");
);
在此处下载示例:
https://play.google.com/store/apps/details?id=com.sothree.umano
ListView - 没有库:
我最近想要相同的功能,这对我来说非常适合:
当用户向上滚动时,ActionBar 将被隐藏,以便用户可以使用整个屏幕。
当用户向下滚动并松开时,ActionBar 将返回。
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 - 没有库
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;
);
如果您需要更多帮助,请告诉我!
【讨论】:
我喜欢它。它似乎有效,但是当它隐藏时操作栏会出现难看的闪烁:-( 我的两个 androids >4.2 工作时没有闪烁,谢谢 这适用于普通列表视图(列表视图标题 + acrion 栏覆盖)如果我的列表视图在带有 pagerrabstips 的 viewpager 片段中怎么办?我想我需要像标题视图这样的东西,但对于 viewpager。有什么建议吗? @SammyT 这些标签已弃用。 @JaredBurrows 谢谢,它已经工作了。错误是我仍在使用以前版本的 recyclerview.jar(我仍在使用 Eclipse)。 jar 需要是最新版本 (v22)。【参考方案2】:您会体验到闪烁,因为通过隐藏/显示 ActionBar 来更改内容布局的可用空间,这会导致重新布局。这样,第一个可见项目的位置索引也会发生变化(您可以通过注销 mLastFirstVisibleItem 和 currentFirstVisibleItem 来验证这一点。
您可以通过让 ActionBar 覆盖您的内容布局来应对闪烁。要为操作栏启用覆盖模式,您需要创建一个扩展现有操作栏主题的自定义主题,并将 android:windowActionBarOverlay 属性设置为 true。
这样您可以消除闪烁,但操作栏会覆盖您的列表视图的内容。一个简单的解决方案是将列表视图(或根布局)的顶部填充设置为操作栏的高度。
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/list"
android:layout_
android:layout_
android:paddingTop="?android:attr/actionBarSize" />
不幸的是,这会导致顶部有一个恒定的填充。此解决方案的一个改进是在列表视图中添加一个标题视图,其高度为 ?android:attr/actionBarSize (并删除之前设置的顶部填充)
【讨论】:
如果您使用 ActionBarSherlock 或 AppCompat,请使用 android:paddingTop="?attr/actionBarSize" 我在我的 GridView 中使用了您的“改进”。我分叉并修复了一个小库。你可以在这里找到它:github.com/alter-ego/GridViewHeader【参考方案3】:您要查找的内容称为Quick Return pattern,应用于操作栏。 Google IO 2014 app 就是这样使用的。我在我的一个应用程序中使用它,您可以查看该 Google 应用程序的 source code 以了解他们是如何获得它的。 BaseActivity 类是您拥有所需内容、阅读代码并仅提取特定功能的地方。享受编码! :)
【讨论】:
但是如何使用 webview 滚动呢? @PiyushKukadiya 实现几乎相同,只需为 Webview 定义一个滚动监听器,这里有一个完整的示例:***.com/questions/14752523/… 我这样做了,但是现在我无法在隐藏操作栏时使布局变大,如何使布局也平滑地适应操作栏的空间【参考方案4】:我确信这不是最好的解决方案。但是我还没有找到更好的。希望对您有所帮助。
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;
);
【讨论】:
即使我达到了相同的解决方案,但无法避免闪烁。是否能够消除由显示/隐藏引起的闪烁? 我的上一个版本是: if (dy > 40) scroll_down = true; else if (dy 当我们慢慢滚动时,有没有人消除这种闪烁效果? 只是动画它的平滑度【参考方案5】:我认为这是个好主意。
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;
【讨论】:
【参考方案6】:我认为它会很好用.....
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;
);
【讨论】:
【参考方案7】:如果您使用的是 CoordinatorLayout,这里有诀窍。
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_
android:layout_
android:background="?attr/colorPrimary"
app:layout_scrollFlags="scroll|enterAlways" />
app:layout_scrollFlags="scroll|enterAlways"
行将导致我们的工具栏在用户向下滚动列表时滚动到屏幕之外,而一旦他开始向上滚动,工具栏就会再次出现。
【讨论】:
以上是关于在 RecyclerView/ListView onScroll 上隐藏 ActionBar的主要内容,如果未能解决你的问题,请参考以下文章
在 RecyclerView/ListView onScroll 上隐藏 ActionBar