2012-02-19 10 views
31

Quello che voglio è semplice, beh almeno ho pensato che sarebbe stato semplice. Voglio solo una finestra in cui un EditText si trova nella parte inferiore dello schermo e il resto dello spazio è pieno di ListView. Sfortunatamente, non ha funzionato come mi aspettavo. Quello che voglio è la seguente immagine. C'è un modo semplice per farlo in XML, o dovrei scrivere un codice speciale per questo? What I wantMantenendo l'ultimo elemento visibile di un ListView quando le dimensioni di ListView cambiano

My Problematic Codice sorgente Android.

<?xml version="1.0" encoding="utf-8"?> 
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
android:layout_width="match_parent" 
android:layout_height="fill_parent" 
android:orientation="vertical" > 
<ListView 
    android:id="@+id/demolist" 
    android:layout_width="match_parent" 
    android:layout_height="fill_parent" 
    android:layout_weight="1" 
    > 
</ListView> 
    <EditText 
     android:id="@+id/editText1" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_weight="0"> 
    </EditText> 
</LinearLayout > 
+1

Hai trovato un modo per farlo? Sto cercando esattamente lo stesso comportamento. –

risposta

19

ciò che si vuole

ultima voce visibile senza tastiera

Last Visible Item Without Keyboard

ultima voce visibile con tastiera

Last Visible Item With Keyboard

ultima voce visibile Con ingresso più grande

Last Visible Item With larger input

Ecco come ho fatto.

Sommario

  • Set android: stackFromBottom = "true" e Android: transcriptMode = "alwaysScroll" nella visualizzazione elenco
  • Set android: windowSoftInputMode = "adjustPan" in Attività
  • Chiama adapter.notifyDataSetChanged(); quando si aggiungono nuovi chat in modo che la vista lista sarà sempre scorrere fino all'ultima posizione
  • Set android: InputType = "textMultiLine" & android: maxLines = "4" in EditText per la coltivazione di casella di testo

dettagli

Attività

<activity android:name="MainActivity" 
android:screenOrientation="portrait" 
android:windowSoftInputMode="adjustPan"></activity> 

Chat View

<RelativeLayout 
    android:id="@+id/chat_header" 
    android:layout_width="fill_parent" 
    android:layout_height="40dp" 
    android:padding="3dp" > 

    <Button 
     android:id="@+id/btnBackChat" 
     android:layout_width="35dp" 
     android:layout_height="35dp" 
     android:layout_alignParentLeft="true" 
     android:background="@drawable/back_button" /> 

    <TextView 
     android:id="@+id/txt_name" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignBottom="@+id/btnBackChat" 
     android:layout_centerHorizontal="true" 
     android:textColor="@android:color/white" 
     android:textSize="18sp" /> 

    <ImageView 
     android:id="@+id/imgViewProfileChat" 
     android:layout_width="35dp" 
     android:layout_height="35dp" 
     android:layout_alignParentRight="true" 
     /> 
</RelativeLayout> 

<ListView 
    android:id="@+id/listView1" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:layout_above="@+id/form" 
    android:layout_below="@+id/chat_header" 
    android:stackFromBottom="true" 
    android:transcriptMode="alwaysScroll"/> 

<RelativeLayout 
    android:id="@+id/form" 
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:layout_alignParentBottom="true" 
    android:layout_alignParentLeft="true" 
    android:orientation="vertical" > 

    <ImageButton 
     android:id="@+id/btnAttach" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:contentDescription="@string/attach" 
     android:src="@drawable/attach_icon" /> 

    <EditText 
     android:id="@+id/txtChat" 
     android:layout_width="fill_parent" 
     android:layout_height="wrap_content" 
     android:layout_toLeftOf="@+id/btnSend" 
     android:layout_toRightOf="@+id/btnAttach" 
     android:inputType="textMultiLine" 
     android:maxLines="4" /> 

    <Button 
     android:id="@+id/btnSend" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentRight="true" 
     android:layout_alignParentTop="true" 
     android:text="@string/send" /> 
</RelativeLayout> 

+0

