2016-06-28 23 views
10

Sto cercando di implementare la funzione di trascinamento della selezione nella vista del riciclatore di Firebase. Non ci sono abbastanza informazioni nei documenti per questa implementazione. Suppongo di dover utilizzare onchildmoved per il listener di eventi ma non so come riordinare i dati.come utilizzare la funzione di trascinamento della vista di riciclaggio utilizzando il database in tempo reale di Firebase

+0

C'è molto poco correlate a Firebase quando si tratta di drag-and-drop. Se hai già trascinato il drag-and-drop in una vista di un riciclatore non Firebase, non dovrebbe essere troppo difficile aggiungere le parti Firebase. Hai già a disposizione le parti non Firebase? Se è così, vederlo renderebbe questa domanda molto più concreta. –

+0

sì lo faccio funzionare ma quando si fa il drag and drop c'è un arraylist che si attacca ad esso che poi devo scambiare tutti gli altri oggetti in una posizione in basso. quando si tratta di Firebase ricevo solo un'istantanea e non so come modificare l'ordine della lista associata al database di Firebase. – Smeekheff

+1

È possibile ridurre il codice necessario al minimo necessario per riprodurre il problema. Tale [MCVE] (http://stackoverflow.com/help/mcve) lo renderebbe molto più concreto. –

risposta

1

Ho avuto un problema simile a questo e hanno fatto la seguente (supponendo che si sta utilizzando una classe che estende ItemTouchHelper.SimpleCallback esempio RecyclerViewTouchHelper):

1) Aggiungere una proprietà al vostro bambino Firebase per registrare il suo ordine in la lista (ad es. "orderNumber").

2) Modificare il metodo onMove() del RecyclerViewTouchHelper per includere la seguente:

@Override 
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) { 

    final int firstPosition = viewHolder.getAdapterPosition();; 
    final int secondPosition = target.getAdapterPosition(); 
    DatabaseReference firstItemRef = mMovieAdapter.getRef(viewHolder.getAdapterPosition()); 
    DatabaseReference secondItemRef = mMovieAdapter.getRef(target.getAdapterPosition()); 

    HashMap<String, Object> updateFirstItemOrderNumber = new HashMap<>(); 
    updateFirstItemOrderNumber.put("orderNumber", secondPosition); 
    firstItemRef.updateChildren(updateFirstItemOrderNumber); 

    HashMap<String, Object> updateSecondItemOrderNumber = new HashMap<>(); 
    updateSecondItemOrderNumber.put("orderNumber", firstPosition); 
    secondItemRef.updateChildren(updateSecondItemOrderNumber); 

    return false; 
} 

3) Quando si crea il RecyclerViewAdapter, assicurarsi che la query si utilizza è ordinato da ORDERNUMBER esempio

Query orderedListQuery = FirebaseRef.orderByChild("orderNumber"); 

Spero che questo aiuti!

1

Ho avuto un po 'di confusione cercando di far funzionare tutto questo sulla Firebase UI 3.1.0. Ecco la mia soluzione finale di lavoro (spiegazione di seguito):

// overrides from ItemTouchHelper 
override fun onMove(recyclerView: RecyclerView, 
       viewHolder: RecyclerView.ViewHolder, 
       target: RecyclerView.ViewHolder): Boolean { 
    val fromPos = viewHolder.adapterPosition 
    val toPos = target.adapterPosition 

    val fromSnapshot = snapshots.first { it.order == fromPos } 
    val toSnapshot = snapshots.first { it.order == toPos } 

    Logger.d("Habit ${fromSnapshot.name} (${fromSnapshot.order}) to $toPos") 
    Logger.d("Habit ${toSnapshot.name} (${toSnapshot.order}) to $fromPos") 
    fromSnapshot.order = toPos 
    toSnapshot.order = fromPos 

    hasDragged = true 

    notifyItemMoved(toPos, fromPos) 
    return true 
} 
// overrides from FirebaseRecyclerAdapter 
override fun onChildChanged(type: ChangeEventType?, snapshot: DataSnapshot?, newIndex: Int, oldIndex: Int) { 
    when (type) { 
     ChangeEventType.MOVED -> if (!hasDragged) { 
      super.onChildChanged(type, snapshot, newIndex, oldIndex) 
     } 
     else -> super.onChildChanged(type, snapshot, newIndex, oldIndex) 
    } 
} 

