와챠의 우당탕탕 개발 기록장

[안드로이드] draggable(movable), clickable view 만들기/onTouch, onClick Listener 동시에 달기(밀리의 서재의 그것) 본문

코딩 일기장/Android(Kotlin)

[안드로이드] draggable(movable), clickable view 만들기/onTouch, onClick Listener 동시에 달기(밀리의 서재의 그것)

minWachya 2021. 8. 16. 16:45
반응형

책을 좀 읽어야겠어서 밀리의 서재를 깔았는데

헉 이거 어케 만든 거임!?!?! 하는 게 또 있었다.

 

뭐냐면 이거임... : 

이렇게

1, 내가 원하는 위치에 드래그도 되고

2, 다시 벽에 붙기도 하고

3, 심지어 클릭도 되는!!!!!

귀엽고 멋진 기능이었다.

 

이거 관련 라이브러리가 분명 어디 있을 거 같은데

못찾겠어서...^

직접 만들어봤다.

 

내가 만든 것 :

 

완전 똑같지는 않지만 내가 구현하고 싶었던 기능들은 다 구현해보았다!!!!!


activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical"
android:background="@color/white">
<!--floating/draggable/clickable layout-->
<!--책 이미지와 책 정보를 담을 레이아웃-->
<LinearLayout
android:id="@+id/floatingLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<!--책 정보 레이아웃 -->
<LinearLayout
android:id="@+id/innerLayout"
android:layout_width="180dp"
android:layout_height="80dp"
android:background="@drawable/custom_layout"
android:visibility="gone"
android:orientation="horizontal"
android:gravity="center">
<!--책 제목, 읽은 정도-->
<LinearLayout
android:id="@+id/inner1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_weight="7">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="애린왕자"
android:textColor="@color/black"
android:textStyle="bold"
android:textSize="14sp"
android:layout_marginStart="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="10%"
android:textColor="@color/black"
android:textSize="10sp"
android:layout_marginStart="10dp"/>
</LinearLayout>
<!--북마크-->
<LinearLayout
android:id="@+id/inner2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/gray"
android:layout_weight="3"
android:gravity="center">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_baseline_bookmark_24"
android:contentDescription="북마크" />
</LinearLayout>
</LinearLayout>
<!--책 이미지-->
<ImageView
android:layout_width="50dp"
android:layout_height="80dp"
android:layout_marginStart="5dp"
android:src="@drawable/img_book"
android:contentDescription="책 이미지" />
</LinearLayout>
</LinearLayout>

floatingView 클릭했을 때 innerLayout이 이동하는 애니메이션들

anim > transform_visible.xml

<?xml version="1.0" encoding="utf-8"?>
<!--innerLayout이 visible일 때 애니메이션-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--(-60%)에서 (20%)만큼 (0.2초간)이동-->
<translate
android:duration="200"
android:fromXDelta="-60%"
android:toXDelta="20%"/>
<!--현재 위치에서 (-20%)만큼 (0.2초간)이동-->
<translate
android:startOffset="200"
android:duration="200"
android:fromXDelta="0"
android:toXDelta="-20%"/>
</set>

anim > transform_gone.xml

<?xml version="1.0" encoding="utf-8"?>
<!--innerLayout이 gone일 때 애니메이션-->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<!--(160%)에서 (-10%)만큼 (0.2초간)이동-->
<translate
android:duration="200"
android:fromXDelta="160%"
android:toXDelta="-10%" />
<!--현재 위치에서 (10%)만큼 (0.2초간)이동-->
<translate
android:startOffset="200"
android:duration="200"
android:fromXDelta="0"
android:toXDelta="10%" />
</set>

MainActivity.kt

