使用RecyclerView实现抽奖
看到这福抽奖图片,大家可以考虑下如何实现?自定义控件,自己绘制?在这里我们我们有更简单的方法,使用3个RecyclerView进行实现。为了实现抽奖,我们会遇到如下2个问题。源码:https://github.com/zhao007z4/jackpot
1、如何控制3个RecyclerView的速度,使得他们在不同的时间停止?
2、如何控制每列值显示,显示的项目个数?
3、从服务器拉取到结果后,如果让RecyclerView,滚动到指定的项目?
带着以上问题,我们来一一实现
一、如何控制3个RecyclerView的速度,使得他们在不同的时间停止?
RecyclerView,自带神器,可以通过自定义LinearLayoutManager实现对滚动速度的控制。代码如下
- public class FastScrollLinearLayoutManager extends LinearLayoutManager {
- public FastScrollLinearLayoutManager(Context context) {
- super(context);
- }
- @Override
- public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
- LinearSmoothScroller linearSmoothScroller = new LinearSmoothScroller(recyclerView.getContext()) {
- @Override
- public PointF computeScrollVectorForPosition(int targetPosition) {
- return FastScrollLinearLayoutManager.this.computeScrollVectorForPosition(targetPosition);
- }
- //该方法控制速度。
- //if returned value is 2 ms, it means scrolling 1000 pixels with LinearInterpolation should take 2 seconds.
- @Override
- protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
- /*
- 控制单位速度, 毫秒/像素, 滑动1像素需要多少毫秒.
- 默认为 (25F/densityDpi) 毫秒/像素
- mdpi上, 1英寸有160个像素点, 25/160,
- xxhdpi,1英寸有480个像素点, 25/480,
- */
- //return 10F / displayMetrics.densityDpi;//可以减少时间,默认25F
- return super.calculateSpeedPerPixel(displayMetrics);
- }
- //该方法计算滑动所需时间。在此处间接控制速度。
- //Calculates the time it should take to scroll the given distance (in pixels)
- @Override
- protected int calculateTimeForScrolling(int dx) {
- /*
- 控制距离, 然后根据上面那个方(calculateSpeedPerPixel())提供的速度算出时间,
- 默认一次 滚动 TARGET_SEEK_SCROLL_DISTANCE_PX = 10000个像素,
- 在此处可以减少该值来达到减少滚动时间的目的.
- */
- //间接计算时提高速度,也可以直接在calculateSpeedPerPixel提高
- if (dx > 3000) {
- dx = 3000;
- }
- int time = super.calculateTimeForScrolling(dx);
- LogUtil.d(time);//打印时间看下
- return time;
- }
- };
- linearSmoothScroller.setTargetPosition(position);
- startSmoothScroll(linearSmoothScroller);
- }
- }
二、如何控制每列中,显示的项目个数
通过之定义ImageView,在onMeasure中控制每个项目大小。每个项目的大小,可以通过RecyclerView高度所占比例/3进行计算,以下代码以背景图1080X1920为基准,RecyclerView高度占比630
@Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
- {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- DisplayMetrics dm = getResources().getDisplayMetrics();
- int iWidth = (dm.heightPixels*630)/(1920*3);
- int iNewWidth = dm.widthPixels*254/1080;
- iWidth = iWidth>iNewWidth?iNewWidth:iWidth;
- setMeasuredDimension(iWidth, iWidth);
- }
三、从服务器拉取到结果后,如果让RecyclerView,滚动到指定的项目?
当开始转动时,我们不知道应用到底需要转动到那个项,这个时候我们设置指定项为MAX_VAULE,
让其一直循环转动。
recycler1.smoothScrollToPosition(Integer.MAX_VALUE); recycler2.smoothScrollToPosition(Integer.MAX_VALUE); recycler3.smoothScrollToPosition(Integer.MAX_VALUE);
当应用获取到服务器给的抽奖结果时,根据抽奖结果,可以计算出每个Recycler应该停止的项目。有了停止项,在获取
每个Recycler的当前项。最后计算出还需要滚动的项,代码如下
- private void dealSpinAndWin(JackpotResult winRetInfo)
- {
- int iCount = JackpotAdapter.getProductCount();
- int pos1 = scrollSpeedLinearLayoutManger[0].findFirstVisibleItemPosition();
- int pos2 = scrollSpeedLinearLayoutManger[1].findFirstVisibleItemPosition();
- int pos3 = scrollSpeedLinearLayoutManger[2].findFirstVisibleItemPosition();
- if(pos2<iCount)
- {
- handler.sendEmptyMessageDelayed(MSG_CODE_WIN,500);
- return;
- }
- int index = 0;
- if(winRetInfo==null)
- {
- bSucc = false;
- index = Rnd(0,iCount);
- }
- else
- {
- bSucc = true;
- index = getIndex(winRetInfo);
- }
- int newpos1 = scrollSpeedLinearLayoutManger[0].findFirstVisibleItemPosition() % iCount;
- int newpos2 = scrollSpeedLinearLayoutManger[1].findFirstVisibleItemPosition() % iCount;
- int newpos3 = scrollSpeedLinearLayoutManger[2].findFirstVisibleItemPosition() % iCount;
- if (newpos1 > index) {
- newpos1 = pos1 - (newpos1 - index);
- } else {
- newpos1 = pos1 - (iCount + (newpos1 - index));
- }
- if (newpos3 > index) {
- newpos3 = pos3 - (newpos3 - index);
- } else {
- newpos3 = pos3 - (iCount + (newpos3 - index));
- }
- if (bSucc) {
- if (newpos2 > index) {
- newpos2 = pos2 - (newpos2 - index);
- } else {
- newpos2 = pos2 - (iCount + (newpos2 - index));
- }
- } else {
- if (newpos2 > index) {
- newpos2 = pos2 - (newpos2 - index) - 1;
- } else {
- newpos2 = pos2 - (iCount + (newpos2 - index)) + 1;
- }
- }
- recycler1.smoothScrollToPosition(newpos1 - 1);
- recycler2.smoothScrollToPosition(newpos2 - 1);
- recycler3.smoothScrollToPosition(newpos3 - 1);
- }
看完之后,大家应该基本了解了,如果做抽奖了。这里不多说了。如果大家敢兴趣,可以下载源码试试:
https://github.com/zhao007z4/jackpot
最后,还要唠叨下如果需要适配android4.4,RecylerView最好自定义固定大小,这样可以避免在android4.4中重复计算子项,导致死机。