#5 Android의 플로팅 윈도우: 윈도우 이동
저는 Floating Apps의 저자입니다. Google Play에서 최초의 앱이자 800만 다운로드 이상을 기록한 가장 인기 있는 앱입니다. 앱을 개발한 지 6년이 지난 후, 나는 그것에 대해 조금 알게 되었습니다. 때로는 까다로워서 문서와 Android 소스 코드를 읽고 실험하는 데 몇 달을 보냈습니다. 수만 명의 사용자로부터 피드백을 받았고 Android 버전이 다른 여러 휴대폰에서 다양한 문제를 확인했습니다.
여기에서 내가 배운 것이 있습니다.
이 기사를 읽기 전에 Floating Windows on Android 4: Floating Window 을 읽는 것이 좋습니다.
이 기사에서는 헤더를 드래그하여 창을 이동 가능하게 만드는 방법을 알려 드리겠습니다.
레이아웃 업데이트
이전 기사에서
WindowManager
와 함께 LayoutParams
에 뷰를 추가하는 방법을 소개했습니다. 단, 창이 추가되는 순간부터 LayoutParams
에 대한 변경 사항은 반영되지 않습니다.변경 사항을 적용하려면
updateViewLayout
의 WindowManager
메서드를 호출해야 합니다. 따라서 창 위치를 변경하기 위해 Window
클래스에 대해 두 가지 추가 메서드를 구현해야 합니다.private fun setPosition(x: Int, y: Int) {
windowParams.x = x
windowParams.y = y
update()
}
private fun update() {
try {
windowManager.updateViewLayout(rootView, windowParams)
} catch (e: Exception) {
// Ignore exception for now, but in production, you should have some
// warning for the user here.
}
}
물론 창의 크기, 불투명도 등을 변경하는 데에도 동일한 원리를 사용할 수 있습니다.
사용자 정의 OnTouchListener
창을 이동하기 위해 초기 지점의 이동을 추적할 수 있는 사용자 지정
OnTouchListener
을 구현해 보겠습니다. 또한 기본 기능인 클릭 및 긴 클릭을 유지하여 예상되는 시스템과 같은 방식으로 작동하도록 합시다.우리의 구현은 멀티터치를 지원하지 않지만 창을 이동하는 방법을 보여주기에는 충분합니다.
새로운
DraggableTouchListener
소스 코드는 다음과 같습니다.class DraggableTouchListener(
context: Context,
private val view: View,
private val initialPosition: () -> Point,
private val positionListener: (x: Int, y: Int) -> Unit
) : View.OnTouchListener {
private val touchSlop = ViewConfiguration.get(context).scaledTouchSlop
private val longClickInterval = ViewConfiguration.getLongPressTimeout()
private var pointerStartX = 0
private var pointerStartY = 0
private var initialX = 0
private var initialY = 0
private var moving = false
private var longClickPerformed = false
private var timer: Timer? = null
init {
view.setOnTouchListener(this)
}
private fun scheduleLongClickTimer() {
if (timer == null) {
timer = Timer()
timer?.schedule(timerTask {
if (!moving && !longClickPerformed) {
view.post {
view.performLongClick()
}
longClickPerformed = true
}
cancelLongClickTimer()
}, longClickInterval.toLong())
}
}
private fun cancelLongClickTimer() {
timer?.cancel()
timer = null
}
override fun onTouch(view: View, motionEvent: MotionEvent): Boolean {
when (motionEvent.action) {
MotionEvent.ACTION_DOWN -> {
pointerStartX = motionEvent.rawX.toInt()
pointerStartY = motionEvent.rawY.toInt()
with(initialPosition()) {
initialX = x
initialY = y
}
moving = false
longClickPerformed = false
scheduleLongClickTimer()
}
MotionEvent.ACTION_MOVE -> {
if (!longClickPerformed) {
val deltaX = motionEvent.rawX - pointerStartX
val deltaY = motionEvent.rawY - pointerStartY
if (moving || hypot(deltaX, deltaY) > touchSlop) {
cancelLongClickTimer()
positionListener(initialX + deltaX.toInt(), initialY + deltaY.toInt())
moving = true
}
}
}
MotionEvent.ACTION_UP -> {
cancelLongClickTimer()
if (!moving && !longClickPerformed) {
view.performClick()
}
}
}
return true
}
}
좀 더 쉽게 사용할 수 있도록 약간의 Kotlin 매직(확장 기능)을 추가할 수 있습니다.
fun View.registerDraggableTouchListener(
initialPosition: () -> Point,
positionListener: (x: Int, y: Int) -> Unit
) {
DraggableTouchListener(context, this, initialPosition, positionListener)
}
이론적으로 위의 코드로 무엇이든 이동할 수 있습니다. 보기는 여기에서 트리거 역할만 합니다.
창문을 움직이자
우리가 해야 할 일은 새로 생성된
DraggableTouchListener
뷰를 창 이동 핸들로 사용하려는 뷰에 연결하는 것입니다.데스크톱 운영 체제의 경우 일반적으로 창의 제목 표시줄이 이러한 용도로 사용되므로 동일한 추세를 따르도록 하겠습니다.
rootView.findViewById<View>(R.id.window_header).registerDraggableTouchListener(
initialPosition = { Point(windowParams.x, windowParams.y) },
positionListener = { x, y -> setPosition(x, y) }
)
그리고 그게 다야!
경계
프로덕션 용도에서는 일부 경계를 구현해야 하므로 창이 화면 밖으로 너무 많이 이동할 수 없습니다.
Floating Apps에서는 사용자가 화면 영역 외부로 창의 50%를 이동할 수 있도록 합니다.
결과
창의 제목 표시줄을 누르고 원하는 곳으로 이동하세요!
소스 코드
이 기사의 전체 소스 코드는 available on Github 입니다.
계속 지켜봐 주세요
Android 개발에 대해 자세히 알고 싶으십니까? Twitter에서 저( )와 Localazy( )를 팔로우하거나 좋아요Localazy on Facebook를 하세요.
시리즈
이 문서는 Android의 Floating Windows 시리즈의 일부입니다.
Reference
이 문제에 관하여(#5 Android의 플로팅 윈도우: 윈도우 이동), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/localazy/5-floating-windows-on-android-moving-window-1192텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)