일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
Tags
- 이모지메모
- Firebase
- 장자명언
- 공부집중
- jetpack compose
- 오픈소스
- kotlin
- 벤자민플랭클린
- 공자명언
- ASMR
- Flutter
- 파이썬
- Coroutine
- bash
- Android
- Streaming
- androidx
- 명언모음
- DART
- 이모지
- 좋은글필사하기
- recyclerview
- 소울칼리버6
- 넷플릭스
- Freesound
- FSM
- 코틀린
- Linux
- 명심보감
- 1인개발자
Archives
- Today
- Total
Vintage appMaker의 Tech Blog
RecyclerView 가로스크롤 자석효과 본문
Android 앱 중에는 가로스크롤 후, 좌측 끝부분을 특정 위치로 재조정하는 것들이 있다.
종종 구현해야 할 필요가 있어 구글링을 해보니 다음링크가 교과서처럼 사용되고 있었다.
https://stackoverflow.com/questions/26370289/snappy-scrolling-in-recyclerview/33774983
위의 코드를 kotlin으로 확장함수를 이용하여 다음과 같이 간편하게 정리했다.
ViewExt.kt
fun RecyclerView.getScrollDistanceOfColumnClosestToLeft(): Int {
val manager = layoutManager as LinearLayoutManager?
val firstVisibleColumnViewHolder = findViewHolderForAdapterPosition(
manager!!.findFirstVisibleItemPosition()
) ?: return 0
val columnWidth = firstVisibleColumnViewHolder.itemView.measuredWidth
val left = firstVisibleColumnViewHolder.itemView.left
val absoluteLeft = Math.abs(left)
return if (absoluteLeft <= columnWidth / 2) left else columnWidth - absoluteLeft
}
fun RecyclerView.setMagneticMove(nStart : Int = 0 ){
addOnScrollListener(object:RecyclerView.OnScrollListener(){
var oldMoveTo : Int = 0
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
val moveTo = getScrollDistanceOfColumnClosestToLeft() - nStart
if(newState == RecyclerView.SCROLL_STATE_IDLE){
// smoothScrollBy()를 사용했을 경우,
// 양쪽 끝자리에서 움직이면 무한루핑이 됨.
// 그래서 이전값과 비교함.
if(moveTo !== oldMoveTo){
recyclerView.smoothScrollBy(moveTo, 0)
oldMoveTo = moveTo
}
}
}
})
}
사용법은 간단하다.
리사이클뷰를 선언시, setMagneticMove를 호출하기만 하면된다.
MainActivity.kt
...
val lst = mutableListOf<SimpleData>()
val colortable = listOf(Color.RED, Color.GRAY, Color.BLUE, Color.GREEN, Color.WHITE)
(0..30).forEach {
val item = Box(color = colortable.get( it % colortable.size), alpha = it * 0.1f % 1.0f )
lst.add( item as SimpleData )
}
// 좌측에서 이동
//recycler.setMagneticMove(dpToPx(60f) * -1)
recycler.setMagneticMove()
val manager = LinearLayoutManager(applicationContext, RecyclerView.HORIZONTAL, false)
recycler.layoutManager = manager
val adt = MagneticAdapter(lst, applicationContext)
recycler.adapter = adt
...
MagneticAdapter.kt
import android.content.Context
import android.graphics.Color
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.test.psw.oftenutilbox.R
import kotlin.random.Random
sealed class SimpleData
data class Box(
var color : Int,
var alpha : Float
) : SimpleData()
class MagneticAdapter(val items : List<SimpleData>, val context: Context) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
var mItems : MutableList <SimpleData> = items.toMutableList()
override fun getItemCount(): Int {
return mItems.size
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return when (viewType){
TYPE_ONE -> {boxViewHolder(LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false))}
else -> {boxViewHolder(LayoutInflater.from(context).inflate(R.layout.recycler_item, parent, false))}
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder.itemViewType){
TYPE_ONE -> { (holder as boxViewHolder).apply {
var item = mItems.get(position) as Box
bind(context, item)
}}
}
}
override fun getItemViewType(position: Int): Int {
return when (mItems.get(position)){
is Box -> {
TYPE_ONE
}
}
}
companion object {
private const val TYPE_ONE = 0
}
}
class boxViewHolder (view: View) : RecyclerView.ViewHolder(view) {
val box = view.findViewById<View>(R.id.colorBox)
val dimmed = view.findViewById<View>(R.id.dimmed)
fun bind(context : Context, item : Box){
box.setBackgroundColor(item.color)
dimmed.setBackgroundColor(Color.BLACK)
dimmed.alpha = item.alpha
}
}
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:background="#000000"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
recycler_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:padding="20dp"
android:orientation="vertical">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:id="@+id/colorBox"
android:layout_width="280dp"
android:layout_height="300dp"/>
<View
android:id="@+id/dimmed"
android:layout_width="280dp"
android:layout_height="300dp"/>
</FrameLayout>
</LinearLayout>
'Source code or Tip > Android(Java, Kotlin)' 카테고리의 다른 글
[ViewModel] ViewModel과 Coroutine을 이용한 타이머 (0) | 2021.08.16 |
---|---|
[android] code로 view의 weight 조절 (0) | 2021.07.22 |
[link 모음] Android Transitions를 이용한 Animation (0) | 2021.07.05 |
[gradle] 한 프로젝트의 다양한 Gradle 빌드환경 - Build Variant (0) | 2021.07.02 |
BottomSheetDialogFragment 배경을 투명하게 (0) | 2021.06.29 |
Comments