15

我想要的是,当设备改变方向时,纵向时屏幕上的顶线仍然是横向屏幕上的顶线。反之亦然。

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

有三个不太完美的解决方案供您参考。也说明了它们的缺点。


首先,最基本的方法:

(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

想象一下在保存时以纵向阅读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

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


然后我发现这种方法确实

(3) 存储第一条可见行

请看一下(第一个答案):如何在屏幕旋转后恢复textview滚动位置?

为什么这不是那么完美:

在纵向中,线条被换行。

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

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

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


您能否提出一个完美的方法?


编辑:

想了想,方法(3)其实和方法(1)是一样的吗?:-/


编辑2:

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

(4) 基于段落的存储

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

然后通过方法(3)之类的代码,或者任何其他方式,不难检测出哪个段落(或块),即哪个TextView对象,当前在屏幕的顶部。

然后恢复并向下滚动到该段落(或块)。答对了!

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

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

PS浴室永远是头脑风暴的最佳场所(-:


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

4

1 回答 1

15

我很自豪地说,我现在有了一个完美的解决方案。

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

废话少说。干得好 !!!

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

就是这样。:-)

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

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

于 2013-03-28T16:03:21.737 回答