Pergunta

Eu quero usar o efeito marquise em um TextView, mas o texto está apenas a ser rolada quando o TextView recebe foco. Isso é um problema, porque no meu caso, não pode.

Eu estou usando:

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

Existe uma maneira de ter o TextView sempre rolar o seu texto? Eu já vi isso sendo feito no aplicativo Android Market, onde o nome do aplicativo irá rolar na barra de título, mesmo se ele não receber o foco, mas eu não poderia encontrar este ser mencionado na documentação da API.

Foi útil?

Solução

Eu têm vindo a enfrentar o problema e a solução mais curta que eu vim com é criar uma nova classe derivada de TextView. A classe deve substituir três métodos onFocusChanged , onWindowFocusChanged e IsFocused para fazer a TextView todos focados.

@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;
}

Outras dicas

Eu finalmente subiu contra este problema hoje e assim despediu-se hierarchyviewer sobre a aplicação Android Market.

Olhando para o título na tela de detalhes de um aplicativo, eles usam um TextView velho liso. Examinando suas propriedades mostrou que não estava focado, não ser focado e foi geralmente muito comum - exceto para o fato de que foi marcado como selecionado

Uma linha de código mais tarde e eu tinha que trabalhar:)

textView.setSelected(true);

Isso faz sentido, dado o que o Javadoc diz :

Uma visão pode ser selecionada ou não. Note-se que a seleção não é o mesmo como o foco. Visualizações são tipicamente selecionado no contexto de uma AdapterView como ListView ou GridView.

i. Quando se desloca sobre um item em uma lista (como no aplicativo Market), só então é que o agora seleccionado início texto de rolagem. E desde que este TextView particular não é focada ou clickable, nunca perderá seu estado de seleção.

Infelizmente, tanto quanto eu sei não há nenhuma maneira para pré-definir o estado selecionado a partir do XML layout.
Mas o one-liner acima funciona bem para mim.

Basta colocar esses parâmetros em sua TextView. Ele funciona:)

    android:singleLine="true" 
    android:ellipsize="marquee"
    android:marqueeRepeatLimit ="marquee_forever"
    android:scrollHorizontally="true"
    android:focusable="true"
    android:focusableInTouchMode="true" 

TranslateAnimation obras de "puxar" a vista em uma direção por uma quantidade especificada. Você pode definir por onde começar esta "puxar" e onde terminar.

TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);

fromXDelta definir o deslocamento da posição de partida do movimento no eixo dos 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 define a posição final de deslocamento do movimento no eixo dos 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.

Se a largura do seu texto é maior que o módulo da diferença entre fromXDelta e toXDelta, o texto não será capaz de movimento totalmente e compeltely dentro da tela.


Exemplo

Vamos supor que o nosso tamanho da tela é 320x240 pxs. Temos um TextView com um texto que tem 700px de largura e queremos criar uma animação que "puxa" o texto para que possamos ver o fim da frase.

                                       (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... ||
                             ---------------------------+|
                             |                           |
                             |                           |
                             |                           |
                             +---------------------------+

Primeiro, fromXDelta = 0 conjunto para que o movimento não tem um deslocamento inicial. Agora precisamos descobrir o valor toXDelta. Para conseguir o efeito desejado é preciso "puxar" o texto exatamente a mesma px que se estende para fora da tela. (No esquema é representado por <<<< X px >>>>) Desde o nosso texto tem 700 largura e a área visível é 320px (largura da tela) que estabelecemos:

tXDelta = 700 - 320 = 380

E como é que vamos descobrir a tela Largura eo texto Largura?


Código

Tomando o Zarah trechos como ponto de partida:

    /**
     * @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;
}

Pode haver maneiras mais fáceis de executar esta, mas isso funciona para cada ponto de vista que você pode pensar e é reutilizável. É especialmente útil se você quiser animar um TextView em um ListView sem quebrar os habilitados / OnFocus habilidades do textView. Também rola permanentemente, mesmo se a vista não é focado.

Eu não sei se você ainda precisa a resposta, mas eu achei uma maneira fácil de fazer isso.

Configurar sua animação assim:

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 e END_POS_Y são valores float, enquanto TICKER_DURATION é um int eu declarei com as minhas outras constantes.

Depois, você pode agora aplicar esta animação para o seu TextView:

TextView tickerText = (TextView) findViewById(R.id.ticker);
tickerText.setAnimation(mAnimation);

E é isso. :)

As minhas animação começa no lado direito fora da tela (300f) e termina no lado esquerdo fora da tela (-300f), com uma duração de 15s (15000).

Eu escrevi o seguinte código para um ListView com itens de texto marquise. Ele baseia-se na solução setSelected descrito acima. Basicamente, eu estou estendendo a classe ArrayAdapter e substituir o método getView para selecionar o TextView antes de devolvê-lo:

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

        }
    }

Esta é a resposta que aparece no topo da minha pesquisa no google, então eu pensei que eu poderia postar uma resposta útil aqui desde que eu luta com a lembrança deste bastante frequência. De qualquer forma, isso funciona para mim e requer atributos XML e A um 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" />

// Em Java

        mtvMarque.setEllipsize(TextUtils.TruncateAt.MARQUEE);
        mtvMarque.setSelected(true);
        mtvMarque.setSingleLine(true);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top