首页 > 其他分享 >recycleview 滑动辅助

recycleview 滑动辅助

时间:2024-11-01 10:32:13浏览次数:1  
标签:辅助 val Int RecyclerView recycleview fun 滑动 layoutManager recyclerView

import android.content.Context
import android.graphics.Rect
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.LinearSmoothScroller
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.delay
import java.lang.ref.SoftReference
import kotlin.math.abs
import kotlin.math.min
import kotlin.math.sqrt

/**

  • https://www.jianshu.com/p/9ec5098655b7

  • 自动播放的工具
    */
    class AutoPlayTool {
    val tag = "AutoPlayTool"

    //辅助接口
    public interface ISelectItemListener {
    /**
    * 参数1与参数2相等则是同一个,无需处理
    * 参数1与参数2不相等,应该停止掉参数2,播放参数1
    */
    fun onItem(new: Int, old: Int)
    }

    private var softSelectItemListener: SoftReference? = null
    private var visiblePercent = 1

    /**
    *热点区域,最接近这个位置的则锚定
    */
    var anchorPoint = 0

    constructor(visiblePercent: Int = 1) {
    this.visiblePercent = visiblePercent
    }

    /**

    • 当滑动停止的时候,开始视频播放
    • @param recyclerView
    • @return
      */
      @Deprecated("")
      fun onActiveWhenNoScrolling(recyclerView: RecyclerView, y: Int): Int {
      val index = calculateIndex(recyclerView, y)
      smoothScrollToPosition(calculateIndex(recyclerView, y))
      return index
      }

    /**

    • 获取可见百分比
    • @param v
    • @return
      */
      private fun getVisiblePercent(v: View): Int {
      val r = Rect()
      val visible = v.getLocalVisibleRect(r)
      if (visible && v.measuredHeight > 0) {
      val percent = 100 * r.height() / v.measuredHeight
      return percent
      }
      return -1
      }

    private fun getVisible(v: View, value: Int): Boolean {
    val r = Rect()
    val visible = v.getLocalVisibleRect(r)
    if (visible && v.visibility == View.VISIBLE) {
    return if (getVisiblePercent(v) >= value) {
    true
    } else {
    false
    }
    }
    return false
    }

    var ss: RecyclerView.OnScrollListener = object : RecyclerView.OnScrollListener() {
    var maxY: Int = 0
    var talY: Int = 0

     override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
         super.onScrollStateChanged(recyclerView, newState)
         if (newState == RecyclerView.SCROLL_STATE_IDLE) {
             recyclerView.removeOnScrollListener(this)
             smoothScrollToPosition(calculateIndex(recyclerView, talY))
    

// onActiveWhenNoScrolling(recyclerView, talY)
maxY = 0
talY = 0
}
}

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)
        Log.d("定位", "onScrolled Y=$dy")
        if (abs(dy.toDouble()) > abs(maxY.toDouble())) {
            maxY = dy
        }
        talY += dy
    }
}
var lastPlay = -1
fun smoothScrollToPosition(position: Int, finish: (() -> Unit)? = null) {
    val viewLocation = IntArray(2)
    withRecyclerView.getLocationOnScreen(viewLocation)
    Log.d(tag, "锚定位置${anchorPoint} 当前RecycleView Y=" + viewLocation[1])
    withRecyclerView.smoothScrollToPositionWithOffset(position, anchorPoint - viewLocation[1]) {
        softSelectItemListener?.get()?.onItem(position, lastPlay)
        Log.d(tag, "新位置$position 旧位置$lastPlay")
        lastPlay = position
        finish?.invoke()
    }
}

fun smoothScrollToPosition1(position: Int, finish: (() -> Unit)? = null) {
    val viewLocation = IntArray(2)
    withRecyclerView.getLocationOnScreen(viewLocation)
    Log.d(tag, "锚定位置${anchorPoint} 当前RecycleView Y=" + viewLocation[1])
    withRecyclerView.smoothScrollToPositionWithOffset1(
        position,
        anchorPoint - viewLocation[1]
    ) {
        softSelectItemListener?.get()?.onItem(position, lastPlay)
        Log.d(tag, "新位置$position 旧位置$lastPlay")
        lastPlay = position
        finish?.invoke()
    }
}

private lateinit var withRecyclerView: RecyclerView
fun attachToRecyclerView(recyclerView: RecyclerView) {
    withRecyclerView = recyclerView
    //增加一层代理,防止移动过程中造成的自动触发跳屏
    recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)
            if (newState == RecyclerView.SCROLL_STATE_DRAGGING) {
                recyclerView.removeOnScrollListener(ss)
                recyclerView.addOnScrollListener(ss)
            }
        }
    })
}

