Android recycleview(kotlin)实现上下滚动,类似中奖信息跑马灯

数据展示我们一般都是通过recycleview来处理,下面记录一下滚动需求的实现方法和步骤:

先看看效果:

第一步:

新建一个实体类(Wininfo ):

 class Wininfo {
    var title: String? = null
    var test: String? = null

}

第二:新建revy的适配器(MyAdapterItem_auto):



/**
 * 适配器
 */
public class MyAdapterItem_auto extends RecyclerView.Adapter<MyAdapterItem_auto.ViewHolder> {

    List<Wininfo> list;
    Context context;
    private boolean bool;
    public MyAdapterItem_auto(List<Wininfo> list, Context context) {
        this.list = list;
        this.context = context;

    }

    //创建新View,被LayoutManager所调用
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_recywin, viewGroup, false);
        ViewHolder vh = new ViewHolder(view);
        return vh;
    }

    //将数据与界面进行绑定的操作
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int position) {
        Wininfo wininfo = list.get(position);
        viewHolder.tv_title.setText(wininfo.getTitle() + ":\n");
        viewHolder.tv_test.setText(wininfo.getTest());

    }

    //获取数据的数量
    @Override
    public int getItemCount() {
           return list == null ? 0 : list.size();

    }

    //自定义的ViewHolder,持有每个Item的的所有界面元素
    class ViewHolder extends RecyclerView.ViewHolder {
        TextView tv_title, tv_test;  

        ViewHolder(View view) {
            super(view);
            tv_title = view.findViewById(R.id.tv_title);
            tv_test = view.findViewById(R.id.tv_test);

        }
    }
}

适配器里面的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/tv_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="4"
        android:gravity="center"
        android:textSize="50sp"
        android:text="烧鸭饭"/>
    <TextView
        android:id="@+id/tv_test"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:textSize="50sp"

        android:text="恭喜手机尾号123xxxxxxxx中奖啦"/>
</LinearLayout>

 第三;重新自定义recycleview(AutoPollRecyclerView):

package com.example.test_01.recy;

import android.content.Context;


import android.util.AttributeSet;
import android.view.MotionEvent;

import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;

import java.lang.ref.WeakReference;

public class AutoPollRecyclerView extends RecyclerView {
    private static final long TIME_AUTO_POLL =1;
    AutoPollTask autoPollTask;
    private boolean running; //标示是否正在自动轮询
    private boolean canRun;//标示是否可以自动轮询,可在不需要的是否置false

    public AutoPollRecyclerView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        autoPollTask = new AutoPollTask(this);
    }

    static class AutoPollTask implements Runnable {
        private final WeakReference<AutoPollRecyclerView> mReference;

        //使用弱引用持有外部类引用->防止内存泄漏
        public AutoPollTask(AutoPollRecyclerView reference) {
            this.mReference = new WeakReference<AutoPollRecyclerView>(reference);
        }

        @Override
        public void run() {
            AutoPollRecyclerView recyclerView = mReference.get();
            if (recyclerView != null && recyclerView.running && recyclerView.canRun) {
                recyclerView.scrollBy(2, 2);
                recyclerView.postDelayed(recyclerView.autoPollTask, recyclerView.TIME_AUTO_POLL);
            }
        }
    }

    //开启:如果正在运行,先停止->再开启
    public void start() {
        if (running)
            stop();
        canRun = true;
        running = true;
        postDelayed(autoPollTask, TIME_AUTO_POLL);
    }

    public void stop() {
        running = false;
        removeCallbacks(autoPollTask);
    }

    @Override
    public boolean onTouchEvent(MotionEvent e) {
        switch (e.getAction()) {
            case MotionEvent.ACTION_DOWN:
                if (running)
                    stop();
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_OUTSIDE:
                if (canRun)
                    start();
                break;
        }
        //return  false,注释掉onTouchEvent()方法里面的stop和start方法,则列表自动滚动且不可触摸
        return super.onTouchEvent(e);}
}

第四步 无缝数据底部回到顶部(RecyclerViewScrollHelper ):

public class RecyclerViewScrollHelper {
    public static void scrollToPosition(RecyclerView recyclerView, int position){
        RecyclerView.LayoutManager manager1 = recyclerView.getLayoutManager();
        if (manager1 instanceof LinearLayoutManager) {
            LinearLayoutManager manager = (LinearLayoutManager) manager1;
            final TopSmoothScroller mScroller = new TopSmoothScroller(recyclerView.getContext());
            mScroller.setTargetPosition(position);
            manager.startSmoothScroll(mScroller);
        }
    }

