Skip to content

Commit 737e8c4

Browse files
update swipe drag sample for both sides
1 parent 430305c commit 737e8c4

File tree

1 file changed

+73
-45
lines changed

1 file changed

+73
-45
lines changed

Tutorial1-1Basics/src/main/java/com/smarttoolfactory/tutorial1_1basics/chapter5_gesture/Tutorital5_16DragHorizontalPager.kt

Lines changed: 73 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.smarttoolfactory.tutorial1_1basics.chapter5_gesture
22

33
import androidx.compose.animation.core.Animatable
4+
import androidx.compose.animation.core.tween
45
import androidx.compose.foundation.Image
56
import androidx.compose.foundation.background
67
import androidx.compose.foundation.border
@@ -32,6 +33,7 @@ import androidx.compose.runtime.rememberCoroutineScope
3233
import androidx.compose.runtime.setValue
3334
import androidx.compose.ui.Modifier
3435
import androidx.compose.ui.draw.clip
36+
import androidx.compose.ui.draw.shadow
3537
import androidx.compose.ui.geometry.Offset
3638
import androidx.compose.ui.graphics.Color
3739
import androidx.compose.ui.graphics.TransformOrigin
@@ -46,14 +48,15 @@ import androidx.compose.ui.input.pointer.pointerInput
4648
import androidx.compose.ui.layout.ContentScale
4749
import androidx.compose.ui.res.painterResource
4850
import androidx.compose.ui.tooling.preview.Preview
49-
import androidx.compose.ui.unit.center
5051
import androidx.compose.ui.unit.dp
5152
import androidx.compose.ui.unit.sp
5253
import com.smarttoolfactory.tutorial1_1basics.R
5354
import com.smarttoolfactory.tutorial1_1basics.chapter2_material_widgets.CheckBoxWithTextRippleFullRow
5455
import com.smarttoolfactory.tutorial1_1basics.chapter5_gesture.gesture.detectDragGesture
5556
import com.smarttoolfactory.tutorial1_1basics.chapter6_graphics.ExposedSelectionMenu
5657
import com.smarttoolfactory.tutorial1_1basics.ui.Blue400
58+
import com.smarttoolfactory.tutorial1_1basics.ui.Green400
59+
import com.smarttoolfactory.tutorial1_1basics.ui.Red400
5760
import com.smarttoolfactory.tutorial1_1basics.ui.backgroundColor
5861
import kotlinx.coroutines.launch
5962

