滚动时Android工具栏的高程

我尝试在google maps android app中实现一个搜索栏:

在此处输入图像描述

当回收者视图处于其初始状态时,工具栏没有高程。 只有当用户开始滚动时,高程才会变得可见。 搜索栏(工具栏)永远不会崩溃。 这是我试图复制的内容:

        

在这里你可以看到结果:

在此处输入图像描述

所以我的解决方案的问题是,工具栏的高程始终可见。 但我希望它只在回收者视图滚动后面才会出现。 设计支持库中有什么能够实现谷歌地图应用程序中的行为吗?

我在用

 com.android.support:appcompat-v7:23.2.0 com.android.support:design:23.2.0 

无论您是否使用CoordinatorLayoutRecyclerView.OnScrollListener似乎都是正确的方法。 但是,根据我的经验, recyclerview.getChild(0).getTop()不可靠, 应该用于确定滚动状态。 相反,这是有效的:

 private static final int SCROLL_DIRECTION_UP = -1; // ... // Put this into your RecyclerView.OnScrollListener > onScrolled() method if (recyclerview.canScrollVertically(SCROLL_DIRECTION_UP) { // Remove elevation } else { // Show elevation } 

确保将LayoutManager分配给RecyclerView或者调用canScrollVertically可能会导致崩溃!

我的片段中有一个RecyclerView。 我可以使用下面的代码实现类似的效果:

这不是最聪明的方式,你可以等待更好的答案。

 @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Initial Elevation final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar); if(toolbar!= null) toolbar.setElevation(0); // get initial position final int initialTopPosition = mRecyclerView.getTop(); // Set a listener to scroll view mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if(toolbar!= null && mRecyclerView.getChildAt(0).getTop() < initialTopPosition ) { toolbar.setElevation(50); } else { toolbar.setElevation(0); } } }); } 

当我想要做类似的事情时,我在页面上find了这个,但对于更复杂的View Hierarchy。

经过一些研究,我能够使用自定义行为获得相同的效果。 这适用于协调器布局中的任何视图(假设有嵌套的滚动元素,例如RecyclerView或NestedScrollView)

注意:这仅适用于API 21及更高版本,因为ViewCompat.setElevation似乎没有任何效果前棒棒糖和AppBarLayout#setTargetElevation已弃用

ShadowScrollBehavior.java

 public class ShadowScrollBehavior extends AppBarLayout.ScrollingViewBehavior implements View.OnLayoutChangeListener { int totalDy = 0; boolean isElevated; View child; public ShadowScrollBehavior(Context context, AttributeSet attrs) { super(context, attrs); } @Override public boolean layoutDependsOn(CoordinatorLayout parent, View child, View dependency) { parent.addOnLayoutChangeListener(this); this.child = child; return super.layoutDependsOn(parent, child, dependency); } @Override public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View directTargetChild, @NonNull View target, int axes, int type) { // Ensure we react to vertical scrolling return axes == ViewCompat.SCROLL_AXIS_VERTICAL || super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, axes, type); } @Override public void onNestedPreScroll(@NonNull CoordinatorLayout coordinatorLayout, @NonNull View child, @NonNull View target, int dx, int dy, @NonNull int[] consumed, int type) { totalDy += dy; if (totalDy < = 0) { if (isElevated) { ViewGroup parent = (ViewGroup) child.getParent(); if (parent != null) { TransitionManager.beginDelayedTransition(parent); ViewCompat.setElevation(child, 0); } } totalDy = 0; isElevated = false; } else { if (!isElevated) { ViewGroup parent = (ViewGroup) child.getParent(); if (parent != null) { TransitionManager.beginDelayedTransition(parent); ViewCompat.setElevation(child, dp2px(child.getContext(), 4)); } } if (totalDy > target.getBottom()) totalDy = target.getBottom(); isElevated = true; } super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type); } private float dp2px(Context context, int dp) { Resources r = context.getResources(); float px = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, r.getDisplayMetrics()); return px; } @Override public void onLayoutChange(View view, int i, int i1, int i2, int i3, int i4, int i5, int i6, int i7) { totalDy = 0; isElevated = false; ViewCompat.setElevation(child, 0); } } 

my_activity_layout.xml