安卓棒棒糖工具栏:如何在滚动时隐藏/显示工具栏?

54

我正在使用引入到appcompat / support-v7中的新工具栏小部件。 我想根据用户向上/向下滚动页面来隐藏/显示工具栏,就像在新的Google Play商店应用程序或NewsStand应用程序中一样。 工具栏小部件内置了这个功能吗?还是我应该将其与FrameLayout和ObservableScrollView结合使用?


我的回答有帮到您吗?如果有的话,请接受它,或者问一下还缺少什么。 - Kuno
还没有尝试过。一定会回来尝试的。同时也期待其他人的想法。 - nomongo
你好,nomongo,你找到解决这个问题的方法了吗? - Adelino
12个回答

80
据我所知,没有内置的工具可以为您完成这项任务。不过,您可以查看Google IO源代码,特别是BaseActivity。搜索“auto hide”或查看onMainContentScrolled
要隐藏Toolbar,只需像这样做:
toolbar.animate().translationY(-toolbar.getBottom()).setInterpolator(new AccelerateInterpolator()).start();

如果您想再次显示它,您需要调用:

toolbar.animate().translationY(0).setInterpolator(new DecelerateInterpolator()).start();

1
在 onCreate 中,您的工具栏尚未布局。这就是为什么 getBottom 返回 0,因此没有距离可以进行动画处理。将 OnGlobalLayoutListener 添加到工具栏的 ViewTreeObserver 中,并在回调中启动动画。不要忘记在之后删除 OnGlobalLayoutListener。 - Kuno
我不熟悉OnGlobalLayoutListener。你能给我一些代码吗? - AruLNadhaN
1
如果我没记错的话,它需要API 12。为了与较低的API级别兼容,请使用http://nineoldandroids.com/。 - Kuno
展示动画的代码如下:private void showToolBar() { mToolBar.animate().translationY(0) .setInterpolator(new DecelerateInterpolator()).start(); } - Shajeel Afzal
你希望工具栏何时隐藏/显示?几乎可以肯定,dispatchTouchEvent 不是做这个的正确位置。 - Kuno
显示剩余5条评论

42

你可以通过以下方式隐藏工具栏:

getSupportActionBar().hide();

所以你只需要添加滚动监听器,当用户滚动时隐藏工具栏!


好的解决方案,但仍未提供动画。这很奇怪,因为其他 Material Design 基础视图(如 FAB)在显示/隐藏时都会提供动画。 - Lampione

27

隐藏:

getSupportActionBar().hide();

展示:

getSupportActionBar().show();

16
答案很简单。只需实现OnScrollListener并在监听器中隐藏/显示工具栏即可。例如,如果您有listview/recyclerview/gridview,则可以按照示例操作。
在您的MainActivity Oncreate方法中,初始化工具栏。
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        toolbar = (Toolbar) findViewById(R.id.toolbar);
        if (toolbar != null) {
            setSupportActionBar(toolbar);
            getSupportActionBar().setDisplayShowHomeEnabled(true);
        }
}

然后实现OnScrollListener

public RecyclerView.OnScrollListener onScrollListener = new RecyclerView.OnScrollListener() {
        boolean hideToolBar = false;
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (hideToolBar) {
                ((ActionBarActivity)getActivity()).getSupportActionBar().hide();
            } else {
                ((ActionBarActivity)getActivity()).getSupportActionBar().show();
            }
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            if (dy > 20) {
                hideToolBar = true;

            } else if (dy < -5) {
                hideToolBar = false;
            }
        }
    };

我从这里得到了灵感:https://dev59.com/P2Yr5IYBdhLWcg3wl7LF#27063901


也加上动画部分,这将是一个非常完美的答案。 - Jaydev

8

感谢您指出“inthecheesefactory”网站!这是一个非常棒的网站,提供了有用的信息! - Filipe Brito

2

实际上,有很多种方法可以在滚动内容时隐藏/显示工具栏。其中一种方法是通过Android Design Support Library或更具体地通过协调布局(也称为超级帧布局)完成。

基本上,您只需要在布局文件中拥有以下结构,就可以实现所需的结果。

<CoordinatorLayout>
   <AppBarLayout>
   </AppBarLayout>
   <NestedScrollView>
   </NestedScrollView>
</CoordinatorLayout>

我已经制作了一段视频,以逐步的方式解释了如何完成。请随意观看,并告诉我是否有所帮助。谢谢! :) https://youtu.be/mEGEVeZK7Nw

2

只需在工具栏中添加此属性,就可以完成操作。

app:layout_scrollFlags="scroll|enterAlways"

这不是很棒吗?


很棒,但对我没用,这段代码自动隐藏了工具栏和选项卡布局。 - AbolfazlSalmani

1
隐藏特定片段的菜单: ```html

要隐藏特定片段的菜单:

```
 setHasOptionsMenu(true); //Inside of onCreate in FRAGMENT:  


   @Override
   public void onPrepareOptionsMenu(Menu menu) {
       menu.findItem(R.id.action_search).setVisible(false);
   }

1

我一直在尝试实现相同的行为,这里是展示和隐藏工具栏的主要代码(放在包含RecyclerView的任何类中):

int toolbarMarginOffset = 0

private int dp(int inPixels){
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, inPixels, getApplicationContext().getResources().getDisplayMetrics());
}

public RecyclerView.OnScrollListener onScrollListenerToolbarHide = new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        toolbarMarginOffset += dy;
        if(toolbarMarginOffset>dp(48)){
            toolbarMarginOffset = dp(48);
        }
        if(toolbarMarginOffset<0){
            toolbarMarginOffset = 0;
        }
        ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)toolbar.getLayoutParams();
        params.topMargin = -1*toolbarMarginOffset; 
        toolbar.setLayoutParams(params);
    }
};

我已包含 dp 函数以将像素转换为 dp,但显然需要将其设置为您的工具栏高度。(用您的工具栏高度替换 dp(48))

在您设置 RecyclerView 的任何地方,包含以下内容:

yourListView.setOnScrollListener(onScrollListenerToolbarHide);

然而,如果您还使用SwipeRefreshLayout,则会出现一些额外的问题。

我不得不将RecyclerView适配器中的第一个元素的marginTop设置为Toolbar的高度加上原始偏移量。(我知道这有点像hack)。这样做的原因是我发现,如果我改变了上述代码以包括在滚动时更改recyclerView的marginTop,那么用户体验就会很差。所以这就是我克服它的方法。因此,基本上设置布局,使得工具栏浮动在RecyclerView的顶部(将其剪切)。类似于这样(在自定义RecyclerView适配器的onBindViewHolder中):

 if(position==0){
     ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams)holder.card.getLayoutParams();
     // params.height = ViewGroup.LayoutParams.WRAP_CONTENT;
     params.topMargin = dp(10+48);
 }

最后,由于存在较大的偏移量,RecyclerView的刷新圆将被剪裁,因此您需要对其进行偏移(回到包含RecyclerView的类的onCreate中):
swipeLayout.setProgressViewOffset(true,dp(48),dp(96));

我希望这能对某些人有所帮助。这是我第一次详细回答,希望我的解答足够详细。


1
当您缓慢滚动时,它会导致屏幕闪烁,看起来不好。 - Golan Shay

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接