Есть ли способ сделать прокрутку ellipsize="marquee" всегда?
Я хочу использовать эффект выделения на TextView, но текст прокручивается только тогда, когда TextView получает фокус. Это проблема, потому что в моем случае это невозможно.
Я использую:
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
Есть ли способ, чтобы TextView всегда прокручивал свой текст? Я видел, как это делается в приложении Android Market, где имя приложения будет прокручиваться в строке заголовка, даже если оно не получает фокуса, но я не смог найти это упомянутое в документации API.
8 ответов
Я столкнулся с проблемой, и самое короткое решение, которое я нашел, - это создать новый класс, производный от TextView. Класс должен переопределить три метода onFocusChanged, onWindowFocusChanged и isFocused, чтобы сделать TextView полностью сфокусированным.
@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;
}
Я наконец столкнулся с этой проблемой сегодня и так загорелся hierarchyviewer
в приложении Android Market.
Глядя на заголовок на подробном экране приложения, они используют простой старый TextView
, Изучение его свойств показало, что оно не сфокусировано, не может быть сфокусировано и, как правило, очень обычное - за исключением того факта, что оно было помечено как выбранное.
Одна строка кода позже, и у меня это работало:)
textView.setSelected(true);
Это имеет смысл, учитывая то, что Javadoc говорит:
Вид может быть выбран или нет. Обратите внимание, что выбор не совпадает с фокусом. Представления обычно выбираются в контексте AdapterView, такого как ListView или GridView.
т.е. когда вы прокручиваете элемент в виде списка (как в приложении "Маркет"), только тогда уже выбранный текст начинает прокручиваться. И так как этот конкретный TextView
не фокусируемый и не активируемый, он никогда не потеряет своего состояния выбора.
К сожалению, насколько я знаю, нет способа предварительно установить выбранное состояние из макета XML.
Но вышеприведенный однострочный текст прекрасно работает для меня.
Просто поместите эти параметры в ваш TextView. Оно работает:)
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit ="marquee_forever"
android:scrollHorizontally="true"
android:focusable="true"
android:focusableInTouchMode="true"
TranslateAnimation
работает, "вытягивая" вид в одном направлении на указанную сумму. Вы можете установить, где начать это "вытягивание" и где закончить.
TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);
fromXDelta установить смещение начальной позиции движения по оси 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 определяет конечную позицию смещения движения по оси 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.
Если ширина вашего текста больше, чем в модуле разницы между fromXDelta и toXDelta, текст не сможет полностью и полностью перемещаться по экрану.
пример
Давайте предположим, что наш размер экрана составляет 320x240 пикселей. У нас есть TextView с текстом шириной 700px, и мы хотим создать анимацию, которая "вытягивает" текст, чтобы мы могли видеть конец фразы.
(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... ||
---------------------------+|
| |
| |
| |
+---------------------------+
Сначала мы установили fromXDelta = 0
так что у движения нет начального смещения. Теперь нам нужно вычислить значение toXDelta. Чтобы добиться желаемого эффекта, нам нужно "вытянуть" текст в том же пикселе, что он выходит за пределы экрана. (на схеме это обозначено <<<< X px >>>>) Так как наш текст имеет ширину 700, а видимая область составляет 320 пикселей (ширина экрана), мы устанавливаем:
tXDelta = 700 - 320 = 380
И как мы вычисляем ширину экрана и ширину текста?
Код
Взяв за основу фрагмент Zarah:
/**
* @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;
}
Возможно, есть более простые способы сделать это, но это работает для каждого представления, которое вы можете придумать, и его можно использовать повторно. Это особенно полезно, если вы хотите анимировать TextView в ListView, не нарушая включенных /onFocus возможностей textView. Он также постоянно прокручивается, даже если вид не сфокусирован.
Я не знаю, нужен ли вам ответ, но я нашел простой способ сделать это.
Настройте анимацию так:
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
а также END_POS_Y
являются float
ценности, в то время как TICKER_DURATION
является int
Я объявил с другими моими константами.
Затем вы можете применить эту анимацию к вашему TextView:
TextView tickerText = (TextView) findViewById(R.id.ticker);
tickerText.setAnimation(mAnimation);
И это все.:)
Моя анимация начинается с правой стороны за пределами экрана (300f) и заканчивается на левой стороне за пределами экрана (-300f) с продолжительностью 15 с (15000).
Я написал следующий код для ListView с текстовыми элементами выделения. Он основан на решении setSelected, описанном выше. По сути, я расширяю класс ArrayAdapter и переопределяю метод getView, чтобы выбрать TextView перед его возвратом:
// 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;
}
}
Это ответ, который появляется в верхней части моего поиска в Google, поэтому я подумал, что смогу опубликовать здесь полезный ответ, так как мне трудно запоминать это довольно часто. В любом случае, это работает для меня и требует атрибутов XML и 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);
}
}
});
// 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" />
// В Java
mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE);
mtvMarque.setSelected(true);
mtvMarque.setSingleLine(true);