Gibt es eine Möglichkeit, Ellipsize = "Festzelt" immer scrollen zu lassen?

93

Ich möchte den Laufschrift-Effekt in einer Textansicht verwenden, aber der Text wird nur gescrollt, wenn die Textansicht den Fokus erhält. Das ist ein Problem, denn in meinem Fall kann es nicht.

Ich benutze:

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

Gibt es eine Möglichkeit, dass die Textansicht immer einen Bildlauf durchführt? Ich habe dies in der Android Market-App gesehen, in der der App-Name in der Titelleiste gescrollt wird, auch wenn er keinen Fokus erhält, aber ich konnte nicht feststellen, dass dies in den API-Dokumenten erwähnt wird.

Matthias
quelle
Damit das Festzelt funktioniert, sollte TextView ausgewählt und nicht fokussiert sein. Fokus gibt Auswahl, aber nicht umgekehrt.
Denis Gladkiy
1
Versuchen Sie immerMarqueeTextView stackoverflow.com/a/28806003/3496570
Zar E Ahmer
Ich würde die richtige Antwort für diese eine stackoverflow.com/a/3700651/4548520
user25

Antworten:

62

Ich habe mich dem Problem gestellt und die kürzeste Lösung, die ich gefunden habe, besteht darin, eine neue Klasse zu erstellen, die von TextView abgeleitet ist. Die Klasse sollte drei Methoden onFocusChanged , onWindowFocusChanged und isFocused überschreiben , damit die Textansicht fokussiert wird.

@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;
}
hnviet
quelle
Perfekt - das ist genau die Lösung, nach der ich gesucht habe.
Jason
6
Sie sollten auch die onWindowFocusChanged-Methode überschreiben, wenn das Auswahlrechteck nicht angehalten werden soll, wenn Menüs angezeigt werden.
Virsir
7
Übrigens hatten wir tatsächlich Probleme mit dieser Lösung, da sie Stateful Drawables durcheinander bringt: Wenn Sie Drawables mit Focus-In / Focus-Out ändern, wird dies nicht funktionieren. Wir brauchten fast eine Stunde zum Debuggen, bis wir merkten, dass dieser Hack es verursachte.
Matthias
Können Sie eine detailliertere Beschreibung des Problems bereitstellen? Ich benutze diese Funktion in vielen Apps. Ich möchte auch auf dieses Problem eingehen.
hnviet
1
Dieser Hack funktioniert hervorragend und wird nur benötigt, wenn mehrere TextViews gleichzeitig auf dem Bildschirm angezeigt werden (wie bei Verwendung in ListView) - da normalerweise nur einer von ihnen fokussiert werden kann, diese Lösung das System jedoch „täuscht“, indem sie alle davon erzählt sind :) Andernfalls sollte für einzelne TextView eine einfachere Antwort wie stackoverflow.com/a/3510891/258848 verwendet werden.
Dimsuz
120

Ich bin heute endlich auf dieses Problem gestoßen und habe mich so aufgeregt hierarchyviewer die Android Market-Anwendung gestartet.

Wenn sie den Titel auf dem Detailbildschirm einer App betrachten, verwenden sie ein einfaches altes TextView. Die Untersuchung seiner Eigenschaften ergab, dass es nicht fokussiert war, nicht fokussiert werden konnte und im Allgemeinen sehr gewöhnlich war - mit Ausnahme der Tatsache, dass es als ausgewählt markiert war .

Eine Codezeile später und ich hatte es funktioniert :)

textView.setSelected(true);

Dies ist angesichts der Aussagen des Javadoc sinnvoll :

Eine Ansicht kann ausgewählt werden oder nicht. Beachten Sie, dass die Auswahl nicht mit dem Fokus identisch ist. Ansichten werden normalerweise im Kontext einer AdapterView wie ListView oder GridView ausgewählt.

dh Wenn Sie in einer Listenansicht über ein Element scrollen (wie in der Market-App), wird der jetzt ausgewählte Text erst dann gescrollt. Und seit diesem besonderenTextView nicht fokussierbar oder anklickbar ist, verliert sie niemals ihren Auswahlstatus.

Leider gibt es meines Wissens keine Möglichkeit, den ausgewählten Status aus dem Layout-XML festzulegen.
Aber der Einzeiler oben funktioniert gut für mich.

Christopher Orr
quelle
Ich frage mich nur: Würde dies auch für TextViews funktionieren, die fokussierbar sind, aber trotzdem scrollen sollten, wenn sie nicht fokussiert sind? Iow, bleibt der Auswahlstatus auch dann bestehen, wenn sich der Fokusstatus ändert?
Matthias
Ich denke schon. Ich verstehe nicht, warum eine Fokusänderung auf eine Basis TextView(dh eine, die nicht in etwas "Auswählbares" wie a eingebettet ist ListView) den ausgewählten Zustand ändern würde.
Christopher Orr
Es funktioniert auch gut für mich. Vielen Dank für Ihre Antwort. Gibt es die Möglichkeit, die Art der Wiederholung zu ändern?!
Tima
@Mur: Ja, lies die TextViewDokumentation und schau sie dir an android:marqueeRepeatLimit.
Christopher Orr
1
Diese Methode ist besser als die mit dem Fokus, da sie den Fokus der Ansichten nicht beeinträchtigt. Wenn Sie Ansichten haben, bei denen die Eltern den Fokus übernehmen müssen, wird diese Methode den Fokus durcheinander bringen. Diese Methode ist einfach, effizient und basiert nicht auf Hacks, um den Fokus jedes Mal zu ändern. Danke dir!
Ionut Negru
75

Fügen Sie diese Parameter einfach in Ihre Textansicht ein. Es klappt :)

    android:singleLine="true" 
    android:ellipsize="marquee"
    android:marqueeRepeatLimit ="marquee_forever"
    android:scrollHorizontally="true"
    android:focusable="true"
    android:focusableInTouchMode="true" 
Vinayak
quelle
1
Wenn dieser Antwort-Thread noch nicht tot ist, sollte dies meiner Meinung nach die akzeptierte Antwort sein. Ich habe dies zu meiner XML-Definition für die Textansicht hinzugefügt und es hat bei der ersten Aufnahme funktioniert. Ich habe andere Vorschläge ausprobiert, und dies ist der einfachste. - Auch das Hinzufügen „android: marqueeRepeatLimit =“ marquee_forever“macht es Blättern Sie auf unbestimmte Zeit
Brack
19
Wenn Sie dies verwenden, wird die Fokusauswahl einer ListView-Zeile unterbrochen, wenn sich die TextView darin befindet.
Tivie
Funktioniert perfekt. Einfache und elegante Lösung. Vielen Dank!
Rabi
So starten und stoppen Sie das Festzelt von TextView
Dwivedi Ji
Dies funktionierte nicht für mich, bis ich die andere Antwort versuchte - textView.setSelected (true);
Justin
13

TranslateAnimationfunktioniert durch "Ziehen" der Ansicht in eine Richtung um einen bestimmten Betrag. Sie können festlegen, wo dieses "Ziehen" beginnen und wo es enden soll.

TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

fromXDelta stellt den Versatz der Startposition der Bewegung in der X-Achse ein.

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 definiert die versetzte Endposition der Bewegung in der X-Achse.

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

Wenn die Breite Ihres Textes größer ist als das Modul der Differenz zwischen von XDelta und toXDelta, kann sich der Text nicht vollständig und vollständig innerhalb des Bildschirms bewegen.


Beispiel