Come ho già detto in un altro commento, preferirei evitare l'uso di android: windowSoftInputMode = "adjustPan ". Inoltre, la soluzione non scorre sempre fino in fondo all'elenco? Voglio che qualsiasi elemento si trovi nella parte inferiore della finestra di visualizzazione elenco per rimanere nella parte inferiore della finestra quando la finestra si restringe, * NON * perché l'elenco resti spostato alla fine dell'elenco. (Nota, la mia applicazione non è un'applicazione di chat come l'OP - Voglio che il nuovo elemento sia inserito dove l'utente sta guardando nell'elenco, non in fondo.) –

+0

Puoi usare android: windowSoftInputMode = "adjustResize" anche con questa soluzione. Quindi la barra delle azioni non scomparirà. – Waltsu

+0

@ sooraj.e Grazie! – Garf1eld

-1

Nella tua ListAdapter, si potrebbe fare qualcosa di simile:

public View getView(int position, View convertView, ViewGroup parent) { 

//buttonMore 
if(position >= super.getCount() ) 
     return textField ; 

    .... 

In questo modo, avrai sempre l'ultima voce dell'elenco come il vostro campo di testo.

+0

No. Si prega di vedere attentamente la mia foto. Ho specificamente menzionato che non è l'ultimo elemento ma l'ultimo elemento "visibile". Vedi la parte più a sinistra dell'immagine. –

+0

Otterrai ciò che desideri. La soluzione che ti ho dato rende il campo di testo l'ultimo elemento nell'elenco. Se non è visibile, poiché l'utente non scorreva fino alla fine dell'elenco, non è visibile ... – Snicolas

-1

è necessario impostare posizione di selezione ... Ma - in un modo strano, io non capisco perché - è necessario farlo con il post()

public void ScrollToLast() { 
    yourList.clearFocus(); 
    yourList.post(new Runnable() { 
     @Override 
     public void run() { 
      yourList.setSelection(items.size() - 1); 
     } 
    }); 
} 

Così si può aggiungere un TextWatcher per il tuo editText e puoi chiamare questo metodo lì ... Quindi la tua lista scorrerà verso il basso.

1

Ho bisogno anche di questa funzionalità. Ecco il mio tentativo, ma non funziona. Lo scorrimento è un po 'irregolare (non finisce sempre dove dovrebbe) e interferisce con la conservazione della posizione di scorrimento quando si ruota lo schermo.

@Override 
public void onResume() { 
    super.onResume(); 
    getListView().addOnLayoutChangeListener(stickyLastItemHandler); 
} 

@Override 
public void onPause() { 
    super.onPause(); 
    getListView().removeOnLayoutChangeListener(stickyLastItemHandler); 
} 

View.OnLayoutChangeListener stickyLastItemHandler = new View.OnLayoutChangeListener() { 
    @Override 
    public void onLayoutChange(View v, 
      int left, int top, int right, int bottom, 
      int oldLeft, int oldTop, int oldRight, int oldBottom) { 

     final int heightChange = (bottom - top) - (oldBottom - oldTop); 
     if (heightChange != 0) { 
      ((AbsListView)v).smoothScrollBy(-heightChange, 1000); 
     } 
    } 
}; 
+0

Come vuoi che si comporti l'ultimo elemento, esegui lo snap in modo che sia completamente visibile o lo tenga come è attualmente (come metà, solo pochi pixel, ecc.)? – Luksprog

+0

Lo snap al completamente visibile sarebbe probabilmente il più teso, credo. La mia app è un elenco di attività e l'utilizzo della casella di modifica dovrebbe aggiungere una nuova attività immediatamente al di sotto dell'ultima visibile. (Seguendo la voce di testo avrei fatto scorrere il nuovo elemento fino alla vista.) –

+0

Si prega di verificare la mia risposta – jaga

7

penso che si consiglia di utilizzare AdapterView.getLastVisiblePosition() prima di visualizzare la tastiera.

Due soluzioni qui:

  • su EditText clicca
  • grazie ad un OnScrollListener (e la sua funzione onscroll) ascoltare il vostro ListView

quindi utilizzare il AdapterView.setSelection per passare a questa voce (o indice - 2 o indice - 3) dopo la messa a fuoco EditText.

+2

Premiato con la taglia per essere l'unica persona a capire la domanda. Avevo già provato a utilizzare OnScrollListener e a utilizzare OnLayoutChangeListener per rilevare l'aspetto della tastiera. Ho avuto un'altra occasione, e sono ancora scontento dei risultati. SetSelection() e smoothScrollToPosition(), ecc. Sembrano inaffidabili :-(Penso che potrei dover rinunciare completamente all'interfaccia utente –

+0

Inoltre, non dimenticare di richiedere anche l'attivazione. LstMessages.requestFocus(); quindi deselezionalo e richiedi altri elementi mettono a fuoco se necessario – MSaudi

+0

Mi dai [il giusto indizio per raggiungere questo obiettivo e mantieni 'adjustResize'] (http://stackoverflow.com/a/34232863/2668136), grazie. Ho appena apportato alcune modifiche usando' setSelectionFromTop() 'invece di' setSelection() 'per visualizzare l'ultimo elemento appena sopra l'edittoxt. – Fllo

1

È possibile farlo attraverso xml:

<ListView 
    android:stackFromBottom="true" 
    android:layout_height=0dp 
    android:layout_weight=1 /> 

impilabile dal basso manterrà ListView scorrere verso il basso per impostazione predefinita, il peso impostazione di ListView riempirà tutto il possibile spazio all'interno genitore LinearLayout verticale.

+0

Sfortunatamente, questo non fa quello che mi serve.L'elenco verrà inizialmente spostato verso il basso, ma quando appare la tastiera virtuale il comportamento è lo stesso com'è senza questo flag –

3

È possibile utilizzare android:windowSoftInputMode="adjustPan" nel vostro AndroidManifest.xml come di seguito

<activity android:name="com.example.SimpleListView" 
      android:label="@string/app_name" 
      android:windowSoftInputMode="adjustPan" > 

Questo dovrebbe produrre l'output desiderato. Ufficiale android documentation.

Opzionalmente è possibile specificare la modalità di trascrizione (se si sta lavorando su alcune funzioni di chat) per la visualizzazione elenco se si desidera scorrere automaticamente fino alla fine di listview. Puoi anche controllare lo android:transcriptMode="normal" e vedere se ciò si adatta.

A relativo SO answer.Ufficiale android doc.

<ListView 
android:id="@+id/comments" 
android:layout_width="match_parent" 
android:layout_height="match_parent" 
android:transcriptMode="alwaysScroll"> 

Questo dovrebbe risolvere la maggior parte dei tuoi problemi, forse tranne l'ultimo (nell'immagine) che non ho testato.

+0

Ho provato già AdjustPan, ma questo fa scorrere la barra di azione fuori dalla vista e rende scomodo scorrere l'elenco con la tastiera visibile. La modalità di trascrizione è inutile, sfortunatamente - non voglio che scorra in fondo alla lista. (Pensavo che l'OP lo avesse già spiegato molto bene, motivo per cui ho aggiunto una taglia al suo posto invece di fondare la mia.) Ho bisogno dell'ultima * visibile * elemento per rimanere l'ultimo elemento visibile quando appare la tastiera. –

