C'è un modo per far scorrere sempre ellipsize = "marquee"?


93

Voglio usare l'effetto di selezione su un TextView, ma il testo viene fatto scorrere solo quando TextView viene messo a fuoco. Questo è un problema, perché nel mio caso non può.

Sto usando:

  android:ellipsize="marquee"
  android:marqueeRepeatLimit="marquee_forever"

C'è un modo per fare in modo che TextView faccia sempre scorrere il suo testo? L'ho visto fare nell'app Android Market, dove il nome dell'app scorrerà nella barra del titolo, anche se non riceve il focus, ma non sono riuscito a trovarlo menzionato nei documenti dell'API.


Per far funzionare la selezione, TextView dovrebbe essere selezionato, non focalizzato. Il fuoco dà la selezione ma non il contrario.
Denis Gladkiy

1
Prova alwaysMarqueeTextView stackoverflow.com/a/28806003/3496570
AndroidGeek

Vorrei cambiare la risposta giusta per questo stackoverflow.com/a/3700651/4548520
user25

Risposte:


62

Ho dovuto affrontare il problema e la soluzione più breve che ho trovato è creare una nuova classe derivata da TextView. La classe dovrebbe sovrascrivere tre metodi onFocusChanged , onWindowFocusChanged e isFocused per rendere TextView tutto focalizzato.

@Override
protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
    if(focused)
        super.onFocusChanged(focused, direction, previouslyFocusedRect);
}

@Override
public void onWindowFocusChanged(boolean focused) {
    if(focused)
        super.onWindowFocusChanged(focused);
}


@Override
public boolean isFocused() {
    return true;
}

Perfetto: questa è solo la soluzione che stavo cercando.
Jason

6
È inoltre necessario sovrascrivere il metodo onWindowFocusChanged se si desidera che il riquadro di selezione non si fermi quando vengono visualizzati i menu.
virsir

7
A proposito, in realtà abbiamo avuto problemi con questa soluzione, poiché incasina i drawables con stato: se cambi i drawables con focus-in / focus-out, questo si interromperà. Ci è voluta quasi un'ora di debug fino a quando non ci siamo resi conto che questo attacco lo stava causando.
Matthias

Potete fornire una descrizione più dettagliata del problema? Uso questa funzione in molte app. Vorrei esaminare anche questo problema.
hnviet

1
Questo hack funziona alla grande ed è necessario solo quando più TextView sono sullo schermo contemporaneamente (come quando viene utilizzato in ListView) - perché di solito solo uno di essi può essere focalizzato, ma questa soluzione `` inganna '' il sistema dicendogli tutti sono :) Altrimenti per un singolo TextView dovrebbe essere usata una risposta più semplice come stackoverflow.com/a/3510891/258848 .
dimsuz

120

Finalmente oggi mi sono imbattuto in questo problema e ho iniziato hierarchyviewera utilizzare l'applicazione Android Market.

Guardando il titolo nella schermata dei dettagli di un'app, usano un semplice vecchio TextView. L'esame delle sue proprietà ha mostrato che non era focalizzato, non poteva essere focalizzato ed era generalmente molto normale, tranne per il fatto che era contrassegnato come selezionato .

Una riga di codice dopo e ho funzionato :)

textView.setSelected(true);

Questo ha senso, dato quello che dice il Javadoc :

Una vista può essere selezionata o meno. Notare che la selezione non è la stessa cosa del focus. Le visualizzazioni vengono in genere selezionate nel contesto di un AdapterView come ListView o GridView.

Ad esempio, quando scorri su un elemento in una visualizzazione elenco (come nell'app Market), solo allora il testo selezionato inizia a scorrere. E poiché questo particolare TextViewnon è attivabile o cliccabile, non perderà mai il suo stato di selezione.

Sfortunatamente, per quanto ne so, non c'è modo di preimpostare lo stato selezionato dal layout XML.
Ma la frase sopra funziona bene per me.


Mi chiedo solo: funzionerebbe anche per TextView che sono attivabili, ma dovrebbero comunque scorrere quando non sono focalizzati? Iow, lo stato di selezione "rimane" anche quando lo stato di attivazione cambia?
Matthias

Credo di si. Non vedo perché un cambio di focus su un basic TextView(cioè uno non incorporato in qualcosa di "selezionabile" come a ListView) cambierebbe lo stato selezionato.
Christopher Orr

Funziona bene anche per me. La ringrazio per la risposta. C'è la possibilità di cambiare il modo di ripetere ?!
Tima

@Mur: Sì, leggi la TextViewdocumentazione e dai un'occhiata android:marqueeRepeatLimit.
Christopher Orr

1
Questo metodo è migliore di quello con il focus poiché non interferisce con il focus delle visualizzazioni. Se hai opinioni che richiedono ai loro genitori di concentrarsi, quel metodo rovinerà l'attenzione. Questo metodo è semplice, efficiente e non si basa su hack per cambiare il focus ogni volta. Grazie!
Ionut Negru

75

Metti semplicemente questi parametri nel tuo TextView. Funziona :)

    android:singleLine="true" 
    android:ellipsize="marquee"
    android:marqueeRepeatLimit ="marquee_forever"
    android:scrollHorizontally="true"
    android:focusable="true"
    android:focusableInTouchMode="true" 

