Published 2020. 12. 22. 13:16
반응형
안드로이드 코틀린 스와이프 메뉴 구성
Android Kotlin Swipe Menu
모바일 특성상 작은 화면에 많은 것을 보여주어야 하기 때문에 메뉴나 삭제와 같은 작은 동작들은 숨겨놓고는 한다.
그래서 대체로 자주 보이는 기능이 클릭을 하였을 때 펼쳐지는 메뉴 혹은 스와이프를 했을 때 나오는 메뉴 기능이다.
구현은 Recyclerview에다가 구현을 하였으며, 꼭 Recyclerview에다가 할 필요 없을 것이다. 라이브러리는 사용하지 않고 ItemTouchHelper를 사용하여 구현한 자료를 참고로 만들어 보았다. 사실 참고라기엔 중간에 망쳐서 다 가져다 썼다..
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:paddingBottom="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="13dp"
android:layout_marginEnd="13dp"
android:background="@android:color/holo_red_dark">
<TextView
android:id="@+id/swipe_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|center_vertical"
android:layout_marginEnd="25dp"
android:text="Delete"
android:textColor="#ffffff" />
</FrameLayout>
<LinearLayout
android:id="@+id/swipe_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginStart="13dp"
android:layout_marginEnd="13dp"
android:background="@android:color/darker_gray"
android:orientation="vertical">
<TextView
android:id="@+id/recyclerview_item_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@android:color/holo_blue_dark"
android:textSize="20dp"
android:textStyle="bold"
tools:text="title here" />
<TextView
android:id="@+id/recyclerview_item_content"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="content here" />
</LinearLayout>
</FrameLayout>
일반 Recyclerview와 코드는 같고 item의 레이아웃만 뒤에 가려져 있는 스와이프 했을 때 나올 메뉴를 겹쳐서 만들어 놓아야 한다.
class SwipeHelperCallback : ItemTouchHelper.Callback() {
private var currentPosition: Int? = null
private var previousPosition: Int? = null
private var currentDx = 0f
private var clamp = 0f
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder
): Int {
return makeMovementFlags(0, LEFT)
}
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder): Boolean {
return false
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
}
override fun clearView(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder) {
currentDx = 0f
getDefaultUIUtil().clearView(getView(viewHolder))
previousPosition = viewHolder.adapterPosition
}
override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
viewHolder?.let {
currentPosition = viewHolder.adapterPosition
getDefaultUIUtil().onSelected(getView(it))
}
}
override fun getSwipeEscapeVelocity(defaultValue: Float): Float {
return defaultValue * 10
}
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
val isClamped = getTag(viewHolder)
setTag(viewHolder, !isClamped && currentDx <= -clamp)
return 2f
}
override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
if (actionState == ACTION_STATE_SWIPE) {
val view = getView(viewHolder)
val isClamped = getTag(viewHolder)
val x = clampViewPositionHorizontal(view, dX, isClamped, isCurrentlyActive)
currentDx = x
getDefaultUIUtil().onDraw(
c,
recyclerView,
view,
x,
dY,
actionState,
isCurrentlyActive
)
}
}
private fun clampViewPositionHorizontal(view: View, dX: Float, isClamped: Boolean,
isCurrentlyActive: Boolean) : Float {
val min: Float = -view.width.toFloat()
val max = 0f
val x = if (isClamped) {
if (isCurrentlyActive) dX - clamp else -clamp
} else {
dX
}
return min(max(min, x), max)
}
// isClamped를 view의 tag로 관리
private fun setTag(viewHolder: RecyclerView.ViewHolder, isClamped: Boolean) {
viewHolder.itemView.tag = isClamped
}
private fun getTag(viewHolder: RecyclerView.ViewHolder) : Boolean {
return viewHolder.itemView.tag as? Boolean ?: false
}
private fun getView(viewHolder: RecyclerView.ViewHolder) : View {
return (viewHolder as SwipeAdapter.ViewHolder).itemView.swipe_view
}
fun setClamp(clamp: Float) {
this.clamp = clamp
}
fun removePreviousClamp(recyclerView: RecyclerView) {
if (currentPosition == previousPosition) {
return
}
previousPosition?.let {
val viewHolder
= recyclerView.findViewHolderForAdapterPosition(it) ?: return
getView(viewHolder).translationX = 0f
setTag(viewHolder, false)
previousPosition = null
}
}
}
스와이프가 동작하는 controller이며 ItemTouchHelper를 상속받아서 만들어 졌다.
필수 메소드는 override를 당연하게 했다. 아직 나도 저 위에 코드를 제대로 이해를 못하였으므로.. 내가 보고 공부한 위 소스가 있는 사이트를 참고해놓겠다. 흙흙..
velog.io/@trycatch98/Android-RecyclerView-Swipe-Menu
ps. swipe는 라이브러리 사용하세요...제발
반응형
'[# 2]…My DevelopStory' 카테고리의 다른 글
안드로이드 구글 플레이스토어로 이동하기 코드 구현 ~ Android Go to PlayStore (0) | 2020.12.30 |
---|---|
안드로이드 앱 설치유무 확인 ~ Android App Install Check (0) | 2020.12.28 |
안드로이드 텍스트 뷰 다국어 간격 변경 ~ Android Textview fallbacklinespacing (0) | 2020.12.11 |
안드로이드 9 webView Directory 관련 이슈 및 Crash ~ Android WebView Error or Crash (0) | 2020.12.04 |
안드로이드 최소 버전 apk 용량 관련 이슈 ~ Android Min Sdk Ver Size Up Issue ~ extractNativeLibs (1) | 2020.11.17 |