+0

Hmm .. difficile, si potrebbe provare a rilevare l'altezza della tastiera e regolare manualmente l'altezza del listview impostare l'ultima posizione visibile (se possibile utilizzando setSelectionFromTop). Tuttavia, la soluzione hackish del lotto. SO relativo post http://stackoverflow.com/questions/13534365/getting-the-dimensions-of-the-soft-keyboard – jaga

0

basta controllare questo fuori: auguriamo che questo ti aiuta ....

Supponendo di sapere quando i dati della lista è stato modificato, puoi dire manualmente all'elenco di scorrere verso il basso impostando la selezione dell'elenco sull'ultima riga.Qualcosa di simile a questo:

private void scrollMyListViewToBottom() { 
    myListView.post(new Runnable() { 
     @Override 
     public void run() { 
      // Select the last row so it will scroll into view... 
      myListView.setSelection(myListAdapter.getCount() - 1) ; 
     } 
    }); 
} 

o si può anche provare questo ..è funziona per me:

ChatAdapter adapter = new ChatAdapter(this); 

ListView lview = (ListView) findViewById(R.id.chatList); 
lview .setTranscriptMode(AbsListView.TRANSCRIPT_MODE_ALWAYS_SCROLL); 
lview .setAdapter(adapter); 

adapter.registerDataSetObserver(new DataSetObserver() { 
    @Override 
    public void onChanged() { 
     super.onChanged(); 
     lv.setSelection(adapter.getCount() - 1);  
    } 
}); 
+0

