私はグーグルマップのように検索バーを実装しようとしますAndroid app:
リサイクラービューが初期状態の場合、ツールバーには標高がありません。ユーザーがスクロールを開始したときのみ、高度が表示されます。また、検索バー(ツールバー)は折りたたまれません。これが私がこれを複製しようとしたものです:
<Android.support.design.widget.CoordinatorLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true">
<Android.support.v7.widget.RecyclerView
Android:id="@+id/recyclerView"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
<Android.support.design.widget.AppBarLayout
Android:id="@+id/appBarLayout"
Android:layout_width="match_parent"
Android:layout_height="wrap_content">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="64dp">
<!-- content -->
</Android.support.v7.widget.Toolbar>
</Android.support.design.widget.AppBarLayout>
</Android.support.design.widget.CoordinatorLayout>
そしてここで結果を見ることができます:
だから私の解決策の問題は、ツールバーの高さが常に見えることです。ただし、リサイクラービューがその後ろにスクロールしたときにのみ表示されるようにします。 Googleマップアプリで見られるような動作を可能にする設計サポートライブラリから何かありますか?
使ってます
com.Android.support:appcompat-v7:23.2.0
com.Android.support:design:23.2.0
CoordinatorLayout
を使用しているかどうかにかかわらず、_RecyclerView.OnScrollListener
_は標高に関する限り、正しい方法のように見えます。ただし、私の経験から、recyclerview.getChild(0).getTop()
は信頼性が低く、スクロール状態の判別にはnotを使用する必要があります。代わりに、これが機能しています:
_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を呼び出すとクラッシュする可能性があります。
これは良い質問ですが、既存の答えはどれも十分に良いものではありません。 getTop()
の呼び出しは信頼性が非常に低いため、絶対にお勧めしません。マテリアルデザインの更新(2018)ガイドラインに準拠した新しいバージョンのGoogleアプリを見ると、最初は標高が非表示になり、ユーザーが下にスクロールするとすぐに標高が追加され、ユーザーがスクロールして再び上に到達すると再び非表示になります。
私は以下を使用して同じ効果を達成することができました:
val toolbar: Android.support.v7.widget.Toolbar? = activity?.findViewById(R.id.toolbar);
recyclerView?.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy);
if(toolbar == null) {
return;
}
if(!recyclerView.canScrollVertically(-1)) {
// we have reached the top of the list
toolbar.elevation = 0f
} else {
// we are not at the top yet
toolbar.elevation = 50f
}
}
});
これは、垂直のリサイクラービューで完全に機能します(タブビューや他のリサイクラービューでも)。
いくつかの重要な注意事項:
activity?.findViewById...
Android:elevation="0dp"
およびapp:elevation="0dp"
属性をToolbarまたはAppBarLayoutに追加して、リサイクラービューの最初に標高がないようにします。これは、同じようなことをしたいときにページを見つけましたが、より複雑なビュー階層でした。
調査の結果、カスタムビヘイビアを使用して同じ効果を得ることができました。これは、コーディネーターレイアウトの任意のビューで機能します(RecyclerViewやNestedScrollViewなどのネストされたスクロール要素がある場合)
注:これはAPI 21以上でのみ機能します。ViewCompat.setElevationはLollipop以前に効果がないようで、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
<Android.support.design.widget.CoordinatorLayout
Android:fitsSystemWindows="true"
Android:layout_height="match_parent"
Android:layout_width="match_parent">
<Android.support.v7.widget.RecyclerView
Android:id="@+id/recyclerView"
Android:layout_height="match_parent"
Android:layout_width="match_parent" />
<Android.support.design.widget.AppBarLayout
Android:id="@+id/appBarLayout"
Android:layout_height="wrap_content"
Android:layout_width="match_parent"
app:layout_behavior="com.myapp.ShadowScrollBehavior">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_height="64dp"
Android:layout_width="match_parent">
<!-- content -->
</Android.support.v7.widget.Toolbar>
</Android.support.design.widget.AppBarLayout>
</Android.support.design.widget.CoordinatorLayout>
フラグメントに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);
}
}
});
}