Je souhaite utiliser l'effet Marquee sur un TextView, mais le texte est en train de défiler uniquement lorsque TextView est activé. C'est un problème, parce que dans mon cas, ça ne peut pas.
J'utilise:
Android:ellipsize="Marquee"
Android:marqueeRepeatLimit="Marquee_forever"
Existe-t-il un moyen de faire en sorte que TextView fasse toujours défiler son texte? J'ai vu cela se faire dans l'application Android Market, où le nom de l'application défilait dans la barre de titre, même s'il ne recevait pas le focus, mais je ne pouvais pas trouver cela mentionné dans les documents de l'API.
J'ai été confronté au problème et la solution la plus courte que j'ai proposée consiste à créer une nouvelle classe dérivée de TextView . La classe doit remplacer trois méthodes onFocusChanged, onWindowFocusChanged et isFocused pour que le TextView soit entièrement focalisé.
@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;
}
Je me suis finalement heurté à ce problème aujourd’hui et j’ai donc enflammé hierarchyviewer
sur l’application Android Market.
En regardant le titre sur l'écran de détail d'une application, ils utilisent une vieille variable TextView
. L'examen de ses propriétés a montré qu'il n'était pas focalisé, que ne pouvait pas et qu'il était généralement très ordinaire, à l'exception du fait qu'il était marqué comme selected.
Une ligne de code plus tard et je l'ai fait fonctionner :)
textView.setSelected(true);
Cela a du sens, étant donné ce que (la Javadoc dit) :
Une vue peut être sélectionnée ou non. Notez que la sélection n’est pas la même chose que le focus. Les vues sont généralement sélectionnées dans le contexte d'un AdapterView tel que ListView ou GridView.
en d'autres termes, lorsque vous faites défiler un élément dans une vue de liste (comme dans l'application Market), le défilement du texte maintenant sélectionné commence alors. Et puisque cette TextView
particulière n'est pas focalisable ou cliquable, elle ne perdra jamais son état de sélection.
Malheureusement, pour autant que je sache, il n'y a aucun moyen de prédéfinir l'état sélectionné à partir du format XML.
Mais le one-liner ci-dessus me convient parfaitement.
Il suffit de mettre ces paramètres dans votre TextView. Ça marche :)
Android:singleLine="true"
Android:ellipsize="Marquee"
Android:marqueeRepeatLimit ="Marquee_forever"
Android:scrollHorizontally="true"
Android:focusable="true"
Android:focusableInTouchMode="true"
TranslateAnimation
fonctionne en "tirant" la vue dans une direction d'un montant spécifié. Vous pouvez définir où commencer ce "tirage" et où se terminer.
TranslateAnimation(fromXDelta, toXDelta, fromYDelta, toYDelta);
fromXDelta définit le décalage de la position de départ du mouvement sur l'axe 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 définit la position finale décalée du mouvement sur l'axe 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 la largeur de votre texte est plus grande que le module de la différence entre fromXDelta et toXDelta, le texte ne pourra pas se déplacer complètement et de manière intégrale dans l'écran.
Supposons que notre taille d'écran est de 320x240 pxs. Nous avons un TextView avec un texte qui a une largeur de 700px et nous souhaitons créer une animation qui "tire" le texte afin que nous puissions voir la fin de la phrase.
(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... ||
---------------------------+|
| |
| |
| |
+---------------------------+
Nous avons d’abord défini fromXDelta = 0
pour que le mouvement n’ait pas de décalage de départ. Nous devons maintenant déterminer la valeur toXDelta. Pour obtenir l'effet souhaité, nous devons "extraire" le texte du même px exact qu'il recouvre de l'écran. (dans le schéma est représenté par <<<< X px >>>>) Comme notre texte a une largeur de 700 et que la zone visible est de 320 pixels (largeur de l'écran), nous définissons:
tXDelta = 700 - 320 = 380
Et comment pouvons-nous déterminer la largeur de l'écran et la largeur du texte?
En prenant l’extrait de Zarah comme point de départ:
/**
* @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;
}
Il existe peut-être des moyens plus simples de réaliser cela, mais cela fonctionne pour toutes les vues imaginables et est réutilisable. Cela est particulièrement utile si vous souhaitez animer un TextView dans un ListView sans interrompre les capacités activé/activé de textView. Il fait également défiler en continu, même si la vue n'est pas mise au point.
Je ne sais pas si vous avez toujours besoin de la réponse, mais j'ai trouvé un moyen facile de le faire.
Configurez votre animation comme suit:
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
et END_POS_Y
sont des valeurs float
, alors que TICKER_DURATION
est un int
j'ai déclaré avec mes autres constantes.
Ensuite, vous pouvez maintenant appliquer cette animation à votre TextView:
TextView tickerText = (TextView) findViewById(R.id.ticker);
tickerText.setAnimation(mAnimation);
Et c'est tout. :)
Mon animation commence sur le côté droit hors écran (300f) et se termine sur le côté gauche hors écran (-300f), avec une durée de 15s (15000).
J'ai écrit le code suivant pour un ListView avec des éléments de texte Marquee. Il est basé sur la solution setSelected décrite ci-dessus. Fondamentalement, j'étends la classe ArrayAdapter et remplace la méthode getView pour sélectionner TextView avant de le renvoyer
// 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;
}
}
C’est la réponse qui apparaît en haut de ma recherche google et j’ai donc pensé que je pourrais poster une réponse utile car j’ai du mal à me souvenir de cela assez souvent . En tout cas, cela fonctionne pour moi et nécessite des attributs XML et A on 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" />
// en Java
mtvMarque.setEllipsize(TextUtils.TruncateAt.Marquee);
mtvMarque.setSelected(true);
mtvMarque.setSingleLine(true);