Skip to content

Instantly share code, notes, and snippets.

@oianmol
Created November 12, 2015 11:40
Show Gist options
  • Save oianmol/cb6849c94f11a3a4e749 to your computer and use it in GitHub Desktop.
Save oianmol/cb6849c94f11a3a4e749 to your computer and use it in GitHub Desktop.
import android.content.Context;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.RecyclerView.OnScrollListener;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.ListView;
import android.widget.TextView;
public class CircleListView extends RecyclerView {
private static final String TAG = CircleListView.class.getSimpleName();
private static final boolean DEBUG = BuildConfig.DEBUG && false;
private static final int DEFAULT_SCROLL_DURATION = 200;
public static final int DEFAULT_SELECTION = Integer.MAX_VALUE / 2;
private boolean mIsForceCentering;
private ViewModifier mViewModifier;
private final CenterRunnable mCenterRunnable = new CenterRunnable();
private int mScrollDuration = DEFAULT_SCROLL_DURATION;
private OnItemCenteredListener mOnItemCenteredListener;
public CircleListView(Context context, AttributeSet attrs) {
super(context, attrs);
setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
if (!mIsForceCentering) {
// Start centering the view
mIsForceCentering = true;
final View childView = findViewAtCenter();
if (childView != null) {
if (DEBUG) {
}
if (mOnItemCenteredListener != null) {
mOnItemCenteredListener.onItemCentered(childView);
}
mCenterRunnable.setView(childView);
ViewCompat.postOnAnimation(CircleListView.this, mCenterRunnable);
}
}
}
}
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (mViewModifier != null) {
final int count = getChildCount();
for (int i = 0; i < count; ++i) {
View v = getChildAt(i);
mViewModifier.applyToView(v, CircleListView.this);
}
}
}
});
setOverScrollMode(RecyclerView.OVER_SCROLL_NEVER);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
this.smoothScrollToPosition(DEFAULT_SELECTION);
}
/**
* Sets the current {@link ViewModifier} for this list.
*
* @param modifier implementation of the {@link ViewModifier} class
* @see ViewModifier
*/
public void setViewModifier(ViewModifier modifier) {
mViewModifier = modifier;
}
/**
* Sets the smooth scroll duration.
*
* @param duration the number of milliseconds the scrolling animation will take
*/
public void setScrollDuration(int duration) {
mScrollDuration = duration;
}
/**
* Sets the listener object that will be notified when the list centers on an item.
*
* @param listener the {@link OnItemCenteredListener} implementation
*/
public void setOnItemCenteredListener(OnItemCenteredListener listener) {
mOnItemCenteredListener = listener;
}
public void smoothScrollToView(View v) {
final float y = v.getY() + v.getHeight() * 0.5f;
final float halfHeight = getHeight() * 0.5f;
final int distance = (int) (y - halfHeight);
smoothScrollBy(distance, mScrollDuration);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
removeCallbacks(mCenterRunnable);
mIsForceCentering = false;
return super.onTouchEvent(ev);
}
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
}
/**
* Finds a View located at the specified point.
*
* @param x x-coordinate of the point
* @param y y-coordinate of the point
* @return {@link View} located at (x, y) or <code>null</code> if not found
*/
public View findViewAt(int x, int y) {
final int count = getChildCount();
for (int i = 0; i < count; ++i) {
final View v = getChildAt(i);
final int x0 = v.getLeft();
final int y0 = v.getTop();
final int x1 = v.getWidth() - x0;
final int y1 = v.getHeight() + y0;
if (x >= x0 && x <= x1 && y >= y0 && y <= y1) {
return v;
}
}
return null;
}
/**
* Finds a {@link View} located in the center of the {@link CircleListView}.
*
* @return the {@link View} at the center of the {@link CircleListView}
*/
public View findViewAtCenter() {
return findViewAt(0, getHeight() / 2);
}
public class CenterRunnable implements Runnable {
private View mView;
public void setView(View v) {
mView = v;
}
public void run() {
smoothScrollToView(mView);
mIsForceCentering = true;
}
}
/**
* Handles the event occurring when the list centers on an item.
*
* @see CircleListView#setOnItemCenteredListener(OnItemCenteredListener)
*/
public interface OnItemCenteredListener {
public void onItemCentered(View v);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment