Skip to content

Commit 9902a97

Browse files
committed
feat: 경로 화면 소요 시간 타임 라인 UI 구현
1 parent 7bd37a2 commit 9902a97

File tree

7 files changed

+133
-86
lines changed

7 files changed

+133
-86
lines changed

presentation/src/main/java/com/stop/ui/route/RouteViewHolder.kt

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,15 @@ class RouteViewHolder(
2121
init {
2222
binding.recyclerviewTimeLine.adapter = adapter
2323
binding.recyclerviewTimeLine.setHasFixedSize(true)
24-
binding.recyclerviewTimeLine.addItemDecoration(object: RecyclerView.ItemDecoration() {
24+
binding.recyclerviewTimeLine.addItemDecoration(object : RecyclerView.ItemDecoration() {
2525
override fun getItemOffsets(
2626
outRect: Rect,
2727
view: View,
2828
parent: RecyclerView,
2929
state: RecyclerView.State
3030
) {
3131
if (parent.getChildAdapterPosition(view) != RecyclerView.NO_POSITION) {
32-
outRect.set(0, 0, -10, 0)
32+
outRect.set(0, 0, 0, 0)
3333
}
3434
}
3535
})
@@ -56,19 +56,21 @@ class RouteViewHolder(
5656
)
5757
}
5858
adapter.submitList(routeItems)
59-
binding.timeLineContainer.submitList(itinerary.routes)
59+
binding.timeLineContainer.post {
60+
binding.timeLineContainer.submitList(itinerary.routes)
61+
}
6062
}
6163

6264
private fun getTypeName(route: Route): String {
63-
return when(route) {
65+
return when (route) {
6466
is WalkRoute -> "도보"
6567
is TransportRoute -> getSubwayTypeName(route)
6668
else -> ""
6769
}
6870
}
6971

7072
private fun getSubwayTypeName(route: TransportRoute): String {
71-
return when(route.mode) {
73+
return when (route.mode) {
7274
MoveType.SUBWAY -> route.routeInfo.replace("수도권", "")
7375
MoveType.BUS -> route.routeInfo.split(":")[1]
7476
else -> route.routeInfo

presentation/src/main/java/com/stop/ui/route/TimeLineContainer.kt

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,12 @@ import android.view.View
1010
import androidx.constraintlayout.widget.ConstraintLayout
1111
import androidx.constraintlayout.widget.ConstraintSet
1212
import androidx.core.content.ContextCompat
13+
import androidx.core.view.doOnLayout
1314
import com.stop.R
1415
import com.stop.databinding.TimeLineItem2Binding
1516
import com.stop.domain.model.route.tmap.custom.MoveType
1617
import com.stop.domain.model.route.tmap.custom.Route
1718
import com.stop.domain.model.route.tmap.custom.TransportRoute
18-
import kotlinx.coroutines.CoroutineScope
1919

2020
class TimeLineContainer(
2121
context: Context,
@@ -26,23 +26,52 @@ class TimeLineContainer(
2626
ContextCompat.getColor(context, R.color.grey_for_route_walk)
2727
private var beforeViewIconId: Int? = null
2828

29+
private var iconWidth: Int? = null
30+
private var iconCount: Int? = null
31+
private var textWidth: Int? = null
32+
private var routeCount: Int? = null
33+
34+
private val density = context.resources.displayMetrics.density
35+
2936
fun submitList(routes: List<Route>) {
37+
var count = 0
3038
routes.forEachIndexed { index, route ->
39+
if (index == 0) {
40+
return@forEachIndexed
41+
}
42+
if (route.mode in listOf(MoveType.WALK, MoveType.TRANSFER)) {
43+
return@forEachIndexed
44+
}
45+
count += 1
46+
}
3147

32-
val timeLineItem2Binding = TimeLineItem2Binding.inflate(
33-
LayoutInflater.from(context),
34-
this,
35-
false,
36-
).apply {
37-
root.id = View.generateViewId()
48+
iconWidth = convertDpToPixel(9f)
49+
// iconWidth = convertDpToPixel(size) * routes.size
50+
iconCount = count + 1
51+
52+
textWidth = convertDpToPixel(30f)
53+
routeCount = routes.size
54+
55+
doOnLayout {
56+
routes.forEachIndexed { index, route ->
57+
val timeLineItem2Binding = TimeLineItem2Binding.inflate(
58+
LayoutInflater.from(context),
59+
this@TimeLineContainer,
60+
false,
61+
).apply {
62+
root.id = View.generateViewId()
63+
}
64+
65+
addView(timeLineItem2Binding.root)
66+
setBindingAttribute(timeLineItem2Binding, route, index)
3867
}
39-
// this.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
40-
addView(timeLineItem2Binding.root)
41-
setBindingAttribute(timeLineItem2Binding, route, index)
42-
TransitionManager.beginDelayedTransition(this@TimeLineContainer)
4368
}
4469
}
4570

71+
private fun convertDpToPixel(size: Float): Int {
72+
return (size * density + 0.5f).toInt()
73+
}
74+
4675
private fun setBindingAttribute(binding: TimeLineItem2Binding, route: Route, index: Int) {
4776

4877
val text = binding.root.resources.getString(
@@ -59,6 +88,8 @@ class TimeLineContainer(
5988
setDefaultColor(binding)
6089
binding.viewIcon.visibility = View.GONE
6190
binding.imageViewIcon.visibility = View.GONE
91+
setWidth(binding, route.proportionOfSectionTime)
92+
setConstraint(binding)
6293
return
6394
}
6495
R.drawable.time_line_directions_walk_16
@@ -95,8 +126,18 @@ class TimeLineContainer(
95126
with(ConstraintSet()) {
96127
clone(this@TimeLineContainer)
97128
connect(binding.root.id, ConstraintSet.START, endId, endSide)
98-
connect(binding.root.id, ConstraintSet.TOP, this@TimeLineContainer.id, ConstraintSet.TOP)
99-
connect(binding.root.id, ConstraintSet.BOTTOM, this@TimeLineContainer.id, ConstraintSet.BOTTOM)
129+
connect(
130+
binding.root.id,
131+
ConstraintSet.TOP,
132+
this@TimeLineContainer.id,
133+
ConstraintSet.TOP
134+
)
135+
connect(
136+
binding.root.id,
137+
ConstraintSet.BOTTOM,
138+
this@TimeLineContainer.id,
139+
ConstraintSet.BOTTOM
140+
)
100141
applyTo(this@TimeLineContainer)
101142
}
102143
beforeViewIconId = binding.root.id
@@ -106,10 +147,16 @@ class TimeLineContainer(
106147
binding: TimeLineItem2Binding,
107148
proportionOfSectionTime: Float
108149
) {
109-
this.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
150+
val iconWidth = iconWidth ?: throw IllegalArgumentException("로직이 잘못 되었습니다.")
151+
val iconCount = iconCount ?: throw IllegalArgumentException("로직이 잘못 되었습니다.")
152+
val textWidth = textWidth ?: throw IllegalArgumentException("로직이 잘못 되었습니다.")
153+
val routeCount = routeCount ?: throw IllegalArgumentException("로직이 잘못 되었습니다.")
154+
155+
val extraWidth =
156+
this@TimeLineContainer.width - iconWidth * iconCount - textWidth * routeCount
157+
binding.root.layoutParams.width =
158+
(extraWidth * proportionOfSectionTime).toInt() + iconWidth + textWidth
110159

111-
val layoutParams = binding.root.layoutParams
112-
layoutParams.width = (this.measuredWidth * proportionOfSectionTime).toInt()
113160
}
114161

115162
private fun setIdentityColor(binding: TimeLineItem2Binding, route: TransportRoute) {
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
<vector android:height="18dp" android:tint="#000000"
1+
<vector android:height="16dp" android:tint="#000000"
22
android:viewportHeight="24" android:viewportWidth="24"
3-
android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
3+
android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
44
<path android:fillColor="@android:color/white" android:pathData="M4,16c0,0.88 0.39,1.67 1,2.22L5,20c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-1h8v1c0,0.55 0.45,1 1,1h1c0.55,0 1,-0.45 1,-1v-1.78c0.61,-0.55 1,-1.34 1,-2.22L20,6c0,-3.5 -3.58,-4 -8,-4s-8,0.5 -8,4v10zM7.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5S6.67,14 7.5,14s1.5,0.67 1.5,1.5S8.33,17 7.5,17zM16.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM18,11L6,11L6,6h12v5z"/>
55
</vector>
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
<vector android:height="18dp" android:tint="#000000"
1+
<vector android:height="9dp" android:tint="#000000"
22
android:viewportHeight="24" android:viewportWidth="24"
3-
android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
3+
android:width="9dp" xmlns:android="http://schemas.android.com/apk/res/android">
44
<path android:fillColor="@android:color/white" android:pathData="M13.5,5.5c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM9.8,8.9L7,23h2.1l1.8,-8 2.1,2v6h2v-7.5l-2.1,-2 0.6,-3C14.8,12 16.8,13 19,13v-2c-1.9,0 -3.5,-1 -4.3,-2.4l-1,-1.6c-0.4,-0.6 -1,-1 -1.7,-1 -0.3,0 -0.5,0.1 -0.8,0.1L6,8.3V13h2V9.6l1.8,-0.7"/>
55
</vector>
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
<vector android:height="18dp" android:tint="#000000"
1+
<vector android:height="16dp" android:tint="#000000"
22
android:viewportHeight="24" android:viewportWidth="24"
3-
android:width="18dp" xmlns:android="http://schemas.android.com/apk/res/android">
4-
<path android:fillColor="@android:color/white" android:pathData="M15.5,16m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
5-
<path android:fillColor="@android:color/white" android:pathData="M8.5,16m-1,0a1,1 0,1 1,2 0a1,1 0,1 1,-2 0"/>
6-
<path android:fillColor="@android:color/white" android:pathData="M7.01,9h10v5h-10zM17.8,2.8C16,2.09 13.86,2 12,2c-1.86,0 -4,0.09 -5.8,0.8C3.53,3.84 2,6.05 2,8.86L2,22h20L22,8.86c0,-2.81 -1.53,-5.02 -4.2,-6.06zM18,15.88c0,1.45 -1.18,2.62 -2.63,2.62l1.13,1.12L16.5,20L15,20l-1.5,-1.5h-2.83L9.17,20L7.5,20v-0.38l1.12,-1.12C7.18,18.5 6,17.32 6,15.88L6,9c0,-2.63 3,-3 6,-3 3.32,0 6,0.38 6,3v6.88z"/>
3+
android:width="16dp" xmlns:android="http://schemas.android.com/apk/res/android">
4+
<path android:fillColor="@android:color/white" android:pathData="M12,2c-4.42,0 -8,0.5 -8,4v9.5C4,17.43 5.57,19 7.5,19L6,20.5v0.5h12v-0.5L16.5,19c1.93,0 3.5,-1.57 3.5,-3.5L20,6c0,-3.5 -3.58,-4 -8,-4zM7.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5S6.67,14 7.5,14s1.5,0.67 1.5,1.5S8.33,17 7.5,17zM11,11L6,11L6,6h5v5zM16.5,17c-0.83,0 -1.5,-0.67 -1.5,-1.5s0.67,-1.5 1.5,-1.5 1.5,0.67 1.5,1.5 -0.67,1.5 -1.5,1.5zM18,11h-5L13,6h5v5z"/>
75
</vector>

presentation/src/main/res/layout/time_line_item.xml

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,21 @@
44
xmlns:tools="http://schemas.android.com/tools">
55

66
<androidx.constraintlayout.widget.ConstraintLayout
7-
android:layout_width="wrap_content"
7+
android:layout_width="match_parent"
88
android:layout_height="wrap_content">
99

1010
<TextView
1111
android:id="@+id/text_view_section_time"
12-
android:layout_width="wrap_content"
12+
android:layout_width="0dp"
1313
android:layout_height="wrap_content"
14-
android:layout_marginTop="6dp"
1514
android:background="@drawable/time_stick_border"
1615
android:gravity="center"
17-
android:minWidth="60dp"
18-
android:minHeight="20dp"
1916
android:paddingVertical="3dp"
2017
android:textSize="12sp"
18+
app:layout_constraintBottom_toBottomOf="@id/dummy_view"
2119
app:layout_constraintEnd_toEndOf="parent"
2220
app:layout_constraintStart_toStartOf="@id/dummy_view"
23-
app:layout_constraintTop_toTopOf="parent"
21+
app:layout_constraintTop_toTopOf="@id/dummy_view"
2422
tools:text="15분" />
2523

2624
<Button
@@ -47,13 +45,13 @@
4745
android:id="@+id/image_view_icon"
4846
android:layout_width="wrap_content"
4947
android:layout_height="wrap_content"
50-
android:padding="8dp"
5148
android:contentDescription="@string/image_view_icon_content_description"
49+
android:padding="8dp"
5250
android:scaleType="centerCrop"
5351
app:layout_constraintBottom_toBottomOf="@id/view_icon"
52+
app:layout_constraintEnd_toEndOf="@id/view_icon"
5453
app:layout_constraintStart_toStartOf="@id/view_icon"
5554
app:layout_constraintTop_toTopOf="@id/view_icon"
56-
app:layout_constraintEnd_toEndOf="@id/view_icon"
5755
tools:src="@drawable/time_line_directions_walk_16" />
5856

5957
</androidx.constraintlayout.widget.ConstraintLayout>
Lines changed: 50 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,57 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
2+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
33
xmlns:app="http://schemas.android.com/apk/res-auto"
4-
xmlns:tools="http://schemas.android.com/tools"
5-
android:layout_width="wrap_content"
6-
android:layout_height="wrap_content">
4+
xmlns:tools="http://schemas.android.com/tools">
75

8-
<TextView
9-
android:id="@+id/text_view_section_time"
10-
android:layout_width="wrap_content"
11-
android:layout_height="wrap_content"
12-
android:layout_marginTop="6dp"
13-
android:background="@drawable/time_stick_border"
14-
android:gravity="center"
15-
android:minWidth="60dp"
16-
android:minHeight="20dp"
17-
android:paddingVertical="3dp"
18-
android:textSize="12sp"
19-
app:layout_constraintStart_toStartOf="@id/dummy_view"
20-
app:layout_constraintTop_toTopOf="parent"
21-
tools:text="15분" />
6+
<androidx.constraintlayout.widget.ConstraintLayout
7+
android:layout_width="match_parent"
8+
android:layout_height="wrap_content">
229

23-
<Button
24-
android:id="@+id/dummy_view"
25-
android:layout_width="0dp"
26-
android:layout_height="0dp"
27-
android:visibility="gone"
28-
app:layout_constraintBottom_toBottomOf="@id/image_view_icon"
29-
app:layout_constraintEnd_toEndOf="@id/image_view_icon"
30-
app:layout_constraintStart_toStartOf="@id/image_view_icon"
31-
app:layout_constraintTop_toTopOf="@id/image_view_icon"
32-
tools:layout_editor_absoluteY="234dp" />
10+
<TextView
11+
android:id="@+id/text_view_section_time"
12+
android:layout_width="0dp"
13+
android:layout_height="wrap_content"
14+
android:background="@drawable/time_stick_border"
15+
android:gravity="center"
16+
android:textSize="12sp"
17+
app:layout_constraintBottom_toBottomOf="@id/dummy_view"
18+
app:layout_constraintEnd_toEndOf="parent"
19+
app:layout_constraintStart_toStartOf="@id/dummy_view"
20+
app:layout_constraintTop_toTopOf="@id/dummy_view"
21+
tools:text="15분" />
3322

34-
<View
35-
android:id="@+id/view_icon"
36-
android:layout_width="36dp"
37-
android:layout_height="36dp"
38-
android:background="@drawable/time_stick_round_background"
39-
app:layout_constraintStart_toStartOf="parent"
40-
app:layout_constraintTop_toTopOf="parent" />
23+
<Button
24+
android:id="@+id/dummy_view"
25+
android:layout_width="0dp"
26+
android:layout_height="0dp"
27+
android:visibility="gone"
28+
app:layout_constraintBottom_toBottomOf="@id/image_view_icon"
29+
app:layout_constraintEnd_toEndOf="@id/image_view_icon"
30+
app:layout_constraintStart_toStartOf="@id/image_view_icon"
31+
app:layout_constraintTop_toTopOf="@id/image_view_icon"
32+
tools:layout_editor_absoluteY="234dp" />
4133

42-
<ImageView
43-
android:id="@+id/image_view_icon"
44-
android:layout_width="wrap_content"
45-
android:layout_height="wrap_content"
46-
android:padding="8dp"
47-
android:contentDescription="@string/image_view_icon_content_description"
48-
android:scaleType="centerCrop"
49-
app:layout_constraintBottom_toBottomOf="@id/view_icon"
50-
app:layout_constraintStart_toStartOf="@id/view_icon"
51-
app:layout_constraintTop_toTopOf="@id/view_icon"
52-
app:layout_constraintEnd_toEndOf="@id/view_icon"
53-
tools:src="@drawable/time_line_directions_walk_16" />
34+
<View
35+
android:id="@+id/view_icon"
36+
android:layout_width="18dp"
37+
android:layout_height="18dp"
38+
android:background="@drawable/time_stick_round_background"
39+
app:layout_constraintBottom_toBottomOf="parent"
40+
app:layout_constraintStart_toStartOf="parent"
41+
app:layout_constraintTop_toTopOf="parent" />
5442

55-
</androidx.constraintlayout.widget.ConstraintLayout>
43+
<ImageView
44+
android:id="@+id/image_view_icon"
45+
android:layout_width="wrap_content"
46+
android:layout_height="wrap_content"
47+
android:contentDescription="@string/image_view_icon_content_description"
48+
android:padding="8dp"
49+
android:scaleType="centerCrop"
50+
app:layout_constraintBottom_toBottomOf="@id/view_icon"
51+
app:layout_constraintEnd_toEndOf="@id/view_icon"
52+
app:layout_constraintStart_toStartOf="@id/view_icon"
53+
app:layout_constraintTop_toTopOf="@id/view_icon"
54+
tools:src="@drawable/time_line_directions_walk_16" />
55+
56+
</androidx.constraintlayout.widget.ConstraintLayout>
57+
</layout>

0 commit comments

Comments
 (0)