添付のサンプルコードに示すように、recyclerviewを使用して折りたたみツールバーレイアウトを実装しました。私の問題は、リストを下にフリングすると、リストが一番上に表示されないことです。
何が起こるかというと、AppBarLayoutが終了するはずのポイントでスクロールが停止します。
私が望む効果は、リストを下に投げることです。リストは一番上まで行き、AppBarLayoutを表示/展開します
私のminSdkは14です。どんな助けや提案も大歓迎です。
<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.AppBarLayout>
<Android.support.design.widget.CollapsingToolbarLayout
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<LinearLayout
app:layout_collapseMode="parallax">
//some elements
</LinearLayout>
</Android.support.design.widget.CollapsingToolbarLayout>
</Android.support.design.widget.AppBarLayout>
<Android.support.v7.widget.RecyclerView
app:layout_behavior="@string/appbar_scrolling_view_behavior"/> //value Android.support.design.widget.AppBarLayout$ScrollingViewBehavior
<Android.support.v7.widget.Toolbar
app:popupTheme="@style/AppTheme.PopupOverlay"
app:layout_collapseMode="parallax" />
setExpanded()
メソッドを使用して、アプリバーを完全に展開または折りたたむことができます。 1つの実装では、Activity
クラスのdispatchTouchEvent()
をオーバーライドし、中間点を超えて折りたたまれているかどうかに基づいてアプリバーを自動折りたたみ/展開します。
_@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_UP) {
float per = Math.abs(mAppBarLayout.getY()) / mAppBarLayout.getTotalScrollRange();
boolean setExpanded = (per <= 0.5F);
mAppBarLayout.setExpanded(setExpanded, true);
}
return super.dispatchTouchEvent(event);
}
_
フリングの最後の位置に自動的にスクロールすることに関して、GitHubにいくつかのコードを配置しました。これは、 特定の場所にプログラムでスムーズにスクロールする 方法を示しています。たとえば、fling
でlist.size() - 1
にスクロールを呼び出すと、動作を複製できます。ちなみに、このコードの一部は StylingAndroid および Novoda ブログから採用されています。
_public class RecyclerLayoutManager extends LinearLayoutManager {
private AppBarManager mAppBarManager;
private int visibleHeightForRecyclerView;
public RecyclerLayoutManager(Context context) {
super(context);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
View firstVisibleChild = recyclerView.getChildAt(0);
final int childHeight = firstVisibleChild.getHeight();
int distanceInPixels = ((findFirstVisibleItemPosition() - position) * childHeight);
if (distanceInPixels == 0) {
distanceInPixels = (int) Math.abs(firstVisibleChild.getY());
}
//Called Once
if (visibleHeightForRecyclerView == 0) {
visibleHeightForRecyclerView = mAppBarManager.getVisibleHeightForRecyclerViewInPx();
}
//Subtract one as adapter position 0 based
final int visibleChildCount = visibleHeightForRecyclerView/childHeight - 1;
if (position <= visibleChildCount) {
//Scroll to the very top and expand the app bar
position = 0;
mAppBarManager.expandAppBar();
} else {
mAppBarManager.collapseAppBar();
}
SmoothScroller smoothScroller = new SmoothScroller(recyclerView.getContext(), Math.abs(distanceInPixels), 1000);
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
public void setAppBarManager(AppBarManager appBarManager) {
mAppBarManager = appBarManager;
}
private class SmoothScroller extends LinearSmoothScroller {
private static final int TARGET_SEEK_SCROLL_DISTANCE_PX = 10000;
private final float distanceInPixels;
private final float duration;
public SmoothScroller(Context context, int distanceInPixels, int duration) {
super(context);
this.distanceInPixels = distanceInPixels;
float millisecondsPerPx = calculateSpeedPerPixel(context.getResources().getDisplayMetrics());
this.duration = distanceInPixels < TARGET_SEEK_SCROLL_DISTANCE_PX ?
(int) (Math.abs(distanceInPixels) * millisecondsPerPx) : duration;
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return RecyclerLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
@Override
protected int calculateTimeForScrolling(int dx) {
float proportion = (float) dx / distanceInPixels;
return (int) (duration * proportion);
}
}
}
_
編集:
上記のコードスニペットのAppBarManager
は、interface
のAppBarLayout
と通信するために使用されるActivity
を指します。アプリバーの折りたたみ/展開メソッドは、アニメーションを使用してまさにそれを行います。最後の方法は、画面に表示されるRecyclerView
行の数を計算するために使用されます。
_public interface AppBarManager {
void collapseAppBar();
void expandAppBar();
int getVisibleHeightForRecyclerViewInPx();
}
_
_public class MainActivity extends AppCompatActivity implements AppBarManager{
@Override
public void collapseAppBar() {
mAppBarLayout.setExpanded(false, true);
}
@Override
public void expandAppBar() {
mAppBarLayout.setExpanded(true, true);
}
@Override
public int getVisibleHeightForRecyclerViewInPx() {
if (mRecyclerFragment == null) mRecyclerFragment =
(RecyclerFragment) getSupportFragmentManager().findFragmentByTag(RecyclerFragment.TAG);
int windowHeight, appBarHeight, headerViewHeight;
windowHeight = getWindow().getDecorView().getHeight();
appBarHeight = mAppBarLayout.getHeight();
headerViewHeight = mRecyclerFragment.getHeaderView().getHeight();
return windowHeight - (appBarHeight + headerViewHeight);
}
_
同様の問題が発生し、RecyclerViewが上に移動するときにAppBarLayoutを展開するための簡単なトリックを使用しました(サポートライブラリ> = 23.x.xが必要です)
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
int firstVisiblePosition = linearLayoutManager.findFirstCompletelyVisibleItemPosition();
if (firstVisiblePosition == 0) {
mAppBarLayout.setExpanded(true, true);
}
}
}
});