简单实现Google play 横向RecyclerListView效果
来源:互联网 发布:云墙mac破解版 编辑:程序博客网 时间:2024/06/07 11:45
现在更好的方式是使用SnapHelper 在RecyclerView 24.2.0 支持库之后添加使用方法
需要实现的功能
这里只实现回弹的效果 和 在一个宽度内显示2个半item的效果。
分析
下面是需要实现的效果:
1.看起来就是一个横向的ListView
,现在有我们可以容易的使用RecyclerView
并配合LinearLayoutManager
实现一个横向的ListView
2.需要支持回弹效果,RecyclerView
本身拥有的scrollToPosition(int targetPosition)
及 smoothScrollToPosition(int targetPosition)
,目前看来很简单。
实现
好吧,看起来没什么可分析的。为了方便使用 自定义一个HorizontalRecyclerView
继承自 RecyclerView
。
HorizontalRecyclerView
public class HorizontalRecyclerView extends RecyclerView { private LinearLayoutManager mLayoutManager; public HorizontalRecyclerView(Context context) { super(context); init(context); } public HorizontalRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); init(context); } public HorizontalRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context){ mLayoutManager = new LinearLayoutManager(context);//自定义的LinearLayoutManager extends LinearLayoutManager mLayoutManager.setOrientation(android.support.v7.widget.LinearLayoutManager.HORIZONTAL); setLayoutManager(mLayoutManager); addOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(RecyclerView recyclerView, int newState) { switch (newState){ case SCROLL_STATE_IDLE:// int firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition(); int firstCompletelyVisibleItem = mLayoutManager.findFirstCompletelyVisibleItemPosition(); int lastCompletelyVisibleItem = mLayoutManager.findLastCompletelyVisibleItemPosition(); if(lastCompletelyVisibleItem == getAdapter().getItemCount()-1) return; if(firstCompletelyVisibleItem == firstVisibleItem) return; View firstItem = mLayoutManager.findViewByPosition(firstVisibleItem); if(Math.abs(firstItem.getLeft())*2>firstItem.getWidth()) { smoothScrollToPosition(firstCompletelyVisibleItem); }else { smoothScrollToPosition(firstVisibleItem); } break; } } @Override public void onScrolled(RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); } }); }}
就是做一个初始化工作,设置一个横向的LinearLayoutManager
,并且添加滑动监听。在监听里判断需要滑到哪个位置,执行滑动。
运行之后发现,并没有进行滑动。下面是我解决的方案:
1.重写LayoutManager
的smoothScrollToPosition
方法使用自定义的MyLinearSmoothScroller
代替LinearLayoutManager
默认的scroller。
@Override public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) { MyLinearSmoothScroller linearSmoothScroller = new MyLinearSmoothScroller(recyclerView.getContext()) { @Override public PointF computeScrollVectorForPosition(int targetPosition) { return LinearLayoutManager.this .computeScrollVectorForPosition(targetPosition); } }; linearSmoothScroller.setTargetPosition(position); startSmoothScroll(linearSmoothScroller); }
2.MyLinearSmoothScroller
继承自LinearSmoothScroller
重写下面两个方法,第一个是为了使移动能够发生,第二个是控制滑动速度。
@Override public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) { switch (snapPreference) { case SNAP_TO_START: return boxStart - viewStart; case SNAP_TO_END: return boxEnd - viewEnd; case SNAP_TO_ANY: final int dtStart = boxStart - viewStart;// if (dtStart > 0) { return dtStart;// }// final int dtEnd = boxEnd - viewEnd;// if (dtEnd < 0) {// return dtEnd;// }// break; default: throw new IllegalArgumentException("snap preference should be one of the" + " constants defined in SmoothScroller, starting with SNAP_"); }// return 0; }
@Override protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) { return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;//返回的是移动一个像素 需要的毫秒数 }
3.控制一次布局展示可以展现 2.5个Item,重写LinearLayoutManager
的测量子view的方法
@Override public void measureChildWithMargins(View child, int widthUsed, int heightUsed) { final RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();//// final Rect insets = mRecyclerView.getItemDecorInsetsForChild(child);// widthUsed += insets.left + insets.right;// heightUsed += insets.top + insets.bottom;//// final int widthSpec = getChildMeasureSpec(getWidth(), getWidthMode(),// getPaddingLeft() + getPaddingRight() +// lp.leftMargin + lp.rightMargin + widthUsed, lp.width,// canScrollHorizontally()); final int widthSpec = getChildMeasureSpec((int) (0.4*getWidth()),getWidthMode(), 0,lp.width,canScrollHorizontally()); final int heightSpec = getChildMeasureSpec(getHeight(), getHeightMode(), getPaddingTop() + getPaddingBottom() + lp.topMargin + lp.bottomMargin + heightUsed, lp.height, canScrollVertically());// if (shouldMeasureChild(child, widthSpec, heightSpec, lp)) { child.measure(widthSpec, heightSpec);// } }
其他
那么为什么之前调用滑动,没有进行滑动呢。还是看这个方法
/** * Helper method for {@link #calculateDxToMakeVisible(android.view.View, int)} and * {@link #calculateDyToMakeVisible(android.view.View, int)} */ public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) { switch (snapPreference) { case SNAP_TO_START: return boxStart - viewStart; case SNAP_TO_END: return boxEnd - viewEnd; case SNAP_TO_ANY: final int dtStart = boxStart - viewStart; if (dtStart > 0) { return dtStart; } final int dtEnd = boxEnd - viewEnd; if (dtEnd < 0) { return dtEnd; } break; default: throw new IllegalArgumentException("snap preference should be one of the" + " constants defined in SmoothScroller, starting with SNAP_"); } return 0; }
我们触发滑动时会穿过去的snapPreference
== SNAP_TO_ANY
然后不满足下面两个if
条件 最后返回 0。然后snapPreference
是个什么?如果能保证snapPreference
==SNAP_TO_START
就不用重写这个方法了。看下面两个方法注释
/** * When the target scroll position is not a child of the RecyclerView, this method calculates * a direction vector towards that child and triggers a smooth scroll. * * @see #computeScrollVectorForPosition(int) */ protected void updateActionForInterimTarget(Action action) { // find an interim target position PointF scrollVector = computeScrollVectorForPosition(getTargetPosition()); if (scrollVector == null || (scrollVector.x == 0 && scrollVector.y == 0)) { Log.e(TAG, "To support smooth scrolling, you should override \n" + "LayoutManager#computeScrollVectorForPosition.\n" + "Falling back to instant scroll"); final int target = getTargetPosition(); action.jumpTo(target); stop(); return; } normalize(scrollVector); mTargetVector = scrollVector; mInterimTargetDx = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.x); mInterimTargetDy = (int) (TARGET_SEEK_SCROLL_DISTANCE_PX * scrollVector.y); final int time = calculateTimeForScrolling(TARGET_SEEK_SCROLL_DISTANCE_PX); // To avoid UI hiccups, trigger a smooth scroll to a distance little further than the // interim target. Since we track the distance travelled in onSeekTargetStep callback, it // won't actually scroll more than what we need. action.update((int) (mInterimTargetDx * TARGET_SEEK_EXTRA_SCROLL_RATIO) , (int) (mInterimTargetDy * TARGET_SEEK_EXTRA_SCROLL_RATIO) , (int) (time * TARGET_SEEK_EXTRA_SCROLL_RATIO), mLinearInterpolator); }
/** *RecyclerView will call this method each time it scrolls until it can find the target * position in the layout.
*SmoothScroller should check dx, dy and if scroll should be changed, update the * provided {@link Action} to define the next scroll.
* * @param dx Last scroll amount horizontally * @param dy Last scroll amount verticaully * @param state Transient state of RecyclerView * @param action If you want to trigger a new smooth scroll and cancel the previous one, * update this object. */ abstract protected void onSeekTargetStep(int dx, int dy, State state, Action action);
- 简单实现Google play 横向RecyclerListView效果
- RecyclerListView
- 类似Google Calendar效果的简单实现
- Android 实现横向滑动效果
- RecyclerView 实现横向滚动效果
- RecyclerView 实现横向滚动效果
- 类似Google Play 平滑动画效果
- SearchView结合Toolbar 筛选RecyclerView中的内容,类似知乎、google play实现的效果
- SearchView结合Toolbar 筛选RecyclerView中的内容,类似知乎、google play实现的效果
- Play Framework 国际化简单实现
- 高仿google now效果的呼吸按钮简单实现
- google play 主界面实现方式:
- TextView 横向滚动效果的实现
- RecyclerView实现横向的GridView效果
- 求横向listview弹性效果实现
- 通过UICollectionView实现横向滚动照片效果
- Android RecyclerView 实现横向滚动效果
- google play
- 三、runtime之消息(三)
- Java获取两个字符串中最大相同子串
- iOS中磨砂视图的实现和总结blurEffectView
- Android 5.0以后版本打开“有权查看使用情况的应用”
- word两幅图并排并且插入题注不会乱
- 简单实现Google play 横向RecyclerListView效果
- 数字的组合
- 第7周项目2:友元类
- mybatis的配置文件结构
- java 数字精准计算方法,解析公式,类似 3*(1+2)
- android开发-获取wifi列表
- hdu 1024(滚动数组优化)
- Linux命令(面试题)
- HTML 元素和有效的 DTD