はじめに

RecyclerViewでのアイテム一覧画面で、スワイプ後に指を離した時、アイテムが中心に来るように自動スクロールする処理を作成。
ViewPager2でも作成可能だが、今回はRecyclerViewで作成。
方法
アイテムが中心に来るように自動スクロールするには、LinearSnapHelper
を使用。
両端のオフセットは、ItemDecoration
を使用。
中心アイテムが変更されたことを検知するためには、OnScrollListener
を使用。
プログラムのポイントとしては、MainActivity.kt
内の処理。
まず、カードビューのレイアウト。テキストビューを配置。
list_item.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/text"
android:layout_width="280dp"
android:layout_height="160dp"
android:layout_marginHorizontal="8dp"
android:background="@color/main"
android:gravity="center"
android:textColor="@color/white"
android:textSize="28sp"
tools:text="1"/>
メイン画面。RcyclerViewを配置。
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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"
android:background="@color/white">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="0dp"
android:layout_height="160dp"
android:orientation="horizontal"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="@layout/list_item"/>
</androidx.constraintlayout.widget.ConstraintLayout>
アダプタークラス。selectItemIndex
で中心アイテムのインデックスを指定し、背景色の変更を行う。
ItemAdapter.kt
class ItemAdapter : RecyclerView.Adapter<ItemAdapter.ViewHolder>() {
var selectItemIndex = 0
set(value) {
field = value
notifyDataSetChanged()
}
class ViewHolder(val binding: ListItemBinding) : RecyclerView.ViewHolder(binding.root)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(ListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.binding.text.text = position.toString()
val color = if (position == selectItemIndex) R.color.main else R.color.sub
holder.binding.text.setBackgroundColor(ContextCompat.getColor(holder.binding.root.context, color))
}
override fun getItemCount() = 10
}
メイン画面の処理。中心自動スクロールや両端のオフセット設定、スクロール検知を行う。
MainActivity.kt
class MainActivity : AppCompatActivity() {
/** ViewBinding */
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.recyclerView.adapter = ItemAdapter()
//両端のオフセット設定
binding.recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val margin = (parent.width - view.layoutParams.width) / 2
val position = parent.getChildAdapterPosition(view)
if (position == 0) outRect.left = margin
if (position == state.itemCount - 1) outRect.right = margin
}
})
//アイテムが中心に来るように自動スクロール
val snapHelper = LinearSnapHelper()
snapHelper.attachToRecyclerView(binding.recyclerView)
//中心アイテム色変更
binding.recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
val view = snapHelper.findSnapView(recyclerView.layoutManager)
if (view != null) {
val position = recyclerView.getChildAdapterPosition(view)
if (position >= 0) (recyclerView.adapter as? ItemAdapter)?.selectItemIndex = position
}
}
})
}
}
参考サイト
関連記事
ViewPager2を使用