맞춤 뷰를 대화형으로 만들기

Compose 방식 사용해 보기
Jetpack Compose는 Android에 권장되는 UI 도구 키트입니다. Compose에서 레이아웃을 사용하는 방법을 알아보세요.
<ph type="x-smartling-placeholder"></ph> 동작 → 를 통해 개인정보처리방침을 정의할 수 있습니다.

UI 그리기는 맞춤 뷰 만들기 과정의 일부일 뿐입니다. 또한 다음을 수행해야 합니다. 뷰가 사용자 입력에 반응하도록 만드는데 실생활에서 하는 행동을 흉내 낼 수 있습니다.

앱의 객체가 실제 객체처럼 작동하도록 합니다. 예를 들어 앱의 이미지는 사라지고 다른 곳에 다시 나타날 수 있습니다. 왜냐하면 객체가 실제로도 그렇게 하지 마세요. 대신 이미지를 한 곳에서 다른 폴더로 있습니다.

사용자는 인터페이스에서 미묘한 행동이나 느낌까지 감지하며 세심한 주의를 기울여야 합니다. 예를 들어 사용자가 UI 객체를 플링하면 움직임을 지연시키는 시작 부분에 관성을 줍니다. 끝부분 물체를 움직일 수 있는 운동의 느낌을 주세요. 플링.

이 페이지에서는 Android 프레임워크의 기능을 사용하여 맞춤 뷰에 적용할 수 있습니다.

다음 링크에서 추가 관련 정보를 찾을 수 있습니다. 입력 이벤트 개요속성 애니메이션 개요를 참고하세요.

입력 동작 처리

다른 많은 UI 프레임워크와 마찬가지로 Android에서는 입력 이벤트 모델을 지원합니다. 사용자 작업이 콜백을 트리거하는 이벤트로 전환되며, 콜백을 사용하여 앱이 사용자에게 응답하는 방식을 맞춤설정할 수 있습니다. 가장 일반적인 입력은 이벤트는 터치이며 터치 포인트는 onTouchEvent(android.view.MotionEvent)입니다. 다음과 같이 이 메서드를 재정의하여 이벤트를 처리합니다.

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return super.onTouchEvent(event)
}

자바

@Override
   public boolean onTouchEvent(MotionEvent event) {
    return super.onTouchEvent(event);
   }

터치 이벤트 자체는 그다지 유용하지 않습니다. 최신 터치 UI 탭, 당기기, 밀어넣기, 플링, 확대/축소 등이 있습니다. 원시 터치 이벤트를 동작으로 변환하기 위해 Android는 제공 GestureDetector

클래스의 인스턴스를 전달하여 GestureDetector를 구성합니다. 이를 구현하는 GestureDetector.OnGestureListener입니다. 몇 가지 동작만 처리하려면 GestureDetector.SimpleOnGestureListener GestureDetector.OnGestureListener를 구현하는 대신 인터페이스에 추가되었습니다. 예를 들어 이 코드는 GestureDetector.SimpleOnGestureListener 및 재정의 onDown(MotionEvent)입니다.

Kotlin

private val myListener =  object : GestureDetector.SimpleOnGestureListener() {
    override fun onDown(e: MotionEvent): Boolean {
        return true
    }
}

private val detector: GestureDetector = GestureDetector(context, myListener)

자바

class MyListener extends GestureDetector.SimpleOnGestureListener {
   @Override
   public boolean onDown(MotionEvent e) {
       return true;
   }
}
detector = new GestureDetector(getContext(), new MyListener());

GestureDetector.SimpleOnGestureListener의 사용 여부와 관계없이 항상 onDown() 이 메서드는 true를 반환합니다. 이렇게 해야 하는 이유는 모든 동작이 onDown() 메시지로 시작합니다. false 반품 시 onDown()에서 GestureDetector.SimpleOnGestureListener가 실행하는 경우, 시스템은 나머지 동작과 GestureDetector.OnGestureListener가 호출되지 않습니다. 반품만 전체를 무시하려는 경우 onDown()false 동작입니다.

GestureDetector.OnGestureListener를 구현하고 만든 후 GestureDetector의 인스턴스를 원한다면 GestureDetector: 수신된 터치 이벤트를 해석 onTouchEvent()입니다.

Kotlin

override fun onTouchEvent(event: MotionEvent): Boolean {
    return detector.onTouchEvent(event).let { result ->
        if (!result) {
            if (event.action == MotionEvent.ACTION_UP) {
                stopScrolling()
                true
            } else false
        } else true
    }
}

자바

@Override
public boolean onTouchEvent(MotionEvent event) {
   boolean result = detector.onTouchEvent(event);
   if (!result) {
       if (event.getAction() == MotionEvent.ACTION_UP) {
           stopScrolling();
           result = true;
       }
   }
   return result;
}

onTouchEvent()에 전달하지 않는 터치 이벤트를 전달할 때 동작의 일부로 인식하면 false를 반환합니다. 그런 다음 자체 맞춤 동작 감지 코드가 있어야 합니다.

물리적으로 그럴듯한 움직임 만들기

동작은 터치스크린 기기를 제어하는 강력한 방법이지만, 물리적으로 제작하지 않으면 직관적이지 않고 기억하기가 타당한 결과를 도출합니다.

