how to achieve on androidTV scrolling mechanism like Netflix with RecyclerView

Viewed 174

I am trying to achieve horizontal scroll mechanism on AndroidTV like Netflix I tried to use SnapHelper without success and also override LinearLayoutManager smoothScroll it looks nice but is not perfect and also bit lag. When I am perform long press, the movement doesn't smoothie and sometimes its stuck. I am receiving focus callback from the next item while I am tapping left or right on the controller and then using recyclerview.smoothScroolToPostion. anyone can help me with that?

    recyclerView.setAdapter(new MyAdapter(new FocusListener() {

        @Override
        public void dispatchFocusChanged(View view, boolean gainFocus) {
            if(gainFocus) {
                    int position = recyclerView.getChildAdapterPosition(view);
                    recyclerView.smoothScrollToPosition(position);
            }
        }
    }));

LinearLayoutManager

@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
    LinearSmoothScroller smoothScroller =
            new LinearSmoothScroller(recyclerView.getContext()) {

                //This returns the milliseconds it takes to
                //scroll one pixel.
                @Override
                protected float calculateSpeedPerPixel
                (DisplayMetrics displayMetrics) {
                    return 500f/displayMetrics.densityDpi;
                }

                @Override
                protected int getHorizontalSnapPreference() {
                    return SNAP_TO_END;
                }

                @Override
                protected int calculateTimeForDeceleration(int dx) {
                    return (int) Math.ceil(calculateTimeForScrolling(dx) / .3356);
                }

                @Override
                protected int calculateTimeForScrolling(int dx) {
                    return 200;//super.calculateTimeForScrolling(dx);
                }

            };

    smoothScroller.setTargetPosition(position);
    startSmoothScroll(smoothScroller);
}

SnapHelper

public class Snap extends LinearSnapHelper {

private Context context;
private OrientationHelper orientationHelper;
private Scroller scroller;
private int maxScrollDistance = 0;

private final static int MAX_SCROLL_ON_FLING_DURATION_MS = 1000;

@Override
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException {
    if (recyclerView != null) {
        context = recyclerView.getContext();
        scroller = new Scroller(context, new DecelerateInterpolator());
    } else {
        scroller = null;
        context = null;
    }
    super.attachToRecyclerView(recyclerView);
}

@Override
public View findSnapView(RecyclerView.LayoutManager layoutManager) {
    return findFirstView(layoutManager, getHelper(layoutManager));
}

public View findFirstView(RecyclerView.LayoutManager layoutManager, OrientationHelper orientationHelper) {

    if (layoutManager == null) return null;

    int childCount = layoutManager.getChildCount();
    if (childCount == 0) return null;

    int absClosest = Integer.MAX_VALUE;
    View closestView = null;
    int start = orientationHelper.getStartAfterPadding();

    for (int i = 0; i < childCount; i++) {
        View child = layoutManager.getChildAt(i);
        int childStart = orientationHelper.getDecoratedStart(child);
        int absDistanceToStart = Math.abs(childStart - start);
        if (absDistanceToStart < absClosest) {
            absClosest = absDistanceToStart;
            closestView = child;
        }
    }
    return closestView;
}

private OrientationHelper getHelper(RecyclerView.LayoutManager layoutManager) {
    if (orientationHelper == null) {
        orientationHelper = OrientationHelper.createHorizontalHelper(layoutManager);
    }
    return orientationHelper;
}

@Override
public int[] calculateDistanceToFinalSnap(RecyclerView.LayoutManager layoutManager, View targetView) {
    int[] out = new int[2];
    out[0] = distanceToStart(targetView, getHelper(layoutManager));
    return out;
}

@Override
public int[] calculateScrollDistance(int velocityX, int velocityY) {
    int[] out = new int[2];
    OrientationHelper helper = orientationHelper;
    if (null == helper)
        return out;

    if (maxScrollDistance == 0) {
        maxScrollDistance = (helper.getEndAfterPadding() - helper.getStartAfterPadding()) / 2;
    }

    scroller.fling(0, 0, velocityX, velocityY, -maxScrollDistance, maxScrollDistance, 0, 0);
    out[0] = scroller.getFinalX();
    out[1] = scroller.getFinalY();
    return out;
}

private int distanceToStart(View targetView, OrientationHelper helper) {

    int childStart = helper.getDecoratedStart(targetView) + convertDpToPixel(40);
    int containerStart = helper.getStartAfterPadding();
    return 0;//childStart - containerStart;
}

public int convertDpToPixel(float dp) {
    DisplayMetrics metrics = Resources.getSystem().getDisplayMetrics();
    float px = dp * (metrics.densityDpi / 160f);
    return (int) Math.round(px);
}

@Nullable
@Override
protected RecyclerView.SmoothScroller createScroller(final RecyclerView.LayoutManager layoutManager) {
    if (layoutManager instanceof RecyclerView.SmoothScroller.ScrollVectorProvider)
        return super.createScroller(layoutManager);
    Context context = this.context;


    return new LinearSmoothScroller(context) {
        @Override
        protected void onTargetFound(View targetView, RecyclerView.State state, Action action) {
            int[] snapDistance = calculateDistanceToFinalSnap(layoutManager, targetView);
            int dx = snapDistance[0];
            int dy = snapDistance[1];
            int dt = calculateTimeForDeceleration(Math.abs(dx));
            int time = Math.max(1, Math.min(MAX_SCROLL_ON_FLING_DURATION_MS, dt));
            action.update(dx, dy, time, mDecelerateInterpolator);
        }
    };
}}
0 Answers
Related