Das seltsame Problem mit dem Recyclerview -Layout -Manager verarbeitet seine untergeordneten Ansichten immer noch, nachdAndroid

Forum für diejenigen, die für Android programmieren
Anonymous
 Das seltsame Problem mit dem Recyclerview -Layout -Manager verarbeitet seine untergeordneten Ansichten immer noch, nachd

Post by Anonymous »

Ich experimentiere mit Funktionalität mit einem Bildschirm, auf dem ein Recyclerview unten positioniert ist.

Code: Select all







Ein Benutzer kann ein Element aus dem Recyclerview herausziehen und es in einen Relatelayout umgeben. Im Allgemeinen funktioniert dies richtig. Wenn der Benutzer das Element jedoch schnell auf den Bildschirm schleppt und fallen lässt, tritt ein Absturz aufgrund eines internen Recyclerview -Problems auf. Ich bin mir derzeit nicht sicher, wie ich dieses Problem beheben soll. Mit anderen Worten, die Ansicht wird aus dem Adapter entfernt (und seine Layoutparameter geändert), bevor der Recyclerview seine internen Updates beendet hat, was zu einem ungültigen Guss führt.

Code: Select all

import android.annotation.SuppressLint
import android.graphics.Canvas
import android.graphics.Point
import android.os.Bundle
import android.view.DragEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlin.math.abs

class MainActivity4 : AppCompatActivity() {
private lateinit var parentLayout: RelativeLayout
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: DraggableAdapter
private var removalTriggered = false

private var parentLeft = 0
private var parentTop = 0
private var recyclerLeft = 0
private var recyclerTop = 0

@SuppressLint("ClickableViewAccessibility")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main4)

parentLayout = findViewById(R.id.parent_layout)
recyclerView = findViewById(R.id.recyclerView)
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)

adapter = DraggableAdapter(removed = {
removalTriggered = false
})

recyclerView.adapter = adapter

// Get parent's location on screen.
val parentLoc = IntArray(2)
parentLayout.getLocationOnScreen(parentLoc)
parentLeft = parentLoc[0]
parentTop = parentLoc[1]

// Get recyclerView's location on screen.
val recLoc = IntArray(2)
recyclerView.getLocationOnScreen(recLoc)
recyclerLeft = recLoc[0]
recyclerTop = recLoc[1]

parentLayout.setOnDragListener { view, event ->
when (event.action) {
DragEvent.ACTION_DRAG_STARTED -> true

DragEvent.ACTION_DRAG_ENTERED -> {
view.invalidate()
true
}

DragEvent.ACTION_DRAG_LOCATION -> true

DragEvent.ACTION_DROP -> {
// Retrieve the original view from localState.
val draggedView = event.localState as? View

draggedView?.let { view ->
// Remove the view from its old parent.
(view.parent as? ViewGroup)?.removeView(view)

// Retrieve the stored initial touch offset from the view's tag.
@Suppress("UNCHECKED_CAST")
val initialTouch = view.getTag(R.id.initial_touch_point) as? Pair
// Use the stored touch offsets, defaulting to the center if not available.
val touchOffsetX = initialTouch?.first ?: (view.width / 2)
val touchOffsetY = initialTouch?.second ?: (view.height / 2)

// Calculate new position based on the drop coordinates and the initial touch offsets.
// event.x and event.y are assumed to be in the coordinate space of the parent layout.
var newX = event.x - touchOffsetX
var newY = event.y - touchOffsetY

// Optionally, clamp the new position so the view stays within the parent's bounds.
newX = newX.coerceIn(0f, (parentLayout.width - view.width).toFloat())
newY = newY.coerceIn(0f, (parentLayout.height - view.height).toFloat())

view.x = newX
view.y = newY

// Update layout parameters if needed.
view.layoutParams = RelativeLayout.LayoutParams(view.width, view.height)
parentLayout.addView(view)
view.visibility = View.VISIBLE
view.bringToFront()
}

true
}

DragEvent.ACTION_DRAG_ENDED ->  {
view.invalidate()
true
}

else -> false
}
}

var itemTouchHelper: ItemTouchHelper? = null

val swipeCallback: ItemTouchHelper.SimpleCallback = object : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.UP) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean = false

override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
return 1f
}

override fun onChildDraw(
c: Canvas,
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
// Let the default implementation update the translation.
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)

// Define a removal threshold: 80% of the item's height.
val removalThreshold = viewHolder.itemView.height * 0.8f

// Get the current vertical translation.
val currentTranslationY = viewHolder.itemView.translationY

// If the view's vertical translation meets/exceeds the threshold, trigger removal.
if (abs(currentTranslationY) >= removalThreshold && !removalTriggered && isCurrentlyActive) {
removalTriggered = true

recyclerView.post {
onSwiped(viewHolder = viewHolder, direction = ItemTouchHelper.UP)
}
}
}

