产品规划要做一个循环滚动展示用户评价的效果,如下图所示,好吧,百度一下,谷歌一下,git上找找,看有没有能用的轮子,一番操作后,TMD,还真没找到能用的。虽然我不提倡重复造轮子,但自己一定要具备造轮子的能力啊,那就自己弄一个呗
在干事之前,得先分析一下思路,算法复杂的画流程图,逻辑不清的画思维导图,分析思路,化繁为简,一步步来
实现思路分析:
public class RecycleCommentWheelAdapterV2 extends BaseQuickAdapter {
public RecycleCommentWheelAdapterV2(@Nullable List data) {
super(R.layout.recycle_rv_item_new_comment_wheel, data);
}
@Override
protected void convert(BaseViewHolder helper, CommentItemInfo item) {
helper.setText(R.id.tv_phone, item.getMobile());
helper.setText(R.id.tv_time, item.getCreate_time());
TextView moneyTv = helper.getView(R.id.tv_money);
moneyTv.setText(StringUtils.getHighlightText(item.getAccount_type() + "收款¥" + item.getRe_money(),
"¥" + item.getRe_money(), Color.parseColor("#FF1A1A")));
RecycleHelper.INSTANCE.setTypefaceDIN(mContext, moneyTv);
helper.setText(R.id.tv_comment, item.getComment());
}
@Nullable
@Override
public CommentItemInfo getItem(int position) {
int realPosition = position % getData().size();
return getData().get(realPosition);
}
@Override
public int getItemViewType(int position) {
int count = getHeaderLayoutCount() + getData().size();
if (count <= 0) {
count = 1;
}
int realPosition = position % count;
return super.getItemViewType(realPosition);
}
@Override
public int getItemCount() {
return Integer.MAX_VALUE;
}
}
关键代码1:getItemCount,返回最大的整形值
关键代码2:getItem,获取到正确位置的数据实体
不啰嗦,直接上完整代码
package com.hdp.testview
import android.content.Context
import android.os.Handler
import android.os.Message
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.MotionEvent
import android.view.View
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import com.huodao.module_recycle.R
import java.lang.ref.WeakReference
import kotlin.math.abs
/**
* author:hdp
* email:[email protected]
* on:2020/4/21 10:46
* desc:
* 自动滚动的RecyclerView
*/
class AutoScrollView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
) : RecyclerView(context, attrs, defStyleAttr) {
private var mPageSize = 2 //可视的条数
private var mEnableScroll: Boolean = true //是否自动滚动
private var mScrollInterval: Long = 3000 //滚动时间间隔
private var mScrollOrientation = 1 //滚动方向
private var mHandler: AutoScrollHandler? = null
companion object {
val TAG = "AutoScrollView"
val SCROLL_MSG = 1001
val COMMENT_MAX_COUNT = 1000L //最多条目
val ORITATION_TOP_2_BOTTOM = 0
val ORITATION_BOTTOM_2_TOP = 1
}
init {
mHandler = AutoScrollHandler(this)
attrs?.let {
val typedArray = context.obtainStyledAttributes(it, R.styleable.AutoScrollView)
mPageSize = typedArray.getInt(R.styleable.AutoScrollView_asv_page_size, 2)
mEnableScroll = typedArray.getBoolean(R.styleable.AutoScrollView_asv_enable_scroll, true)
mScrollInterval = typedArray.getInt(R.styleable.AutoScrollView_asv_scroll_interval, 3000).toLong()
mScrollOrientation = typedArray.getInt(R.styleable.AutoScrollView_asv_scroll_orientation, 0)
typedArray.recycle()
}
}
private fun startLoop() {
if (!mEnableScroll) return
// LogUtils.eTag(TAG, "startLoop")
val layoutManager = layoutManager as LinearLayoutManager
val initPosition = layoutManager.findFirstVisibleItemPosition()
if (initPosition < 10) {
if (mScrollOrientation == ORITATION_TOP_2_BOTTOM) {
scrollToPosition(999)
}
}
mHandler?.sendEmptyMessageDelayed(SCROLL_MSG, 2000)
}
override fun onVisibilityChanged(changedView: View, visibility: Int) {
super.onVisibilityChanged(changedView, visibility)
// LogUtils.eTag(TAG, "onVisibilityChanged:${visibility == View.VISIBLE}")
if (View.VISIBLE != visibility) {
mHandler?.removeCallbacksAndMessages(null)
} else {
startLoop()
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
// LogUtils.eTag(TAG, "onDetachedFromWindow")
mHandler?.removeCallbacksAndMessages(null)
}
override fun onInterceptTouchEvent(e: MotionEvent?): Boolean {
try {
super.onInterceptTouchEvent(e)
} catch (e1: Exception) {
e1.printStackTrace()
}
return false
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
return false
}
class AutoScrollHandler(weakView: AutoScrollView) : Handler() {
private var weakReference: WeakReference? = null
init {
weakReference = WeakReference(weakView)
}
override fun handleMessage(msg: Message?) {
when (msg?.what) {
SCROLL_MSG -> {
val autoScrollView = weakReference?.get()
autoScrollView?.let {
val layoutManger = it.layoutManager as LinearLayoutManager
val lastVisiPosition = layoutManger.findLastVisibleItemPosition()
var toPosition = 0L
if (it.mScrollOrientation == ORITATION_TOP_2_BOTTOM) {
//从上往下滚动
val smoothScroll = object : LinearSmoothScroller(autoScrollView.context) {
override fun getVerticalSnapPreference(): Int {
return SNAP_TO_START
}
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
return 3f / displayMetrics.density
}
}
toPosition = abs(lastVisiPosition - it.mPageSize) % COMMENT_MAX_COUNT
if (toPosition == 1L) {
toPosition = COMMENT_MAX_COUNT
}
if (toPosition > lastVisiPosition || abs(lastVisiPosition - toPosition) >= it.mPageSize + 1) {
layoutManger.scrollToPosition(toPosition.toInt())
} else {
if (layoutManger.isSmoothScrolling.not()) {
smoothScroll.targetPosition = toPosition.toInt()
layoutManger.startSmoothScroll(smoothScroll)
}
}
} else {
//从下往上滚动
val smoothScroll = object : LinearSmoothScroller(autoScrollView.context) {
override fun getVerticalSnapPreference(): Int {
return SNAP_TO_END
}
override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float {
return 3f / displayMetrics.density
}
}
toPosition = abs(lastVisiPosition + 1) % COMMENT_MAX_COUNT
if (toPosition < lastVisiPosition || abs(lastVisiPosition - toPosition) >= it.mPageSize + 1) {
layoutManger.scrollToPosition(toPosition.toInt())
} else {
if (layoutManger.isSmoothScrolling.not()) {
smoothScroll.targetPosition = toPosition.toInt()
layoutManger.startSmoothScroll(smoothScroll)
}
}
}
// LogUtils.eTag(TAG, "lastPosition==$lastVisiPosition,toPosition=$toPosition")
autoScrollView.mHandler?.sendEmptyMessageDelayed(SCROLL_MSG, autoScrollView.mScrollInterval)
}
}
}
}
}
}
核心逻辑就是在handlemessage里面,分别处理两个方向的滚动
override fun onInterceptTouchEvent(e: MotionEvent?): Boolean {
try {
super.onInterceptTouchEvent(e)
} catch (e1: Exception) {
e1.printStackTrace()
}
return false
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
return false
}
override fun onVisibilityChanged(changedView: View, visibility: Int) {
super.onVisibilityChanged(changedView, visibility)
// LogUtils.eTag(TAG, "onVisibilityChanged:${visibility == View.VISIBLE}")
if (View.VISIBLE != visibility) {
mHandler?.removeCallbacksAndMessages(null)
} else {
startLoop()
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
// LogUtils.eTag(TAG, "onDetachedFromWindow")
mHandler?.removeCallbacksAndMessages(null)
}
AutoScrollView需要设置一个固定的总高度,总高度=一个Item的高度*pageSize,笔者这里一个Item的高度是104,显示2个,故总高度设置成208,pageSize设置成2