2015-02-18 14 views
5

Mam TextView z tekstem wewnątrz i chcę go animować z przewijaniem animacji markizy. Zobaczyłem, że to popular question o wymuszaniu animacji markizy, jednak kod w odpowiedziach działa tylko wtedy, gdy tekst jest wystarczająco długi, aby wyjść poza granice TextView (i dlatego tekst jest obcięty), szukałem rozwiązania, aby na stałe utworzyć tekst ma tę animację zaznaczenia niezależnie od szerokości tekstu; czy to możliwe?Android TextView: czy istnieje sposób na wymuszenie animacji markiz z krótkim tekstem?

+0

Jaki jest sens animacji markizy, jeśli tekst nie jest wystarczająco długi, aby przekroczyć granicę TextView? – Karakuri

+0

To dla jakiegoś tekstu tytułowego, a ze względu na konsystencję/branding, chciałem animacji zawsze na EDIT: i wygląda ładnie oczywiście: P – AndroidNoob

Odpowiedz

3

Biorąc @ sugestią JodiMiddleton chodzi o dopełnienie tekstu skonstruowałem kilka metod pomocnika pad tekst do szerokość celu oparta na obiekcie TextPaint (zapewniającym prawidłowe dobieranie czcionek itp. podczas pomiaru):

/** 
* Pad a target string of text with spaces on the right to fill a target 
* width 
* 
* @param text The target text 
* @param paint The TextPaint used to measure the target text and 
*   whitespaces 
* @param width The target width to fill 
* @return the original text with extra padding to fill the width 
*/ 
public static CharSequence padText(CharSequence text, TextPaint paint, int width) { 

    // First measure the width of the text itself 
    Rect textbounds = new Rect(); 
    paint.getTextBounds(text.toString(), 0, text.length(), textbounds); 

    /** 
    * check to see if it does indeed need padding to reach the target width 
    */ 
    if (textbounds.width() > width) { 
     return text; 
    } 

    /* 
    * Measure the text of the space character (there's a bug with the 
    * 'getTextBounds() method of Paint that trims the white space, thus 
    * making it impossible to measure the width of a space without 
    * surrounding it in arbitrary characters) 
    */ 
    String workaroundString = "a a"; 
    Rect spacebounds = new Rect(); 
    paint.getTextBounds(workaroundString, 0, workaroundString.length(), spacebounds); 

    Rect abounds = new Rect(); 
    paint.getTextBounds(new char[] { 
     'a' 
    }, 0, 1, abounds); 

    float spaceWidth = spacebounds.width() - (abounds.width() * 2); 

    /* 
    * measure the amount of spaces needed based on the target width to fill 
    * (using Math.ceil to ensure the maximum whole number of spaces) 
    */ 
    int amountOfSpacesNeeded = (int)Math.ceil((width - textbounds.width())/spaceWidth); 

    // pad with spaces til the width is less than the text width 
    return amountOfSpacesNeeded > 0 ? padRight(text.toString(), text.toString().length() 
      + amountOfSpacesNeeded) : text; 
} 

/** 
* Pads a string with white space on the right of the original string 
* 
* @param s The target string 
* @param n The new target length of the string 
* @return The target string padded with whitespace on the right to its new 
*   length 
*/ 
public static String padRight(String s, int n) { 
    return String.format("%1$-" + n + "s", s); 
} 

Więc kiedy użyć metod opartych na TextView nazwałbyś:

textView.setText(padText(myTargetString, textView.getPaint(), textView.getWidth())); 

To nie jest elegancki i jestem prawie pewien, że to ulepszenia, które mogą zostać wprowadzone (nie wspominając o lepszy sposób to zrobić) ale mimo to używam go w moim kodzie i wygląda na to, że robi to sztuczkę :)

1

Brzmi brudno, ale ścieżka najmniejszego oporu prawdopodobnie będzie padać tekst ze spacjami, aby umożliwić przewijanie.

Możesz usunąć je na Kliknij, jeśli to konieczne.

+0

Rozważyłem to podejście i jest dość brudne, ale wykonałoby to zadanie. Główny problem polega na określeniu ilości spacji, które mają zostać dodane do limitu przewijania ... – AndroidNoob

+0

Widzę, że jest to problem z widokiem tekstu o dynamicznym rozmiarze. Prawdopodobnie możesz użyć kodu wypełniającego stąd: http://stackoverflow.com/questions/388461/how-can-i-pad-a-string-in-java, aby zrobić to nawet po obu stronach. Następnie użyj szerokości TextView jako współczynnika mnożnika. Wszystko brudne, ale wygląda na to, że nawet zmusza to do hackowania. – JodiMiddleton

15

Stwórz własną animację.

anim/marquee.xml

<?xml version="1.0" encoding="utf-8"?> 
<set xmlns:android="http://schemas.android.com/apk/res/android"> 
    <translate 
     android:fromXDelta="100%" 
     android:toXDelta="-100%" 
     android:duration="10000" 
     android:repeatCount="infinite" 
     android:repeatMode="restart" 
     android:interpolator="@android:anim/linear_interpolator"/> 
</set> 

aw swojej działalności,

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.my_activity); 

    TextView myTextView = (TextView) findViewById(R.id.myTextView); 
    Animation marquee = AnimationUtils.loadAnimation(this, R.anim.marquee); 
    myTextView.startAnimation(marquee); 
} 
+0

Świetne rozwiązanie, jednak interpolator powinien być ustawiony w zestawie, a nie tłumacz. – Leon

+0

@karaokyo Tekst tekstowy jest przycinany na końcu, gdy wyświetlany jest w porządku (zgodnie z szerokością widoku), ale animacja pokazuje również tekst skrócony dla animacji zamiast pełnego tekstu. Czy możesz mi powiedzieć dlaczego? Jeśli ustawię textview.setselected na true, wtedy pełny tekst pojawi się w animacji, ale animacja rozpocznie się bez interakcji użytkownika. –

+0

Ta animacja to nie tylko przenoszenie tekstu, ale cały tekst. Mam czarne tło na widok tekstu i białą aktywność. Cały ruch tekstowy porusza się (wraz z tłem), a nie tylko tekst. –