요약
지난 번에 공부했던, anchoredDraggable
을 이용하여 슬라이드를 통한 공을 던지는 모션을 제작해보고자 합니다.
공의 시작 위치는 기기의 하단 가운데 이며 위로 스크롤 하게 되면, 상단 중앙 포수가 있는 위치까지 날아가게 됩니다.
사용자가 던지게 되면, graphicsLayer
를 통해 rotationZ
값을 drag
된 위치에 따라 계산하여, 회전하는 듯한 모션을 주어 공을 던지는 느낌을 주었습니다.
또한 공이 포수 위치까지 도달하게 되면, coroutine
을 이용하여 0.5
초 딜레이를 주어 다시 원래 초기 위치로 돌아가도록 설정하였습니다.
완성
전체 코드
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ShootingballTheme {
// A surface container using the 'background' color from the theme
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colorScheme.background
) {
Ground()
}
} } }
}
@OptIn(ExperimentalFoundationApi::class)
@Composable
private fun Ground(modifier: Modifier = Modifier){
var componentSize by remember {
mutableStateOf(IntSize.Zero)
}
val density = LocalDensity.current
var state = remember {
AnchoredDraggableState(
initialValue = Position.Start,
positionalThreshold = {totalDistance : Float -> totalDistance},
velocityThreshold = {Float.MIN_VALUE},
animationSpec = tween()
)
}
LaunchedEffect(componentSize){
if(componentSize.width > 0) {
val endPosition = with(density){(componentSize.height - 40.dp.toPx()) - 60.dp.toPx()}
state.updateAnchors(
DraggableAnchors {
Position.Start at -0f
Position.End at -endPosition
}
)
if(state.offset.isNaN()) {
}
}
}
LaunchedEffect(state.currentValue){
if(state.currentValue == Position.End){
delay(1000)
state.snapTo(Position.Start)
}
}
Box(
modifier = modifier
.fillMaxSize()
.background(color = Color.LightGray)
.onGloballyPositioned {
componentSize = it.size
}
){
Image(
painter = painterResource(id = R.drawable.posu),
contentDescription = "",
modifier = Modifier
.size(120.dp)
.align(Alignment.TopCenter)
)
Text(
text = if(state.currentValue == Position.Start) "던지세요" else "스트라이크",
style = MaterialTheme.typography.bodyLarge,
modifier = Modifier.align(Alignment.Center)
)
val safeOffset = if(state.offset.isNaN()) 0f else state.offset
Box(
modifier = Modifier
.align(Alignment.BottomCenter)
.offset {
IntOffset(0, (safeOffset.roundToInt()))
}
.scale((componentSize.height - state.offset) / componentSize.height)
){
Image(
painter = painterResource(id = R.drawable.baseball),
contentDescription = "",
modifier = Modifier
.size(40.dp)
.clip(CircleShape)
.anchoredDraggable(
state = state,
orientation = Orientation.Vertical
)
.graphicsLayer {
rotationZ = state.offset % 360
}
)
}
}}
enum class Position{
Start, End
}
깃허브
https://github.com/Myeongcheol-shin/shooting-ball
'안드로이드 > Compose' 카테고리의 다른 글
[Kotlin/Compose] SnowFall Effect 만들기 (0) | 2023.12.24 |
---|---|
[Kotlin/Compose] 반응형 이미지 만들기 (2) | 2023.12.22 |
[Kotlin/Compose] Scroll Fade-In/Out animation (0) | 2023.12.22 |
[Kotlin/Compose] Slide-Unlock(밀어서 잠금해제) 기능 개발하기 (2) (0) | 2023.12.15 |
[Kotlin/Compose] Slide-Unlock(밀어서 잠금해제) 기능 개발하기 (1) (0) | 2023.12.15 |