J'ai une TextView
à laquelle j'ajoute du texte de manière dynamique.
dans mon fichier main.xml
, j'ai les propriétés définies pour rendre mes lignes et barres de défilement maximales 19 verticales.
dans le fichier .Java
, j'utilise textview.setMovementMethod(new ScrollingMovementMethod());
pour permettre le défilement.
Le défilement fonctionne très bien. Dès que 19 lignes sont occupées et que d'autres lignes sont ajoutées, le défilement commence comme il se doit. Le problème est que je veux que le nouveau texte défile dans l'affichage.
J'écris la valeur pour textview.getScrollY()
et il reste à 0
quoi qu'il en soit (même si je le déplace manuellement vers le bas et ajoute une nouvelle ligne de texte).
par conséquent textview.scrollTo(0, textview.getScrollY());
ne fait rien pour moi.
Existe-t-il une autre méthode que je devrais utiliser pour obtenir le montant de défilement vertical pour la variable textview
? Tout ce que j'ai lu dit que, à toutes fins utiles, ce que je fais devrait fonctionner: /
Il m'a fallu fouiller dans la source TextView, mais voici ce que j'ai proposé. Cela ne vous oblige pas à envelopper le TextView dans un ScrollView et, autant que je sache, 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 de pouvoir corriger les bugs dans mon application;)
Edit: je devrais mentionner que j'utilise aussi
mTextView.setMovementMethod(new ScrollingMovementMethod());
après avoir instancié mon TextView.
Utilisez Android:gravity="bottom"
sur le TextView dans votre mise en page XML. Par exemple.
<TextView
...
Android:gravity="bottom"
...
/>
Ne me demandez pas pourquoi ça marche.
Le seul problème avec cette méthode est que si vous voulez faire défiler la vue texte vers le haut, elle continue à être "abaissée" vers le bas à chaque nouvelle insertion de texte.
c’est ce que j’utilise pour défiler jusqu’au bas du texte de mon 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 la mise en page XML
<?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 fonctionnaient pas correctement pour moi, cela fonctionne cependant.
Créez un TextView et procédez comme suit:
// ...
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 t'aides.
TextView possède déjà le défilement automatique si vous définissez le texte à l'aide de chaînes Spannable ou Editable avec la position du curseur définie.
Tout d'abord, définissez la méthode de défilement:
mTextView.setMovementMethod(new ScrollingMovementMethod());
Ensuite, 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);
SetSelection () déplace le curseur sur cet index. Lorsqu'un TextView est défini sur SPANNABLE, il défilera automatiquement pour rendre le curseur visible. Notez que cela ne dessine pas le curseur, il fait simplement défiler l'emplacement du curseur pour qu'il soit dans la section visible du TextView.
De plus, puisque TextView.append () met à niveau le texte en TextView.BufferType.EDITABLE et Editable implémente Spannable, vous pouvez le faire:
mTextView.append(string);
Editable editable = mTextView.getEditableText();
Selection.setSelection(editable, editable.length());
Voici une implémentation complète du widget. Appelez simplement setText () ou append () sur ce widget. Il diffère légèrement de ce qui est décrit ci-dessus, car il s’agit de EditText, qui force 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 utilisez ceci dans 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"/>
(2017) utilisant 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 fonctionne pour moi
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>
// 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>
Une mise en oeuvre simple ... dans votre mise en page XML, définissez votre TextView avec ces attributs:
<TextView
...
Android:gravity="bottom"
Android:scrollbars="vertical"
/>
https://stackoverflow.com/a/7350267/4411645 n'a pas fonctionné exactement pour moi
Inutile de dire que c'est un bon point de départ. Voici ma variante de l'implémentation, dans un textwatcher. Nous devons soustraire le top textView du bas lors du calcul du delta car getLineTop () renvoie également la valeur relative au top textView.
@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 délai pour améliorer votre ux.
pour éviter de créer factice scrollview je l'ai fait
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);
}
});