Есть ли способ сделать прокрутку ellipsize = "marquee" всегда? - PullRequest
88 голосов
/ 01 декабря 2009

Я хочу использовать эффект выделения для TextView, но текст прокручивается только тогда, когда TextView получает фокус. Это проблема, потому что в моем случае это невозможно.

Я использую:

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

Есть ли способ, чтобы TextView всегда прокручивал свой текст? Я видел, как это делается в приложении Android Market, где имя приложения будет прокручиваться в строке заголовка, даже если оно не получит фокус, но я не смог найти это упомянутое в документации API.

Ответы [ 8 ]

116 голосов
/ 13 сентября 2010

Сегодня я наконец столкнулся с этой проблемой и поэтому запустил hierarchyviewer в приложении Android Market.

Глядя на заголовок на подробном экране приложения, они используют старый TextView. Изучение его свойств показало, что оно не сфокусировано, не может быть сфокусировано и, как правило, очень просто & mdash; за исключением того факта, что он был помечен как выбранный .

Одна строка кода позже, и у меня все заработало:)

textView.setSelected(true);

Это имеет смысл, учитывая то, что Javadoc говорит :

Вид может быть выбран или нет. Обратите внимание, что выбор не совпадает с фокусом. Представления обычно выбираются в контексте AdapterView, например ListView или GridView.

т.е. Когда вы прокручиваете элемент в представлении списка (как в приложении Market), только тогда текст теперь выбранный начинает прокручиваться. А поскольку этот конкретный TextView не может быть фокусируемым или кликабельным, он никогда не потеряет свое состояние выбора.

К сожалению, насколько я знаю, нет способа предварительно установить выбранное состояние из XML макета.
Но у меня хорошо работает однострочник.

72 голосов
/ 18 августа 2010

Просто поместите эти параметры в ваш TextView. Работает:)

    android:singleLine="true" 
    android:ellipsize="marquee"
    android:marqueeRepeatLimit ="marquee_forever"
    android:scrollHorizontally="true"
    android:focusable="true"
    android:focusableInTouchMode="true" 
61 голосов
/ 24 марта 2010

Я столкнулся с проблемой, и самое короткое решение, которое я нашел, - это создать новый класс, производный от 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;
}
13 голосов
/ 09 декабря 2010

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. Он также непрерывно прокручивается, даже если вид не сфокусирован.

12 голосов
/ 12 августа 2010

Я не знаю, нужен ли вам ответ, но я нашел простой способ сделать это.

Настройте анимацию так:

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).

5 голосов
/ 19 января 2012

Я написал следующий код для 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;

        }
    }
2 голосов
/ 29 декабря 2016

Это ответ, который появляется в верхней части моего поиска в 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);
            }
        }
    });
1 голос
/ 05 декабря 2018

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