auto-scrolling TextView dans android pour mettre du texte en vue
j'ai un TextView
que j'ajoute dynamiquement du texte.
dans mon main.xml
le fichier que j'ai les propriétés définies pour faire mon max de lignes 19 et les barres de défilement verticale.
dans le .java
fichier que j'utilise textview.setMovementMethod(new ScrollingMovementMethod());
pour permettre le défilement.
Le défilement fonctionne très bien. Dès que 19 lignes sont prises, et plus de lignes sont ajoutées, il commence à défiler comme il se doit. Le problème est que je veux que le nouveau texte soit affiché.
je suis en train d'écrire le valeur de textview.getScrollY()
et il reste à 0
n'importe quoi (même si je les faire défiler manuellement et ajouter une nouvelle ligne de texte).
donc textview.scrollTo(0, textview.getScrollY());
ne fait rien pour moi.
y a-t-il une autre méthode que je devrais utiliser pour obtenir la valeur de défilement vertical pour le <!--7? Tout ce que j'ai lu indique que, à toutes fins pratiques, ce que je fais devrait fonctionner:/
12 réponses
J'ai creusé un peu dans la source de TextView Mais voici ce que j'ai trouvé. Cela ne vous oblige pas à envelopper le TextView dans un ScrollView et, pour autant que je puisse dire, fonctionne parfaitement.
// function to append a string to a TextView as a new line
// and scroll to the bottom if needed
private void addMessage(String msg) {
// append the new string
mTextView.append(msg + "\n");
// find the amount we need to scroll. This works by
// asking the TextView's internal layout for the position
// of the final line and then subtracting the TextView's height
final int scrollAmount = mTextView.getLayout().getLineTop(mTextView.getLineCount()) - mTextView.getHeight();
// if there is no need to scroll, scrollAmount will be <=0
if (scrollAmount > 0)
mTextView.scrollTo(0, scrollAmount);
else
mTextView.scrollTo(0, 0);
}
s'il vous Plaît laissez-moi savoir si vous trouvez un cas où cela échoue. J'apprécierais d'être en mesure de corriger les bugs dans mon app ;)
Edit: je tiens à préciser que j'ai aussi utiliser
mTextView.setMovementMethod(new ScrollingMovementMethod());
après avoir instancié mon TextView.
Utiliser android:gravity="bottom"
sur le TextView de votre mise en page XML. E. g.
<TextView
...
android:gravity="bottom"
...
/>
Ne me demandez pas pourquoi cela fonctionne.
le seul problème avec cette méthode est que si vous voulez ensuite faire défiler vers le haut le textview, il continue d'être "tiré vers le bas" à chaque fois que le nouveau texte est inséré.
c'est ce que j'utilise pour faire défiler jusqu'au bas de mon texte de chat ...
public void onCreate(Bundle savedInstanceState)
{
this.chat_ScrollView = (ScrollView) this.findViewById(R.id.chat_ScrollView);
this.chat_text_chat = (TextView) this.findViewById(R.id.chat_text_chat);
}
public void addTextToTextView()
{
String strTemp = "TestlineOne\nTestlineTwo\n";
//append the new text to the bottom of the TextView
chat_text_chat.append(strTemp);
//scroll chat all the way to the bottom of the text
//HOWEVER, this won't scroll all the way down !!!
//chat_ScrollView.fullScroll(View.FOCUS_DOWN);
//INSTEAD, scroll all the way down with:
chat_ScrollView.post(new Runnable()
{
public void run()
{
chat_ScrollView.fullScroll(View.FOCUS_DOWN);
}
});
}
EDIT: voici le code XML de mise en page
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<!-- center chat display -->
<ScrollView android:id="@+id/chat_ScrollView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true">
<TextView android:id="@+id/chat_text_chat"
android:text="center chat"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:singleLine="false" />
</ScrollView>
</RelativeLayout>
les réponses Précédentes ne fonctionnent pas correctement pour moi, cela fonctionne cependant.
Créer un TextView et procédez de la manière suivante:
// ...
mTextView = (TextView)findViewById(R.id.your_text_view);
mTextView.setMovementMethod(new ScrollingMovementMethod());
// ...
utilisez la fonction suivante pour ajouter du texte à TextView.
private void appendTextAndScroll(String text)
{
if(mTextView != null){
mTextView.append(text + "\n");
final Layout layout = mTextView.getLayout();
if(layout != null){
int scrollDelta = layout.getLineBottom(mTextView.getLineCount() - 1)
- mTextView.getScrollY() - mTextView.getHeight();
if(scrollDelta > 0)
mTextView.scrollBy(0, scrollDelta);
}
}
}
J'espère que cela vous aidera.
TextView a déjà l'auto-scrolling si vous définissez le texte en utilisant des chaînes de caractères pouvant être insérées ou éditables avec la position du curseur qui y est définie.
tout d'abord, définissez la méthode de défilement:
mTextView.setMovementMethod(new ScrollingMovementMethod());
puis utilisez ce qui suit pour définir le texte:
SpannableString spannable = new SpannableString(string);
Selection.setSelection(spannable, spannable.length());
mTextView.setText(spannable, TextView.BufferType.SPANNABLE);
le setSelection () déplace le curseur vers cet index. Lorsqu'une fenêtre TextView est positionnée sur une fenêtre SPANNABLE, elle défile automatiquement pour rendre le curseur visible. Notez que cela ne dessine pas le curseur, il ne fait que défiler l'emplacement du curseur à être dans la section visible de TextView.
aussi, depuis TextView.ajoute () met à jour le texte de TextView.BufferType.ÉDITABLE et Modifiable implémente Spannable, vous pouvez faire ceci:
mTextView.append(string);
Editable editable = mTextView.getEditableText();
Selection.setSelection(editable, editable.length());
Voici une implémentation widget complète. Il suffit d'appeler setText() ou append() sur ce widget. Il est légèrement différent de celui ci-dessus parce qu'il s'étend de EditText qui oblige déjà son texte interne à être modifiable.
import android.content.Context;
import android.support.v7.widget.AppCompatEditText;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
import android.text.method.MovementMethod;
import android.text.method.ScrollingMovementMethod;
import android.text.method.Touch;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;
public class AutoScrollTextView extends AppCompatEditText {
public AutoScrollTextView(Context context) {
this(context, null);
}
public AutoScrollTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public AutoScrollTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected boolean getDefaultEditable() {
return false;
}
@Override
protected MovementMethod getDefaultMovementMethod() {
return new CursorScrollingMovementMethod();
}
@Override
public void setText(CharSequence text, BufferType type) {
super.setText(text, type);
scrollToEnd();
}
@Override
public void append(CharSequence text, int start, int end) {
super.append(text, start, end);
scrollToEnd();
}
public void scrollToEnd() {
Editable editable = getText();
Selection.setSelection(editable, editable.length());
}
@Override
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
super.onInitializeAccessibilityEvent(event);
event.setClassName(AutoScrollTextView.class.getName());
}
/**
* Moves cursor when scrolled so it doesn't auto-scroll on configuration changes.
*/
private class CursorScrollingMovementMethod extends ScrollingMovementMethod {
@Override
public boolean onTouchEvent(TextView widget, Spannable buffer, MotionEvent event) {
widget.moveCursorToVisibleOffset();
return super.onTouchEvent(widget, buffer, event);
}
}
}
scrollview=(ScrollView)findViewById(R.id.scrollview1);
tb2.setTextSize(30);
tb2=(TextView)findViewById(R.id.textView2);
scrollview.fullScroll(View.FOCUS_DOWN);
Ou de l'utiliser dans le TextView:
<TextView
android:id="@+id/tb2"
android:layout_width="fill_parent"
android:layout_height="225sp"
android:gravity="top"
android:background="@android:drawable/editbox_background"
android:scrollbars="vertical"/>
j'ai utilisé un petit truc ... dans mon cas....
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/textView"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_above="@+id/imageButton">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/scrollView"
android:layout_gravity="left|top" >
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:inputType="textMultiLine"
android:ems="10"
android:text="@string/your_text" />
</ScrollView>
</FrameLayout>
mise en œuvre Simple...dans votre mise en page XML définir votre TextView avec ces attributs:
<TextView
...
android:gravity="bottom"
android:scrollbars="vertical"
/>
(2017) à l'aide de Kotlin:
// you need this to enable scrolling:
mTextView.movementMethod = ScrollingMovementMethod()
// to enable horizontal scrolling, that means word wrapping off:
mTextView.setHorizontallyScrolling(true)
...
mTextView.text = "Some long long very long text content"
mTextView.post {
val scrollAmount = mTextView.layout.getLineTop(mTextView.lineCount) - mTextView.height
mTextView.scrollTo(0, scrollAmount)
}
Ce fichier works pour moi
// Layout Views
private TextView mConversationView;
private ScrollView mConversationViewScroller;
use it either in :
public void onCreate(Bundle savedInstanceState)
{
//...blabla
setContentView(R.layout.main);
//...blablabla
mConversationView = (TextView) findViewById(R.id.in);
mConversationViewScroller = (ScrollView) findViewById(R.id.scroller);
}
or in "special" method e.g.
public void initializeChatOrSth(...){
//...blabla
mConversationView = (TextView) findViewById(R.id.in);
mConversationViewScroller = (ScrollView) findViewById(R.id.scroller);
}
public void addTextToTextView()
{
//...blablabla some code
byte[] writeBuf = (byte[]) msg.obj;
// construct a string from the buffer - i needed this or You can use by"stringing"
String writeMessage = new String(writeBuf);
mConversationView.append("\n"+"Me: " + writeMessage);
mConversationViewScroller.post(new Runnable()
{
public void run()
{
mConversationViewScroller.fullScroll(View.FOCUS_DOWN);
}
});
}
this one works fine, also we can maually scroll text to the very top - which is impossible when gravity tag in XML is used.
Of course XML (main) the texview should be nested inside scrollview , e.g:
<ScrollView
android:id="@+id/scroller"
android:layout_width="match_parent"
android:layout_height="280dp"
android:fillViewport="true"
android:keepScreenOn="true"
android:scrollbarStyle="insideInset"
android:scrollbars="vertical" >
<TextView
android:id="@+id/in"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:keepScreenOn="true"
android:scrollbars="vertical" >
</TextView>
</ScrollView>
pour éviter de créer mannequin scroolview je n'ai
int top_scr,rec_text_scrollY;
top_scr=(int)rec_text.getTextSize()+rec_text.getHeight();
rec_text_scrollY=rec_text.getLineBounds(rec_text.getLineCount()-1, null)-top_scr;
//repeat scroll here and in rec_text.post.
//If not scroll here text will be "jump up" after new append, and immediately scroll down
//If not scroll in post, than scroll will not be actually processed
if(rec_text_scrollY>0)rec_text.scrollTo(0, rec_text_scrollY);
rec_text.post(new Runnable(){
@Override
public void run() {
if(rec_text_scrollY>0)rec_text.scrollTo(0, rec_text_scrollY);
}
});
https://stackoverflow.com/a/7350267/4411645 n'a pas vraiment fonctionné pour moi pour
- le getLayout pouvez jeter NPE lorsque le texte est changé récemment.
- scrollTo doit être remplacé par scrollBy
- il ne tient pas compte de la position relative du textview ou des paddings.
Inutile de dire que c'est un bon point de départ. Voici ma variante de l'implémentation, au sein d'un textwatcher. Nous devons soustraire les textView en haut et en bas lors du calcul du delta, car getLineTop() renvoie également la valeur par rapport à la textView haut.
@Override
public void afterTextChanged(Editable editable) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
Layout layout = textView.getLayout();
if (layout != null) {
int lineTop = layout.getLineTop(textView.getLineCount());
final int scrollAmount = lineTop + textView.getPaddingTop()
+ textView.getPaddingBottom() - textView.getBottom() + textView.getTop();
if (scrollAmount > 0) {
textView.scrollBy(0, scrollAmount);
} else {
textView.scrollTo(0, 0);
}
}
}
}, 1000L);
}
Vous pouvez jouer avec le retard pour améliorer votre expérience utilisateur.