1
se questo thread di risposta non è già morto, questa dovrebbe essere la risposta accettata, secondo me. L'ho aggiunto alla mia definizione XML per la visualizzazione del testo e ha funzionato al primo scatto. Ho provato altri suggerimenti e questo è il più semplice. - Inoltre, l'aggiunta di "android: marqueeRepeatLimit =" marquee_forever "fa scorrere indefinitamente
parentesi

19
L'utilizzo di questo interrompe la selezione dello stato attivo di una riga ListView se TextView è al suo interno.
Tivie

Funziona perfettamente. Soluzione semplice ed elegante. Grazie!
Rabi

Come avviare e interrompere la selezione di TextView
Dwivedi Ji

Questo non ha funzionato per me fino a quando non ho provato l'altra risposta: textView.setSelected (true);
Justin

13

TranslateAnimationfunziona "tirando" la vista in una direzione di una quantità specificata. È possibile impostare dove iniziare questo "tirare" e dove finire.

TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

fromXDelta imposta l'offset della posizione iniziale del movimento nell'asse X.

fromXDelta = 0 //no offset. 
fromXDelta = 300 //the movement starts at 300px to the right.
fromXDelta = -300 //the movement starts at 300px to the left

toXDelta definisce la posizione finale di offset del movimento nell'asse X.

toXDelta = 0 //no offset. 
toXDelta = 300 //the movement ends at 300px to the right.
toXDelta = -300 //the movement ends at 300px to the left.

Se la larghezza del tuo testo è maggiore del modulo della differenza tra fromXDelta e toXDelta, il testo non sarà in grado di muoversi totalmente e compeltamente all'interno dello schermo.


Esempio

Supponiamo che le dimensioni dello schermo siano 320x240 px. Abbiamo un TextView con un testo che ha una larghezza di 700px e desideriamo creare un'animazione che "tira" il testo in modo da poter vedere la fine della frase.

                                       (screen)
                             +---------------------------+
                             |<----------320px---------->|
                             |                           |
                             |+---------------------------<<<< X px >>>>
               movement<-----|| some TextView with text that goes out...
                             |+---------------------------
                             |  unconstrained size 700px |
                             |                           |
                             |                           |
                             +---------------------------+


                             +---------------------------+
                             |                           |
                             |                           |
               <<<< X px >>>>---------------------------+|
movement<----- some TextView with text that goes out... ||
                             ---------------------------+|
                             |                           |
                             |                           |
                             |                           |
                             +---------------------------+

Per prima cosa impostiamo in fromXDelta = 0modo che il movimento non abbia un offset iniziale. Ora dobbiamo calcolare il valore toXDelta. Per ottenere l'effetto desiderato, dobbiamo "tirare" il testo con lo stesso identico px che si estende fuori dallo schermo. (nello schema è rappresentato da <<<< X px >>>>) Dato che il nostro testo ha una larghezza di 700 e l'area visibile è di 320px (larghezza dello schermo), impostiamo:

tXDelta = 700 - 320 = 380

E come si calcolano la larghezza dello schermo e la larghezza del testo?


Codice

Prendendo lo Snippet di Zarah come punto di partenza:

    /**
     * @param view The Textview or any other view we wish to apply the movement
     * @param margin A margin to take into the calculation (since the view
     *               might have any siblings in the same "row")
     *
     **/
public static Animation scrollingText(View view, float margin){

    Context context = view.getContext(); //gets the context of the view

            // measures the unconstrained size of the view
            // before it is drawn in the layout
    view.measure(View.MeasureSpec.UNSPECIFIED, 
                         View.MeasureSpec.UNSPECIFIED); 

            // takes the unconstrained wisth of the view
    float width = view.getMeasuredWidth();

            // gets the screen width
    float screenWidth = ((Activity) context).getWindowManager().getDefaultDisplay().getWidth();


            // perfrms the calculation
    float toXDelta = width - (screenWidth - margin);

            // sets toXDelta to 0 if the text width is smaller that the screen size
    if (toXDelta < 0) {toXDelta = 0; } else { toXDelta = 0 - toXDelta;}

            // Animation parameters
    Animation mAnimation = new TranslateAnimation(0, toXDelta, 0, 0);
    mAnimation.setDuration(15000); 
    mAnimation.setRepeatMode(Animation.RESTART);
    mAnimation.setRepeatCount(Animation.INFINITE);

    return mAnimation;
}

Potrebbero esserci modi più semplici per eseguire questa operazione, ma funziona per ogni visualizzazione a cui puoi pensare ed è riutilizzabile. È particolarmente utile se si desidera animare un TextView in un ListView senza interrompere le capacità abilitate / onFocus di textView. Inoltre scorre continuamente anche se la vista non è a fuoco.


