Android Design Libraryを使用して、ツールバーとTabLayoutでアプリを作成しました。
実際には2つのタブがあり、どちらにも2つのRecyclerViewがあり、スクロールするとツールバーが自動的に折りたたまれます。
私の質問は次のとおりです。RecyclerViewに項目がほとんどなく、画面に完全に収まった場合(TAB 2のように)、ツールバーの折りたたみを無効にできますか?
CheeseSquare のような多くの例を見てきました。これは、問題がまだ存在するGoogle従業員によって作成されました。RecyclerViewに1つのアイテムしかない場合でも、ツールバーはスクロールを隠し続けます。
私は、RecyclerViewの最初の項目が画面上に表示されているかどうか、そしてもしそうであればツールバーの折りたたみを無効にするかどうかを知ることができると思います。前者は実装が簡単ですが、後者はどうですか?
これは私のレイアウトです:
<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/coordinator_layout"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.design.widget.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:fitsSystemWindows="true"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
app:layout_scrollFlags="scroll|enterAlwaysCollapsed"
Android:background="?attr/colorPrimary"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
<Android.support.design.widget.TabLayout
Android:id="@+id/tab_layout"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="@color/glucosio_pink"
app:tabSelectedTextColor="@Android:color/white"
app:tabIndicatorColor="@color/glucosio_accent"
app:tabTextColor="#80ffffff"/>
</Android.support.design.widget.AppBarLayout>
<Android.support.v4.view.ViewPager
Android:id="@+id/pager"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"/>
<Android.support.design.widget.FloatingActionButton
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:id="@+id/main_fab"
Android:layout_margin="16dp"
Android:onClick="onFabClicked"
app:backgroundTint="@color/glucosio_accent"
Android:src="@drawable/ic_add_black_24dp"
Android:layout_gravity="bottom|right"
/>
</Android.support.design.widget.CoordinatorLayout>
最終ソリューション(MichałZに感謝)
ツールバーのスクロールをオフ/オンにする方法:
public void turnOffToolbarScrolling() {
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar_layout);
//turn off scrolling
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
toolbarLayoutParams.setScrollFlags(0);
mToolbar.setLayoutParams(toolbarLayoutParams);
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(null);
appBarLayout.setLayoutParams(appBarLayoutParams);
}
public void turnOnToolbarScrolling() {
Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar);
AppBarLayout appBarLayout = (AppBarLayout) findViewById(R.id.appbar_layout);
//turn on scrolling
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
toolbarLayoutParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS);
mToolbar.setLayoutParams(toolbarLayoutParams);
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(new AppBarLayout.Behavior());
appBarLayout.setLayoutParams(appBarLayoutParams);
}
RecyclerViewの最後のアイテムがフラグメントに表示されているかどうかを確認します。
はいの場合、スクロールを無効にします。
public void updateToolbarBehaviour(){
if (mLayoutManager.findLastCompletelyVisibleItemPosition() == items.size()-1) {
((MainActivity) getActivity()).turnOffToolbarScrolling();
} else {
((MainActivity)getActivity()).turnOnToolbarScrolling();
}
}
RecyclerView
が(バージョン23.2以降)wrap_content
をサポートするようになりました。高さとしてwrap_content
を使用するだけです。
RecyclerView
の最後のアイテムが表示されているかどうかを確認できます。そうでない場合は、このメソッドを使用してプログラムでスクロールをオフにします。
//turn off scrolling
AppBarLayout.LayoutParams toolbarLayoutParams = (AppBarLayout.LayoutParams) mToolbar.getLayoutParams();
toolbarLayoutParams.setScrollFlags(0);
mToolbar.setLayoutParams(toolbarLayoutParams);
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(null);
appBarLayout.setLayoutParams(appBarLayoutParams);
私はこれを解決するためにわずかに異なるアプローチを取りました。
セルに基づいて自己を無効にするカスタムAppBarBehaviorを作成しました。
public class CustomAppBarBehavior extends AppBarLayout.Behavior {
private RecyclerView recyclerView;
private boolean enabled;
public CustomAppBarBehavior() {
}
public CustomAppBarBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
updatedEnabled();
return enabled && super.onInterceptTouchEvent(parent, child, ev);
}
@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
return enabled && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
}
@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
return enabled && super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
}
private void updatedEnabled() {
enabled = false;
if(recyclerView != null) {
RecyclerView.Adapter adapter = recyclerView.getAdapter();
if (adapter != null) {
int count = adapter.getItemCount();
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
if (layoutManager != null) {
int lastItem = 0;
if (layoutManager instanceof LinearLayoutManager) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
lastItem = Math.abs(linearLayoutManager.findLastCompletelyVisibleItemPosition());
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
int[] lastItems = staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(new int[staggeredGridLayoutManager.getSpanCount()]);
lastItem = Math.abs(lastItems[lastItems.length - 1]);
}
enabled = lastItem < count - 1;
}
}
}
}
public void setRecyclerView(RecyclerView recyclerView) {
this.recyclerView = recyclerView;
}
}
次に、アプリバーレイアウトでカスタム動作を設定します
appBarBehavior = new CustomAppBarBehavior();
CoordinatorLayout.LayoutParams appBarLayoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
appBarLayoutParams.setBehavior(appBarBehavior);
appBarLayout.setLayoutParams(appBarLayoutParams);
ビューページャーの最終ページの変更により、動作のRecyclerViewが更新されました
private ViewPager.OnPageChangeListener pageChangeListener = new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { }
@Override
public void onPageSelected(final int position) {
appBarLayout.setExpanded(true, true);
appBarLayout.post(new Runnable() {
@Override
public void run() {
appBarBehavior.setRecyclerView(childFragments.get(position).getRecyclerView());
}
});
}
@Override
public void onPageScrollStateChanged(int state) { }
};
これは、データセットの変更で機能するはずです。
アダプターのデータを変更した後、このコードを追加します。
recyclerView.afterMeasured {
val isTurnedOff = recyclerView.turnOffNestedScrollingIfEnoughItems()
if (isTurnedOff) appBarLayout.setExpanded(true)
}
そして、これは機能です:
inline fun <T: View> T.afterMeasured(crossinline action: T.() -> Unit) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
viewTreeObserver.removeOnGlobalLayoutListener(this)
action()
}
})
}
fun RecyclerView.turnOffNestedScrollingIfEnoughItems(): Boolean {
val lm = (layoutManager as LinearLayoutManager)
val count = if (lm.itemCount <= 0) 0 else lm.itemCount - 1
val isFirstVisible = lm.findFirstCompletelyVisibleItemPosition() == 0
val isLastItemVisible = lm.findLastCompletelyVisibleItemPosition() == count
isNestedScrollingEnabled = !(isLastItemVisible && isFirstVisible)
return isNestedScrollingEnabled.not()
}