我有TextView
我正在动态添加文字。
在我的main.xml
文件中,我将属性设置为使我的最大线19和滚动条垂直。
在.java
文件中我使用textview.setMovementMethod(new ScrollingMovementMethod());
来允许滚动。
滚动效果很好。一旦占用了19行,并且添加了更多行,它就会开始滚动。问题是,我希望新文本滚动到视图中。
我正在写出textview.getScrollY()
的值,无论如何都会保持0
(即使我手动向下滚动并添加新的文本行)。
因此textview.scrollTo(0, textview.getScrollY());
对我没有任何作用。
我应该使用另一种方法来获取textview
的垂直滚动量吗?我读过的所有内容都表明,无论出于什么意图和目的,我正在做的工作应该是:/
答案 0 :(得分:70)
通过TextView源进行了一些挖掘,但这是我想出的。它不需要你将TextView包装在ScrollView中,据我所知,它可以很好地工作。
// 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);
}
如果您发现失败的情况,请告诉我。我很高兴能够修复我的应用程序中的任何错误;)
编辑:我应该提一下,我也使用
mTextView.setMovementMethod(new ScrollingMovementMethod());
实例化我的TextView。
答案 1 :(得分:52)
在XML布局中的TextView上使用android:gravity="bottom"
。 E.g。
<TextView
...
android:gravity="bottom"
...
/>
不要问我为什么会这样。
此方法的唯一问题是,如果您想要向后滚动文本视图,每次插入新文本时它都会再次“拉下”到底部。
答案 2 :(得分:28)
这是我用来一直滚动到聊天文字底部的内容......
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);
}
});
}
编辑:这是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>
答案 3 :(得分:21)
以前的答案对我来说无法正常工作,但这有效。
创建TextView并执行以下操作:
// ...
mTextView = (TextView)findViewById(R.id.your_text_view);
mTextView.setMovementMethod(new ScrollingMovementMethod());
// ...
使用以下函数将文本附加到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);
}
}
}
希望这有帮助。
答案 4 :(得分:7)
如果使用设置了光标位置的Spannable或Editable字符串设置文本,TextView已经自动滚动。
首先,设置滚动方法:
mTextView.setMovementMethod(new ScrollingMovementMethod());
然后使用以下内容设置文本:
SpannableString spannable = new SpannableString(string);
Selection.setSelection(spannable, spannable.length());
mTextView.setText(spannable, TextView.BufferType.SPANNABLE);
setSelection()将光标移动到该索引。当TextView设置为SPANNABLE时,它将自动滚动以使光标可见。请注意,这不会绘制光标,只是将光标的位置滚动到TextView的可查看部分。
此外,由于TextView.append()将文本升级为TextView.BufferType.EDITABLE而Editable实现了Spannable,因此您可以这样做:
mTextView.append(string);
Editable editable = mTextView.getEditableText();
Selection.setSelection(editable, editable.length());
这是一个完整的小部件实现。只需在此小部件上调用setText()或append()即可。它与上面略有不同,因为它从EditText扩展,它已强制其内部文本可编辑。
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);
}
}
}
答案 5 :(得分:4)
scrollview=(ScrollView)findViewById(R.id.scrollview1);
tb2.setTextSize(30);
tb2=(TextView)findViewById(R.id.textView2);
scrollview.fullScroll(View.FOCUS_DOWN);
或者在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"/>
答案 6 :(得分:2)
我用了一个小技巧......就我而言......
<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>
答案 7 :(得分:2)
(2017)使用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)
}
这适合我的文件
答案 8 :(得分:1)
// 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>
答案 9 :(得分:1)
简单实现...在XML布局中使用以下属性定义TextView:
<TextView
...
android:gravity="bottom"
android:scrollbars="vertical"
/>
答案 10 :(得分:0)
为了避免创建虚拟滚动视图我做了
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);
}
});
答案 11 :(得分:0)
https://stackoverflow.com/a/7350267/4411645并不适合我
毋庸置疑,这是一个很好的起点。这是我在textwatcher中实现的变体。在计算delta时,我们必须从底部减去textView top,因为getLineTop()也返回相对于textView top的值。
@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);
}
你可以通过延迟来改善你的ux。
答案 12 :(得分:0)
基于KNfLrPn的答案,并纠正了该答案的一些问题,有一种解决方案在2019年的 Android Studio 3.4.2 中仍然有效,并且我已经在我正在开发的应用中进行了测试。
private void addMessage(String msg) {
mTextView.append(msg + "\n");
final int scrollAmount =
max(mTextView.getLayout().getLineBottom(
mTextView.getLineCount()-1) - mTextView.getHeight(),0);
mTextView.post(new Runnable() {
public void run() {
mTextView.scrollTo(0, mScrollAmount +
mTextView.getLineHeight()/3);
}});
mTextView.scrollTo(0, scrollAmount);
}
存在一些问题,其中一些在注释和其他答案中指出:
a)行mTextView.getLayout().getLineTop(mTextView.getLineCount())
给出了绑定错误。与mTextView.getLayout().getLineTop(L)
等效的是mTextView.getLayout().getLineBottom(L-1)
。所以我用一行代替了
mTextView.getLayout().getLineBottom(
mTextView.getLineCount()-1) - mTextView.getHeight()
b) max
只是为了简化逻辑
c) scrollTo
应该以一种线程形式出现在post
方法内。
d)普通香草最后一行的底部显然不能完全解决问题,因为存在一个错误,即TextView
的最后一行应完全出现在视图中,但出现了剪切关。因此,我向滚动添加了行高的1/3。可以校准,但是对我来说效果很好。
-/-
有时需要说出显而易见的内容:x
和y
的值对应于scrollTo
例程,该值与左侧不可见的文本中的像素数完全匹配(x
)和顶部不可见的文本像素数(y
)。这恰好对应于小部件scrollX
和scrollY
属性的值。
因此,当一个人从文本的最后一行取y
时,并且如果该值大于窗口小部件的高度,则它必须与需要调整的文本的像素数完全对应。隐藏,作为scrollTo
方法的参数输入。
我添加的线条高度的三分之一,将滚动条稍高一点,使最后一行完全可见,这恰恰是由于实际操作与理论所倡导的不完全一致。