La mia risposta sopra (cioè aggiungere una riga di codice :) textView.setSelected(true);non funziona nella tua situazione?
Christopher Orr

Sfortunatamente no. Avevo un ListView popolato con diversi TextView in ogni riga (da qui la crisi spaziale = P). ogni riga della visualizzazione di testo è selezionabile e fa apparire un menu contestuale. L'impostazione di setSelected su true sembra interrompere il menu contestuale.
Tivie

è? Potrebbe essere una specie di superamento nella maggior parte dei casi. Per me, per il motivo sopra descritto, era l'unica soluzione. (è riutilizzabile, btw!) = P
Tivie

12

Non so se hai ancora bisogno della risposta, ma ho trovato un modo semplice per farlo.

Imposta la tua animazione in questo modo:

Animation mAnimation = new TranslateAnimation(START_POS_X, END_POS_X, 
                START_POS_Y, END_POS_Y);
mAnimation.setDuration(TICKER_DURATION); 
mAnimation.setRepeatMode(Animation.RESTART);
mAnimation.setRepeatCount(Animation.INFINITE);

START_POS_X, END_POS_X, START_POS_YE END_POS_Ysono floati valori, mentre TICKER_DURATIONè un intdichiarai con le mie altre costanti.

Quindi ora puoi applicare questa animazione al tuo TextView:

TextView tickerText = (TextView) findViewById(R.id.ticker);
tickerText.setAnimation(mAnimation);

E questo è tutto. :)

La mia animazione inizia sul lato destro fuori dallo schermo (300f) e termina sul lato sinistro fuori dallo schermo (-300f), con una durata di 15 secondi (15000).


1
Non sembra molto semplice. Ma non credo che abbia ancora bisogno della risposta; vedi la risposta accettata sopra .. :)
Christopher Orr

2
Ma penso che questa soluzione sia più semplice della creazione di una nuova classe. : D Così com'è, puoi anche riutilizzare l'oggetto animazione per altre viste che desideri animare. ;)
Zarah

Funziona bene, ma cosa devo fare per visualizzare testi lunghi ?! Ora il mio testo sarà appena tagliato
Tima

@Mur Votema: Hai provato a impostare la larghezza di TextView su wrap_content?
Zarah

3
Non è un'ottima soluzione, poiché i parametri di dimensione e durata dipendono estremamente dalla dimensione del testo. Inoltre, si animerà, anche se la lunghezza del testo è inferiore alla larghezza della vista. setSelected (true) è davvero la soluzione più semplice.
Anm

5

Ho scritto il codice seguente per un ListView con elementi di testo di selezione. Si basa sulla soluzione setSelected descritta sopra. Fondamentalmente, sto estendendo la classe ArrayAdapter e sovrascrivo il metodo getView per selezionare TextView prima di restituirlo:

    // Create an ArrayAdapter which selects its TextViews before returning      
    // them. This would enable marqueeing while still making the list item
    // clickable.
    class SelectingAdapter extends ArrayAdapter<LibraryItem>
    {
        public
        SelectingAdapter(
            Context context, 
            int resource, 
            int textViewResourceId, 
            LibraryItem[] objects
        )
        {
            super(context, resource, textViewResourceId, objects);
        }

        @Override
        public
        View getView(int position, View convertView, ViewGroup parent)
        {
            View view = super.getView(position, convertView, parent);
            TextView textview = (TextView) view.findViewById(
                R.id.textview_playlist_item_title
            );
            textview.setSelected(true);
            textview.setEnabled(true);
            textview.setFocusable(false);
            textview.setTextColor(0xffffffff);
            return view;

        }
    }

1

Questa è la risposta che compare nella parte superiore della mia ricerca su Google, quindi ho pensato di poter pubblicare una risposta utile qui poiché ho difficoltà a ricordarlo abbastanza spesso. Ad ogni modo, per me funziona e richiede attributi XML e A un onFocusChangeListener.

//XML
        <TextView
            android:id="@+id/blank_title"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="5dp"
            android:layout_gravity="center_horizontal|center_vertical"
            android:background="#a4868585"
            android:textColor="#fff"
            android:textSize="15sp"
            android:singleLine="true"
            android:lines="1"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit ="marquee_forever"
            android:scrollHorizontally="true"
            android:focusable="true"
            android:focusableInTouchMode="true"
            tools:ignore="Deprecated" />

//JAVA
    titleText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
        @Override
        public void onFocusChange(View v, boolean hasFocus) {
            if (!hasFocus) {
                titleText.setSelected(true);
            }
        }
    });

1

// xml

 <TextView
            android:id="@+id/tvMarque"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ellipsize="marquee"
            android:layout_gravity="center_horizontal"
            android:fadingEdge="horizontal"
            android:marqueeRepeatLimit="marquee_forever"
            android:scrollHorizontally="true"
            android:padding="5dp"
            android:textSize="16sp"
            android:text=""
            android:textColor="@color/colorSyncText"
            android:visibility="visible" />

// In Java

        mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        mtvMarque.setSelected(true);
        mtvMarque.setSingleLine(true);
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.