一、第1个item和最后一个item能够滑动至RecycleView中间位置。
实现:设置第1个item的左边距和最后一个item的右边距。
public class RecyclerItemCenterDecoration extends RecyclerView.ItemDecoration {
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
// 获得Item的数量
int itemCount = parent.getAdapter().getItemCount();
if (itemCount > 0){
// 获取当前Item的position
int position = parent.getChildAdapterPosition(view);
int endPosition = itemCount - 1;
if (position == 0 || position == endPosition){
// 测量view的宽度
view.measure(0, 0);
// 默认值
int childViewWidth = DensityUtils.dip2px(120);
if (view.getMeasuredWidth() > 0){
childViewWidth = view.getMeasuredWidth();
}
int parentWidth = parent.getWidth();
if (parentWidth <= 0) {
parentWidth = DensityUtils.getScreenWidth(parent.getContext());
}
//所需的最小边距
int minMargin = (parentWidth / 2 - childViewWidth / 2);
RecyclerView.LayoutParams layoutParams = (RecyclerView.LayoutParams) view.getLayoutParams();
// 第1个item左边距不够剧中
if (position == 0 && layoutParams.leftMargin < minMargin){
layoutParams.setMargins(minMargin, layoutParams.topMargin, layoutParams.rightMargin, layoutParams.bottomMargin);
view.setLayoutParams(layoutParams);
}
// 最后的item右边距不够剧中
if (position == endPosition && layoutParams.rightMargin < minMargin){
layoutParams.setMargins(layoutParams.leftMargin, layoutParams.topMargin, minMargin, layoutParams.bottomMargin);
view.setLayoutParams(layoutParams);
}
}
}
super.getItemOffsets(outRect, view, parent, state);
}
}
二、(1)抬起手指时,能够让距离RecyclerView中心位置最近的控件正好居中(2)惯性滚动最多只能滚动1个item
实现:(1)LinearShapHelper可以实现控件自动修正至居中,但由于惯性加速度的影响使得目标view并非是距离中心位置最近的那个,需要重写findSnapView方法,实现指定我们想要选中的view(2)由于每个item的宽度都比RecyclerView小,PagerShapHelper无效。这里通过重写LinearShapHelper的findTargetSnapPosition方法,实现指定惯性滑动最终的view。
public class FlingOneLinearSnapHelper extends LinearSnapHelper {
private RecyclerView mRecyclerView;
@Override
public void attachToRecyclerView(@Nullable RecyclerView recyclerView) throws IllegalStateException {
mRecyclerView = recyclerView;
super.attachToRecyclerView(recyclerView);
}
/**
* 惯性滑动获取RecyclerView的最终位置
*
* @param layoutManager RecyclerView的布局管理器
* @return 返回中心位置对应的控件
*/
@Override
public int findTargetSnapPosition(RecyclerView.LayoutManager layoutManager, int velocityX, int velocityY) {
int resultPosition = RecyclerView.NO_POSITION;
View centerView = findSnapView(layoutManager);
if (centerView != null){
int centerX = mRecyclerView.getMeasuredWidth() / 2;
int viewCenterX = centerView.getLeft() + centerView.getWidth() / 2;
int centerPotion = layoutManager.getPosition(centerView);
if (velocityX > 0){
// 向左滑
if (viewCenterX < centerX) {
// 当前控件已经位于中线左边,则移动至下个位置
resultPosition = centerPotion + 1;
} else {
resultPosition = centerPotion;
}
} else {
// 向右滑
if (viewCenterX > centerX) {
// 当前控件已经位于中线右边,则移动至上个位置
resultPosition = centerPotion - 1;
} else {
resultPosition = centerPotion;
}
}
}
if (resultPosition < layoutManager.getItemCount()){
return resultPosition;
} else {
return RecyclerView.NO_POSITION;
}
}
/**
* 获取RecyclerView的中心位置对应的控件
*
* @param layoutManager RecyclerView的布局管理器
* @return 返回中心位置对应的控件
*/
@Override
public View findSnapView(RecyclerView.LayoutManager layoutManager) {
int count = layoutManager.getChildCount();
if (mRecyclerView != null && count > 0) {
int centerX = mRecyclerView.getMeasuredWidth() / 2;
if (centerX > 0){
int distance = 0;
for (int i = 0; i < count; i++){
View view = layoutManager.getChildAt(i);
if (view.getRight() < centerX){
distance = centerX - view.getRight();
} else {
if (view.getLeft() <= centerX){
return view;
} else {
int currentDistance = view.getLeft() - centerX;
if (currentDistance > distance){
return layoutManager.getChildAt(i - 1);
} else if (currentDistance < distance) {
return view;
}
}
}
}
}
}
return null;
}
/**
* 获取RecyclerView的中心位置对应的item位置
*
* @param layoutManager RecyclerView的布局管理器
* @return 返回中心位置对应的item位置
*/
public int getCenterPotion(RecyclerView.LayoutManager layoutManager){
View centerView = findSnapView(layoutManager);
return centerView == null ? RecyclerView.NO_POSITION : layoutManager.getPosition(centerView);
}
三、代码方式选中某个控件,能够将该控件滚动至居中
实现:重写LinearLayoutManager的smoothScrollToPosition方法,实现
recyclerView.smoothScrollToPosition(potion)能将控件滚动至中心位置
public class CenterLayoutManager extends LinearLayoutManager {
public CenterLayoutManager(Context context) {
super(context);
}
public CenterLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public CenterLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private static class CenterSmoothScroller extends LinearSmoothScroller {
CenterSmoothScroller(Context context) {
super(context);
}
@Override
public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
}
}
}