fun withToRecyclerView(recyclerView: RecyclerView) {
    withRecyclerView = recyclerView
}

/**
 * 计算位置,滑动方向影响计算方式
 *
 * @param recyclerView
 * @param direction 0表示未滑动,1表示向上滑(内容底部到顶部),-1表示下拉(内容从顶部到底部)
 * @return
 */
fun calculateIndex(recyclerView: RecyclerView, direction: Int = 0): Int {
    var layoutManager: LinearLayoutManager? = null
    var position = -1
    if (recyclerView.layoutManager is LinearLayoutManager) {
        layoutManager = recyclerView.layoutManager as LinearLayoutManager?
    }
    val viewLocation = IntArray(2)
    recyclerView.getLocationOnScreen(viewLocation)
    Log.d(tag, "RecycleView Y=" + viewLocation[1])
    if (layoutManager != null) {
        var firstItemPosition = layoutManager.findFirstVisibleItemPosition()
        val lastItemPosition = layoutManager.findLastVisibleItemPosition()
        val items: LinkedHashMap<Int, RecyclerView.ViewHolder> = LinkedHashMap()
        while (firstItemPosition <= lastItemPosition) {
            val holder = recyclerView.findViewHolderForLayoutPosition(firstItemPosition)
            val view = holder?.itemView
            if (view != null && getVisible(view, visiblePercent)) {
                items[firstItemPosition] = holder
            }
            firstItemPosition++
        }
        //最小距离
        var minDistance = Int.MAX_VALUE
        //找出距离中间最近的一个
        for ((key, value) in items) {
            val itemDistance = calculatedDistance(value.itemView, direction = direction)
            if (itemDistance < minDistance) {
                minDistance = itemDistance
                position = key
            }
        }
    }
    return position
}


/**
 * 计算视图距离屏幕中心的距离。
 * 该方法通过获取视图在屏幕上的位置,然后计算该位置与屏幕中心垂直距离的绝对值。
 * 这样做的目的是为了评估视图与屏幕中心的相对位置,用于某些基于位置的布局或交互逻辑。
 *
 * @param view 要计算距离的视图对象。
 * @param point 屏幕目标绝对位置。
 * @param direction 0表示未滑动,1表示向上滑(内容底部到顶部),-1表示下拉(内容从顶部到底部)
 * @return 视图距离屏幕中心的垂直距离的绝对值。
 */
private fun calculatedDistance(view: View, point: Int = anchorPoint, direction: Int = 0): Int {
    val viewLocation = IntArray(2)
    view.getLocationOnScreen(viewLocation)
    //检测用户意图偏移量
    val tagPoint = when (direction) {
        in 1..Int.MAX_VALUE -> { //上滑动
            point + (view.height * 0.8).toInt()
        }

        in Int.MIN_VALUE..(-1) -> {//拉下滑动
            // 处理小于等于-1的情况
            point - (view.height * 0.8).toInt()
        }

        else -> {
            point
        }
    }
    return abs((viewLocation[1] - tagPoint).toDouble()).toInt()
}

}

private fun RecyclerView.smoothScrollToPositionWithOffset(
position: Int,
offset: Int,
finish: (() -> Unit)? = null
) {
val linearSmoothScroller = object : LinearSmoothScroller(context) {
override fun onTargetFound(
targetView: View,
state: RecyclerView.State,
action: Action
) {
super.onTargetFound(targetView, state, action)
val dx = calculateDxToMakeVisible(targetView, horizontalSnapPreference)
val dy = calculateDyToMakeVisible(targetView, SNAP_TO_START)

        val distance = sqrt((dx * dx + dy * dy).toDouble()).toInt()
        val time = calculateTimeForDeceleration(distance)
        if (time > 0) {
            action.update(-dx, -dy - offset, time, mDecelerateInterpolator)
        }
    }

    override fun onStop() {
        super.onStop()
        finish?.invoke()
    }
}
linearSmoothScroller.targetPosition = position
layoutManager?.startSmoothScroll(linearSmoothScroller)

}

private fun RecyclerView.smoothScrollToPositionWithOffset1(
position: Int,
offset: Int,
finish: (() -> Unit)? = null
) {
(layoutManager as? LinearLayoutManager)?.scrollToPositionWithOffset(position, offset)
post { finish?.invoke() }

}

