• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

陈文管的博客

分享有价值的内容

  • Android
  • Affiliate
  • SEO
  • 前后端
  • 网站建设
  • 自动化
  • 开发资源
  • 关于

Android 弧形 RecyclerView 实现(Kotlin)

2023年6月12日发布 | 最近更新于 2023年8月24日

项目改版需要实现一个圆弧效果的滑动列表,网上没找到很好的开源实现,自己改了一版,给出具体实现步骤和源码,以下是项目实现效果截图。

Android圆弧列表实现

一、实现步骤

要求:当前选中的项要居中显示,总共要显示5个可见列表项,前后要各填充两个空数据,列表要以圆弧效果滚动,滑动停止之后要进行居中校正显示处理。

思路:监听列表滑动事件,在滑动的时候动态计算设置每个列表项距离顶部的距离,在滑动停止之后获取当前第一个可见列表项,平滑滚动到居中位置。

这个只是一个简单的基础数学题,滑动的时候计算设置GF两点的距离值即可,整个RecyclerView列表当做圆的一部分弧形区域。

三角形勾股定理

1. 列表滚动监听

在onScrolled方法中监听滚动,动态计算每个列表项需要距离顶部的值,来实现滑动的时候圆弧滚动效果。在onScrollStateChanged方法中,监听SCROLL_STATE_IDLE状态,进行居中校正。

mRVList?.addOnScrollListener(object : RecyclerView.OnScrollListener() {
    var isManualScroll = false
    override fun onScrollStateChanged(@NonNull recyclerView: RecyclerView, newState: Int) {
        super.onScrollStateChanged(recyclerView, newState)
        when (newState) {
            RecyclerView.SCROLL_STATE_IDLE -> {
                if (isManualScroll) {
                    var manager = recyclerView.layoutManager as LinearLayoutManager
                    var firstVisibleItemPosition = manager.findFirstVisibleItemPosition()
                    syncShow(firstVisibleItemPosition)
                }
                isManualScroll = false
            }
            RecyclerView.SCROLL_STATE_DRAGGING -> {
                isManualScroll = true
            }
        }
    }
    override fun onScrolled(@NonNull recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)
        for (i in 0 until recyclerView.childCount) {
            val paddingTop: Int = calculateMargin(recyclerView.getChildAt(i).left)
            recyclerView.getChildAt(i).setPadding(0, paddingTop, 0, 0)
        }
    }
})
private fun calculateMargin(marginLeft: Int): Int {
    val display = resources.displayMetrics
    val widthPixel = display.widthPixels.toDouble()
    val halfItemWidth = mArcAdapter?.dp2px(20f) ?:0
    // 偏离中点距离(AH)
    val offset = Math.abs((widthPixel / 2).minus(marginLeft.plus(halfItemWidth)))
    // 直角三角形一条直角边(OG)
    val height = Math.sqrt(Math.pow(widthPixel * 2, 2.0) - Math.pow(offset, 2.0))
   // 距离顶部的值就是圆弧半径(OH)-直角边(OG)
    val marginTop = widthPixel * 2 - height
    return marginTop.toInt()
}

上面的代码中,列表项宽度设置为40dp,圆弧的半径是屏幕宽度的两倍,参数根据自己实际需求调整即可。

2. 居中校正平滑滚动处理

实现设置LinearSmoothScroller对象,calculateTimeForScrolling设置滚动的时间,单位毫秒,让滚动更平滑。

private fun syncShow(position: Int) {
    mRVList?.smoothSnapToPosition(position)
    mArcAdapter?.firstVisiblePosition = position
    mArcAdapter?.notifyDataSetChanged()
}

fun RecyclerView.smoothSnapToPosition(
    position: Int,
    snapMode: Int = LinearSmoothScroller.SNAP_TO_START
) {
    val smoothScroller = object : LinearSmoothScroller(this.context) {
        override fun getVerticalSnapPreference(): Int = snapMode
        override fun getHorizontalSnapPreference(): Int = snapMode
        override fun calculateTimeForScrolling(dx: Int): Int {
            return 250
        }
    }
    smoothScroller.targetPosition = position
    layoutManager?.startSmoothScroll(smoothScroller)
}

3. 点击列表项设置居中

增加点击列表项的时候的居中校正处理,保证选中项始终显示在中间位置。

object: AdapterView.OnItemClickListener {
    override fun onItemClick(p0: AdapterView<*>?, p1: View?, position: Int, p3: Long) {
        if (position > 1 && position < (mArcAdapter?.list?.size ?:0 - 2)) {
            syncShow(position - 2)
        }
    }
}

RecyclerView并没有setOnItemClickListener接口,需要在ViewHolder中实现

inner class ItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), View.OnClickListener {
    val mTvTitle: TextView = itemView.findViewById(R.id.mTvTitle)

    init {
        itemView.setOnClickListener(this)
    }

    override fun onClick(view: View?) {
        onItemClickListener?.onItemClick(null, view, getAdapterPosition(), (view?.id ?:0).toLong());
    }
}

二、项目源码

https://github.com/wenguan0927/ArcRecyclerView

扩展阅读:

美图手机音乐Widget动画实现

Android 心率动画自定义控件实现

Android 卡片旋转切换动效实现详解

Android 残影数字动画实现详解

转载请注明出处:陈文管的博客 – Android 弧形RecyclerView实现

博客公众号

微信公众号 扫一扫关注

文章目录

  • 一、实现步骤
    • 1. 列表滚动监听
    • 2. 居中校正平滑滚动处理
    • 3. 点击列表项设置居中
  • 二、项目源码
博客公众号

闽ICP备18001825号-1 · Copyright © 2025 · Powered by chenwenguan.com