最佳方式:保存&在ScrollView中恢复TextView位置

时间:2013-03-28 09:42:02

标签: android android-layout textview android-orientation android-scrollview

我想要的是,在设备更改方向时,屏幕中的顶行在纵向时仍然是横向屏幕的顶行。反之亦然。

由于纵向和横向之间的屏幕宽度可能不同,因此文本的线宽(也就是TextViewScrollView的宽度)会有所不同。因此,在不同的屏幕配置(纵向与横向,大与小)中,换行将有所不同。在不同的情况下,换行符将处于不同的位置。

有三种 不那么完美的 解决方案供您参考。还解释了它们的缺点。


首先,最基本的方法:

(1)仅将y偏移存储在像素

请查看:http://eliasbland.wordpress.com/2011/07/28/how-to-save-the-position-of-a-scrollview-when-the-orientation-changes-in-android/

为什么这不是那么完美:

在肖像中,线条被包裹。

Line_1_Word_A Line_1_Word_B Line_1_Word_C
Line_1_Word_D
Line_2_Word_A Line_2_Word_B Line_2_Word_C
Line_2_Word_D
Line_3_Word_A Line_3_Word_B Line_3_Word_C
Line_3_Word_D

在横向中,行包裹。

Line_1_Word_A Line_1_Word_B Line_1_Word_C Line_1_Word_D
Line_2_Word_A Line_2_Word_B Line_2_Word_C Line_2_Word_D
Line_3_Word_A Line_3_Word_B Line_3_Word_C Line_3_Word_D

想象一下,在保存时,在Portrait中阅读Line_2_Word_A(在屏幕顶部)。当更改为横向时,它将显示Line_3_Word_A(在屏幕顶部)。 (因为顶部有两行偏移的像素。)


然后我提出了一种方法,

(2)通过保存滚动百分比

@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()));
        }
    });
}

当且仅当每行的长度相同时,这才能完美地工作。

为什么这不是那么完美:

在肖像中,线条被包裹。

Line_1_Word_A Line_1_Word_B
Line_1_Word_C Line_1_Word_D
Line_1_Word_E Line_1_Word_F
Line_2_Word_A
Line_3_Word_A
Line_4_Word_A

在横向中,行包裹。

Line_1_Word_A Line_1_Word_B Line_1_Word_C Line_1_Word_D Line_1_Word_E Line_1_Word_F
Line_2_Word_A
Line_3_Word_A
Line_4_Word_A

想象一下,在保存时,在Portrait中阅读Line_2_Word_A(在屏幕顶部)。当更改为横向时,它将显示Line_3_Word_A(在屏幕顶部)。 (因为它滚动了50%。)


然后我发现这种方法确实

(3)存储第一条可见线

请看一下(第一个答案):How to restore textview scrolling position after screen rotation?

为什么这不是那么完美:

在肖像中,线条被包裹。

Line_1_Word_A Line_1_Word_B
Line_1_Word_C Line_1_Word_D
Line_1_Word_E Line_1_Word_F
Line_2_Word_A
Line_3_Word_A
Line_4_Word_A

在横向中,行包裹。

Line_1_Word_A Line_1_Word_B Line_1_Word_C Line_1_Word_D Line_1_Word_E Line_1_Word_F
Line_2_Word_A
Line_3_Word_A
Line_4_Word_A

想象一下,在保存时,在Portrait中阅读Line_1_Word_E(在屏幕顶部)。当更改为横向时,它将显示Line_3_Word_A(在屏幕顶部)。 (因为它是第三行。)

完美的一个是,在横向广告中,在屏幕顶部显示Line_1_Word_A(以及Line_1_Word_E)。


请你建议一个完美的方法吗?


编辑:

经过一番思考,方法(3)实际上与方法(1)相同吗? : - /


编辑2:

好吧,我刚刚提出了另一种 不那么完美但更完美的 方法,而不是上述三种方法:

(4)基于段落的存储

将段落(或文本块)分隔为不同的TextView对象。

然后通过类似方法(3)的代码或任何其他方式,不难发现哪个段落(或块),即哪个TextView对象当前位于屏幕顶部。

然后恢复并向下滚动到该段落(或块)。宾果!

正如我所说, 不那么完美 。但至少用户可以回到他/她正在阅读的段落(或块)。他/她只需要向下看一下就可以找到那条特定的线。 (或者甚至可能更好地提醒读者前几行,即从段落的开头读取。)我知道如果我们有一个很长的长段落可能会非常糟糕: - /

好吧,我们实际上可以“改进”这种方法。简化为单词级别,单词为TextView。所以它在逻辑上是“完美的”。但是,我想,这不是一个明智的选择。

P.S。浴室一直是头脑风暴的最佳场所( - :


仍在寻找你的完美答案!!

1 个答案:

答案 0 :(得分:14)

哇哇哇哇 - 嘿伙计们!我很自豪地说,我现在得到了一个完美的解决方案* * * * *

Sh ....(对不起,我太兴奋了。如果你发现任何错误/错误/弱点,请给我你宝贵的建议,请随时纠正我。: - )

切掉垃圾。你去吧!!!

@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    final ScrollView scrollView = (ScrollView) findViewById(R.id.Trial_C_ScrollViewContainer);
    final TextView textView = (TextView) scrollView.getChildAt(0);
    final int firstVisableLineOffset = textView.getLayout().getLineForVertical(scrollView.getScrollY());
    final int firstVisableCharacterOffset = textView.getLayout().getLineStart(firstVisableLineOffset);
    outState.putInt(ScrollViewContainerTextViewFirstVisibleCharacterOffset, firstVisableCharacterOffset);
}

@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    super.onRestoreInstanceState(savedInstanceState);
    final int firstVisableCharacterOffset = savedInstanceState.getInt(ScrollViewContainerTextViewFirstVisibleCharacterOffset);

    final ScrollView scrollView = (ScrollView) findViewById(R.id.Trial_C_ScrollViewContainer);
    scrollView.post(new Runnable() {
        public void run() {
            final TextView textView = (TextView) scrollView.getChildAt(0);
            final int firstVisableLineOffset = textView.getLayout().getLineForOffset(firstVisableCharacterOffset);
            final int pixelOffset = textView.getLayout().getLineTop(firstVisableLineOffset);
            scrollView.scrollTo(0, pixelOffset);
        }
    });
}

就是这样。 : - )

如果对您有所帮助,请拍手。 < - 这很重要!!

如果您愿意,请点击那个小直立三角形。 (确保你先拍了拍手!)

欢呼声,
midnite