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.
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
Ich experimentiere mit Funktionalität mit einem Bildschirm, auf dem ein Recyclerview unten positioniert ist.[code]
[/code]
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 [url=viewtopic.php?t=20324]Problem[/url] 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]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)
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())
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 }
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) [/code] Bitte lassen Sie mich wissen, ob es hier Ideen zu möglichen Lösungen gibt
Ich möchte meinen Recyclerview auf Klicken erweitern, aber gleichzeitig mit diesem ersten Klick möchte ich, dass ein Recyclerview -Element keinen Fokus erhält. Recyclerview -Element sollte sich auf...
Ist es eine gute Praxis, ViewPager2 mit einem einzelnen Fragment für nur ein Element in der Recyclerview zu verwenden, während andere Elemente normale Ansichten sind? Gibt es bei diesem Ansatz eine...