web-dev-qa-db-ja.com

recyclerviewが上にスクロール/フリングされたときにappbarlayoutを展開します

添付のサンプルコードに示すように、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" />
11
momoja

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にいくつかのコードを配置しました。これは、 特定の場所にプログラムでスムーズにスクロールする 方法を示しています。たとえば、flinglist.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は、interfaceAppBarLayoutと通信するために使用されるActivityを指します。アプリバーの折りたたみ/展開メソッドは、アニメーションを使用してまさにそれを行います。最後の方法は、画面に表示されるRecyclerView行の数を計算するために使用されます。

AppBarManager.Java

_public interface AppBarManager {

    void collapseAppBar();
    void expandAppBar();
    int getVisibleHeightForRecyclerViewInPx();

}
_

MainActivity.Java

_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);
}
_
9
PPartisan

同様の問題が発生し、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);
                    }
                }
            }
});
12
kazhiu