Skip to content

Commit

Permalink
refactor: add DraggableView class
Browse files Browse the repository at this point in the history
- update README
- add more specific example
- possibly breaking with previous implementation
- update dependencies / kotlin version
- deprecate DraggableImageView & previous extension method
  • Loading branch information
hyuwah committed Jan 27, 2021
1 parent 12e59a5 commit 038ab3a
Show file tree
Hide file tree
Showing 27 changed files with 1,127 additions and 591 deletions.
336 changes: 162 additions & 174 deletions README.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.

buildscript {
ext.kotlin_version = '1.3.71'
ext.kotlin_version = '1.4.21'
repositories {
google()
jcenter()

}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
Expand Down
16 changes: 7 additions & 9 deletions draggableviewlib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,15 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'

android {
compileSdkVersion 28


compileSdkVersion 29

defaultConfig {
minSdkVersion 19
targetSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'

}

Expand All @@ -29,10 +27,10 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])

implementation 'com.android.support:appcompat-v7:28.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
testImplementation 'junit:junit:4.13'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'

implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
}

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package io.github.hyuwah.draggableviewlib

object Draggable {

@Deprecated(
"Use DraggableView.Mode",
ReplaceWith("DraggableView.Mode", "io.github.hyuwah.draggableviewlib.DraggableView.Mode")
)
enum class STICKY {
NONE,
AXIS_X,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import android.content.Context
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import android.widget.ImageView
import androidx.appcompat.widget.AppCompatImageView
import io.github.hyuwah.draggableviewlib.Draggable.DRAG_TOLERANCE
import kotlin.math.abs
import kotlin.math.max
Expand All @@ -14,7 +14,9 @@ import kotlin.math.min
* 29/01/2019
* muhammad.whydn@gmail.com
*/
class DraggableImageView(context: Context, attrs: AttributeSet) : ImageView(context, attrs) {
@Deprecated("Setup any view programmatically using DraggableView class instead")
class DraggableImageView(context: Context, attrs: AttributeSet) :
AppCompatImageView(context, attrs) {

companion object {
const val NON_STICKY = 0
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
package io.github.hyuwah.draggableviewlib

import android.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.view.View
import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator

class DraggableView<T : View> private constructor(
targetView: T,
sticky: Mode,
animated: Boolean,
listener: DraggableListener?
) {

private var targetView: T = targetView
var sticky: Mode = Mode.NON_STICKY
set(value) {
field = value
enableDrag()
}
var animated: Boolean = true
set(value) {
field = value
enableDrag()
}
var listener: DraggableListener? = null
set(value) {
field = value
enableDrag()
}
var isMinimized: Boolean = false
private set

init {
this.sticky = sticky
this.animated = animated
this.listener = listener
enableDrag()
}

fun getView(): T = targetView

fun setViewPosition(x: Float, y: Float) {
targetView.x = x
targetView.y = y
}

/**
*
*/
fun disableDrag() {
targetView.setOnTouchListener(null)
}

/**
*
*/
fun enableDrag() {
targetView.setupDraggable(sticky, animated, listener)
}

/**
*
*/
fun show(durationMs: Int = 300) {
with(targetView) {
if (visibility != View.VISIBLE) {
visibility = View.VISIBLE
animate().scaleY(1f).scaleX(1f)
.setDuration(durationMs.toLong())
.setInterpolator(DecelerateInterpolator())
.setListener(null)
.start()
}
}
}

/**
*
*/
fun hide(durationMs: Int = 300) {
with(targetView) {
if (visibility != View.GONE) {
if (animation?.hasEnded() != false) {
animate().scaleY(0f).scaleX(0f)
.setInterpolator(AccelerateInterpolator())
.setDuration(durationMs.toLong())
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
super.onAnimationEnd(animation)
visibility = View.GONE
}
})
.start()
}
}
}
}

/**
*
*/
fun undock() {
if (!isMinimized) return
with(targetView) {
val parentWidth = (parent as View).width.toFloat()
when (sticky) {
Mode.STICKY_X -> {
when {
x < marginStart() -> {
animate().translationX(0f).start()
// minimizeButton?.animate()?.rotationBy(180f)
}
x > parentWidth - width - marginEnd() ->
animate().translationXBy(-(width / 2f) - marginEnd()).start()
}
enableDrag()
isMinimized = false
}
Mode.STICKY_Y -> {
// TODO
}
else -> return
}
}
}

/**
*
*/
fun dockToEdge() {
if (isMinimized) return
with(targetView) {
val parentWidth = (parent as View).width.toFloat()
when (sticky) {
Mode.STICKY_X -> {
when (x) {
marginStart() -> {
val targetDockedX = -((width.toFloat()) / 2 + marginStart())
animate().translationXBy(targetDockedX).start()
// minimizeButton?.animate()?.rotationBy(-180f)
}
parentWidth - width - marginEnd() -> {
val targetDockedX = ((width.toFloat() / 2) + marginEnd())
animate().translationXBy(targetDockedX).start()
}
}
disableDrag()
isMinimized = true
}
Mode.STICKY_Y -> {
// TODO
}
else -> return
}
}
}

/**
* Initialize draggable view
* - sticky mode set to Draggable.STICKY.NONE by default
* - animated set to true by default
*
* @param targetView target view
*/
class Builder<VIEW : View>(private var targetView: VIEW) {
private var stickyMode: Mode = Mode.NON_STICKY
private var animated: Boolean = true
private var listener: DraggableListener? = null

fun setStickyMode(mode: Mode) = apply { this.stickyMode = mode }
fun setAnimated(value: Boolean) = apply { this.animated = value }
fun setListener(listener: DraggableListener?) = apply { this.listener = listener }
fun build() = DraggableView(targetView, stickyMode, animated, listener)
}

enum class Mode {
NON_STICKY,
STICKY_X,
STICKY_Y,
STICKY_XY
}

// internal enum class StickyRestSide {
// INITIAL, HIDE, LEFT, TOP, RIGHT, BOTTOM,
// }
}
Loading

0 comments on commit 038ab3a

Please sign in to comment.