Есть ли способ сделать прокрутку 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);
Другие вопросы по тегам