override fun onDataChanged() { 
    hasDragged = false 
} 

I può essere facendo qualcosa di sbagliato, ma sembrava che this answer above sopra il codice sforzo duplicato dal momento che il FirebaseRecyclerAdapter e le istantanee osservabili saranno automagicamente aggiornare la notifica. Ciò ha causato la fine improvvisa del trascinamento con nuovi valori. Stavo anche ricevendo numeri di ordinazione errati (probabilmente colpa mia) usando getSnapshots(). Get (pos) (istantanee [fromPos] in kotlin). Ciò ha causato alcune animazioni davvero strane. Inoltre, durante le notifiche in movimento, ho dovuto invertire le posizioni da/a (target/viewHolder). Tuttavia, si noti che questo si basa sull'ordinazione nella query utilizzando il campo dell'ordine. E infine, non voglio lasciare che il metodo FirebaseRecyclerAdapter # onChildChanged per chiamare se è a causa di un trascinamento dell'utente, questo provoca anche animazioni indesiderate e sforzi duplicati.

1

Qui inserisco la soluzione che ha funzionato per me. Si basa sulla risposta di @ prodaea, che ha un approccio corretto ma non completamente funzionale. Manca l'aggiornamento del database Firebase e il controllo aggiuntivo contro ChangeEventType.CHANGED per evitare l'interruzione dell'animazione quando gli aggiornamenti di Firebase.

Codice vive dentro adattatore che si estende FirebaseRcyclerAdapter e implementa l'interfaccia con un solo metodo onItemMove(fromPosition: Int, toPosition: Int): Boolean:

override fun onItemMove(fromPosition: Int, toPosition: Int): Boolean { 

    snapshots[fromPosition].sort = toPosition.toDouble() 
    snapshots[toPosition].sort = fromPosition.toDouble() 

    // update recycler locally to complete the animation 
    notifyItemMoved(fromPosition, toPosition) 

    updateFirebase(fromPosition, toPosition) 

    return true 
} 

private fun updateFirebase(fromPos: Int, toPos: Int) { 

    // flag which prevents callbacks from interrupting the drag animation when firebase database updates 
    hasDragged = true 

    val firstPath = getRef(fromPos).getPath() 
    val secondPath = getRef(toPos).getPath() 

    Log.d(_tag, "onItemMove: firstPath: $firstPath, secondPath: $secondPath") 
    val updates = mapOf(
      Pair(firstPath + "/sort", snapshots[fromPos].sort), 
      Pair(secondPath + "/sort", snapshots[toPos].sort)) 
    getRef(fromPos).root.updateChildren(updates) 

    Log.d(_tag, "updateFirebase, catA: \"${snapshots[fromPos]}\", catB: \"${snapshots[toPos]}\"") 
} 

private fun DatabaseReference.getPath() = toString().substring(root.toString().length) 

override fun onChildChanged(type: ChangeEventType, 
          snapshot: DataSnapshot, 
          newIndex: Int, 
          oldIndex: Int) { 

    Log.d(_tag, "onChildChanged:else, type:$type, new: $newIndex, old: $oldIndex, hasDragged: $hasDragged, snapshot: $snapshot") 

    when (type) { 
     // avoid the drag animation interruption by checking against 'hasDragged' flag 
     ChangeEventType.MOVED -> if (!hasDragged) { 
      super.onChildChanged(type, snapshot, newIndex, oldIndex) 
     } 
     ChangeEventType.CHANGED -> if (!hasDragged) { 
      super.onChildChanged(type, snapshot, newIndex, oldIndex) 
     } 
     else -> { 
      super.onChildChanged(type, snapshot, newIndex, oldIndex) 
     } 
    } 
} 

override fun onDataChanged() { 
    hasDragged = false 
    Log.d(_tag, "onDataChanged, hasDragged: $hasDragged") 
} 
Problemi correlati