디자인 시스템을 개발하던 중, 내가 구현한 스와이프 기능에 대해 소개해보고자 한다.
AnchoredDraggable
스와이프 기능이 들어가는 컴포넌트는 스낵바이다.
화면에 띄워진 스낵바를 아래로 스와이프 했을 때 사라지도록 해야 하는 것이다.
처음에 나는 Modifier에서 제공하는 swipeable 속성을 사용하고 싶었다.
하지만 이는 Deprecated 되었다고 한다ㅜㅜ
그래서 찾아보니, swipeable을 대신해줄 AnchoredDraggable라는 속성이 있어서 이를 활용해주고자 했다.
아래는 AnchoredDraggable에 대해 설명하는 공식문서 링크이다!
https://developer.android.com/develop/ui/compose/touch-input/pointer-input/migrate-swipeable?hl=ko
Swipeable에서 AnchoredDraggable로 이전 | Jetpack Compose | Android Developers
이 페이지는 Cloud Translation API를 통해 번역되었습니다. Swipeable에서 AnchoredDraggable로 이전 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. Swipeable는 Compose Materia
developer.android.com
AnchoredDraggable에는 고정된 상태로 드래그 가능한 구성요소를 빌드하기 위한 Foundation API 하단 시트, 창 또는 스와이프하여 닫기 등 여러 가지 옵션이 있습니다. (by 공식문서)
공식문서를 참고하여 내가 작성한 코드에 대해 설명해보겠다.
✅우선, 드래그의 상태(DragValue)를 만들어준다.
나는 시작(스낵바가 화면에 있을 때)과 끝(스낵바를 아래로 드래그 했을 때)의 상태만 알면 됐기 때문에 Start와 End로 구성하였다.
enum class DragValue {
Start, End
}
✅그 다음, 드래그 가능한 상태를 관리하는 객체인 AnchoredDraggableState를 만들어준다.
val state = remember {
AnchoredDraggableState(
initialValue = DragValue.Start,
anchors = DraggableAnchors {
with(density) {
DragValue.Start at 0f
DragValue.End at 20.dp.toPx()
}
},
positionalThreshold = { distance: Float -> distance * 0.5f },
velocityThreshold = { with(density) { 50.dp.toPx() } },
animationSpec = tween(),
)
}
각 속성에 대해 설명하자면 아래와 같다.
- initialValue: 드래그의 시작 위치를 DragValue.Start로 설정한다.
- anchors: 드래그 가능한 지점을 정의한다.
- Start의 위치는 0f, End의 위치는 20dp아래로 잡아준다.
- 이때 toPx()를 사용하는데, 주의해야 할 사항은 LocalDensity를 통해 Density 객체를 얻어야 한다는 것이다!!
- positionalThreshold: 사용자가 어느 정도 거리까지 드래그해야 하는지를 결정한다.
- velocityThreshold: 사용자가 빠르게 스와이프할 경우 거리에 상관없이 End 위치로 스냅할지 결정합니다.
- animationSpec: 스냅 애니메이션을 설정한다.
✅ Modifier의 속성을 활용해준다.
val offsetY = remember { Animatable(0f) }
Column(
modifier = modifier
.offset {
IntOffset(
x = 0,
y = offsetY.value.roundToInt()
)
}
.anchoredDraggable(
state = state,
orientation = Orientation.Vertical,
)
)
- offset: offset을 사용해 스낵바 위치를 조정한다.
- anchoredDraggable: 드래그 기능을 추가해준다.
- 위에서 작성한 AnchoredDraggableState를 연결하여 스와이프 동작을 활성화한다.
- orientation 속성을 vertical로 작성하여 드래그 방향을 수직으로 제한한다.
✅ 마지막으로 드래그의 상태가 End일 때의 상황을 작성해준다.
if (state.currentValue == DragValue.End) {
onDismiss()
}
위 코드는 경우에 따라 유동적으로 작성해주면 될 것 같다!!
이번에 내가 구현한 스낵바의 경우 onDismiss()는 SnackBarData의 dismiss 함수를 호출하는 역할을 한다.
아래는 최종 구현 영상과 전체 코드이다.
@OptIn(ExperimentalFoundationApi::class)
@Composable
fun InfoSnackBar(
text: String,
onDismiss: () -> Unit,
modifier: Modifier = Modifier,
) {
val density = LocalDensity.current
val state = remember {
AnchoredDraggableState(
initialValue = DragValue.Start,
anchors = DraggableAnchors {
with(density) {
DragValue.Start at 0f
DragValue.End at 20.dp.toPx()
}
},
positionalThreshold = { distance: Float -> distance * 0.5f },
velocityThreshold = { with(density) { 50.dp.toPx() } },
animationSpec = tween(),
)
}
val offsetY = remember { Animatable(0f) }
if (state.currentValue == DragValue.End) {
onDismiss()
}
Column(
modifier = modifier
.offset {
IntOffset(
x = 0,
y = offsetY.value.roundToInt()
)
}
.padding(horizontal = 16.dp)
.fillMaxWidth()
.clip(RoundedCornerShape(12.dp))
.background(HandyTheme.colors.snackBarInfo)
.padding(16.dp)
.anchoredDraggable(
state = state,
orientation = Orientation.Vertical,
)
) {
Text(
text = text,
color = HandyTheme.colors.textBasicWhite,
maxLines = 2,
style = HandyTypography.B3Sb14
)
}
}
'Develop > Android' 카테고리의 다른 글
[Android] 단어 단위의 개행하기 (Compose) (0) | 2024.11.22 |
---|---|
[Android] LineBreak 속성 알아보기 (0) | 2024.11.08 |
[Android] 엠플리튜드(Amplitude) 안드로이드에 설치하기 (0) | 2024.10.15 |
[Android] 릴리즈 키 해시 뽑기 (0) | 2024.08.29 |
[Android] aab 파일 만들기 (0) | 2024.08.25 |