Un'altra persona che non ha letto la domanda. Non voglio che scorra in fondo alla lista. –

+0

Quindi, esattamente quello che vuoi, puoi condividere lo schema grafico ... Grazie –

+0

I diagrammi della domanda lo spiegano perfettamente. Prendete nota in particolare degli schemi etichettati "senza tastiera" e "I want THIS", e notate dove "l'ultimo elemento visibile" è posizionato in questi diagrammi. Si noti che "ultimo elemento visibile" non è l'ultimo elemento nell'elenco. –

1

ho creato un motore di layout per Android che permette di ascoltare per la tastiera nascosti e visibili cambiamenti di stato (tra molte altre caratteristiche principali). Questa libreria è disponibile al http://phil-brown.github.io/AbLE/.

È sufficiente aggiungere il jar alla directory libs (creare questa cartella se non esiste), e invece di ereditare da un Activity, ereditano da AbLEActivity. Successivamente, l'override dei metodi onKeyboardShown e onKeyboardHidden, e in questi è possibile animare il vostro contenuto verso l'alto o verso il basso, come necessario:

@Override 
public void onKeyboardShown() { 
    //animate up 
} 

@Override 
public void onKeyboardHidden() { 
    //animate down 
} 
+0

Cosa mi dà che OnLayoutChangeListener non lo fa? –

2

ho effettivamente avuto lo stesso comportamento che è necessario con l'aggiunta di Activity dichiarazione manifesta android:windowSoftInputMode="adjustResize" ea la dichiarazione ListViewandroid:transcriptMode="normal". Per entrambe le modifiche alla tastiera e all'orientamento.

0
Follow these steps 
-------------------- 
1. Update your activity in AndroidManifest.xml file like below 
<activity 
      android:name=".MyListActivity" 
      android:windowSoftInputMode="adjustResize" /> 

2. Set your list view with like below. 
mListView.setTranscriptMode(ListView.TRANSCRIPT_MODE_ALWAYS_SCROLL); 
mListView.setStackFromBottom(true); 

Spero che risolva il problema.

3

Basta sovrascrivere il metodo ListView # onSizeChanged (int w, int h, int oldw, int oldh) come di seguito: PS: L'altezza del tuo ListView non può essere 0 in qualsiasi momento, se può 0, non funziona.

@Override 
protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
    if (getChildCount() == 0) { 
     return; 
    } 
    final int lastVisiblePosition = getLastVisiblePosition(); 
    int firstVisiblePosition = getFirstVisiblePosition(); 

    View last = getChildAt(lastVisiblePosition - firstVisiblePosition); 
    int top = last.getTop(); 
    final int newTop = top + (h - oldh); 
    Log.d(getClass().getSimpleName(), "onSizeChanged(" + w + ", " + h + ", " + oldw + ", " + oldh + ")"); 
    if (mFocusSelector == null) { 
     mFocusSelector = new FocusSelector(); 
    } 
    post(mFocusSelector.setup(lastVisiblePosition, newTop)); 
    super.onSizeChanged(w, h, oldw, oldh); 
} 

private class FocusSelector implements Runnable { 
    private int mPosition; 
    private int mPositionTop; 

    public FocusSelector setup(int position, int top) { 
     mPosition = position; 
     mPositionTop = top; 
     return this; 
    } 

    public void run() { 
     setSelectionFromTop(mPosition, mPositionTop); 
    } 
} 
Problemi correlati