Chcę użyć efektu marquee na TextView, ale tekst jest przewijany tylko wtedy, gdy TextView staje się fokusem. To jest problem, ponieważ w moim przypadku tak nie jest.
Ja używam:
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
Czy istnieje sposób, aby TextView zawsze przewijał swój tekst? Widziałem, jak to się robi w aplikacji Android Market, gdzie nazwa aplikacji przewija się na pasku tytułu, nawet jeśli nie jest aktywna, ale nie mogłem znaleźć tego w dokumentacji API.
Odpowiedzi:
Miałem do czynienia z problemem i najkrótszym rozwiązaniem, jakie wymyśliłem, jest utworzenie nowej klasy pochodnej od TextView. Klasa powinna przesłonić trzy metody onFocusChanged , onWindowFocusChanged i isFocused, aby obiekt TextView był skupiony.
@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; }
źródło
W końcu natknąłem się dzisiaj na ten problem i tak uruchomiłem
hierarchyviewer
aplikację Android Market.Patrząc na tytuł na ekranie szczegółów aplikacji, używają zwykłego starego
TextView
. Badanie jego właściwości wykazało, że nie był skupiony, nie mógł być skupiony i generalnie był bardzo zwyczajny - poza tym, że został oznaczony jako wybrany .Jedna linijka kodu później i już działało :)
textView.setSelected(true);
Ma to sens, biorąc pod uwagę to, co mówi Javadoc :
tzn. kiedy przewijasz element w widoku listy (jak w aplikacji Market), tylko wtedy wybrany tekst zaczyna się przewijać. A ponieważ ten konkretny
TextView
nie jest aktywny ani klikalny, nigdy nie straci swojego stanu wyboru.Niestety o ile wiem nie ma możliwości wcześniejszego ustawienia wybranego stanu z układu XML.
Ale powyższa jedna linijka działa dobrze dla mnie.
źródło
TextView
(tj. Taki, który nie jest osadzony w czymś „wybieralnym”, takim jak aListView
) miałby zmienić wybrany stan.TextView
dokumentację i przyjrzyj sięandroid:marqueeRepeatLimit
.Po prostu umieść te parametry w swoim TextView. To działa :)
android:singleLine="true" android:ellipsize="marquee" android:marqueeRepeatLimit ="marquee_forever" android:scrollHorizontally="true" android:focusable="true" android:focusableInTouchMode="true"
źródło
TranslateAnimation
działa na zasadzie „ciągnięcia” widoku w jednym kierunku o określoną wartość. Możesz ustawić, gdzie rozpocząć i zakończyć to „ciągnięcie”.TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);
fromXDelta ustawia przesunięcie pozycji początkowej ruchu w osi 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 określa przesunięcie pozycji końcowej ruchu w osi 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.
Jeśli szerokość twojego tekstu jest większa niż moduł różnicy między fromXDelta i toXDelta, tekst nie będzie mógł całkowicie i przymusowo poruszać się po ekranie.
Przykład
Załóżmy, że rozmiar naszego ekranu to 320x240 pikseli. Mamy TextView z tekstem o szerokości 700 pikseli i chcemy stworzyć animację, która „ciągnie” tekst, abyśmy mogli zobaczyć koniec frazy.
(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... || ---------------------------+| | | | | | | +---------------------------+
Najpierw ustawiliśmy
fromXDelta = 0
tak, aby ruch nie miał offsetu początkowego. Teraz musimy obliczyć wartość toXDelta. Aby osiągnąć pożądany efekt, musimy „wyciągnąć” tekst dokładnie z tego samego piksela, który rozciąga się poza ekran. (w schemacie jest reprezentowane przez <<<< X px >>>>) Ponieważ nasz tekst ma 700 szerokości, a widoczny obszar to 320px (szerokość ekranu) ustalamy:tXDelta = 700 - 320 = 380
Jak obliczymy szerokość ekranu i szerokość tekstu?
Kod
Biorąc fragment Zarah jako punkt wyjścia:
/** * @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; }
Mogą istnieć prostsze sposoby, aby to zrobić, ale działa to w przypadku każdego widoku, o którym myślisz, i można go użyć ponownie. Jest to szczególnie przydatne, jeśli chcesz animować TextView w ListView bez przerywania możliwości enabled / onFocus w textView. Przewija się również w sposób ciągły, nawet jeśli widok nie jest ustawiony.
źródło
textView.setSelected(true);
nie działa w Twojej sytuacji?Nie wiem, czy nadal potrzebujesz odpowiedzi, ale znalazłem łatwy sposób, aby to zrobić.
Skonfiguruj swoją animację w następujący sposób:
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_Y
IEND_POS_Y
sąfloat
wartościami, aTICKER_DURATION
toint
oświadczyłem z moich innych stałych.Następnie możesz teraz zastosować tę animację do swojego TextView:
I to wszystko. :)
Moja animacja zaczyna się po prawej stronie poza ekranem (300f) i kończy po lewej stronie poza ekranem (-300f), z czasem trwania 15s (15000).
źródło
Napisałem następujący kod dla ListView z elementami tekstowymi marquee. Opiera się na opisanym powyżej rozwiązaniu setSelected. Zasadniczo rozszerzam klasę ArrayAdapter i nadpisuję metodę getView, aby wybrać TextView przed jej zwróceniem:
// 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; } }
źródło
To jest odpowiedź, która pojawia się na górze mojej wyszukiwarki Google, więc pomyślałem, że mógłbym zamieścić tutaj przydatną odpowiedź, ponieważ mam problemy z zapamiętaniem tego dość często. W każdym razie to działa dla mnie i wymaga atrybutów XML oraz A 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); } } });
źródło
// 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" />
// W Javie
mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE); mtvMarque.setSelected(true); mtvMarque.setSingleLine(true);
źródło