Skip to content

Commit d2082ae

Browse files
authored
Merge pull request #23 from ese111/main
[funny] 목록 삭제시 스크롤 올라가는 문제 수정, 스와이프 삭제 구현 중
2 parents 1cae9da + 9fdf3c2 commit d2082ae

File tree

10 files changed

+224
-38
lines changed

10 files changed

+224
-38
lines changed

android/todo-list/app/src/main/java/com/example/todolist/data/TodoRepository.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,19 @@ class TodoRepository {
2020
return todoTaskList
2121
}
2222

23+
private var num = todoTaskList.size
2324

2425
fun testAdd(title: String, content: String) {
25-
todoTaskList.add(Task("sam", todoTaskList.size, "todo", title, content, todoTaskList.size))
26+
todoTaskList.add(Task("sam", num, "todo", title, content, num))
27+
num++
2628
}
2729

2830
fun setTaskList(task: Task) {
2931

3032
}
3133

3234
fun deleteTask(task: Task) {
33-
35+
todoTaskList.remove(task)
3436
}
3537

3638

android/todo-list/app/src/main/java/com/example/todolist/ui/CreateCardDialogFragment.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,5 +93,4 @@ class CreateCardDialogFragment : DialogFragment() {
9393
})
9494
}
9595

96-
9796
}

android/todo-list/app/src/main/java/com/example/todolist/ui/MainActivity.kt

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ import androidx.activity.viewModels
66
import androidx.appcompat.app.AppCompatActivity
77
import androidx.core.view.GravityCompat
88
import androidx.databinding.DataBindingUtil
9+
import androidx.recyclerview.widget.ItemTouchHelper
910
import com.example.todolist.R
1011
import com.example.todolist.databinding.ActivityMainBinding
12+
import com.example.todolist.ui.common.TodoTouchHelper
1113
import com.example.todolist.ui.todo.TodoAdapter
1214

