|
|
@ -190,105 +190,109 @@ class DragSelectTouchHelper( |
|
|
|
private var mLastRealEnd = RecyclerView.NO_POSITION |
|
|
|
private var mLastRealEnd = RecyclerView.NO_POSITION |
|
|
|
private var mSlideStateStartPosition = RecyclerView.NO_POSITION |
|
|
|
private var mSlideStateStartPosition = RecyclerView.NO_POSITION |
|
|
|
private var mHaveCalledSelectStart = false |
|
|
|
private var mHaveCalledSelectStart = false |
|
|
|
private val mScrollRunnable: Runnable = object : Runnable { |
|
|
|
private val mScrollRunnable: Runnable by lazy { |
|
|
|
override fun run() { |
|
|
|
object : Runnable { |
|
|
|
if (mIsScrolling) { |
|
|
|
override fun run() { |
|
|
|
scrollBy(mScrollDistance) |
|
|
|
if (mIsScrolling) { |
|
|
|
ViewCompat.postOnAnimation(mRecyclerView!!, this) |
|
|
|
scrollBy(mScrollDistance) |
|
|
|
|
|
|
|
ViewCompat.postOnAnimation(mRecyclerView!!, this) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
private val mOnItemTouchListener: OnItemTouchListener = object : OnItemTouchListener { |
|
|
|
private val mOnItemTouchListener: OnItemTouchListener by lazy { |
|
|
|
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { |
|
|
|
object : OnItemTouchListener { |
|
|
|
Logger.d("onInterceptTouchEvent: x:" + e.x + ",y:" + e.y |
|
|
|
override fun onInterceptTouchEvent(rv: RecyclerView, e: MotionEvent): Boolean { |
|
|
|
+ ", " + MotionEvent.actionToString(e.action)) |
|
|
|
Logger.d("onInterceptTouchEvent: x:" + e.x + ",y:" + e.y |
|
|
|
val adapter = rv.adapter |
|
|
|
+ ", " + MotionEvent.actionToString(e.action)) |
|
|
|
if (adapter == null || adapter.itemCount == 0) { |
|
|
|
val adapter = rv.adapter |
|
|
|
return false |
|
|
|
if (adapter == null || adapter.itemCount == 0) { |
|
|
|
} |
|
|
|
return false |
|
|
|
var intercept = false |
|
|
|
} |
|
|
|
val action = e.action |
|
|
|
var intercept = false |
|
|
|
when (action and MotionEvent.ACTION_MASK) { |
|
|
|
val action = e.action |
|
|
|
MotionEvent.ACTION_DOWN -> { |
|
|
|
when (action and MotionEvent.ACTION_MASK) { |
|
|
|
mDownY = e.y |
|
|
|
MotionEvent.ACTION_DOWN -> { |
|
|
|
// call the selection start's callback before moving |
|
|
|
mDownY = e.y |
|
|
|
if (mSelectState == SELECT_STATE_SLIDE && isInSlideArea(e)) { |
|
|
|
// call the selection start's callback before moving |
|
|
|
mSlideStateStartPosition = getItemPosition(rv, e) |
|
|
|
if (mSelectState == SELECT_STATE_SLIDE && isInSlideArea(e)) { |
|
|
|
if (mSlideStateStartPosition != RecyclerView.NO_POSITION) { |
|
|
|
mSlideStateStartPosition = getItemPosition(rv, e) |
|
|
|
mCallback.onSelectStart(mSlideStateStartPosition) |
|
|
|
if (mSlideStateStartPosition != RecyclerView.NO_POSITION) { |
|
|
|
mHaveCalledSelectStart = true |
|
|
|
mCallback.onSelectStart(mSlideStateStartPosition) |
|
|
|
|
|
|
|
mHaveCalledSelectStart = true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
intercept = true |
|
|
|
} |
|
|
|
} |
|
|
|
intercept = true |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
MotionEvent.ACTION_MOVE -> if (mSelectState == SELECT_STATE_DRAG_FROM_NORMAL |
|
|
|
MotionEvent.ACTION_MOVE -> if (mSelectState == SELECT_STATE_DRAG_FROM_NORMAL |
|
|
|
|
|
|
|
|| mSelectState == SELECT_STATE_DRAG_FROM_SLIDE |
|
|
|
|
|
|
|
) { |
|
|
|
|
|
|
|
Logger.i("onInterceptTouchEvent: drag mode move") |
|
|
|
|
|
|
|
intercept = true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
MotionEvent.ACTION_UP -> { |
|
|
|
|
|
|
|
if (mSelectState == SELECT_STATE_DRAG_FROM_NORMAL |
|
|
|
|
|
|
|
|| mSelectState == SELECT_STATE_DRAG_FROM_SLIDE |
|
|
|
|| mSelectState == SELECT_STATE_DRAG_FROM_SLIDE |
|
|
|
) { |
|
|
|
) { |
|
|
|
|
|
|
|
Logger.i("onInterceptTouchEvent: drag mode move") |
|
|
|
intercept = true |
|
|
|
intercept = true |
|
|
|
} |
|
|
|
} |
|
|
|
// finger is lifted before moving |
|
|
|
MotionEvent.ACTION_UP -> { |
|
|
|
if (mSlideStateStartPosition != RecyclerView.NO_POSITION) { |
|
|
|
if (mSelectState == SELECT_STATE_DRAG_FROM_NORMAL |
|
|
|
selectFinished(mSlideStateStartPosition) |
|
|
|
|| mSelectState == SELECT_STATE_DRAG_FROM_SLIDE |
|
|
|
mSlideStateStartPosition = RecyclerView.NO_POSITION |
|
|
|
) { |
|
|
|
} |
|
|
|
intercept = true |
|
|
|
// selection has triggered |
|
|
|
} |
|
|
|
if (mStart != RecyclerView.NO_POSITION) { |
|
|
|
// finger is lifted before moving |
|
|
|
selectFinished(mEnd) |
|
|
|
if (mSlideStateStartPosition != RecyclerView.NO_POSITION) { |
|
|
|
|
|
|
|
selectFinished(mSlideStateStartPosition) |
|
|
|
|
|
|
|
mSlideStateStartPosition = RecyclerView.NO_POSITION |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
// selection has triggered |
|
|
|
|
|
|
|
if (mStart != RecyclerView.NO_POSITION) { |
|
|
|
|
|
|
|
selectFinished(mEnd) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
MotionEvent.ACTION_CANCEL -> { |
|
|
|
MotionEvent.ACTION_CANCEL -> { |
|
|
|
if (mSlideStateStartPosition != RecyclerView.NO_POSITION) { |
|
|
|
if (mSlideStateStartPosition != RecyclerView.NO_POSITION) { |
|
|
|
selectFinished(mSlideStateStartPosition) |
|
|
|
selectFinished(mSlideStateStartPosition) |
|
|
|
mSlideStateStartPosition = RecyclerView.NO_POSITION |
|
|
|
mSlideStateStartPosition = RecyclerView.NO_POSITION |
|
|
|
} |
|
|
|
|
|
|
|
if (mStart != RecyclerView.NO_POSITION) { |
|
|
|
|
|
|
|
selectFinished(mEnd) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (mStart != RecyclerView.NO_POSITION) { |
|
|
|
else -> { |
|
|
|
selectFinished(mEnd) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
else -> { |
|
|
|
// Intercept only when the selection is triggered |
|
|
|
} |
|
|
|
Logger.d("intercept result: $intercept") |
|
|
|
|
|
|
|
return intercept |
|
|
|
} |
|
|
|
} |
|
|
|
// Intercept only when the selection is triggered |
|
|
|
|
|
|
|
Logger.d("intercept result: $intercept") |
|
|
|
|
|
|
|
return intercept |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) { |
|
|
|
override fun onTouchEvent(rv: RecyclerView, e: MotionEvent) { |
|
|
|
if (!isActivated) { |
|
|
|
if (!isActivated) { |
|
|
|
return |
|
|
|
return |
|
|
|
} |
|
|
|
} |
|
|
|
Logger.d("onTouchEvent: x:" + e.x + ",y:" + e.y |
|
|
|
Logger.d("onTouchEvent: x:" + e.x + ",y:" + e.y |
|
|
|
+ ", " + MotionEvent.actionToString(e.action)) |
|
|
|
+ ", " + MotionEvent.actionToString(e.action)) |
|
|
|
val action = e.action |
|
|
|
val action = e.action |
|
|
|
when (action and MotionEvent.ACTION_MASK) { |
|
|
|
when (action and MotionEvent.ACTION_MASK) { |
|
|
|
MotionEvent.ACTION_MOVE -> { |
|
|
|
MotionEvent.ACTION_MOVE -> { |
|
|
|
if (mSlideStateStartPosition != RecyclerView.NO_POSITION) { |
|
|
|
if (mSlideStateStartPosition != RecyclerView.NO_POSITION) { |
|
|
|
selectFirstItem(mSlideStateStartPosition) |
|
|
|
selectFirstItem(mSlideStateStartPosition) |
|
|
|
// selection is triggered |
|
|
|
// selection is triggered |
|
|
|
mSlideStateStartPosition = RecyclerView.NO_POSITION |
|
|
|
mSlideStateStartPosition = RecyclerView.NO_POSITION |
|
|
|
Logger.i("onTouchEvent: after slide mode down") |
|
|
|
Logger.i("onTouchEvent: after slide mode down") |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
processAutoScroll(e) |
|
|
|
|
|
|
|
if (!mIsInTopHotspot && !mIsInBottomHotspot) { |
|
|
|
|
|
|
|
updateSelectedRange(rv, e) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
processAutoScroll(e) |
|
|
|
MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> selectFinished(mEnd) |
|
|
|
if (!mIsInTopHotspot && !mIsInBottomHotspot) { |
|
|
|
else -> { |
|
|
|
updateSelectedRange(rv, e) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
MotionEvent.ACTION_CANCEL, MotionEvent.ACTION_UP -> selectFinished(mEnd) |
|
|
|
|
|
|
|
else -> { |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) { |
|
|
|
override fun onRequestDisallowInterceptTouchEvent(disallowIntercept: Boolean) { |
|
|
|
if (disallowIntercept) { |
|
|
|
if (disallowIntercept) { |
|
|
|
inactiveSelect() |
|
|
|
inactiveSelect() |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -316,13 +320,11 @@ class DragSelectTouchHelper( |
|
|
|
if (mRecyclerView === recyclerView) { |
|
|
|
if (mRecyclerView === recyclerView) { |
|
|
|
return // nothing to do |
|
|
|
return // nothing to do |
|
|
|
} |
|
|
|
} |
|
|
|
if (mRecyclerView != null) { |
|
|
|
mRecyclerView?.removeOnItemTouchListener(mOnItemTouchListener) |
|
|
|
mRecyclerView!!.removeOnItemTouchListener(mOnItemTouchListener) |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
mRecyclerView = recyclerView |
|
|
|
mRecyclerView = recyclerView |
|
|
|
if (mRecyclerView != null) { |
|
|
|
mRecyclerView?.let { |
|
|
|
mRecyclerView!!.addOnItemTouchListener(mOnItemTouchListener) |
|
|
|
it.addOnItemTouchListener(mOnItemTouchListener) |
|
|
|
mRecyclerView!!.addOnLayoutChangeListener(mOnLayoutChangeListener) |
|
|
|
it.addOnLayoutChangeListener(mOnLayoutChangeListener) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -510,8 +512,8 @@ class DragSelectTouchHelper( |
|
|
|
|
|
|
|
|
|
|
|
private fun activeSelectInternal(position: Int) { |
|
|
|
private fun activeSelectInternal(position: Int) { |
|
|
|
// We should initialize the hotspot here, because its data may be delayed load |
|
|
|
// We should initialize the hotspot here, because its data may be delayed load |
|
|
|
if (mRecyclerView != null) { |
|
|
|
mRecyclerView?.let { |
|
|
|
init(mRecyclerView!!.height) |
|
|
|
init(it.height) |
|
|
|
} |
|
|
|
} |
|
|
|
if (position == RecyclerView.NO_POSITION) { |
|
|
|
if (position == RecyclerView.NO_POSITION) { |
|
|
|
Logger.logSelectStateChange(mSelectState, SELECT_STATE_SLIDE) |
|
|
|
Logger.logSelectStateChange(mSelectState, SELECT_STATE_SLIDE) |
|
|
@ -553,7 +555,7 @@ class DragSelectTouchHelper( |
|
|
|
updateSelectedRange(rv, e.x, e.y) |
|
|
|
updateSelectedRange(rv, e.x, e.y) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun updateSelectedRange(rv: RecyclerView?, x: Float, y: Float) { |
|
|
|
private fun updateSelectedRange(rv: RecyclerView, x: Float, y: Float) { |
|
|
|
val position = getItemPosition(rv, x, y) |
|
|
|
val position = getItemPosition(rv, x, y) |
|
|
|
if (position != RecyclerView.NO_POSITION && mEnd != position) { |
|
|
|
if (position != RecyclerView.NO_POSITION && mEnd != position) { |
|
|
|
mEnd = position |
|
|
|
mEnd = position |
|
|
@ -685,7 +687,7 @@ class DragSelectTouchHelper( |
|
|
|
private fun stopAutoScroll() { |
|
|
|
private fun stopAutoScroll() { |
|
|
|
if (mIsScrolling) { |
|
|
|
if (mIsScrolling) { |
|
|
|
mIsScrolling = false |
|
|
|
mIsScrolling = false |
|
|
|
mRecyclerView!!.removeCallbacks(mScrollRunnable) |
|
|
|
mRecyclerView?.removeCallbacks(mScrollRunnable) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -698,7 +700,7 @@ class DragSelectTouchHelper( |
|
|
|
} |
|
|
|
} |
|
|
|
mRecyclerView!!.scrollBy(0, scrollDistance) |
|
|
|
mRecyclerView!!.scrollBy(0, scrollDistance) |
|
|
|
if (mLastX != Float.MIN_VALUE && mLastY != Float.MIN_VALUE) { |
|
|
|
if (mLastX != Float.MIN_VALUE && mLastY != Float.MIN_VALUE) { |
|
|
|
updateSelectedRange(mRecyclerView, mLastX, mLastY) |
|
|
|
updateSelectedRange(mRecyclerView!!, mLastX, mLastY) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -720,8 +722,8 @@ class DragSelectTouchHelper( |
|
|
|
return getItemPosition(rv, e.x, e.y) |
|
|
|
return getItemPosition(rv, e.x, e.y) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private fun getItemPosition(rv: RecyclerView?, x: Float, y: Float): Int { |
|
|
|
private fun getItemPosition(rv: RecyclerView, x: Float, y: Float): Int { |
|
|
|
val v = rv!!.findChildViewUnder(x, y) |
|
|
|
val v = rv.findChildViewUnder(x, y) |
|
|
|
if (v == null) { |
|
|
|
if (v == null) { |
|
|
|
val layoutManager = rv.layoutManager |
|
|
|
val layoutManager = rv.layoutManager |
|
|
|
if (layoutManager is GridLayoutManager) { |
|
|
|
if (layoutManager is GridLayoutManager) { |
|
|
|