diff --git a/drag/src/main/java/com/tuanhav95/drag/DragView.kt b/drag/src/main/java/com/tuanhav95/drag/DragView.kt index 98635b0..53a8d5b 100644 --- a/drag/src/main/java/com/tuanhav95/drag/DragView.kt +++ b/drag/src/main/java/com/tuanhav95/drag/DragView.kt @@ -2,6 +2,7 @@ package com.tuanhav95.drag import android.annotation.SuppressLint import android.content.Context +import android.graphics.Rect import android.util.AttributeSet import android.view.* import android.widget.RelativeLayout @@ -10,7 +11,7 @@ import com.google.android.material.appbar.AppBarLayout import com.tuanhav95.drag.utils.* import com.tuanhav95.drag.widget.DragBehavior import com.tuanhav95.drag.widget.DragLayout -import kotlinx.android.synthetic.main.layout_draggable_panel.view.* +import kotlinx.android.synthetic.main.layout_drag_view.view.* import kotlin.math.abs open class DragView @JvmOverloads constructor( @@ -19,6 +20,8 @@ open class DragView @JvmOverloads constructor( companion object { + var DEBUG = true + private var scaledTouchSlop = 0 private fun getScaledTouchSlop(context: Context): Int { @@ -41,29 +44,31 @@ open class DragView @JvmOverloads constructor( } } + var showKeyboard = false var frameInitializing = false// toàn bộ giao diện đã được khởi tạo hay chưa - var finalState: State? = null// trạng thái của Draggable đang hướng đến - var finalHeight = 0// chiều tao của view first đang hướng đến khi max - + var needExpand = true// cần expand appbarLayout var firstViewMove = false// view first đang được di chuyển - var velocityY = 0f - var velocityTracker: VelocityTracker? = null + var mTempState: State? = null// trạng thái của Draggable đang hướng đến + var mTempHeight = 0// chiều tao của view first đang hướng đến khi max + + var velocityY = 0f// tốc độ khi MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL + var velocityTracker: VelocityTracker? = null // tốc độ khi MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL var mCurrentState: State? = null var mCurrentPercent = -1f var mCurrentMarginTop = -1 var mHeightWhenMax = 0 - var mHeightWhenMaxDefault = 0 + var mHeightWhenMaxDefault = -1 var mHeightWhenMiddle = 0 - var mHeightWhenMiddleDefault = 0 + var mHeightWhenMiddleDefault = -1 var mPercentWhenMiddle = 0f var mHeightWhenMin = 0 - var mHeightWhenMinDefault = 0 + var mHeightWhenMinDefault = -1 var mMarginTopWhenMin = 0 var mMarginEdgeWhenMin = 0 @@ -75,11 +80,11 @@ open class DragView @JvmOverloads constructor( visibility = View.INVISIBLE - inflate(context, R.layout.layout_draggable_panel, this) + inflate(context, R.layout.layout_drag_view, this) if (attrs != null) { val typedArray = context.obtainStyledAttributes(attrs, R.styleable.DragView) - mHeightWhenMax = typedArray.getDimensionPixelSize(R.styleable.DragView_height_when_max, 200.toPx()) + mTempHeight = typedArray.getDimensionPixelSize(R.styleable.DragView_height_when_max, 200.toPx()) mPercentWhenMiddle = typedArray.getFloat(R.styleable.DragView_percent_when_middle, 0.9f) @@ -89,11 +94,11 @@ open class DragView @JvmOverloads constructor( mMarginBottomWhenMin = typedArray.getDimensionPixelSize(R.styleable.DragView_margin_bottom_when_min, 8.toPx()) - finalState = State.values()[typedArray.getInt(R.styleable.DragView_state, 3)] + mTempState = State.values()[typedArray.getInt(R.styleable.DragView_state, 3)] typedArray.recycle() } else { - mHeightWhenMax = 200.toPx() + mTempHeight = 200.toPx() mPercentWhenMiddle = 0.9f @@ -103,11 +108,10 @@ open class DragView @JvmOverloads constructor( mMarginBottomWhenMin = 8.toPx() - finalState = State.CLOSE + mTempState = State.CLOSE } - finalHeight = mHeightWhenMax - mHeightWhenMaxDefault = mHeightWhenMax + mHeightWhenMaxDefault = mTempHeight mHeightWhenMinDefault = mHeightWhenMin frameDrag.onTouchListener = object : DragLayout.OnTouchListener { @@ -179,24 +183,37 @@ open class DragView @JvmOverloads constructor( } viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { + private var currentHeight = 0 override fun onGlobalLayout() { - viewTreeObserver.removeOnGlobalLayoutListener(this) - initFrame() - } - }) + if (height == currentHeight) return + currentHeight = height + + val r = Rect() - appbarLayout.addOnOffsetChangedListener(object : AppBarLayout.OnOffsetChangedListener { + getWindowVisibleDisplayFrame(r) - private var verticalOffsetOld = 0 + val screenHeight = rootView.height + val keyboardHeight = screenHeight - r.bottom - override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) { - if (frameInitializing && mCurrentPercent == 0f && !firstViewMove) { - val offset = abs(verticalOffset) - val delta = offset - verticalOffsetOld - verticalOffsetOld = offset + if (keyboardHeight > 200) { + showKeyboard = true + appbarLayout.setExpanded(false, false) + } else { + showKeyboard = false + } - mHeightWhenMin += delta - mHeightWhenMiddle += delta + initFrame() + } + }) + + appbarLayout.addOnOffsetChangedListener(AppBarLayout.OnOffsetChangedListener { _, verticalOffset -> + if (frameInitializing && !firstViewMove) { + if (mCurrentPercent == 0f) { + mHeightWhenMin = mHeightWhenMinDefault - verticalOffset + mHeightWhenMiddle = mHeightWhenMiddleDefault - verticalOffset + } else if (mCurrentPercent == 1f && showKeyboard) { + mHeightWhenMin = mHeightWhenMinDefault + mHeightWhenMiddle = mHeightWhenMiddleDefault } } }) @@ -208,36 +225,59 @@ open class DragView @JvmOverloads constructor( open fun initFrame() { frameInitializing = true - val params = frameFirst.layoutParams as CoordinatorLayout.LayoutParams - params.behavior = DragBehavior(frameSecond) - frameFirst.layoutParams = params + mMarginTopWhenMin = height - mHeightWhenMinDefault - mMarginBottomWhenMin - mMarginTopWhenMin = height - mHeightWhenMin - mMarginBottomWhenMin + if (mCurrentState == null) { + val params = frameFirst.layoutParams as CoordinatorLayout.LayoutParams + params.behavior = DragBehavior(frameSecond) + frameFirst.layoutParams = params + } - mHeightWhenMax = finalHeight - mHeightWhenMaxDefault = (width * 9 / 16f).toInt() + mHeightWhenMax = mTempHeight + if (mCurrentState == null) { + mHeightWhenMaxDefault = (width * 9 / 16f).toInt() + } mHeightWhenMiddle = (height - mPercentWhenMiddle * mMarginBottomWhenMin - mPercentWhenMiddle * mMarginTopWhenMin).toInt() - mHeightWhenMiddleDefault = mHeightWhenMiddle + if (mCurrentState == null) { + mHeightWhenMiddleDefault = mHeightWhenMiddle + } - /** - * close - */ - translationY = (mHeightWhenMinDefault + mMarginBottomWhenMin).toFloat() - setMarginTop(mMarginTopWhenMin) - gone() - when (finalState) { - State.MAX -> { - maximize() - } - State.MIN -> { - minimize() - } - else -> { - close() + if (mCurrentState == null) { + + translationY = (mHeightWhenMinDefault + mMarginBottomWhenMin).toFloat() + setMarginTop(mMarginTopWhenMin) + gone() + + when (mTempState) { + State.MAX -> { + maximize() + } + State.MIN -> { + minimize() + } + else -> { + close() + } } + } else { + refresh() + mCurrentMarginTop = (frameDrag.layoutParams as LayoutParams).topMargin } + + } + + open fun isMaximize(): Boolean { + return mCurrentState == State.MAX + } + + open fun isMinimize(): Boolean { + return mCurrentState == State.MIN + } + + open fun isClose(): Boolean { + return mCurrentState == State.CLOSE } open fun getFrameDrag(): ViewGroup { @@ -259,44 +299,70 @@ open class DragView @JvmOverloads constructor( /** * thiết lập chiều cao first view */ - open fun setHeightMax(height: Int) { - finalHeight = height - if (frameInitializing && finalState == mCurrentState) {// nếu view đã được khởi tạo và đã không drag thì sẽ mở rộng + open fun setHeightMax(height: Int, goToMaximize: Boolean = true) { + needExpand = true + mTempHeight = height + if (frameInitializing && mTempState == mCurrentState && goToMaximize) {// nếu view đã được khởi tạo và đã không drag thì sẽ mở rộng maximize() } } /** - * mở rộng view + * mở rộng lâyout */ open fun maximize() { - finalState = State.MAX + mTempState = State.MAX if (!frameInitializing) { return } when (mCurrentState) { State.MAX -> { - appbarLayout.resizeAnimation(-1, finalHeight, 300) { - mHeightWhenMax = finalHeight + appbarLayout.resizeAnimation(-1, mTempHeight, 300) { + mHeightWhenMax = mTempHeight + + if (mCurrentPercent != 0f || (!needExpand && !showKeyboard)) { + updateState() + return@resizeAnimation + } + + appbarLayout.addOnOffsetChangedListener(object : AppBarLayout.OnOffsetChangedListener { + override fun onOffsetChanged(appBarLayout: AppBarLayout?, verticalOffset: Int) { + if (mCurrentPercent != 0f || !needExpand) { + appbarLayout.removeOnOffsetChangedListener(this) + return + } + + if (abs(verticalOffset) == 0) { + updateState() + + needExpand = false + + mDragListener?.onExpanded() + + appbarLayout.removeOnOffsetChangedListener(this) + } + } + }) appbarLayout.setExpanded(true, true) - updateState() } } State.MIN -> { minToMaxAnim { maximize() } } - else -> { + State.CLOSE -> { visible() closeToMinAnim { maximize() } } + else -> { + } } } /** - * thu nhỏ view + * thu nhỏ layout */ open fun minimize() { - finalState = State.MIN + mTempState = State.MIN if (!frameInitializing) { return } @@ -308,18 +374,20 @@ open class DragView @JvmOverloads constructor( visible() updateState() } - else -> { + State.CLOSE -> { visible() closeToMinAnim { minimize() } } + else -> { + } } } /** - * đóng view + * đóng layout */ open fun close() { - finalState = State.CLOSE + mTempState = State.CLOSE if (!frameInitializing) { return } @@ -330,10 +398,13 @@ open class DragView @JvmOverloads constructor( State.MIN -> { minToCloseAnim { close() } } - else -> { + State.CLOSE -> { gone() updateState() } + else -> { + + } } } @@ -389,7 +460,7 @@ open class DragView @JvmOverloads constructor( } /** - * cập nhật toàn bộ giao diện + * update ui all view */ open fun refresh() { @@ -422,7 +493,7 @@ open class DragView @JvmOverloads constructor( } /** - * cập nhật giao diện First View + * update ui frame first */ open fun refreshFrameFirst() { val frameFistHeight = if (mCurrentPercent < mPercentWhenMiddle) { @@ -430,28 +501,29 @@ open class DragView @JvmOverloads constructor( } else { (mHeightWhenMiddle - (mHeightWhenMiddle - mHeightWhenMin) * (mCurrentPercent - mPercentWhenMiddle) / (1 - mPercentWhenMiddle)) } + appbarLayout.reHeight(frameFistHeight.toInt()) } private fun minToMaxAnim(onEnd: () -> Unit) { - finalState = State.MAX + mTempState = State.MAX springYAnim(0f, onEnd) } private fun maxToMinAnim(onEnd: () -> Unit) { - finalState = State.MIN + mTempState = State.MIN springYAnim(mMarginTopWhenMin.toFloat(), onEnd) } private fun minToCloseAnim(onEnd: () -> Unit) { - finalState = State.CLOSE + mTempState = State.CLOSE translationYAnim((mHeightWhenMinDefault + mMarginBottomWhenMin).toFloat()) { onEnd() } } private fun closeToMinAnim(onEnd: () -> Unit) { - finalState = State.MIN + mTempState = State.MIN translationYAnim((0).toFloat()) { onEnd() } @@ -484,7 +556,6 @@ open class DragView @JvmOverloads constructor( } else { null } - if (state != null && mCurrentState != state) { mCurrentState = state mDragListener?.onChangeState(mCurrentState!!) @@ -493,6 +564,7 @@ open class DragView @JvmOverloads constructor( } interface DragListener { + fun onExpanded() {} fun onChangeState(state: State) {} fun onChangePercent(percent: Float) {} } diff --git a/drag/src/main/java/com/tuanhav95/drag/utils/UtilsExtensions.kt b/drag/src/main/java/com/tuanhav95/drag/utils/UtilsExtensions.kt index 763e6f9..d4d15f4 100644 --- a/drag/src/main/java/com/tuanhav95/drag/utils/UtilsExtensions.kt +++ b/drag/src/main/java/com/tuanhav95/drag/utils/UtilsExtensions.kt @@ -18,6 +18,12 @@ fun Float.springAnimation(minValue: Float, endValue: Float, onUpdate: (Float) -> Unit, onEnd: () -> Unit) { + + println("" + + minValue + " " + + maxValue + " " + + startValue + " " + + endValue + " " ) val springX = SpringForce(endValue) springX.dampingRatio = 0.7f springX.stiffness = 300f diff --git a/drag/src/main/res/layout/layout_draggable_panel.xml b/drag/src/main/res/layout/layout_drag_view.xml similarity index 100% rename from drag/src/main/res/layout/layout_draggable_panel.xml rename to drag/src/main/res/layout/layout_drag_view.xml diff --git a/example/src/main/java/com/tuanhav95/example/CustomActivity.kt b/example/src/main/java/com/tuanhav95/example/CustomActivity.kt index a59e0c8..7ff6975 100644 --- a/example/src/main/java/com/tuanhav95/example/CustomActivity.kt +++ b/example/src/main/java/com/tuanhav95/example/CustomActivity.kt @@ -1,12 +1,15 @@ package com.tuanhav95.example -import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import androidx.appcompat.app.AppCompatActivity import com.tuanhav95.drag.DragView +import com.tuanhav95.drag.utils.toPx import com.tuanhav95.example.fragment.BottomFragment import com.tuanhav95.example.fragment.TopFragment import kotlinx.android.synthetic.main.activity_custom.* import kotlinx.android.synthetic.main.layout_bottom.* +import kotlin.math.max +import kotlin.math.min class CustomActivity : AppCompatActivity() { @@ -32,5 +35,15 @@ class CustomActivity : AppCompatActivity() { btnMin.setOnClickListener { dragView.minimize() } btnClose.setOnClickListener { dragView.close() } + btnSetHeightMax.setOnClickListener { + var heightMax = 0 + if (etHeightMax.text.isNotEmpty()) { + heightMax = etHeightMax.text.toString().toInt() + } + heightMax = max(heightMax, 200) + heightMax = min(heightMax, 400) + + dragView.setHeightMax(heightMax.toPx(), true) + } } } diff --git a/example/src/main/res/layout/activity_custom.xml b/example/src/main/res/layout/activity_custom.xml index a8f3bd9..5880d76 100644 --- a/example/src/main/res/layout/activity_custom.xml +++ b/example/src/main/res/layout/activity_custom.xml @@ -29,6 +29,20 @@ android:layout_height="wrap_content" android:text="Close" /> + + +