Nehmen wir an, unsere Bildschirmgröße beträgt 320 x 240 Pixel. Wir haben eine Textansicht mit einem Text mit einer Breite von 700 Pixel und möchten eine Animation erstellen, die den Text "zieht", damit wir das Ende der Phrase sehen können.

                                       (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... ||
                             ---------------------------+|
                             |                           |
                             |                           |
                             |                           |
                             +---------------------------+

Zuerst stellen wir fromXDelta = 0so ein, dass die Bewegung keinen Startversatz hat. Jetzt müssen wir den toXDelta-Wert berechnen. Um den gewünschten Effekt zu erzielen, müssen wir den Text genau so px "ziehen", wie er sich aus dem Bildschirm erstreckt. (im Schema wird durch <<<< X px >>>> dargestellt) Da unser Text eine Breite von 700 hat und der sichtbare Bereich 320px (Bildschirmbreite) beträgt, setzen wir:

tXDelta = 700 - 320 = 380

Und wie berechnen wir die Bildschirmbreite und die Textbreite?


Code

Nehmen Sie das Zarah-Snippet als Ausgangspunkt:

    /**
     * @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;
}

Es gibt möglicherweise einfachere Möglichkeiten, dies durchzuführen, aber dies funktioniert für jede erdenkliche Ansicht und ist wiederverwendbar. Dies ist besonders nützlich, wenn Sie eine Textansicht in einer Listenansicht animieren möchten, ohne die aktivierten / onFocus-Funktionen der Textansicht zu beeinträchtigen. Es wird auch kontinuierlich gescrollt, auch wenn die Ansicht nicht fokussiert ist.

Tivie
quelle
Funktioniert meine obige Antwort (dh eine Codezeile hinzufügen textView.setSelected(true);:) in Ihrer Situation nicht?
Christopher Orr
Unglücklicherweise nicht. Ich hatte eine ListView mit mehreren TextViews in jeder Zeile (daher die Weltraumkrise = P). Jede Zeile der Textansicht ist anklickbar und öffnet ein Kontextmenü. Wenn Sie setSelected auf true setzen, wird das Kontextmenü anscheinend unterbrochen.
Tivie
ist es? Könnte in den meisten Fällen eine Art Überschreitung sein. Für mich war aus dem oben beschriebenen Grund die einzige Lösung. (es ist übrigens wiederverwendbar!) = P
Tivie
12

Ich weiß nicht, ob Sie die Antwort noch brauchen, aber ich habe einen einfachen Weg gefunden, dies zu tun.

Richten Sie Ihre Animation folgendermaßen ein:

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_YUnd END_POS_Ysind floatWerte, während TICKER_DURATIONeine istint , erklärte ich mit meinen anderen Konstanten.

Dann können Sie diese Animation jetzt auf Ihre Textansicht anwenden:

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

Und das ist es. :) :)

Meine Animation beginnt auf der rechten Seite außerhalb des Bildschirms (300f) und endet auf der linken Seite außerhalb des Bildschirms (-300f) mit einer Dauer von 15s (15000).

Zarah
quelle
1
Das scheint nicht sehr einfach zu sein. Aber ich glaube nicht, dass er noch die Antwort braucht; siehe die akzeptierte Antwort oben .. :)
Christopher Orr
2
Aber ich denke, diese Lösung ist einfacher als das Erstellen einer neuen Klasse. : D So wie es ist, können Sie das Animationsobjekt auch für andere Ansichten wiederverwenden, die Sie animieren möchten. ;)
Zarah
Es funktioniert zwar gut, aber was soll ich tun, um lange Texte anzuzeigen?! Jetzt wird mein Text gerade geschnitten
Tima
@Mur Votema: Haben Sie versucht, die Breite Ihrer TextView auf wrap_content zu setzen?
Zarah
3
Keine gute Lösung, da die Parameter für Größe und Dauer stark von der Textgröße abhängen. Außerdem wird animiert, selbst wenn die Textlänge kleiner als die Ansichtsbreite ist. setSelected (true) ist wirklich die einfachste Lösung.
Anm
5

Ich habe den folgenden Code für eine ListView mit Laufschrifttextelementen geschrieben. Es basiert auf der oben beschriebenen setSelected-Lösung. Grundsätzlich erweitere ich die ArrayAdapter-Klasse und überschreibe die getView-Methode, um die TextView auszuwählen, bevor ich sie zurückgebe:

    // 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;

        }
    }
Smichak
quelle
1

Dies ist die Antwort, die oben in meiner Google-Suche angezeigt wird, sodass ich dachte, ich könnte hier eine nützliche Antwort veröffentlichen, da ich Schwierigkeiten habe, mich ziemlich oft daran zu erinnern. Auf jeden Fall funktioniert dies für mich und erfordert XML-Attribute und A einen 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);
            }
        }
    });
Thunderstick
quelle
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);
Soni Kumar
quelle