override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
val view: View = viewHolder.itemView
val position: Int = viewHolder.bindingAdapterPosition

if (position != RecyclerView.NO_POSITION) {
adapter.removeItem(position)
view.visibility = View.INVISIBLE
}

val shadowBuilder = MyDragShadowBuilder(view = view)
view.startDragAndDrop(null, shadowBuilder, view, 0)
}
}

itemTouchHelper = ItemTouchHelper(swipeCallback)
itemTouchHelper.attachToRecyclerView(recyclerView)
}
}

private class MyDragShadowBuilder(view: View) : View.DragShadowBuilder(view) {
override fun onProvideShadowMetrics(shadowSize: Point, shadowTouchPoint: Point) {
val width = view.width
val height = view.height
shadowSize.set(width, height)
val clampedX = width / 2
val clampedY = height / 2
shadowTouchPoint.set(clampedX, clampedY)
}

override fun onDrawShadow(canvas: Canvas) {
view.draw(canvas)
}
}

class DraggableAdapter(
val removed: () -> Unit
) : RecyclerView.Adapter() {

// Use a mutable list so we can remove items.
private val items: MutableList  = mutableListOf()

init {
for (i in 0 until 10) {
items.add("Drag me $i")
}
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DraggableViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.item_draggable, parent, false) as TextView
return DraggableViewHolder(view)
}

override fun getItemCount(): Int = items.size

override fun onBindViewHolder(holder: DraggableViewHolder, position: Int) {
holder.textView.text = items[position]
}

fun removeItem(position: Int) {
if (position in 0 until items.size) {
items.removeAt(position)
notifyItemRemoved(position)
}

removed()
}

class DraggableViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
}
< /code>
Fehler: < /p>
FATAL EXCEPTION: main (Ask Gemini)
Process: com.dragndrop, PID: 12824
java.lang.ClassCastException:  a n d r o i d . w i d g e t . R e l a t i v e L a y o u t $ L a y o u t P a r a m s   c a n n o t   b e   c a s t   t o   a n d r o i d x . r e c y c l e r v i e w . w i d g e t . R e c y c l e r V i e w $ L a y o u t P a r a m s < b r   / >                                         a t   a n d r o i d x . r e c y c l e rview.widget.RecyclerView.getChildViewHolderInt(RecyclerView.java:5422)
at androidx.recyclerview.widget.RecyclerView$6.getChildViewHolder(RecyclerView.java:1043)
at androidx.recyclerview.widget.ChildHelper.findHiddenNonRemovedView(ChildHelper.java:257)
at androidx.recyclerview.widget.RecyclerView$Recycler.getScrapOrHiddenOrCachedHolderForPosition(RecyclerView.java:7409)
at androidx.recyclerview.widget.RecyclerView$Recycler.tryGetViewHolderForPositionByDeadline(RecyclerView.java:6890)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6853)
at androidx.recyclerview.widget.RecyclerView$Recycler.getViewForPosition(RecyclerView.java:6849)
at androidx.recyclerview.widget.LinearLayoutManager$LayoutState.next(LinearLayoutManager.java:2422)
at androidx.recyclerview.widget.LinearLayoutManager.layoutChunk(LinearLayoutManager.java:1722)
at androidx.recyclerview.widget.LinearLayoutManager.fill(LinearLayoutManager.java:1682)
at androidx.recyclerview.widget.LinearLayoutManager.onLayoutChildren(LinearLayoutManager.java:747)
at androidx.recyclerview.widget.RecyclerView.dispatchLayoutStep2(RecyclerView.java:4737)
at androidx.recyclerview.widget.RecyclerView.onMeasure(RecyclerView.java:4133)
at android.view.View.measure(View.java:27853)
at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:735)
at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:481)
at android.view.View.measure(View.java:27853)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7403)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at androidx.appcompat.widget.ContentFrameLayout.onMeasure(ContentFrameLayout.java:141)
at android.view.View.measure(View.java:27853)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7403)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:27853)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7403)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:27853)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7403)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1552)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:842)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:721)
at android.view.View.measure(View.java:27853)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:7403)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.DecorView.onMeasure(DecorView.java:1390)
at android.view.View.measure(View.java:27853)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:4882)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:3461)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:3767)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:3151)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:11068)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1321)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:1329)
at android.view.Choreographer.doCallbacks(Choreographer.java:930)
at android.view.Choreographer.doFrame(Choreographer.java:859)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:1303)
at android.os.Handler.handleCallback(Handler.java:942)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:226)
Bitte lassen Sie mich wissen, ob es hier Ideen zu möglichen Lösungen gibt

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post