1315
// 해야할 일 뷰 어뎁터, 뷰모델
@@ -23,19 +25,25 @@ class MainActivity : AppCompatActivity() {
2325
override fun onCreate(savedInstanceState: Bundle?) {
2426
super.onCreate(savedInstanceState)
2527
setContentView(R.layout.activity_main)
26-
val adapter = TodoAdapter()
28+
val adapter = TodoAdapter(viewModel)
2729
binding.rvTodo.adapter = adapter
2830
setOnClickMenu()
2931
setOnClickTodoAdd()
32+
viewModel
33+
val swipeHelperCallback = TodoTouchHelper()
34+
ItemTouchHelper(swipeHelperCallback).attachToRecyclerView(binding.rvTodo)
35+
36+
viewModel.loadTodoTask()
3037

3138
viewModel.todoTaskList.observe(this) {
3239
Log.d("AppTest", "observer")
3340
adapter.submitList(it.toList()) {
34-
binding.rvTodo.smoothScrollToPosition(0)
41+
if (viewModel.state == 1) {
42+
binding.rvTodo.scrollToPosition(0)
43+
}
3544
}
3645
}
3746

38-
3947
}
4048

4149
override fun onBackPressed() {

android/todo-list/app/src/main/java/com/example/todolist/ui/TaskViewModel.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,18 +20,25 @@ class TaskViewModel : ViewModel() {
2020
private val _completeTaskList = MutableLiveData<List<Task>>()
2121
val completeTaskList: LiveData<List<Task>> = _todoTaskList
2222

23-
init {
24-
loadTodoTask()
25-
}
23+
private var _state = 0
24+
val state: Int
25+
get() = _state
2626

27-
private fun loadTodoTask() {
27+
fun loadTodoTask() {
2828
_todoTaskList.value = repository.getTaskList()
2929
}
3030

3131
fun addTodo(title: String, content: String) {
3232
Log.d("AppTest", "add todo")
3333
repository.testAdd(title, content)
34-
_todoTaskList.value = repository.getTaskList()
34+
loadTodoTask()
35+
_state = 1
36+
}
37+
38+
fun deleteTodoCard(task: Task) {
39+
repository.deleteTask(task)
40+
loadTodoTask()
41+
_state = 0
3542
}
3643

3744
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.example.todolist.ui.common
2+
3+
import android.graphics.Canvas
4+
import android.view.View
5+
import androidx.recyclerview.widget.ItemTouchHelper
6+
import androidx.recyclerview.widget.ItemTouchHelper.*
7+
import androidx.recyclerview.widget.RecyclerView
8+
import com.example.todolist.R
9+
10+
class TodoTouchHelper :
11+
ItemTouchHelper.Callback() {
12+
private var currentPosition: Int? = null // 현재 선택된 recycler view의 position
13+
private var previousPosition: Int? = null // 이전에 선택했던 recycler view의 position
14+
private var currentDx = 0f // 현재 x 값
15+
private var isSwiped = false
16+
private var swipedViewPosition = -1
17+
private var clamp = 0f
18+
override fun getMovementFlags(
19+
recyclerView: RecyclerView,
20+
viewHolder: RecyclerView.ViewHolder
21+
): Int {
22+
return makeMovementFlags(UP or DOWN, LEFT or RIGHT)
23+
}
24+
25+
override fun onMove(
26+
recyclerView: RecyclerView,
27+
viewHolder: RecyclerView.ViewHolder,
28+
target: RecyclerView.ViewHolder
29+
): Boolean {
30+
val fromPos = viewHolder.adapterPosition
31+
val toPos = viewHolder.adapterPosition
32+
return true
33+
}
34+
35+
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
36+
}
37+
38+
override fun onChildDraw(
39+
c: Canvas,
40+
recyclerView: RecyclerView,
41+
viewHolder: RecyclerView.ViewHolder,
42+
dX: Float,
43+
dY: Float,
44+
actionState: Int,
45+
isCurrentlyActive: Boolean
46+
) {
47+
if (actionState == ACTION_STATE_SWIPE) {
48+
val view = getView(viewHolder)
49+
val textView = getTv(viewHolder)
50+
val textSize = getWidth(viewHolder)
51+
val newX = if ((dX / 2) > 0) {
52+
textView.visibility = View.GONE
53+
0f
54+
} else {
55+
textView.visibility = View.VISIBLE
56+
dX / 2
57+
}
58+
getDefaultUIUtil().onDraw(
59+
c,
60+
recyclerView,
61+
view,
62+
newX,
63+
dY,
64+
actionState,
65+
isCurrentlyActive
66+
)
67+
}
68+
}
69+
70+
private fun setSwipedView(viewHolder: RecyclerView.ViewHolder) {
71+
swipedViewPosition = viewHolder.adapterPosition
72+
}
73+
74+
private fun getWidth(viewHolder: RecyclerView.ViewHolder) =
75+
viewHolder.itemView.findViewById<View>(R.id.tv_delete_card).width.toFloat()
76+
77+
fun getSwipedView() = swipedViewPosition
78+
79+
private fun getTv(viewHolder: RecyclerView.ViewHolder) =
80+
viewHolder.itemView.findViewById<View>(R.id.tv_delete_card)
81+
82+
private fun getView(viewHolder: RecyclerView.ViewHolder): View =
83+
viewHolder.itemView.findViewById(R.id.cio_screen)
84+
}
85+
86+
// 나중에 논의할 것
87+
/*@SuppressLint("NewApi")
88+
private fun clampViewPositionHorizontal(
89+
dX: Float,
90+
isClamped: Boolean,
91+
isCurrentlyActive: Boolean
92+
): Float {
93+
// RIGHT 방향으로 swipe 막기
94+
val max = 0f
95+
// 고정할 수 있으면
96+
*//*val newX = if (isClamped) {
97+
Log.d("안되는거?", "$isClamped")
98+
// 현재 swipe 중이면 swipe되는 영역 제한
99+
if (isCurrentlyActive)
100+
// 오른쪽 swipe일 때
101+
if (dX < 0) dX / 3 - test
102+
// 왼쪽 swipe일 때
103+
else dX - test
104+
// swipe 중이 아니면 고정시키기
105+
else {
106+
Log.d("되는거?", "$isClamped")
107+
-test
108+
}
109+
}
110+
// 고정할 수 없으면 newX는 스와이프한 만큼
111+
else {
112+
Log.d("ㄹㅇ되는거?", "$isClamped")
113+
dX / 2
114+
}*//**//*
115+
return min(max, dX / 2)
116+
}
117+
private fun setTag(viewHolder: RecyclerView.ViewHolder, isClamped: Boolean) {
118+
viewHolder.itemView.tag = isClamped
119+
}
120+
private fun getTag(viewHolder: RecyclerView.ViewHolder): Boolean =
121+
viewHolder.itemView.tag as? Boolean ?: false
122+
fun setClamp(clamp: Float) {
123+
this.clamp = clamp
124+
}
125+
private fun getWidth(viewHolder: RecyclerView.ViewHolder) = viewHolder.itemView.width
126+
private fun setWidth(viewHolder: RecyclerView.ViewHolder) {
127+
this.test = viewHolder.itemView.findViewById<TextView>(R.id.tv_delete_card).width.toFloat()
128+
this.clamp = viewHolder.itemView.width.toFloat()
129+
}*/

android/todo-list/app/src/main/java/com/example/todolist/ui/todo/TodoAdapter.kt

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,40 @@ package com.example.todolist.ui.todo
22

33
import android.view.LayoutInflater
44
import android.view.ViewGroup
5+
import androidx.lifecycle.ViewModel
56
import androidx.recyclerview.widget.ListAdapter
67
import androidx.recyclerview.widget.RecyclerView
78
import com.example.todolist.data.Task
89
import com.example.todolist.databinding.ItemTodoBinding
10+
import com.example.todolist.ui.TaskViewModel
911
import com.example.todolist.ui.common.DiffUtil
1012

11-
class TodoAdapter : ListAdapter<Task, TodoAdapter.TodoViewHolder>(DiffUtil) {
13+
class TodoAdapter(
14+
val viewModel: TaskViewModel
15+
) : ListAdapter<Task, TodoAdapter.TodoViewHolder>(DiffUtil) {
1216

1317
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TodoViewHolder {
14-
val binding = ItemTodoBinding.inflate(LayoutInflater.from(parent.context), parent, false)
18+
val binding = ItemTodoBinding.inflate(LayoutInflater.from(parent.context), parent, false)
1519
return TodoViewHolder(binding)
1620
}
1721

1822
override fun onBindViewHolder(holder: TodoViewHolder, position: Int) {
1923
holder.bind(getItem(position))
2024
}
2125

22-
class TodoViewHolder(private val binding: ItemTodoBinding) : RecyclerView.ViewHolder(binding.root) {
26+
inner class TodoViewHolder(private val binding: ItemTodoBinding) :
27+
RecyclerView.ViewHolder(binding.root) {
2328

24-
fun bind(task : Task) {
29+
fun bind(task: Task) {
2530
binding.task = task
2631
binding.executePendingBindings()
32+
deleteCard(task)
33+
}
34+
35+
private fun deleteCard(task: Task) {
36+
binding.tvDeleteCard?.setOnClickListener {
37+
viewModel.deleteTodoCard(task)
38+
}
2739
}
2840

2941
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<shape xmlns:android="http://schemas.android.com/apk/res/android"
3+
android:shape="rectangle" >
4+
<solid android:color="@color/todo_red"/>
5+
<corners android:topRightRadius="20dp" android:bottomRightRadius="20dp"/>
6+
</shape>

android/todo-list/app/src/main/res/layout-land/item_todo.xml

Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,55 @@
1515
android:layout_height="wrap_content"
1616
android:layout_marginTop="16dp"
1717
android:layout_marginBottom="10dp"
18-
android:background="@drawable/background_white"
19-
android:padding="16dp">
18+
android:background="@drawable/background_white">
2019

2120
<TextView
22-
android:id="@+id/tv_title"
23-
style="@style/TextSubtitle.Black.Bold"
24-
android:layout_width="wrap_content"
25-
android:layout_height="wrap_content"
26-
android:layout_marginBottom="8dp"
27-
android:text="@{task.title}"
28-
app:layout_constraintStart_toStartOf="parent"
29-
app:layout_constraintTop_toTopOf="parent" />
30-
31-
<TextView
32-
android:id="@+id/tv_body"
33-
style="@style/TextBody.Black"
34-
android:layout_width="0dp"
35-
android:layout_height="wrap_content"
36-
android:layout_marginBottom="8dp"
37-
android:ellipsize="end"
38-
android:maxLines="3"
39-
android:text="@{task.body}"
21+
android:id="@+id/tv_delete_card"
22+
style="@style/TextBody.White"
23+
android:layout_width="112dp"
24+
android:layout_height="0dp"
25+
android:background="@drawable/background_red"
26+
android:gravity="center"
27+
android:text="@string/delete"
28+
android:visibility="gone"
4029
app:layout_constraintBottom_toBottomOf="parent"
4130
app:layout_constraintEnd_toEndOf="parent"
42-
app:layout_constraintStart_toStartOf="@+id/tv_title"
43-
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
31+
app:layout_constraintTop_toTopOf="parent" />
32+
33+
<androidx.constraintlayout.widget.ConstraintLayout
34+
android:id="@+id/cio_screen"
35+
android:layout_width="match_parent"
36+
android:layout_height="match_parent"
37+
android:background="@drawable/background_white"
38+
android:padding="16dp"
39+
app:layout_constraintStart_toStartOf="parent"
40+
app:layout_constraintTop_toTopOf="parent"
41+
tools:visibility="invisible">
42+
43+
<TextView
44+
android:id="@+id/tv_title"
45+
style="@style/TextSubtitle.Black.Bold"
46+
android:layout_width="wrap_content"
47+
android:layout_height="wrap_content"
48+
android:layout_marginBottom="8dp"
49+
android:text="@{task.title}"
50+
app:layout_constraintStart_toStartOf="parent"
51+
app:layout_constraintTop_toTopOf="parent" />
4452

53+
<TextView
54+
android:id="@+id/tv_body"
55+
style="@style/TextBody.Black"
56+
android:layout_width="0dp"
57+
android:layout_height="wrap_content"
58+
android:layout_marginBottom="8dp"
59+
android:ellipsize="end"
60+
android:maxLines="3"
61+
android:text="@{task.body}"
62+
app:layout_constraintBottom_toBottomOf="parent"
63+
app:layout_constraintEnd_toEndOf="parent"
64+
app:layout_constraintStart_toStartOf="@+id/tv_title"
65+
app:layout_constraintTop_toBottomOf="@+id/tv_title" />
4566

67+
</androidx.constraintlayout.widget.ConstraintLayout>
4668
</androidx.constraintlayout.widget.ConstraintLayout>
4769
</layout>

android/todo-list/app/src/main/res/values/colors.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,5 @@
1010
<color name="todo_white_40">#66FFFFFF</color>
1111
<color name="todo_light_blue">#86C6FF</color>
1212
<color name="todo_blue">#0075DE</color>
13-
13+
<color name="todo_red">#FF4343</color>
1414
</resources>

android/todo-list/app/src/main/res/values/strings.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,5 @@
2020
<string name="input_content">내용을 입력하세요</string>
2121
<string name="dialog_register">등록</string>
2222
<string name="dialog_cancel">취소</string>
23+
<string name="delete">삭제</string>
2324
</resources>

0 commit comments

Comments
 (0)