package com.luorrak.ouroboros.thread; import android.content.Context; import android.support.v7.widget.RecyclerView; import android.util.AttributeSet; import android.view.MotionEvent; /** * Ouroboros - An 8chan browser * Copyright (C) 2015 Luorrak * <p/> * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * <p/> * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * <p/> * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ public final class SnappyRecyclerView extends RecyclerView { public SnappyRecyclerView(Context context) { super(context); } public SnappyRecyclerView(Context context, AttributeSet attrs) { super(context, attrs); } public SnappyRecyclerView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean fling(int velocityX, int velocityY) { final LayoutManager lm = getLayoutManager(); if (lm instanceof ISnappyLayoutManager) { super.smoothScrollToPosition(((ISnappyLayoutManager) getLayoutManager()) .getPositionForVelocity(velocityX, velocityY)); return true; } return super.fling(velocityX, velocityY); } @Override public boolean onTouchEvent(MotionEvent e) { // We want the parent to handle all touch events--there's a lot going on there, // and there is no reason to overwrite that functionality--bad things will happen. final boolean ret = super.onTouchEvent(e); final LayoutManager lm = getLayoutManager(); if (lm instanceof ISnappyLayoutManager && (e.getAction() == MotionEvent.ACTION_UP || e.getAction() == MotionEvent.ACTION_CANCEL) && getScrollState() == SCROLL_STATE_IDLE) { // The layout manager is a SnappyLayoutManager, which means that the // children should be snapped to a grid at the end of a drag or // fling. The motion event is either a user lifting their finger or // the cancellation of a motion events, so this is the time to take // over the scrolling to perform our own functionality. // Finally, the scroll state is idle--meaning that the resultant // velocity after the user's gesture was below the threshold, and // no fling was performed, so the view may be in an unaligned state // and will not be flung to a proper state. smoothScrollToPosition(((ISnappyLayoutManager) lm).getFixScrollPos()); } return ret; } /** * An interface that LayoutManagers that should snap to grid should implement. */ public interface ISnappyLayoutManager { /** * @param velocityX * @param velocityY * @return the resultant position from a fling of the given velocity. */ int getPositionForVelocity(int velocityX, int velocityY); /** * @return the position this list must scroll to to fix a state where the * views are not snapped to grid. */ int getFixScrollPos(); } }