-
-
Save beersheba/7990c4924334a4f88dc8e1834cca80ad to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.superup.tools.tools.Extensions.RecyclerUtils; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.graphics.Point; | |
import android.graphics.PointF; | |
import android.graphics.Rect; | |
import android.support.v4.view.ViewCompat; | |
import android.support.v7.widget.LinearLayoutManager; | |
import android.support.v7.widget.LinearSmoothScroller; | |
import android.support.v7.widget.RecyclerView; | |
import android.util.AttributeSet; | |
import android.view.Display; | |
import android.view.GestureDetector; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.view.WindowManager; | |
import android.view.animation.DecelerateInterpolator; | |
import java.util.List; | |
import java.util.Vector; | |
import static android.widget.AbsListView.OnScrollListener.SCROLL_STATE_FLING; | |
import static android.widget.AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL; | |
public class SnappingRecyclerView extends RecyclerView { | |
private static final String TAG = "qwe"; | |
private final static int MINIMUM_SCROLL_EVENT_OFFSET_MS = 20; | |
public Vector<ChildFocusListener> ChildFocusListeners = new Vector<>(); | |
private boolean mSnapEnabled = false; | |
private boolean mUserScrolling = false; | |
private boolean mScrolling = false; | |
private int mScrollState; | |
private long lastScrollTime = 0; | |
private boolean mScaleUnfocusedViews = false; | |
private View targetView = null; | |
private float snapScale = 1f; | |
private float minScale = 0.5f; | |
private float spaceBetweenItemsCenter; | |
private float mFlingFactor; | |
private GestureDetector detector; | |
protected float scaleFactor = 1f; | |
private float innerScale = 1f; | |
/** | |
* layout manager to fix the scroll issuse | |
*/ | |
public class SannpingLayoutManager extends LinearLayoutManager { | |
public SannpingLayoutManager(Context context) { | |
super(context); | |
} | |
@Override | |
public boolean supportsPredictiveItemAnimations() { | |
return false; | |
} | |
private static final int DEFAULT_EXTRA_LAYOUT_SPACE = 1200; | |
private int extraLayoutSpace = -1; | |
public void setExtraLayoutSpace(int extraLayoutSpace) { | |
this.extraLayoutSpace = extraLayoutSpace; | |
} | |
@Override | |
protected int getExtraLayoutSpace(RecyclerView.State state) { | |
if (extraLayoutSpace > 0) { | |
return extraLayoutSpace; | |
} | |
return DEFAULT_EXTRA_LAYOUT_SPACE; | |
} | |
@Override | |
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { | |
LinearSmoothScroller linearSmoothScroller = new Scroller(recyclerView.getContext()); | |
linearSmoothScroller.setTargetPosition(position); | |
startSmoothScroll(linearSmoothScroller); | |
} | |
/** | |
* helpful for compute the middle of the product | |
* | |
* @return the offest need to center item | |
*/ | |
private float getCenteredItemOffset(int itemPosition) { | |
float offest = spaceBetweenItemsCenter; //getMeasuredWidth() * 0.5f - ForceWidthRelativeLayout.getScreenWidth(getContext()) * 0.275f; | |
for (int i = 0; i < mItemDecorations.size(); i++) { | |
Rect outRect = new Rect(); | |
mItemDecorations.get(i).getItemOffsets(outRect, itemPosition, SnappingRecyclerView.this); | |
offest -= outRect.left; | |
} | |
return offest; | |
} | |
/** | |
* ********** Inner Classes ********** | |
*/ | |
private class Scroller extends LinearSmoothScroller { | |
public Scroller(Context context) { | |
super(context); | |
} | |
@Override | |
public PointF computeScrollVectorForPosition(int targetPosition) { | |
return SannpingLayoutManager.this.computeScrollVectorForPosition(targetPosition); | |
} | |
@Override | |
public int calculateDxToMakeVisible(View view, int snapPreference) { | |
return super.calculateDxToMakeVisible(view, snapPreference) + (int) getCenteredItemOffset(((LayoutParams) view.getLayoutParams()).getViewLayoutPosition()); | |
} | |
@Override | |
protected int getHorizontalSnapPreference() { | |
return SNAP_TO_START; | |
} | |
} | |
@Override | |
public void scrollToPosition(final int position) { | |
//System.out.println("scrolltoPosition:" + position); | |
// ovveride for fixing scroll to position | |
// | |
super.scrollToPositionWithOffset(position, (int) getCenteredItemOffset(position)); | |
} | |
} | |
private class SpacesItemDecoration extends RecyclerView.ItemDecoration { | |
private int space; | |
public SpacesItemDecoration() { | |
this.space = getScreenWidth(getContext()) / 2; | |
} | |
/** | |
* @deprecated Use {@link #getItemOffsets(Rect, View, RecyclerView, State)} | |
*/ | |
@Override | |
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { | |
// for recycling perpose | |
outRect.left = 0; | |
outRect.right = 0; | |
if (ViewCompat.getLayoutDirection(SnappingRecyclerView.this) == ViewCompat.LAYOUT_DIRECTION_LTR) { | |
if (itemPosition + 1 == parent.getAdapter().getItemCount()) { | |
outRect.right = space; | |
} | |
if (itemPosition == 0) { | |
outRect.left = space; | |
} | |
} else { | |
if (itemPosition + 1 == parent.getAdapter().getItemCount()) { | |
outRect.left = space; | |
} | |
if (itemPosition == 0) { | |
outRect.right = space; | |
} | |
} | |
} | |
} | |
@Override | |
public boolean fling(int velocityX, int velocityY) { | |
if (mFlingFactor > 0) { | |
return super.fling((int) (velocityX * mFlingFactor), velocityY); | |
} | |
return super.fling(velocityX, velocityY); | |
} | |
private List<ItemDecoration> mItemDecorations = new Vector<>(); | |
/** | |
* Vladislav Karpman | |
* <p> | |
* Is appear animation working | |
*/ | |
protected boolean mAppearAnimationIsWorking = false; | |
/** | |
* Duration of each view which will be animated. | |
* By default | |
*/ | |
private long mCenterViewAppearAnimationDuration = 750; | |
private long mLeftToCenterViewAppearAnimationDuration = 1500; | |
private long mRightToCenterViewAppearAnimationDuration = 1500; | |
public SnappingRecyclerView(Context context) { | |
this(context, null); | |
} | |
public SnappingRecyclerView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
setChildrenDrawingOrderEnabled(true); | |
SannpingLayoutManager layoutManager = new SannpingLayoutManager(getContext()); | |
layoutManager.setOrientation(HORIZONTAL); | |
setLayoutManager(layoutManager); | |
detector = new GestureDetector(getContext(), new GestureDetector.SimpleOnGestureListener() { | |
@Override | |
public boolean onSingleTapUp(MotionEvent e) { | |
if (getScrollState() == SCROLL_STATE_IDLE) { | |
View centerView = getCenterView(); | |
if (getChildClosestToPosition((int) e.getX()) == centerView) { | |
int Position = getChildAdapterPosition(centerView); | |
for (ChildFocusListener ChildFocusListener : ChildFocusListeners) | |
ChildFocusListener.onChildSelected( | |
getChildViewHolder(centerView), | |
Position); | |
} | |
} | |
return true; | |
} | |
}); | |
} | |
public float getScaleFactor() { | |
return this.scaleFactor * innerScale; | |
} | |
public void setSnapScale(float snapScale, float minScale, float spaceBetweenItemsCenter) { | |
this.snapScale = snapScale; | |
this.minScale = minScale; | |
this.spaceBetweenItemsCenter = spaceBetweenItemsCenter; | |
} | |
public void addSpaceItemDecoration() { | |
addItemDecoration(new SpacesItemDecoration()); | |
} | |
public NegativeItemDec createNegativeItemDecoration(float scaleX) { | |
return new NegativeItemDec(scaleX, 0f); | |
} | |
public class NegativeItemDec extends ItemDecoration { | |
private int spaceX; | |
private int spaceY; | |
public NegativeItemDec(float scaleX, float scaleY) { | |
this.spaceX = -(int) (scaleX * getScreenWidth(getContext())); | |
} | |
public int getAbsulteX() { | |
return this.spaceX; | |
} | |
public int getAbsulteY() { | |
return this.spaceY; | |
} | |
/* | |
@Override | |
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, | |
RecyclerView.State state) { | |
outRect.bottom = spaceY; | |
outRect.top = spaceY; | |
outRect.left = spaceX; | |
outRect.right = spaceX; | |
}*/ | |
/** | |
* @deprecated Use {@link #getItemOffsets(Rect, View, RecyclerView, State)} | |
*/ | |
@Deprecated | |
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { | |
outRect.bottom = spaceY; | |
outRect.top = spaceY; | |
outRect.left = spaceX; | |
outRect.right = spaceX; | |
} | |
} | |
/** | |
* setting fling factor to control fling effect of recycler view | |
* | |
* @param flingFactor | |
*/ | |
public void setFlingFactor(float flingFactor) { | |
mFlingFactor = flingFactor; | |
} | |
@Override | |
public void setAdapter(final Adapter adapter) { | |
setAdapter(adapter, true); | |
} | |
public void setAdapter(final Adapter adapter, boolean animateApprenece) { | |
super.setAdapter(adapter); | |
/** Vladislav Karpman | |
* | |
* It is used to hide all movement(such as scrolling to center view {@link #scrollToCenterView()}) | |
* before all view's appearance | |
*/ | |
adapter.registerAdapterDataObserver(new AdapterDataObserver() { | |
@Override | |
public void onChanged() { | |
super.onChanged(); | |
postDelayed(new Runnable() { | |
@Override | |
public void run() { | |
if (getCenterView() != null) { | |
ViewHolder Contain = findContainingViewHolder(getCenterView()); | |
if (Contain != null) { | |
int Position = getChildAdapterPosition(Contain.itemView); | |
for (ChildFocusListener ChildFocusListener : ChildFocusListeners) | |
ChildFocusListener.onChildInFocus(Contain, Position); | |
} | |
} | |
} | |
}, 1); | |
} | |
}); | |
if (animateApprenece) { | |
mAppearAnimationIsWorking = true; | |
addOnLayoutChangeListener(new OnLayoutChangeListener() { | |
@Override | |
public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { | |
final View centerView = getCenterView(); | |
final View leftToCenter = getChildClosestToPosition(0); | |
final View rightToCenter = getChildClosestToPosition(getScreenWidth(getContext())); | |
if (centerView != null && leftToCenter != null && rightToCenter != null) { | |
runAppearAnimation(); | |
removeOnLayoutChangeListener(this); | |
} | |
} | |
}); | |
} | |
} | |
/** | |
* Vladislav Karpman | |
* <p> | |
* Runs appear animation | |
*/ | |
public void runAppearAnimation() { | |
/** | |
* Vladislav Karpman | |
* | |
* Finding center view and views to the left and right of center | |
*/ | |
final View centerView = getCenterView(); | |
final View leftToCenter = getChildClosestToPosition(0); | |
final View rightToCenter = getChildClosestToPosition(getScreenWidth(getContext())); | |
/** | |
* Vladislav Karpman | |
* | |
* To be on the safe side setting scale and alpha for view which are going to be animated | |
*/ | |
centerView.setScaleX(0); | |
centerView.setScaleY(0); | |
centerView.setAlpha(0); | |
leftToCenter.setScaleX(0); | |
leftToCenter.setScaleY(0); | |
leftToCenter.setAlpha(0); | |
rightToCenter.setAlpha(0); | |
rightToCenter.setScaleY(0); | |
rightToCenter.setScaleX(0); | |
/** | |
* Vladislav Karpman | |
* | |
* Set x coordinates for left and right views to achieve effect as follow "moving from sides to center" | |
*/ | |
leftToCenter.setTranslationX(-leftToCenter.getMeasuredWidth()); | |
rightToCenter.setTranslationX(getMeasuredWidth()); | |
centerView.setTranslationX(0); | |
centerView.animate() | |
.scaleX(computeScale(centerView)).scaleY(computeScale(centerView)) | |
.alpha(1) | |
.setDuration(mCenterViewAppearAnimationDuration) | |
.setInterpolator(new DecelerateInterpolator()) | |
.start(); | |
leftToCenter.animate().alpha(1).translationX(0) | |
.scaleX(computeScale(leftToCenter)) | |
.scaleY(computeScale(leftToCenter)) | |
.setDuration(mLeftToCenterViewAppearAnimationDuration) | |
.setInterpolator(new DecelerateInterpolator()) | |
.start(); | |
rightToCenter.animate().alpha(1).translationX(0) | |
.scaleX(computeScale(rightToCenter)) | |
.scaleY(computeScale(rightToCenter)) | |
.setDuration(mRightToCenterViewAppearAnimationDuration) | |
.setInterpolator(new DecelerateInterpolator()) | |
.start(); | |
/** | |
* Vladislav Karpman | |
* | |
* Clearing animation and indicating that appear animation doesn't works | |
*/ | |
postDelayed(new Runnable() { | |
@Override | |
public void run() { | |
centerView.clearAnimation(); | |
leftToCenter.clearAnimation(); | |
rightToCenter.clearAnimation(); | |
mAppearAnimationIsWorking = false; | |
} | |
}, Math.max( | |
mRightToCenterViewAppearAnimationDuration, | |
Math.max(mCenterViewAppearAnimationDuration, mLeftToCenterViewAppearAnimationDuration))); | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent e) { | |
/** | |
* Vladislav Karpman | |
* | |
* Prevents touching event while appear animation is working | |
*/ | |
return !mAppearAnimationIsWorking && super.onTouchEvent(e); | |
} | |
/** | |
* Getting device's screen width | |
* | |
* @return screen width | |
*/ | |
private int getScreenWidth(Context context) { | |
int width = 0; | |
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); | |
Display display = wm.getDefaultDisplay(); | |
Point size = new Point(); | |
display.getSize(size); | |
width = size.x; | |
return width; | |
} | |
@Override | |
protected int getChildDrawingOrder(int childCount, int i) { | |
int centerChild; | |
//find center row | |
if ((childCount % 2) == 0) { //even childCount number | |
centerChild = childCount / 2; // if childCount 8 (actualy 0 - 7), then 4 and 4-1 = 3 is in centre. | |
int otherCenterChild = centerChild - 1; | |
//Which more in center? | |
View child = this.getChildAt(centerChild); | |
final int left = child.getLeft(); | |
final int right = child.getRight(); | |
//if this row goes through center then this | |
final int absParentCenterX = getLeft() + getWidth() / 2; | |
//Log.i("even", i + " from " + (childCount - 1) + ", while centerChild = " + centerChild); | |
if ((left < absParentCenterX) && (right > absParentCenterX)) { | |
//this child is in center line, so it is last | |
//centerChild is in center, no need to change | |
} else { | |
centerChild = otherCenterChild; | |
} | |
} else {//not even - done | |
centerChild = childCount / 2; | |
//Log.i("not even", i + " from " + (childCount - 1) + ", while centerChild = " + centerChild); | |
} | |
int rez; | |
//find drawIndex by centerChild | |
if (i > centerChild) { | |
//below center | |
rez = (childCount - 1) - i + centerChild; | |
} else if (i == centerChild) { | |
//center row | |
//draw it last | |
rez = childCount - 1; | |
} else { | |
//above center - draw as always | |
// i < centerChild | |
rez = i; | |
} | |
//Log.i("return", "" + rez); | |
return rez; | |
} | |
@Override | |
protected void onLayout(boolean changed, int l, int t, int r, int b) { | |
super.onLayout(changed, l, t, r, b); | |
if (!mSnapEnabled) | |
return; | |
updateViews(); | |
} | |
View prevView = null; | |
@Override | |
public void onScrolled(int dx, int dy) { | |
super.onScrolled(dx, dy); | |
updateViews(); | |
View View = getCenterView(); | |
if (View != prevView) { | |
ViewHolder Contain = findContainingViewHolder(View); | |
if (Contain != null) { | |
int Position = getChildAdapterPosition(View); | |
for (ChildFocusListener ChildFocusListener : ChildFocusListeners) | |
ChildFocusListener.onChildInFocus(Contain, Position); | |
} | |
prevView = View; | |
} | |
} | |
@Override | |
public void onScrollStateChanged(int newState) { | |
super.onScrollStateChanged(newState); | |
if (!mSnapEnabled) | |
return; | |
/** if scroll is caused by a touch (scroll touch, not any touch) **/ | |
if (newState == SCROLL_STATE_TOUCH_SCROLL) { | |
/** if scroll was initiated already, this is not a user scrolling, but probably a tap, else set userScrolling **/ | |
if (!mScrolling) { | |
mUserScrolling = true; | |
} | |
} else if (newState == SCROLL_STATE_IDLE) { | |
if (mUserScrolling) { | |
scrollToView(getCenterView()); | |
} | |
mUserScrolling = false; | |
mScrolling = false; | |
} else if (newState == SCROLL_STATE_FLING) { | |
mScrolling = true; | |
} | |
mScrollState = newState; | |
} | |
/** | |
* Enable snapping behaviour for this recyclerView | |
* | |
* @param enabled enable or disable the snapping behaviour | |
*/ | |
void setSnapEnabled(boolean enabled) { | |
mSnapEnabled = enabled; | |
} | |
public ViewHolder getCenterViewHolder() { | |
if (getCenterView() != null) | |
return getChildViewHolder(getCenterView()); | |
return null; | |
} | |
@Override | |
public void onDraw(Canvas c) { | |
/** | |
* important !!!! need to be called else system will think | |
* that we are in old version of android | |
*/ | |
super.onDraw(c); | |
} | |
public void addChildFocusListener(ChildFocusListener ChildFocusListener) { | |
this.ChildFocusListeners.add(ChildFocusListener); | |
} | |
public void removeChildFocusListener(ChildFocusListener ChildFocusListener) { | |
this.ChildFocusListeners.remove(ChildFocusListener); | |
} | |
/** | |
* Enable snapping behaviour for this recyclerView | |
* | |
* @param enabled enable or disable the snapping behaviour | |
* @param scaleUnfocusedViews downScale the views which are not focused based on how far away they are from the center | |
*/ | |
public void setSnapEnabled(boolean enabled, boolean scaleUnfocusedViews) { | |
this.mScaleUnfocusedViews = scaleUnfocusedViews; | |
setSnapEnabled(enabled); | |
} | |
/** | |
* Add an {@link ItemDecoration} to this RecyclerView. Item decorations can | |
* affect both measurement and drawing of individual item views. | |
* <p> | |
* <p>Item decorations are ordered. Decorations placed earlier in the list will | |
* be run/queried/drawn first for their effects on item views. Padding added to views | |
* will be nested; a padding added by an earlier decoration will mean further | |
* item decorations in the list will be asked to draw/pad within the previous decoration's | |
* given area.</p> | |
* | |
* @param decor Decoration to add | |
* @param index Position in the decoration chain to insert this decoration at. If this value | |
* is negative the decoration will be added at the end. | |
*/ | |
@Override | |
public void addItemDecoration(ItemDecoration decor, int index) { | |
if (index < 0) { | |
mItemDecorations.add(decor); | |
} else { | |
mItemDecorations.add(index, decor); | |
} | |
super.addItemDecoration(decor, index); | |
} | |
private float computeScale(View View) { | |
float percentage = getPercentageFromCenter(View); | |
float scale = 1f - (snapScale * percentage); | |
return Math.max(scale, minScale); | |
} | |
protected final void updateViews() { | |
for (int i = 0; i < getChildCount(); i++) { | |
View child = getChildAt(i); | |
//setMarginsForChild(child); | |
if (mAppearAnimationIsWorking) | |
child.setAlpha(0); | |
else | |
child.setAlpha(1); | |
if (mScaleUnfocusedViews && !mAppearAnimationIsWorking) { | |
float scale = computeScale(child); | |
child.setTranslationY(-getMeasuredHeight() * (1 - scaleFactor) / 2); | |
child.setScaleX(scale * scaleFactor * innerScale); | |
child.setScaleY(scale * scaleFactor * innerScale); | |
} | |
} | |
} | |
public void setInnerScale(float scale) { | |
this.innerScale = scale; | |
this.updateViews(); | |
} | |
private boolean isBlockScrollEvent = false; | |
public void setIsBlockScrollEvent(boolean isBlockScrollEvent) { | |
this.isBlockScrollEvent = isBlockScrollEvent; | |
} | |
@Override | |
public boolean dispatchTouchEvent(MotionEvent event) { | |
detector.onTouchEvent(event); | |
if (isBlockScrollEvent) | |
return true; | |
if (event.getAction() == MotionEvent.ACTION_DOWN) { | |
targetView = getChildClosestToPosition((int) event.getX()); | |
} | |
if (!mSnapEnabled) | |
return super.dispatchTouchEvent(event); | |
long currentTime = System.currentTimeMillis(); | |
/** if touch events are being spammed, this is due to user scrolling right after a tap, | |
* so set userScrolling to true **/ | |
if (mScrolling && mScrollState == SCROLL_STATE_TOUCH_SCROLL) { | |
if ((currentTime - lastScrollTime) < MINIMUM_SCROLL_EVENT_OFFSET_MS) { | |
mUserScrolling = true; | |
} | |
} | |
lastScrollTime = currentTime; | |
if (!mUserScrolling) { | |
if (event.getAction() == MotionEvent.ACTION_UP) { | |
if (targetView != null && targetView != getCenterView()) { | |
scrollToView(targetView); | |
targetView = null; | |
return true; | |
} | |
} | |
} | |
return super.dispatchTouchEvent(event); | |
} | |
@Override | |
public boolean onInterceptTouchEvent(MotionEvent e) { | |
if (!mSnapEnabled) | |
return super.onInterceptTouchEvent(e); | |
View targetView = getChildClosestToPosition((int) e.getX()); | |
if (targetView != getCenterView()) { | |
return true; | |
} | |
return super.onInterceptTouchEvent(e); | |
} | |
protected final View getChildClosestToPosition(int x) { | |
if (getChildCount() <= 0) | |
return null; | |
int itemWidth = getChildAt(0).getMeasuredWidth(); | |
int closestX = 9999; | |
View closestChild = null; | |
for (int i = 0; i < getChildCount(); i++) { | |
View child = getChildAt(i); | |
int childCenterX = ((int) child.getX() + (itemWidth / 2)); | |
int xDistance = childCenterX - x; | |
/** if child center is closer than previous closest, set it as closest **/ | |
if (Math.abs(xDistance) < Math.abs(closestX)) { | |
closestX = xDistance; | |
closestChild = child; | |
} | |
} | |
return closestChild; | |
} | |
private View getCenterView() { | |
return getChildClosestToPosition(getMeasuredWidth() / 2); | |
} | |
protected void scrollToView(View child) { | |
if (child == null || mAppearAnimationIsWorking) // prevents scrolling when appear animation is working | |
return; | |
stopScroll(); | |
int scrollDistance = getScrollDistance(child); | |
if (scrollDistance != 0) | |
super.smoothScrollBy(scrollDistance, 0); | |
} | |
/** | |
* Animate a scroll by the given amount of pixels along either axis. | |
* | |
* @param dx Pixels to scroll horizontally | |
* @param dy Pixels to scroll vertically | |
*/ | |
public void smoothScrollBy(int dx, int dy) { | |
// super.smoothScrollBy(dx,dy); | |
} | |
private int getScrollDistance(View child) { | |
int itemWidth = getChildAt(0).getMeasuredWidth(); | |
int centerX = getMeasuredWidth() / 2; | |
int childCenterX = ((int) child.getX() + (itemWidth / 2)); | |
return childCenterX - centerX; | |
} | |
private float getPercentageFromCenter(View child) { | |
float centerX = (getMeasuredWidth() / 2); | |
float childCenterX = child.getLeft() + (child.getWidth() / 2); | |
float offSet = Math.max(centerX, childCenterX) - Math.min(centerX, childCenterX); | |
int maxOffset = (getMeasuredWidth() / 2) + child.getWidth(); | |
return (offSet / maxOffset); | |
} | |
public boolean isChildCenterView(View child) { | |
return child == getCenterView(); | |
} | |
@Override | |
protected void onDetachedFromWindow() { | |
super.onDetachedFromWindow(); | |
} | |
public static interface ChildFocusListener { | |
public void onChildInFocus(ViewHolder View, int Position); | |
public void onChildSelected(ViewHolder View, int Position); | |
} | |
public void setCenterViewAppearAnimationDuration(long centerViewAppearAnimationDuration) { | |
mCenterViewAppearAnimationDuration = centerViewAppearAnimationDuration; | |
} | |
public void setLeftToCenterViewAppearAnimationDuration(long leftToCenterViewAppearAnimationDuration) { | |
mLeftToCenterViewAppearAnimationDuration = leftToCenterViewAppearAnimationDuration; | |
} | |
public void setRightToCenterViewAppearAnimationDuration(long rightToCenterViewAppearAnimationDuration) { | |
mRightToCenterViewAppearAnimationDuration = rightToCenterViewAppearAnimationDuration; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment