[Comppose] 터치 - Press

panax·2024년 1월 16일
0

Compose

목록 보기
3/4
post-thumbnail

☕Press

사용자 동작 중에서 누르는 동작에 대한 내용을 소개
High-level 단계에서 처리하는 방법이 중심으로 작성됨

Tap(Click): 누르고 떼기
Double tap: Tap 이후 일정 시간 안에 Tap
Press: 누르고 있기
Long press: 일정 시간 Press

☕clickable

가장 기본적인 클릭 처리 방법

// 컴포넌트 크기 만큼 터치 가능
Modifier
	.size(100.dp)
	.background(Color.Cyan)
	.clickable {}

// 컴포넌트 크기에서 10.dp 만큼 줄어든 영역만 터치 가능
Modifier
	...
	.padding(10.dp)
	.clickable{}

padding 속성 이후에 선언하면 패딩이 적용된 영역만 터치가 적용된다.

☕combinedClickable

combinedClickable은 clickable에서 더블 클릭길게 누르기가 추가됐다.

Modifier
	.combinedClickable(
        onLongClick = {},
        onDoubleClick = {},
        onClick = {}
    )

기본적으로 더블 클릭과 길게 누르기의 시간은 각각 0.3, 0.4초로 설정되어 있다.
만약 시간을 바꾸려면 ViewConfiguration 인터페이스를 구현해야 한다.
구현한 클래스를 LocalViewConfiguration에 설정하면 시간을 변경할 수 있다.

// 커스텀 ViewConfriguration
// touchSlop는 8f가 기본으로 되어 있다.
private class CustomViewConfiguration : ViewConfiguration {
    override val doubleTapMinTimeMillis: Long
        get() = 1000
    override val doubleTapTimeoutMillis: Long
        get() = 2000
    override val longPressTimeoutMillis: Long
        get() = 3000
    override val touchSlop: Float
        get() = 8f
}

// 커스텀 클래스를 설정해준다.
CompositionLocalProvider(
    LocalViewConfiguration provides CustomViewConfiguration()
) {
	// 테스트 확인용 텍스트
    var text by remember { mutableStateOf("") }

    Text(
        modifier = Modifier
            .combinedClickable(
                onLongClick = { text = "Long Clicked" },
                onDoubleClick = { text = "Double Clicked" },
                onClick = { text = "Clicked" }
            ),
        text = text,
    )
}

☕selectable

선택하는 컴포넌트를 구현할 때 사용하는 Modifier 속성
clickable로 비슷한 동작을 만들 수 있고, 실제 내부 코드를 보면 clickable을 사용하고 있다.
selectable을 사용하는 이유는 UI 접근성테스트 때문으로 자세한 내용은 공식 문서 참조

clickable와 달리 선택된 상태를 전달해야 한다.

Modifier
	.selectable(
       selected = true or false,
       onClick = { },
    )

☕toggleable

toggleable은 다른 속성과 달리 콜백 함수로 토글 상태를 전달받는다.
toggleable도 clickable로 구현이 되지만, not 연산자동이라 좀 더 편하다.
toggleable은 내부적으로 밑에서 나올 triStateToggleable을 사용한다.

// onValueChange은 항상 value에 not 연산 결과가 나온다.
// 이 경우에는 false가 나온다.
Modifier
	.toggleable(
       value = true,
       onValueChange = { state -> },
    )

☕triStateToggleable

내부적으로 clickable을 사용한다.
toggleable와 다른 점은 toggleable은 콜백으로 Boolean 타입을 주지만
triStateToggleable은 ToggleableState라는 enum 클래스를 반환한다.

ToggleableState는 On, Off, Indeterminate로 이루어져 있다.
토글 기능을 만들 때 On, Off 외에 다른 상태를 사용하고 싶을 때 사용할 수 있다.

Modifier
    .triStateToggleable(
        state = ToggleableState.Indeterminate,
        onClick = {  },
    )

☕Ripple effect

Ripple은 버튼을 눌렀을 때 살짝 어두워지는 효과를 말한다.
위에 나온 속성을 적용하면 기본 효과가 적용되는데, 디자인에 따라 변경해야할 수도 있다.
크게 2가지 방법으로 직접 만들거Indication을 적용하는 방법이 있다.

직접 만드는 방법은 말 그대로 클릭 상태에 따라 background 색상을 바꾸는 방법이다.
디자인에 따라 쉬울 수도 있지만, 컴포넌트마다 따로 만들어야 하는 문제가 있다.

반면 Indication을 사용하는 방법은 여러 컴포넌트에 사용할 수 있고 전체에 적용할 수도 있다.

InteractionSource: 사용자 상호작용 정보를 가지는 인터페이스, 속성마다 존재
Indication: InteractionSource에서 전달받은 정보로 시각적인 효과를 만듬

먼저 Indication을 만든다. 색상은 빨간색으로 만들었다.

private class CustomIndication: Indication {
    private class CustomIndicationInstance(
        private val isPressed: State<Boolean>,
        private val isHovered: State<Boolean>,
        private val isFocused: State<Boolean>,
    ) : IndicationInstance {
        override fun ContentDrawScope.drawIndication() {
            drawContent()
            if (isPressed.value) {
                drawRect(color = Color.Red.copy(alpha = 0.8f), size = size)
            } else if (isHovered.value || isFocused.value) {
                drawRect(color = Color.Red.copy(alpha = 0.8f), size = size)
            }
        }
    }

    @Composable
    override fun rememberUpdatedInstance(
        interactionSource: InteractionSource
    ): IndicationInstance {
    
        val isPressed = interactionSource.collectIsPressedAsState()
        val isHovered = interactionSource.collectIsHoveredAsState()
        val isFocused = interactionSource.collectIsFocusedAsState()
        
        return remember(interactionSource) {
            CustomIndicationInstance(isPressed, isHovered, isFocused)
        }
    }
}

컴포넌트 하나에 적용하려면 컴포넌트 파라미터 중에 indication에 추가하면 된다.

Modifier
	.clickable(
        interactionSource = remember { MutableInteractionSource() },
        indication = CustomIndication(),
        onClick = {}
    )

컴포넌트 전체에 적용하려면 CompositionLocalProvider를 사용한다.

CompositionLocalProvider(
	LocalIndication provides CustomIndication()
) {
	...
    Modifier
    	.clickable {}
    ...
}

더 자세한 내용은 공식 문서 참조

profile
안드로이드 개발자

0개의 댓글