首页 > 解决方案 > 如何在 Kotlin 的 RecyclerView 中返回位置?

问题描述

我正在使用水平 RecyclerView 和 SnapHelper(以便在移动结束时图像最终位于相同的位置)。

因此,当图像停止移动时,我希望能够在 MainActivity.kt 中显示结果(RecyclerView 位置)?

我不确定这是否需要在适配器或 SnapHelder 中完成?任何帮助都非常感谢 - 我正在努力解决这个问题!

谢谢

用户适配器.kt

class UsersAdapter(
    private val users: ArrayList<User>
    ) : RecyclerView.Adapter<UsersAdapter.DataViewHolder>() {

class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    fun bind(user: User) {
        itemView.textViewUserName.text = user.name
        Glide.with(itemView.imageViewAvatar.context)
            .load(user.avatar)
                .into(itemView.imageViewAvatar)
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
        DataViewHolder(
                LayoutInflater.from(parent.context).inflate(
                        R.layout.item_layout, parent,
                        false
                )
        )

override fun getItemCount(): Int = Int.MAX_VALUE

// Lets say your list had 100 items
override fun onBindViewHolder(holder: DataViewHolder, position: Int) {
    // position can be larger than 100 (ex 101), because our getItemCount doesn't return actual list size
    // so if we receive position as 101, which item should we display?
    // that should be item 1. (for 102 -> 2, 201 -> 1) and so on
    // this suggests use of modules

    val pos = position % users.size
    holder.bind(users[pos])        // bind the actual item

    // Show the number that is being shown
    Log.d(Constraints.TAG, "JH onBindViewHolder:" + pos)
}
}

SnapHelper.kt

class ItemSnapHelper : LinearSnapHelper() {
companion object {
    private const val MILLISECONDS_PER_INCH = 100f
    private const val MAX_SCROLL_ON_FLING_DURATION_MS = 1000
}

private var context: Context? = null
private var helper: OrientationHelper? = null
private var scroller: Scroller? = null
private var maxScrollDistance: Int = 0

override fun attachToRecyclerView(recyclerView: RecyclerView?) {
    if (recyclerView != null) {
        context = recyclerView.context
        scroller = Scroller(context, DecelerateInterpolator())
    } else {
        scroller = null
        context = null
    }
    super.attachToRecyclerView(recyclerView)
}

override fun findSnapView(layoutManager: RecyclerView.LayoutManager?): View? =
        findFirstView(layoutManager, helper(layoutManager))

override fun calculateDistanceToFinalSnap(layoutManager: RecyclerView.LayoutManager, targetView: View): IntArray {
    val out = IntArray(2)
    out[0] = distanceToStart(targetView, helper(layoutManager))
    return out
}

override fun calculateScrollDistance(velocityX: Int, velocityY: Int): IntArray {
    val out = IntArray(2)
    val helper = helper ?: return out

    if (maxScrollDistance == 0) {
        maxScrollDistance = (helper.endAfterPadding - helper.startAfterPadding) / 2
    }

    scroller?.fling(0, 0, velocityX, velocityY, -maxScrollDistance, maxScrollDistance, 0, 0)
    out[0] = scroller?.finalX ?: 0
    out[1] = scroller?.finalY ?: 0
    return out
}

override fun createScroller(layoutManager: RecyclerView.LayoutManager): RecyclerView.SmoothScroller? {
    if (layoutManager !is RecyclerView.SmoothScroller.ScrollVectorProvider)
        return super.createScroller(layoutManager)
    val context = context ?: return null
    return object : LinearSmoothScroller(context) {
        override fun onTargetFound(targetView: View, state: RecyclerView.State, action: Action) {
            val snapDistance = calculateDistanceToFinalSnap(layoutManager, targetView)
            val dx = snapDistance[0]
            val dy = snapDistance[1]
            val dt = calculateTimeForDeceleration(Math.abs(dx))
            val time = Math.max(1, Math.min(MAX_SCROLL_ON_FLING_DURATION_MS, dt))
            action.update(dx, dy, time, mDecelerateInterpolator)
        }

        override fun calculateSpeedPerPixel(displayMetrics: DisplayMetrics): Float =
                MILLISECONDS_PER_INCH / displayMetrics.densityDpi
    }
}

private fun distanceToStart(targetView: View, helper: OrientationHelper): Int {
    val childStart = helper.getDecoratedStart(targetView)
    val containerStart = helper.startAfterPadding
    return childStart - containerStart
}

private fun findFirstView(layoutManager: RecyclerView.LayoutManager?, helper: OrientationHelper): View? {
    if (layoutManager == null) return null

    val childCount = layoutManager.childCount
    if (childCount == 0) return null

    var absClosest = Integer.MAX_VALUE
    var closestView: View? = null
    val start = helper.startAfterPadding

    for (i in 0 until childCount) {
        val child = layoutManager.getChildAt(i)
        val childStart = helper.getDecoratedStart(child)
        val absDistanceToStart = Math.abs(childStart - start)
        if (absDistanceToStart < absClosest) {
            absClosest = absDistanceToStart
            closestView = child
        }
    }
    return closestView
}

private fun helper(layoutManager: RecyclerView.LayoutManager?): OrientationHelper {
    if (helper == null) {
        helper = OrientationHelper.createHorizontalHelper(layoutManager)
    }

    return helper!!
}
}

MainActivity.kt

class MainActivity : AppCompatActivity() {

lateinit var adapter: ConcatAdapter
lateinit var userVerticalAdapter: UsersAdapter

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    setupDataInRecyclerView()
    
}

private fun setupDataInRecyclerView() {
    recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
    userVerticalAdapter = UsersAdapter(DataSource.getUser())

    val listOfAdapters = listOf(userVerticalAdapter)
    adapter = ConcatAdapter(listOfAdapters)
    recyclerView.adapter = adapter

    // When RV is loaded scroll it to middle, so that user doesn't hit limit on both ends(easily)
    recyclerView.scrollToPosition(Int.MAX_VALUE/2)

    //addItemDecoration(SpaceItemDecoration(this, R.dimen.divider_space))

    ItemSnapHelper().attachToRecyclerView(recyclerView)
}

public fun ShowWhatRecieved(isitthere: Int){
    ShowMeIt.text = isitthere.toString()
}
}

标签: androidkotlin

解决方案


推荐阅读