예를 들어 가로 플링 동작을 구현하고 싶다고 가정해 보겠습니다. 는 세로 축을 중심으로 회전하는 보기에 그려지는 항목을 설정합니다. 이 동작 UI가 플링 방향으로 빠르게 움직이면 마치 사용자가 플라이휠을 밀고 돌리는 것처럼 속도가 느려집니다.

스크롤을 애니메이션으로 표시 동작은 자체 스코어를 구현하는 방법에 관한 자세한 설명을 제공합니다. 있습니다. 하지만 플라이휠의 느낌을 시뮬레이션하는 것은 간단한 일이 아닙니다. 물리학이 많음 플라이휠 모델이 올바르게 작동하려면 수학이 필요합니다. 다행히 Android는 이 동작과 기타 동작을 시뮬레이션하는 도우미 클래스를 제공합니다. 이 Scroller 클래스는 플라이휠 스타일의 플링 동작을 처리하기 위한 기초입니다.

플링을 시작하려면 다음을 호출합니다. fling() 시작 속도와 최소 및 최대 속도인 xy 플링의 값입니다. 속도 값의 경우 GestureDetector

Kotlin

fun onFling(e1: MotionEvent, e2: MotionEvent, velocityX: Float, velocityY: Float): Boolean {
    scroller.fling(
            currentX,
            currentY,
            (velocityX / SCALE).toInt(),
            (velocityY / SCALE).toInt(),
            minX,
            minY,
            maxX,
            maxY
    )
    postInvalidate()
    return true
}

자바

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
   scroller.fling(currentX, currentY, velocityX / SCALE, velocityY / SCALE, minX, minY, maxX, maxY);
   postInvalidate();
    return true;
}
<ph type="x-smartling-placeholder">

fling() 호출은 플링의 물리 모델을 설정합니다. 동작입니다. 그런 다음 다음을 호출하여 Scroller를 업데이트합니다. Scroller.computeScrollOffset() 주기적으로 점검합니다. computeScrollOffset()Scroller 객체의 내부 상태를 물리학 모델을 사용하여 해당 지점에서 xy 위치를 계산합니다. 있습니다. 전화걸기 getCurrX()getCurrY() 이 값을 검색할 수 있습니다.

대부분의 뷰는 Scroller 객체의 xy를 전달합니다. 바로 배치할 수 있는 scrollTo()입니다. 이 예는 약간 다릅니다. 현재 스크롤 x 위치를 사용합니다. 보기의 회전 각도를 설정할 수 있습니다.

Kotlin

scroller.apply {
    if (!isFinished) {
        computeScrollOffset()
        setItemRotation(currX)
    }
}

자바

if (!scroller.isFinished()) {
    scroller.computeScrollOffset();
    setItemRotation(scroller.getCurrX());
}

Scroller 클래스는 스크롤 위치를 계산하지만 는 해당 위치를 뷰에 자동으로 적용하지 않습니다. 새 좌표 적용 스크롤 애니메이션이 부드럽게 보이도록 해야 합니다. 두 가지 방법으로 수행:

  • 다음을 호출하여 강제로 다시 그리세요. postInvalidate() fling() 호출 후 이 기법을 사용하려면 스크롤 오프셋을 계산하여 onDraw() 스크롤 오프셋이 실행될 때마다 postInvalidate() 호출 있습니다.
  • 설정 ValueAnimator 플링 시간 동안 애니메이션을 적용하고 프로세스에 리스너를 추가합니다. 애니메이션 업데이트 addUpdateListener()입니다. 이 기법을 사용하면 View

원활한 전환

사용자는 최신 UI가 상태(UI 요소) 간에 원활하게 전환되기를 기대합니다. 나타났다가 사라지는 대신 페이드 인되었다가 풀리며, 모션이 시작되어 갑작스럽게 시작했다가 멈추지 않고 부드럽게 종료하는 것이 일반적입니다. Android 속성 애니메이션 프레임워크를 사용하면 매끄러운 전환이 더 쉬워집니다.

속성이 변경될 때마다 애니메이션 시스템을 사용하려면 속성을 직접 변경하지 마세요. 대신 ValueAnimator하여 변경합니다. 다음 예에서 뷰에서 선택한 하위 구성요소를 수정하면 렌더링된 전체 구성요소가 선택 포인터가 중앙에 오도록 뷰가 회전합니다. ValueAnimator는 수백 개의 기간 동안 회전을 변경합니다. 새 회전 값을 즉시 설정하는 대신 밀리초 단위로 설정합니다.

Kotlin

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0).apply {
    setIntValues(targetAngle)
    duration = AUTOCENTER_ANIM_DURATION
    start()
}

자바

autoCenterAnimator = ObjectAnimator.ofInt(this, "Rotation", 0);
autoCenterAnimator.setIntValues(targetAngle);
autoCenterAnimator.setDuration(AUTOCENTER_ANIM_DURATION);
autoCenterAnimator.start();

변경하려는 값이 기본 View 중 하나인 경우 속성을 사용하면 애니메이션이 훨씬 더 쉽습니다. ViewPropertyAnimator 인코더-디코더는 여러 속성의 동시 애니메이션에 최적화된 다음 예를 참고하세요.

Kotlin

animate()
    .rotation(targetAngle)
    .duration = ANIM_DURATION
    .start()

Java

animate().rotation(targetAngle).setDuration(ANIM_DURATION).start();