I am trying to build a drag and drop activity, where user can drag an item from Recyclerview to a card view, i am following android's drag and drop documentation,
the dragging is working fine, have shadows, but when i drop the item to one of the cardviews, it throwing the error,androidx.recyclerview.widget.RecyclerView cannot be cast to androidx.cardview.widget.CardView
i have worked it in the past, but it was dragging item from textView to ConstraintLayout.
The error is in TrueOrFalseActivity
Adapterclass
class StatementAdapter(
private val context: Context,
private val statementList: ArrayList<Statement>
) :
RecyclerView.Adapter<StatementAdapter.StatementViewHolder>() {
private var mListener: OnItemLongClickListener? = null
interface OnItemLongClickListener {
fun onItemLongClick(view: View)
}
fun setOnItemLongClickListener(listener: OnItemLongClickListener) {
mListener = listener
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): StatementViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val statementBinding: StatementBinding =
DataBindingUtil.inflate(layoutInflater, R.layout.statement_list, parent, false)
return StatementViewHolder(statementBinding, mListener)
}
override fun getItemCount(): Int {
return statementList.size
}
override fun onBindViewHolder(holder: StatementViewHolder, position: Int) {
val statementViewModel = statementList[position]
holder.bind(statementViewModel)
}
class StatementViewHolder(
private val statementBinding: StatementBinding,
private val listener: OnItemLongClickListener?
) : RecyclerView.ViewHolder(statementBinding.root) {
fun bind(statementViewModel: Statement) {
this.statementBinding.statementModel = statementViewModel
itemView.setOnLongClickListener {
listener?.onItemLongClick(itemView)
true
}
statementBinding.executePendingBindings()
}
}
}
Activity
class TrueOrFalseActivity : AppCompatActivity(), StatementAdapter.OnItemLongClickListener {
private lateinit var trueOrFalseBinding: ActivityTrueOrFalseBinding
private var rvStatement: RecyclerView? = null
private var statementAdapter: StatementAdapter? = null
private val dragMessage = "Added"
private val inBucket = "in bucket"
private val offBucket = "not in bucket"
private lateinit var draggingItem : View
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
trueOrFalseBinding = ActivityTrueOrFalseBinding.inflate(layoutInflater)
setContentView(trueOrFalseBinding.root)
rvStatement = findViewById(R.id.rvStatement)
val statementViewModel = ViewModelProvider(this).get(StatementViewModel::class.java)
statementViewModel.generateStatement()
statementViewModel.newMStatementList.observe(this) {
statementAdapter = StatementAdapter(this@TrueOrFalseActivity, it)
rvStatement!!.layoutManager = LinearLayoutManager(this@TrueOrFalseActivity)
rvStatement!!.adapter = statementAdapter
statementAdapter?.setOnItemLongClickListener(this)
}
// trueOrFalseBinding.cardTruthBox
trueOrFalseBinding.cardTruthBox.setOnDragListener(statementDragListener)
// trueOrFalseBinding.cardFalseBox.setOnDragListener(statementDragListener)
}
private val statementDragListener = View.OnDragListener { view, dragEvent ->
// val draggableItem = dragEvent.localState as View
val draggableItem = draggingItem
when (dragEvent.action) {
DragEvent.ACTION_DRAG_STARTED -> {
true
}
DragEvent.ACTION_DRAG_ENTERED -> {
trueOrFalseBinding.cardTruthBox.alpha = 0.3f
true
}
DragEvent.ACTION_DRAG_LOCATION -> {
true
}
DragEvent.ACTION_DRAG_EXITED -> {
trueOrFalseBinding.cardTruthBox.alpha = 1.0f
draggableItem.visibility = View.INVISIBLE
view.invalidate()
true
}
DragEvent.ACTION_DROP -> {
trueOrFalseBinding.cardTruthBox.alpha = 1.0f
// if (dragEvent.clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)){
// val draggedData = dragEvent.clipData.getItemAt(0).text
// }
//re-position the card in the updated x, y co-ordinates
// with mask center position pointing to new x,y co-ordinates
draggableItem.x = dragEvent.x - (draggableItem.width / 2)
draggableItem.y = dragEvent.y - (draggableItem.height / 2)
//on drop event remove the card from parent viewGroup
val parent = draggableItem.parent as CardView
parent.removeView(draggableItem)
val dropArea = view as CardView
dropArea.addView(draggableItem)
checkIfCardIsOnBucket(dragEvent)
true
}
DragEvent.ACTION_DRAG_ENDED -> {
draggableItem.visibility = View.INVISIBLE
view.invalidate()
// statementAdapter?.notifyDataSetChanged()
true
}
else -> {
false
}
}
}
private fun checkIfCardIsOnBucket(dragEvent: DragEvent?) {
val bucketXStart = trueOrFalseBinding.cardTruthBox.x
val bucketYStart = trueOrFalseBinding.cardTruthBox.y
val faceXEnd = bucketXStart trueOrFalseBinding.cardTruthBox.width
val faceYEnd = bucketYStart trueOrFalseBinding.cardTruthBox.height
val toastMsg =
if (dragEvent!!.x in bucketXStart..faceXEnd && dragEvent.y in bucketYStart..faceYEnd) {
inBucket
} else {
offBucket
}
//4
Toast.makeText(this, toastMsg, Toast.LENGTH_SHORT).show()
}
override fun onItemLongClick(view: View) {
//Toast.makeText(this@TrueOrFalseActivity, itemView.toString(), Toast.LENGTH_LONG).show()
val item = ClipData.Item(dragMessage)
val dragData = ClipData(
dragMessage,
arrayOf(ClipDescription.MIMETYPE_TEXT_PLAIN),
item
)
val myShadow = MyDragShadowBuilder(view)
view.startDragAndDrop(dragData, myShadow, null, 0)
draggingItem = view
}
}
private class MyDragShadowBuilder(v: View) : View.DragShadowBuilder(v) {
private val shadow = ColorDrawable(Color.LTGRAY)
override fun onProvideShadowMetrics(size: Point?, touch: Point?) {
val width: Int = view.width
val height: Int = view.height
shadow.setBounds(0, 0, width, height)
size?.set(width, height)
touch?.set(width, height)
}
override fun onDrawShadow(canvas: Canvas?) {
super.onDrawShadow(canvas)
}
}
java.lang.ClassCastException: androidx.recyclerview.widget.RecyclerView cannot be cast to androidx.cardview.widget.CardView
at com.example.simmone.view.TrueOrFalseActivity.statementDragListener$lambda-1(TrueOrFalseActivity.kt:94)
at com.example.simmone.view.TrueOrFalseActivity.$r8$lambda$Uf0--ln2uKD0LrTLx3eNYF0CoE8(Unknown Source:0)
at com.example.simmone.view.TrueOrFalseActivity$$ExternalSyntheticLambda0.onDrag(Unknown Source:2)
at android.view.View.callDragEventHandler(View.java:26592)
at android.view.View.dispatchDragEvent(View.java:26583)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1837)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewRootImpl.handleDragEvent(ViewRootImpl.java:7258)
at android.view.ViewRootImpl.access$1200(ViewRootImpl.java:191)
at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:5098)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
StackTrace
java.lang.ClassCastException: androidx.recyclerview.widget.RecyclerView cannot be cast to androidx.cardview.widget.CardView
at com.example.simmone.view.TrueOrFalseActivity.statementDragListener$lambda-1(TrueOrFalseActivity.kt:94)
at com.example.simmone.view.TrueOrFalseActivity.$r8$lambda$Uf0--ln2uKD0LrTLx3eNYF0CoE8(Unknown Source:0)
at com.example.simmone.view.TrueOrFalseActivity$$ExternalSyntheticLambda0.onDrag(Unknown Source:2)
at android.view.View.callDragEventHandler(View.java:26592)
at android.view.View.dispatchDragEvent(View.java:26583)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1837)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewGroup.dispatchDragEvent(ViewGroup.java:1819)
at android.view.ViewRootImpl.handleDragEvent(ViewRootImpl.java:7258)
at android.view.ViewRootImpl.access$1200(ViewRootImpl.java:191)
at android.view.ViewRootImpl$ViewRootHandler.handleMessage(ViewRootImpl.java:5098)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Is this possible to achieve, or any other ways to do this?
CodePudding user response:
Try
val parent = draggableItem.parent as RecyclerView