@@ -99,14 +102,12 @@ fun DragPagerAndSwipeTest() {
99102
.padding(16.dp)
100103
) {
101104

102-
var text by remember {
103-
mutableStateOf("")
104-
}
105-
106105
var isDraggable by remember {
107106
mutableStateOf(false)
108107
}
109108

109+
val angleThreshold = 18f
110+
110111
Box {
111112
items.forEachIndexed { index, _ ->
112113

@@ -115,61 +116,72 @@ fun DragPagerAndSwipeTest() {
115116
currentList.size
116117
}
117118

118-
val animatable = remember {
119+
val angleAnimatable = remember {
119120
Animatable(0f)
120121
}
121122

122-
val offset = remember {
123+
val offsetAnimatable = remember {
123124
Animatable(0f)
124125
}
125126

127+
var text by remember {
128+
mutableStateOf(
129+
"drag from left to right on first page or right left on last page" +
130+
"\nto swipe item off the list when threshold angle is passed"
131+
)
132+
}
133+
126134
val dragModifier = Modifier
127135
.pointerInput(Unit) {
128136
val width = size.width.toFloat()
129-
val centerX = size.center.x.toFloat()
130137

131138
detectDragGesture(
132-
requireUnconsumed = true,
133-
shouldAwaitTouchSlop = false,
139+
requireUnconsumed = false,
140+
shouldAwaitTouchSlop = true,
134141
passForSlopDetection = PointerEventPass.Main,
135142
passForDrag = PointerEventPass.Initial,
136-
onDragStart = { change, offset ->
137-
text = "onDragStart..."
138-
isDraggable =
139-
change.position.x <= centerX &&
140-
pagerState.currentPage == 0 &&
141-
offset.x <= 0f
142-
println("onDragStart offset: ${offset.x}")
143+
onDragStart = { _, offset ->
144+
text = "onDragStart...offset: $offset"
145+
146+
val firstPageDraggable = pagerState.currentPage == 0 && offset.x > 0
147+
val lastPageDraggable =
148+
pagerState.currentPage == pagerState.pageCount - 1 && offset.x < 0
149+
150+
isDraggable = firstPageDraggable || lastPageDraggable
143151
},
144152
onDrag = { change, dragAmount ->
145153

154+
var currentOffset = offsetAnimatable.value
155+
146156
if (isDraggable) {
147157
change.consume()
148-
val posX = change.position.x.coerceIn(0f, width)
149-
val tempPos = (posX - centerX).coerceAtMost(0f)
150-
151-
if (tempPos == 0f) {
152-
isDraggable = false
153-
} else {
154-
var currentOffset = offset.value
155-
currentOffset += dragAmount.x * 1.25f
158+
currentOffset -= dragAmount.x * 2f
159+
var angle = 0f
160+
if (pagerState.currentPage == 0) {
156161
currentOffset = currentOffset.coerceAtMost(0f)
157-
var angle = 60f * (currentOffset) / centerX
162+
angle = 80f * (currentOffset) / width
158163
angle = angle.coerceAtMost(0f)
164+
}
159165

160-
coroutineScope.launch {
161-
animatable.animateTo(angle)
162-
}
166+
if (pagerState.currentPage == pagerState.pageCount - 1) {
167+
currentOffset = currentOffset.coerceAtLeast(0f)
168+
angle = 60f * (currentOffset) / width
169+
angle = angle.coerceAtLeast(0f)
170+
}
171+
172+
coroutineScope.launch {
173+
angleAnimatable.animateTo(angle)
174+
}
163175

164-
coroutineScope.launch {
165-
offset.animateTo(currentOffset)
166-
}
176+
coroutineScope.launch {
177+
offsetAnimatable.animateTo(currentOffset)
167178
}
168179
}
169180

170181
text = "onDrag...$dragAmount\n" +
171-
"offset: ${offset.value}, " +
172-
"angle: ${animatable.value}"
182+
"offset: ${offsetAnimatable.value}, " +
183+
"angle: ${angleAnimatable.value}"
184+
173185

174186
},
175187
onDragCancel = {
@@ -178,21 +190,27 @@ fun DragPagerAndSwipeTest() {
178190
},
179191
onDragEnd = {
180192

181-
val angle = animatable.value
182-
if (angle < -20f) {
193+
val angle = angleAnimatable.value
194+
if (angle < -angleThreshold || angle > angleThreshold) {
183195
coroutineScope.launch {
184-
animatable.animateTo(-70f)
196+
angleAnimatable.animateTo(
197+
targetValue = angle * 2f,
198+
animationSpec = tween(250)
199+
)
185200
items.remove(items.lastIndex)
186201
}
187202
coroutineScope.launch {
188-
offset.animateTo(offset.value * 3f)
203+
offsetAnimatable.animateTo(
204+
targetValue = offsetAnimatable.value * 2f,
205+
animationSpec = tween(250)
206+
)
189207
}
190208
} else {
191209
coroutineScope.launch {
192-
animatable.animateTo(0f)
210+
angleAnimatable.animateTo(0f)
193211
}
194212
coroutineScope.launch {
195-
offset.animateTo(0f)
213+
offsetAnimatable.animateTo(0f)
196214
}
197215
}
198216
isDraggable = false
@@ -202,8 +220,8 @@ fun DragPagerAndSwipeTest() {
202220
)
203221
}
204222
.graphicsLayer {
205-
val angle = animatable.value
206-
val pos = offset.value
223+
val angle = angleAnimatable.value
224+
val pos = offsetAnimatable.value
207225
translationX = pos
208226
translationY = -pos * .25f
209227
rotationZ = angle
@@ -216,11 +234,21 @@ fun DragPagerAndSwipeTest() {
216234

217235
) {
218236

237+
val shape = RoundedCornerShape(16.dp)
238+
val angle = angleAnimatable.value
239+
240+
val borderColor = if (angle < -angleThreshold) {
241+
Red400
242+
} else if (angle > angleThreshold) {
243+
Green400
244+
} else {
245+
Color.LightGray
246+
}
219247
Column(
220248
modifier = Modifier
221-
.clip(RoundedCornerShape(16.dp))
222-
.border(1.dp, Color.LightGray, RoundedCornerShape(16.dp))
223-
.background(Color.White, RoundedCornerShape(16.dp))
249+
.shadow(elevation = 0.1.dp, shape = shape)
250+
.border(width = 2.dp, borderColor, shape = shape)
251+
.background(Color.White, shape)
224252
) {
225253
HorizontalPager(
226254
modifier = Modifier,

0 commit comments

Comments
 (0)