RecyclerView实现横向滑动后自动选中条目,点击其它条目自动移动到中间位置并选中;
横向的列表就是上面的效果,下面是动图;
效果就是这样的 , 有当前选中回调 , 也可以设置当前选中的条目;
代码无封装,看着更直观;
- 获取中间位置,这个位置就是Item需要停留到的位置;
- 滑动后计算出距离中间位置最近的一个Item , 然后让此Item滑动到居中位置;
- 点击其它条目时 , 计算此条目距离中间的位置 , 然后滑动到中间;
- 可以选中第一个条目和最后一个条目 ,使用隐藏的View填充;
1、获取中间位置:
recyclerView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
}
centerToLiftDistance = recyclerView.getWidth() / 2;
}
});
2、滑动后计算需要移动的Item:
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == AbsListView.OnScrollListener.SCROLL_STATE_IDLE) {
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
int fi = linearLayoutManager.findFirstVisibleItemPosition();
int la = linearLayoutManager.findLastVisibleItemPosition();
Log.i("ccb", "onScrollStateChanged:首个item: " + fi + " 末尾item:" + la);
if (isTouch) {
isTouch = false;
//获取最中间的Item View
int centerPositionDiffer = (la - fi) / 2;
int centerChildViewPosition = fi + centerPositionDiffer; //获取当前所有条目中中间的一个条目索引
centerViewItems.clear();
//遍历循环,获取到和中线相差最小的条目索引(精准查找最居中的条目)
if (centerChildViewPosition != 0){
for (int i = centerChildViewPosition -1 ; i < centerChildViewPosition+2; i++) {
View cView = recyclerView.getLayoutManager().findViewByPosition(i);
int viewLeft = cView.getLeft()+(cView.getWidth()/2);
centerViewItems.add(new CenterItemUtils.CenterViewItem(i ,Math.abs(centerToLiftDistance - viewLeft)));
}
CenterItemUtils.CenterViewItem centerViewItem = CenterItemUtils.getMinDifferItem(centerViewItems);
centerChildViewPosition = centerViewItem.position;
}
scrollToCenter(centerChildViewPosition);
}
}
}
@Override
public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
}
});
recyclerView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View view, MotionEvent motionEvent) {
isTouch = true;
return false;
}
});
private DecelerateInterpolator decelerateInterpolator = new DecelerateInterpolator();
/**
* 移动指定索引到中心处 , 只可以移动可见区域的内容
* @param position
*/
private void scrollToCenter(int position){
position = position < childViewHalfCount ? childViewHalfCount : position;
position = position < mAdapter.getItemCount() - childViewHalfCount -1 ? position : mAdapter.getItemCount() - childViewHalfCount -1;
LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();
View childView = linearLayoutManager.findViewByPosition(position);
Log.i("ccb", "滑动后中间View的索引: " + position);
//把当前View移动到居中位置
if (childView == null) return;
int childVhalf = childView.getWidth() / 2;
int childViewLeft = childView.getLeft();
int viewCTop = centerToLiftDistance;
int smoothDistance = childViewLeft - viewCTop + childVhalf;
Log.i("ccb", "\n居中位置距离左部距离: " + viewCTop
+ "\n当前居中控件距离左部距离: " + childViewLeft
+ "\n当前居中控件的一半高度: " + childVhalf
+ "\n滑动后再次移动距离: " + smoothDistance);
recyclerView.smoothScrollBy(smoothDistance, 0,decelerateInterpolator);
mAdapter.setSelectPosition(position);
tv.setText("当前选中:" + mDatas.get(position));
}
3、点击选中:
final int fp = position;
vh.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
scrollToCenter(fp);
Toast.makeText(HorizontalSelectActivity.this, "点击" + mDatas.get(fp), Toast.LENGTH_SHORT).show();
}
});
4、选中第一个和最后一个:
int childViewHeight = UiUtils.dip2px(HorizontalSelectActivity.this, CHILDVIEWSIZE); //43是当前已知的 Item的高度
childViewHalfCount = (recyclerView.getWidth() / childViewHeight + 1) / 2;
if (mDatas == null) mDatas = new ArrayList<>();
for (int i = 0; i < 55; i++) {
mDatas.add("条目" + i);
}
for (int j = 0; j < childViewHalfCount; j++) { //头部的空布局
mDatas.add(0, null);
}
for (int k = 0; k < childViewHalfCount; k++) { //尾部的空布局
mDatas.add(null);
}
if (TextUtils.isEmpty(mDatas.get(position))){
vh.itemView.setVisibility(View.INVISIBLE);
}else {
vh.itemView.setVisibility(View.VISIBLE);
vh.tv.setText(mDatas.get(position));
}
OK , 以上只是主要代码和大致思路,全部的代码请移步到
CSDN:https://download.csdn.net/download/qq_35605213/12470655
Github:https://github.com/CuiChenbo/ArcSelectList , 欢迎Star
同理 , 竖直的列表也是这样实现: