-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
e48dff4
commit 24d1e7d
Showing
13 changed files
with
3,433 additions
and
0 deletions.
There are no files selected for viewing
73 changes: 73 additions & 0 deletions
73
base/src/main/java/com/heyongrui/base/widget/layoutmanager/AutoPlayRecyclerView.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package com.heyongrui.base.widget.layoutmanager; | ||
|
||
import android.content.Context; | ||
import android.util.AttributeSet; | ||
import android.view.MotionEvent; | ||
|
||
import androidx.annotation.Nullable; | ||
import androidx.recyclerview.widget.RecyclerView; | ||
|
||
/** | ||
* An implement of {@link RecyclerView} which support auto play. | ||
*/ | ||
|
||
public class AutoPlayRecyclerView extends RecyclerView { | ||
|
||
private AutoPlaySnapHelper autoPlaySnapHelper; | ||
|
||
public AutoPlayRecyclerView(Context context) { | ||
this(context, null); | ||
} | ||
|
||
public AutoPlayRecyclerView(Context context, @Nullable AttributeSet attrs) { | ||
this(context, attrs, 0); | ||
} | ||
|
||
public AutoPlayRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { | ||
super(context, attrs, defStyle); | ||
autoPlaySnapHelper = new AutoPlaySnapHelper(AutoPlaySnapHelper.TIME_INTERVAL, AutoPlaySnapHelper.RIGHT); | ||
} | ||
|
||
@Override | ||
public boolean dispatchTouchEvent(MotionEvent ev) { | ||
boolean result = super.dispatchTouchEvent(ev); | ||
switch (ev.getAction()) { | ||
case MotionEvent.ACTION_DOWN: | ||
if (autoPlaySnapHelper != null) { | ||
autoPlaySnapHelper.pause(); | ||
} | ||
break; | ||
case MotionEvent.ACTION_UP: | ||
if (autoPlaySnapHelper != null) { | ||
autoPlaySnapHelper.start(); | ||
} | ||
} | ||
return result; | ||
} | ||
|
||
public void setTimeInterval(int timeInterval) { | ||
if (null != autoPlaySnapHelper) { | ||
autoPlaySnapHelper.setTimeInterval(timeInterval); | ||
} | ||
} | ||
|
||
public void setDirection(int direction) { | ||
if (null != autoPlaySnapHelper) { | ||
autoPlaySnapHelper.setDirection(direction); | ||
} | ||
} | ||
|
||
public void start() { | ||
autoPlaySnapHelper.start(); | ||
} | ||
|
||
public void pause() { | ||
autoPlaySnapHelper.pause(); | ||
} | ||
|
||
@Override | ||
public void setLayoutManager(LayoutManager layout) { | ||
super.setLayoutManager(layout); | ||
autoPlaySnapHelper.attachToRecyclerView(this); | ||
} | ||
} |
116 changes: 116 additions & 0 deletions
116
base/src/main/java/com/heyongrui/base/widget/layoutmanager/AutoPlaySnapHelper.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
package com.heyongrui.base.widget.layoutmanager; | ||
|
||
import android.os.Handler; | ||
import android.os.Looper; | ||
import android.view.animation.DecelerateInterpolator; | ||
import android.widget.Scroller; | ||
|
||
import androidx.annotation.Nullable; | ||
import androidx.recyclerview.widget.RecyclerView; | ||
|
||
|
||
/** | ||
* Used by {@link AutoPlayRecyclerView} to implement auto play effect | ||
*/ | ||
|
||
class AutoPlaySnapHelper extends CenterSnapHelper { | ||
final static int TIME_INTERVAL = 2000; | ||
|
||
final static int LEFT = 1; | ||
final static int RIGHT = 2; | ||
|
||
private Handler handler; | ||
private int timeInterval; | ||
private Runnable autoPlayRunnable; | ||
private boolean runnableAdded; | ||
private int direction; | ||
|
||
AutoPlaySnapHelper(int timeInterval, int direction) { | ||
checkTimeInterval(timeInterval); | ||
checkDirection(direction); | ||
handler = new Handler(Looper.getMainLooper()); | ||
this.timeInterval = timeInterval; | ||
this.direction = direction; | ||
} | ||
|
||
@Override | ||
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException { | ||
if (mRecyclerView == recyclerView) { | ||
return; // nothing to do | ||
} | ||
if (mRecyclerView != null) { | ||
destroyCallbacks(); | ||
} | ||
mRecyclerView = recyclerView; | ||
if (mRecyclerView != null) { | ||
final RecyclerView.LayoutManager layoutManager = mRecyclerView.getLayoutManager(); | ||
if (!(layoutManager instanceof ViewPagerLayoutManager)) return; | ||
|
||
setupCallbacks(); | ||
mGravityScroller = new Scroller(mRecyclerView.getContext(), | ||
new DecelerateInterpolator()); | ||
|
||
snapToCenterView((ViewPagerLayoutManager) layoutManager, | ||
((ViewPagerLayoutManager) layoutManager).onPageChangeListener); | ||
|
||
((ViewPagerLayoutManager) layoutManager).setInfinite(true); | ||
|
||
autoPlayRunnable = new Runnable() { | ||
@Override | ||
public void run() { | ||
final int currentPosition = | ||
((ViewPagerLayoutManager) layoutManager).getCurrentPositionOffset() * | ||
(((ViewPagerLayoutManager) layoutManager).getReverseLayout() ? -1 : 1); | ||
ScrollHelper.smoothScrollToPosition(mRecyclerView, | ||
(ViewPagerLayoutManager) layoutManager, direction == RIGHT ? currentPosition + 1 : currentPosition - 1); | ||
handler.postDelayed(autoPlayRunnable, timeInterval); | ||
} | ||
}; | ||
handler.postDelayed(autoPlayRunnable, timeInterval); | ||
runnableAdded = true; | ||
} | ||
} | ||
|
||
@Override | ||
void destroyCallbacks() { | ||
super.destroyCallbacks(); | ||
if (runnableAdded) { | ||
handler.removeCallbacks(autoPlayRunnable); | ||
runnableAdded = false; | ||
} | ||
} | ||
|
||
void pause() { | ||
if (runnableAdded) { | ||
handler.removeCallbacks(autoPlayRunnable); | ||
runnableAdded = false; | ||
} | ||
} | ||
|
||
void start() { | ||
if (!runnableAdded) { | ||
handler.postDelayed(autoPlayRunnable, timeInterval); | ||
runnableAdded = true; | ||
} | ||
} | ||
|
||
void setTimeInterval(int timeInterval) { | ||
checkTimeInterval(timeInterval); | ||
this.timeInterval = timeInterval; | ||
} | ||
|
||
void setDirection(int direction) { | ||
checkDirection(direction); | ||
this.direction = direction; | ||
} | ||
|
||
private void checkDirection(int direction) { | ||
if (direction != LEFT && direction != RIGHT) | ||
throw new IllegalArgumentException("direction should be one of left or right"); | ||
} | ||
|
||
private void checkTimeInterval(int timeInterval) { | ||
if (timeInterval <= 0) | ||
throw new IllegalArgumentException("time interval should greater than 0"); | ||
} | ||
} |
166 changes: 166 additions & 0 deletions
166
base/src/main/java/com/heyongrui/base/widget/layoutmanager/CarouselLayoutManager.java
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
package com.heyongrui.base.widget.layoutmanager; | ||
|
||
import android.content.Context; | ||
import android.view.View; | ||
|
||
/** | ||
* An implementation of {@link ViewPagerLayoutManager} | ||
* which layouts items like carousel | ||
*/ | ||
|
||
public class CarouselLayoutManager extends ViewPagerLayoutManager { | ||
|
||
private int itemSpace; | ||
private float minScale; | ||
private float moveSpeed; | ||
|
||
public CarouselLayoutManager(Context context, int itemSpace) { | ||
this(new Builder(context, itemSpace)); | ||
} | ||
|
||
public CarouselLayoutManager(Context context, int itemSpace, int orientation) { | ||
this(new Builder(context, itemSpace).setOrientation(orientation)); | ||
} | ||
|
||
public CarouselLayoutManager(Context context, int itemSpace, int orientation, boolean reverseLayout) { | ||
this(new Builder(context, itemSpace).setOrientation(orientation).setReverseLayout(reverseLayout)); | ||
} | ||
|
||
public CarouselLayoutManager(Builder builder) { | ||
this(builder.context, builder.itemSpace, builder.minScale, builder.orientation, | ||
builder.maxVisibleItemCount, builder.moveSpeed, builder.distanceToBottom, | ||
builder.reverseLayout); | ||
} | ||
|
||
private CarouselLayoutManager(Context context, int itemSpace, float minScale, int orientation, | ||
int maxVisibleItemCount, float moveSpeed, int distanceToBottom, | ||
boolean reverseLayout) { | ||
super(context, orientation, reverseLayout); | ||
setEnableBringCenterToFront(true); | ||
setDistanceToBottom(distanceToBottom); | ||
setMaxVisibleItemCount(maxVisibleItemCount); | ||
this.itemSpace = itemSpace; | ||
this.minScale = minScale; | ||
this.moveSpeed = moveSpeed; | ||
} | ||
|
||
public int getItemSpace() { | ||
return itemSpace; | ||
} | ||
|
||
public float getMinScale() { | ||
return minScale; | ||
} | ||
|
||
public float getMoveSpeed() { | ||
return moveSpeed; | ||
} | ||
|
||
public void setItemSpace(int itemSpace) { | ||
assertNotInLayoutOrScroll(null); | ||
if (this.itemSpace == itemSpace) return; | ||
this.itemSpace = itemSpace; | ||
removeAllViews(); | ||
} | ||
|
||
public void setMinScale(float minScale) { | ||
assertNotInLayoutOrScroll(null); | ||
if (minScale > 1f) minScale = 1f; | ||
if (this.minScale == minScale) return; | ||
this.minScale = minScale; | ||
requestLayout(); | ||
} | ||
|
||
public void setMoveSpeed(float moveSpeed) { | ||
assertNotInLayoutOrScroll(null); | ||
if (this.moveSpeed == moveSpeed) return; | ||
this.moveSpeed = moveSpeed; | ||
} | ||
|
||
@Override | ||
protected float setInterval() { | ||
return (mDecoratedMeasurement - itemSpace); | ||
} | ||
|
||
@Override | ||
protected void setItemViewProperty(View itemView, float targetOffset) { | ||
float scale = calculateScale(targetOffset + mSpaceMain); | ||
itemView.setScaleX(scale); | ||
itemView.setScaleY(scale); | ||
} | ||
|
||
@Override | ||
protected float getDistanceRatio() { | ||
if (moveSpeed == 0) return Float.MAX_VALUE; | ||
return 1 / moveSpeed; | ||
} | ||
|
||
@Override | ||
protected float setViewElevation(View itemView, float targetOffset) { | ||
return itemView.getScaleX() * 5; | ||
} | ||
|
||
private float calculateScale(float x) { | ||
float deltaX = Math.abs(x - (mOrientationHelper.getTotalSpace() - mDecoratedMeasurement) / 2f); | ||
return (minScale - 1) * deltaX / (mOrientationHelper.getTotalSpace() / 2f) + 1f; | ||
} | ||
|
||
public static class Builder { | ||
private static final float DEFAULT_SPEED = 1f; | ||
private static final float MIN_SCALE = 0.5f; | ||
|
||
private Context context; | ||
private int itemSpace; | ||
private int orientation; | ||
private float minScale; | ||
private float moveSpeed; | ||
private int maxVisibleItemCount; | ||
private boolean reverseLayout; | ||
private int distanceToBottom; | ||
|
||
public Builder(Context context, int itemSpace) { | ||
this.itemSpace = itemSpace; | ||
this.context = context; | ||
orientation = HORIZONTAL; | ||
minScale = MIN_SCALE; | ||
this.moveSpeed = DEFAULT_SPEED; | ||
reverseLayout = false; | ||
maxVisibleItemCount = ViewPagerLayoutManager.DETERMINE_BY_MAX_AND_MIN; | ||
distanceToBottom = ViewPagerLayoutManager.INVALID_SIZE; | ||
} | ||
|
||
public Builder setOrientation(int orientation) { | ||
this.orientation = orientation; | ||
return this; | ||
} | ||
|
||
public Builder setMinScale(float minScale) { | ||
this.minScale = minScale; | ||
return this; | ||
} | ||
|
||
public Builder setReverseLayout(boolean reverseLayout) { | ||
this.reverseLayout = reverseLayout; | ||
return this; | ||
} | ||
|
||
public Builder setMoveSpeed(float moveSpeed) { | ||
this.moveSpeed = moveSpeed; | ||
return this; | ||
} | ||
|
||
public Builder setMaxVisibleItemCount(int maxVisibleItemCount) { | ||
this.maxVisibleItemCount = maxVisibleItemCount; | ||
return this; | ||
} | ||
|
||
public Builder setDistanceToBottom(int distanceToBottom) { | ||
this.distanceToBottom = distanceToBottom; | ||
return this; | ||
} | ||
|
||
public CarouselLayoutManager build() { | ||
return new CarouselLayoutManager(this); | ||
} | ||
} | ||
} |
Oops, something went wrong.