如何在屏幕旋转后恢复TextView的滚动位置?

5
在我的Android布局中,我有一个TextView。这个TextView显示了一段相当大的可滚动的Spannable文本。现在,当手机旋转时,View被销毁并重新创建,我必须再次使用setText()设置TextView,将滚动位置重置为开头。
我知道我可以使用getScrolly()和scrollTo()来滚动到像素位置,但由于View宽度的改变,行变得更长,原来在400像素位置的行现在可能在250像素位置。所以这不是很有用。
我需要一种方法在onDestroy()中找到TextView中第一个可见的行,然后让TextView滚动到旋转后的这个特定的文本位置。
有什么想法吗?
3个回答

14

这是一个老问题,但当我搜索同样的问题时,我就会来到这里,所以这是我想出的解决方案。我结合了这三个问题的答案中的想法:

我尝试从我的应用程序中提取仅相关的代码,请原谅任何错误。还要注意,如果您旋转到横屏然后再旋转回来,可能不会停在您开始的位置。例如,假设"Peter"是纵向上可见的第一个单词,在旋转到横屏时,"Peter"是其行中的最后一个单词,而第一个单词是"Larry"。当您旋转回来时,"Larry"将可见。

private static float scrollSpot;

private ScrollView scrollView;
private TextView textView;

protected void onCreate(Bundle savedInstanceState) {
    textView = new TextView(this);
    textView.setText("Long text here...");
    scrollView = new ScrollView(this);
    scrollView.addView(textView);

    // You may want to wrap this in an if statement that prevents it from
    // running at certain times, such as the first time you launch the 
    // activity with a new intent.
    scrollView.post(new Runnable() {
        public void run() {
            setScrollSpot(scrollSpot);
        }
    });

    // more stuff here, including adding scrollView to your main layout
}

protected void onDestroy() {
    scrollSpot = getScrollSpot();
}

/**
 * @return an encoded float, where the integer portion is the offset of the
 *         first character of the first fully visible line, and the decimal
 *         portion is the percentage of a line that is visible above it.
 */
private float getScrollSpot() {
    int y = scrollView.getScrollY();
    Layout layout = textView.getLayout();
    int topPadding = -layout.getTopPadding();
    if (y <= topPadding) {
        return (float) (topPadding - y) / textView.getLineHeight();
    }

    int line = layout.getLineForVertical(y - 1) + 1;
    int offset = layout.getLineStart(line);
    int above = layout.getLineTop(line) - y;
    return offset + (float) above / textView.getLineHeight();
}

private void setScrollSpot(float spot) {
    int offset = (int) spot;
    int above = (int) ((spot - offset) * textView.getLineHeight());
    Layout layout = textView.getLayout();
    int line = layout.getLineForOffset(offset);
    int y = (line == 0 ? -layout.getTopPadding() : layout.getLineTop(line))
        - above;
    scrollView.scrollTo(0, y);
}

1

同样的问题。TextView 只保存像素位置,而不是文本位置。旋转后,我必须计算一个新的像素位置,以便与之前显示相同的文本。 - Josh

0

我通过搜索得到了最好的答案。

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
final ScrollView scrollView = (ScrollView) findViewById(R.id.Trial_C_ScrollViewContainer);
outState.putFloatArray(ScrollViewContainerScrollPercentage,
        new float[]{
        (float) scrollView.getScrollX()/scrollView.getChildAt(0).getWidth(),
        (float) scrollView.getScrollY()/scrollView.getChildAt(0).getHeight() });
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
final float[] scrollPercentage = savedInstanceState.getFloatArray(ScrollViewContainerScrollPercentage);
final ScrollView scrollView = (ScrollView) findViewById(R.id.Trial_C_ScrollViewContainer);
scrollView.post(new Runnable() {
    public void run() {
        scrollView.scrollTo(
                Math.round(scrollPercentage[0]*scrollView.getChildAt(0).getWidth()),
                Math.round(scrollPercentage[1]*scrollView.getChildAt(0).getHeight()));
    }
});

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接