    public static class TopSmoothScroller extends LinearSmoothScroller {
        TopSmoothScroller(Context context) {
            super(context);
        }
        @Override
        protected int getHorizontalSnapPreference() {
            return SNAP_TO_START;
        }
        @Override
        protected int getVerticalSnapPreference() {
            return SNAP_TO_START;
        }
    }
}

第五步  新建测试的activity的布局(activity_recy):

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    tools:context=".recy.RecyActivity">

    <com.example.test_01.recy.AutoPollRecyclerView
        android:id="@+id/recy01"
        android:layout_width="match_parent"
        android:layout_height="300dp"/>
</RelativeLayout>

第六步  activity测试:

package com.example.test_01.recy

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.test_01.R
import kotlinx.android.synthetic.main.activity_recy.*
import java.util.*

class RecyActivity : AppCompatActivity() {
    //滚动版
    var myAdapterItem_doctor_auto: MyAdapterItem_auto? = null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_recy)
        var list: MutableList<Wininfo>? = ArrayList()
        for (s in 0..9) {
            var tt = Wininfo()
            tt.test = "恭喜手机尾号18xxxxxx3541中奖"
            tt.title = "奶茶店$s"
            list!!.add(tt)
        }

        //垂直方向
        val linearLayoutManager = LinearLayoutManager(this)
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL)
        recy01.setLayoutManager(linearLayoutManager)
        myAdapterItem_doctor_auto = MyAdapterItem_auto(list, this) //滚动版

        recy01.setAdapter(myAdapterItem_doctor_auto)
        recy01.start()
        recy01.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                super.onScrollStateChanged(recyclerView, newState)
            }

            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)
                if (isSlideToBottom(recyclerView)) {
                    // LogUtils.e("是否滑动到底部?" + isSlideToBottom(recyclerView) + "");
                    runOnUiThread(Runnable { // recy_doctor_all.scrollToPosition(0);
                        RecyclerViewScrollHelper.scrollToPosition(recy01, 0)
                    })
                }
            }


        })
    }

    private fun isSlideToBottom(recyclerView: RecyclerView?): Boolean {
        if (recyclerView == null) return false
        return if (recyclerView.computeVerticalScrollExtent() + recyclerView.computeVerticalScrollOffset() >= recyclerView.computeVerticalScrollRange()) true else false
    }
}

 到这里就实现了滚动,虽然这不是最好的办法,我想要的是效果不用从底部跳到0项数据开始滚动,而是从最后一项直接拼接到首项0开始继续循环下去,如果你有更好的方式,评论留言交流一下,实现的方式。

 

------------------2020、7、20---记录---------------------------------------

java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{30583c0 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} ,长时间运行的话,会出现这个问题,我在数据滑动之前会执行list.clear的方法,不知道是不是这个原因造成的,引用一位大佬的文章,参考一下里面的内容:

http://www.bubuko.com/infodetail-1452093.html

https://blog.csdn.net/fangxincxy/article/details/100740052

 

------------------2020、7、27--使用出现的问题记录-----------------------------------

由于上面的方式放在实际项目中,还是会出现IndexOutOfBoundsException,所以让 他滚动到最底部,先让她延迟一秒,避免过快回到回到顶部,造成影响。



        recy01.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (recyclerView == null) {
                    return;
                }
                if (isSlideToBottom(recyclerView) && isSlideTo == true) {
                    LogUtils.e("是否滑动到底部?" + isSlideToBottom(recyclerView));
                    handler.postDelayed(new RecycleviewRunable(), 1000);
                }
            }
        });

    

    private class RecycleviewRunable implements Runnable {
        @Override
        public void run() {
            // RecyclerViewScrollHelper.scrollToPosition(recy_doctor_all, 0);
            recy01.scrollToPosition(0);
        }
    }

由于这种错误在项目运行很久的情况下才出现,这样处理后,的确可以一定程度上解决了问题,但是很大的问题上,是在recycleview的数据在滚动过程中,自己去测试重复打开和隐藏页面,都会造成这个数组下标的问题,我这边代码逻辑处理没写好,导致在页面切换的时候,线程那些处理,也是一个潜在的因素。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值