android - textedit - ¿Hay alguna manera de hacer que ellipsize="marquee" siempre se desplace?
textview and button android example (7)
Quiero utilizar el efecto de marquesina en un TextView, pero el texto solo se desplaza cuando se enfoca el TextView. Eso es un problema, porque en mi caso, no puede.
Estoy usando:
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
¿Hay alguna manera de hacer que TextView siempre desplace su texto? He visto esto hecho en la aplicación Android Market, donde el nombre de la aplicación se desplazará en la barra de título, incluso si no recibe el foco, pero no pude encontrarlo en los documentos de la API.
Escribí el siguiente código para un ListView con elementos de texto de marquesina. Se basa en la solución setSelected descrita anteriormente. Básicamente, amplío la clase ArrayAdapter y anulo el método getView para seleccionar TextView antes de devolverlo:
// 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 es la respuesta que aparece en la parte superior de mi búsqueda de Google, así que pensé que podría publicar una respuesta útil aquí, ya que tengo problemas para recordar esto con bastante frecuencia. De todos modos, esto funciona para mí y requiere atributos XML y A an 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);
}
}
});
Finalmente me encontré con este problema hoy y por eso encendí el hierarchyviewer
en la aplicación Android Market.
Al mirar el título en la pantalla de detalles de una aplicación, usan un viejo TextView
. El examen de sus propiedades mostró que no estaba enfocado, no podía enfocarse y que, por lo general, era muy común, excepto por el hecho de que estaba marcado como seleccionado .
Una línea de código más tarde y lo tuve funcionando :)
textView.setSelected(true);
Esto tiene sentido, dado lo que dice el Javadoc :
Una vista puede ser seleccionada o no. Tenga en cuenta que la selección no es lo mismo que el enfoque. Las vistas se seleccionan típicamente en el contexto de un AdapterView como ListView o GridView.
es decir, cuando se desplaza sobre un elemento en una vista de lista (como en la aplicación Market), solo entonces comienza a desplazarse el texto ahora seleccionado . Y dado que este TextView
particular no se puede TextView
ni hacer clic, nunca perderá su estado de selección.
Desafortunadamente, hasta donde yo sé, no hay forma de predefinir el estado seleccionado desde el diseño XML.
Pero el one-liner anterior funciona bien para mí.
He estado enfrentando el problema y la solución más corta que he encontrado es crear una nueva clase derivada de TextView. La clase debe anular tres métodos en FocusChanged , onWindowFocusChanged y isFocused para enfocar todo en 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;
}
No sé si todavía necesitas la respuesta, pero encontré una manera fácil de hacerlo.
Configura tu animación así:
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
y END_POS_Y
son valores float
, mientras TICKER_DURATION
es un int
que declare con mis otras constantes.
Entonces ahora puede aplicar esta animación a su TextView:
TextView tickerText = (TextView) findViewById(R.id.ticker);
tickerText.setAnimation(mAnimation);
Y eso es. :)
Mi animación comienza en el lado derecho fuera de la pantalla (300f) y termina en el lado izquierdo fuera de la pantalla (-300f), con una duración de 15s (15000).
Simplemente ponga estos parámetros en su TextView. Funciona :)
android:singleLine="true"
android:ellipsize="marquee"
android:marqueeRepeatLimit ="marquee_forever"
android:scrollHorizontally="true"
android:focusable="true"
android:focusableInTouchMode="true"
TranslateAnimation
funciona "tirando" la Vista en una dirección en una cantidad específica. Puede establecer dónde comenzar este "tiro" y dónde terminar.
TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);
fromXDelta establece el desplazamiento de la posición inicial del movimiento en el eje 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 la posición final de desplazamiento del movimiento en el eje 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.
Si el ancho de su texto es mayor que el módulo de la diferencia entre fromXDelta y toXDelta, el texto no podrá moverse total y competentemente dentro de la pantalla.
Ejemplo
Supongamos que nuestro tamaño de pantalla es de 320x240 px. Tenemos un TextView con un texto que tiene un ancho de 700px y deseamos crear una animación que "jale" el texto para que podamos ver el final de la 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... ||
---------------------------+|
| |
| |
| |
+---------------------------+
Primero establecemos desde fromXDelta = 0
para que el movimiento no tenga un desplazamiento inicial. Ahora necesitamos calcular el valor toDelta. Para lograr el efecto deseado, necesitamos "tirar" del texto exactamente el mismo px que se extiende fuera de la pantalla. (en el esquema está representado por <<<< X px >>>>) Dado que nuestro texto tiene 700 de ancho, y el área visible es de 320px (ancho de pantalla) establecemos:
tXDelta = 700 - 320 = 380
¿Y cómo calculamos el ancho de la pantalla y el ancho del texto?
Código
Tomando el fragmento de Zarah como punto 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;
}
Puede haber formas más sencillas de realizar esto, pero esto funciona para cada vista que se te ocurra y es reutilizable. Es especialmente útil si desea animar un TextView en un ListView sin romper las capacidades habilitadas / onFocus de textView. También se desplaza continuamente incluso si la Vista no está enfocada.