/**

  • 寻找完全可见的item
  • @param last 是否是最后一个
  • @return 下标
    */
    fun RecyclerView.findCompletelyVisibleItemPosition(last: Boolean = false): Int {
    var completelyVisibleItemPosition = -1
    // 滑动结束,获取第一个完全可见的 item
    val layoutManager = layoutManager
    if (layoutManager is LinearLayoutManager) {
    // 对于 LinearLayoutManager
    completelyVisibleItemPosition =
    if (last) layoutManager.findLastCompletelyVisibleItemPosition() else layoutManager.findFirstCompletelyVisibleItemPosition()
    } else if (layoutManager is GridLayoutManager) {
    completelyVisibleItemPosition =
    if (last) layoutManager.findLastCompletelyVisibleItemPosition() else layoutManager.findFirstCompletelyVisibleItemPosition()
    }
    return completelyVisibleItemPosition
    }

/**

  • 获取可见百分比
  • @param v
  • @return
    */
    fun View.getVisiblePercent(): Int {
    val r = Rect()
    val visible = getLocalVisibleRect(r)
    if (visible && measuredHeight > 0) {
    val percent = 100 * r.height() / measuredHeight
    return percent
    }
    return 0
    }

标签:辅助,val,Int,RecyclerView,recycleview,fun,滑动,layoutManager,recyclerView
From: https://www.cnblogs.com/lizhanqi/p/18519665

相关文章

  • Autodesk AutoCAD 2025.1 (macOS, Windows) - 自动计算机辅助设计软件
    AutodeskAutoCAD2025.1(macOS,Windows)-自动计算机辅助设计软件AutoCAD2024开始原生支持AppleSilicon请访问原文链接:https://sysin.org/blog/autodesk-autocad/查看最新版。原创作品,转载请保留出处。作者主页:sysin.org具有设计自动化以及工具组合、Web和移动应......
  • AI 辅助编程的效果如何衡量?
    作者:耘越本文主要介绍了如何度量研发效能,以及AI辅助编程是如何影响效能的,进而阐述如何衡量AI辅助编程带来的收益。理解度量:有效区分度量指标为了帮助研发团队更好地理解和度量研发效能,可以将指标分为三类:能力和行为指标、交付效能指标和业务结果指标。该分类有助于从不同维度评......
  • 自动化滑动极验v3示例
    importrandomimportddddocrfromplaywright.sync_apiimportsync_playwrightimporttimeimportrequestswithsync_playwright()asp:det=ddddocr.DdddOcr(det=False,ocr=False)browser=p.chromium.launch(headless=False,args=['-......
  • ChatGPT-o1在辅助论文参考文献写作中的表现如何?有哪些提升?
    学境思源,一键生成论文初稿:AcademicIdeas-学境思源AI论文写作ChatGPT-o1简介ChatGPT-o1是OpenAI推出的最新大模型,通过强化学习方法,提升了复杂推理能力,在数学、编程、物理和化学等复杂领域的基准测试中,达到了接近博士生的水平。这使得它在处理学术论文中的复杂问题时更为得......
  • Springboot计算机毕业设计高校教学辅助管理系统95xv7
    Springboot计算机毕业设计高校教学辅助管理系统本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能:学生,教师,课程类别,网上课堂,学生考勤,学生成绩开题报告内容一、项目背景与意义随着信息技术的快......
  • C++算法练习-day26——239.滑动窗口的最大值
    题目来源:.-力扣(LeetCode)题目思路分析题目:给定一个整数数组 nums 和一个整数 k,请找出该数组中所有长度为 k 的子数组中的最大元素,并返回这些最大元素组成的数组。思路:滑动窗口:这是一个典型的滑动窗口问题,其中窗口的大小为 k。我们需要遍历整个数组,同时保持一......
  • 239. 滑动窗口最大值(难)
    目录题目法一、暴力枚举法二、双端队列题目给你一个整数数组nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。法一、暴力枚举遍历数组,获取每个窗口的子数......
  • 【无人机路径规划】基于深度强化学习的多无人机辅助边缘计算网络路径规划(Matlab代码实
    ......
  • Unity 滑动条 SlideView
    usingUnityEngine;usingSystem.Collections;usingUnityEngine.UI;publicclassSlideView:MonoBehaviour{publicSliderslide;publicScrollbarsb;//UsethisforinitializationvoidStart(){if(transform.name=="Sc......
  • 在C语言中进行网络编程时,有哪些辅助工具可用
    标题:在C语言中进行网络编程时,有哪些辅助工具可用?在C语言中进行网络编程时,可用的辅助工具包括套接字库(如Winsock、BSDSockets)、协议库(如OpenSSL)、网络调试工具(如Wireshark)、以及集成开发环境(如Eclipse、VisualStudio)。这些工具为开发者提供了强大的支持,使得在C语言中进行网络编......