package com.example.millietest
import android.annotation.SuppressLint
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.view.animation.AnimationUtils
import android.widget.LinearLayout
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.min
class MainActivity : AppCompatActivity() {
private var widgetInitialX: Float = 0F
private var widgetDX: Float = 0F
private var widgetInitialY: Float = 0F
private var widgetDY: Float = 0F
@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val floatingLayout = findViewById<LinearLayout>(R.id.floatingLayout)
val innerLayout = findViewById<LinearLayout>(R.id.innerLayout)
val inner1 = findViewById<LinearLayout>(R.id.inner1)
val inner2 = findViewById<LinearLayout>(R.id.inner2)
// 사용자가 드래그한대로 움직이기
floatingLayout.setOnTouchListener { v, event ->
val viewParent = v.parent as View
val parentHeight = viewParent.height
val parentWidth = viewParent.width
val xMax = parentWidth - v.width
val yMax = parentHeight - v.height
when (event.action) {
// 드래그 시작
MotionEvent.ACTION_DOWN -> {
// 시작 위치 저장
widgetDX = v.x - event.rawX
widgetDY = v.y - event.rawY
widgetInitialX = v.x
widgetInitialY = v.y
true
}
// 드래그 중
MotionEvent.ACTION_MOVE -> {
// 드래그된 위치로 view 위치 변경
var newX = event.rawX + widgetDX
newX = max(0F, newX)
newX = min(xMax.toFloat(), newX)
v.x = newX
var newY = event.rawY + widgetDY
newY = max(0F, newY)
newY = min(yMax.toFloat(), newY)
v.y = newY
true
}
// 드래그 끝
MotionEvent.ACTION_UP -> {
// y는 그대로, x만 벽에 달라붙게 하기
// v.animate().x(xMax.toFloat()).setDuration(300L).start() // 이렇게 하면 오른쪽 벽에 달라붙음
// v.animate().x(0f).setDuration(300L).start() // 왼쪽 벽에 달라붙기
// 벽 안으롱 들어갔다가 나오는 (튕기는) 애니메이션 달기
v.animate().x(-50f).setDuration(200L).withEndAction {
v.animate().x(0f).setDuration(200L).start()
}.start()
// 이동이 별로 없다면 터치로 인식
if (abs(v.x - widgetInitialX) <= 16 && abs(v.y - widgetInitialY) <= 16)
v.performClick()
true
}
else -> false
}
}
// innerLayout이 보일 때와 안 보일 때 애니메이션 달기
val aniVisible = AnimationUtils.loadAnimation(applicationContext,R.anim.translate_visible)
val aniGone = AnimationUtils.loadAnimation(applicationContext,R.anim.transform_gone)
floatingLayout.setOnClickListener {
// innerLayout 보이기
if (innerLayout.visibility == View.GONE) {
innerLayout.visibility = View.VISIBLE
floatingLayout.startAnimation(aniVisible)
}
// innerLayout 사라지기
else {
innerLayout.visibility = View.GONE
floatingLayout.startAnimation(aniGone)
}
}
// innerLayout 안의 child에 클릭 리스너 달기
inner1.setOnClickListener {
Toast.makeText(applicationContext, "애린왕자 : 10%", Toast.LENGTH_SHORT).show()
}
inner2.setOnClickListener {
Toast.makeText(applicationContext, "북마크 클릭", Toast.LENGTH_SHORT).show()
}
}
}
view raw MainActivity.kt hosted with ❤ by GitHub

floatingLayout 참고

https://kimch3617.tistory.com/entry/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EA%B0%84%EB%8B%A8%ED%9E%88-View-%EC%9B%80%EC%A7%81%EC%9D%B4%EA%B2%8C-%ED%95%98%EA%B8%B0-Drag-and-Drop?category=615642 

 

안드로이드 간단히 View 움직이게 하기 (Drag and Drop)

View에 Touch 이벤트로 움직이는 모션을 구현하고자 할 때 var moveX = 0f var moveY = 0f move_view.setOnTouchListener { v, event -> when(event.action) { MotionEvent.ACTION_DOWN -> { moveX = v.x - event...

kimch3617.tistory.com

https://developer.android.com/guide/topics/ui/drag-drop#StartDrag

 

드래그 앤 드롭  |  Android 개발자  |  Android Developers

Android 드래그 앤 드롭 프레임워크를 사용하면 사용자가 그래픽 드래그 앤 드롭 동작을 사용하여 데이터를 옮길 수 있습니다. 이 작업은 자체 앱의 뷰 간에 또는 멀티 윈도우 모드를 사용 설정한

developer.android.com

https://stackoverflow.com/questions/46370836/android-movable-draggable-floating-action-button-fab

 

Android - Movable/Draggable Floating Action Button (FAB)

I am using a FloatingActionButton in my app. Occasionally, it overlaps essential content, so I would like to make it so the user can drag the FAB out of the way. No drag and drop functionality, pe...

stackoverflow.com

https://github.com/hyuwah/DraggableView

 

GitHub - hyuwah/DraggableView: DraggableView is an Android library to make floating draggable view easily using extensions on Ko

DraggableView is an Android library to make floating draggable view easily using extensions on Kotlin & provided utils class on Java - GitHub - hyuwah/DraggableView: DraggableView is an Android...

github.com


animation 참고

https://m.blog.naver.com/tkddlf4209/220700530627

 

[Android] 안드로이드 애니메이션(Animation)효과 주기 트윈애니메이션(TweenAnimation)

오늘은 트윈애니메이션(TweenAnimation)을 사용해 보도록 하겠습니다. * 트윈애니메이션 : 위치나 크기, ...

blog.naver.com

https://www.crocus.co.kr/1690

 

Crocus

Beginner와 Developer사이의 Crocus

www.crocus.co.kr


+)아니 분명 관련 라이브러리가 있을 거 같은데,,,,,,,,,,이상하다

 

++)아!! 이거 만들면서 재밌는 일이 있었다.

내가 코드를 잘못 짰다고 생각했는데 이게 잘 돌아가는 거다 ㅋㅋㅋㅋㅋ

실행 화면을 보면서 물음표를 백만개 띄운 그 순간이 참 재밌었다...킥킥

 

그동안 코딩하면서 "왜 안되지?" 하는 순간이 많았는데

이번엔 첨으로 "왜 되지?!"하는 순간이 생겨서 넘 재밌었다.

반응형
Comments