使用场景
  • 有时我们可能会有一个列表,不要求一下子全部显示,让其自行进行进行上下滚动显示。
解决方案
  • 对于列表我们会想到ListView或者RecyclerView,但是要使其自动的无线滚动的话,因为是对布局的内容进行滑动,所以我们可以考虑使用ScrollTo()/ScrollBy()以及动画。在这里我们可以考虑使ScrollBy()来实现布局内容的滑动。
解决步骤
  • 1.解决列表滑动问题
  • 1.自定义RecyclerView,实现Runable接口。
  • 2.通过PostDelayed()发送延迟消息。
  • 3.在run方法中,通过scrollBy()对RecyclerView进行滑动处理,并再次发送延迟消息
  • 4.在onDetachedFromWindow()中移除延迟消息,停止其滑动。
  • 2.解决列表无线滚动
  • 对于无线滚动,我们只需要让列表的个数尽可能无线就可以了,所以我们只需要让列表的getItemCount()返回数值尽可能大就行
  • 3.解决用户触摸事件
  • 对于用户触摸有两种解决方式
1.不处理用户事件,即用户触摸对滑动无影响,继续滚动。


2.用户触摸后停止滚动,等用户松开后继续滚动。
具体实现
  • 1.自定义RecyclerView,在onAttachedToWindow()中通过PostDealyed()发送延迟消息来开始滚动(在View被添加到界面时触发该方法),在onDetachedFromWindow()中通过removeCallbacks()来停止滚动(在View从界面移除时触发)。
import android.content.Context
  	import android.support.v7.widget.RecyclerView
  	import android.util.AttributeSet
  	import android.view.MotionEvent
  	 
  	/**
  	 * Author:mj
  	 * Time: 2018/10/9 16:27
  	 * 描述:
  	 * Version:
  	 */
  	class AutoVerticalRollRecyclerView @JvmOverloads constructor(
  	        context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
  	) : RecyclerView(context, attrs, defStyleAttr), Runnable {
  	
  	    /**是否正在滑动*/
  	    private var mIsRolling = false
  	
  	    /**
  	     * View被添加到界面时触发
  	     */
  	    override fun onAttachedToWindow() {
  	        super.onAttachedToWindow()
  	        startRoll()
  	    }
  	
  	    /**
  	     * View从界面移除时触发
  	     */
  	    override fun onDetachedFromWindow() {
  	        super.onDetachedFromWindow()
  	        stopRoll()
  	    }
  	
  	    /**
  	     * 开始滑动
  	     */
  	    private fun startRoll() {
  	        //已经滑动时/没有设置适配器时直接返回
  	        if (mIsRolling && adapter == null) return
  	        mIsRolling = true
  	        postDelayed(this,30)
  	    }
  	
  	    /**
  	     * 停止滑动
  	     */
  	    private fun stopRoll() {
  	        if(!mIsRolling)  return
  	        mIsRolling=false
  	        removeCallbacks(this)
  	    }
  	
  	
  	    override fun run() {
  	        if(this!=null&&this.mIsRolling){
  	            scrollBy(0,2)
  	            postDelayed(this,30)
  	        }
  	    }
  	
  	
  	    /**
  	     * 事件触摸:
  	     * 1.若让滑动不受用户触摸影响,直接返回false,表示不处理事件
  	     * 2.若需要在用户触摸时停止,用户离开时开始,只需要根据情况触摸事件进行处理即可
  	     */
  	    override fun onTouchEvent(e: MotionEvent?): Boolean {
  	        //1.若让滑动不受用户触摸影响,直接返回false,表示不处理事件
  	        return false
  	        //2.若需要在用户触摸时停止,用户离开时开始,只需要根据情况触摸事件进行处理即可
  	//        when(e?.action){
  	//            MotionEvent.ACTION_DOWN,MotionEvent.ACTION_MOVE -> stopRoll()
  	//            MotionEvent.ACTION_UP,MotionEvent.ACTION_CANCEL,MotionEvent.ACTION_OUTSIDE -> startRoll()
  	//        }
  	//        return super.onTouchEvent(e)
  	    }
  	}
  • 2.自定义Adapter,在getItemCount()方法中返回最大值
class SimpleAdapter(list: MutableList<String>, mContext: Context) : RecyclerView.Adapter<SimpleAdapterViewHolder>() {
  
      /**数据源*/
      private var list: MutableList<String> = list
      /**上下文*/
      private var mContext: Context = mContext
  
      override fun onCreateViewHolder(p0: ViewGroup, p1: Int): SimpleAdapterViewHolder {
          val view=LayoutInflater.from(mContext).inflate(R.layout.item_layout,p0,false)
          return SimpleAdapterViewHolder(view)
      }
  
      /**
       * 为了实现无线循环,需要将数据的源的个数设置为比较大的值
       */
      override fun getItemCount(): Int {
          return Int.MAX_VALUE
      }
  
      override fun onBindViewHolder(p0: SimpleAdapterViewHolder, p1: Int) {
          p0.mTvData?.text=list!![p1%list!!.size]
      }
  }
  • 自定义ViewHolder
class SimpleAdapterViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

      var mTvData: TextView? = null
  
      init {
          mTvData = itemView.findViewById(R.id.tvData)
      }
  
  }
  • item布局:item_layout
<?xml version="1.0" encoding="utf-8"?>
  <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      xmlns:app="http://schemas.android.com/apk/res-auto">
     <TextView
         android:id="@+id/tvData"
         android:layout_width="match_parent"
         android:layout_height="30dp"
         android:text="数据"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintLeft_toLeftOf="parent"
         app:layout_constraintRight_toRightOf="parent"
         android:textSize="15sp"
         android:gravity="center"/>
  </android.support.constraint.ConstraintLayout>
  • 主布局
<?xml version="1.0" encoding="utf-8"?>
  <android.support.constraint.ConstraintLayout 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"
      tools:context=".ui.MainActivity">
  
      <com.view.widget.AutoVerticalRollRecyclerView
          android:id="@+id/mRecyclerView"
          android:layout_width="match_parent"
          android:layout_height="130dp"
          app:layout_constraintLeft_toLeftOf="parent"
          app:layout_constraintRight_toRightOf="parent"
          app:layout_constraintTop_toTopOf="parent" />
  
  </android.support.constraint.ConstraintLayout>
  • 具体代码调用
var list= mutableListOf<String>()
  for (i in 0 until  10){
      list.add("数据$i")
  }
  mRecyclerView.layoutManager=LinearLayoutManager(this)
  mRecyclerView.adapter=SimpleAdapter(list,this)
  • 效果图