最好的方法。保存& 恢复滚动视图中的TextView位置

问题描述 投票:15回答:1

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

由于屏幕的宽度在纵向和横向之间很可能是不同的,所以文字的行宽,也就是说文字的宽度也是不同的。TextViewScrollView因此,在不同的屏幕配置(纵向与横向,大与小)下,线条的缠绕会有所不同。因此,在不同的屏幕配置(纵向与横向,大屏幕与小屏幕)中,线条的包覆将是不同的。在不同的情况下,断线的位置也会不同。

有三种 不太完美 的解决方案,供大家参考。同时也解释了其中的不足之处。


首先,最基本的方法。

(1)只需将y-offset存储在像素上

请看一下。http:/eliasbland.wordpress.com20110728如何保存滚动视图的位置--当方向改变时--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) 储存第一条可见线

请看一下(第一个答案)。屏幕旋转后如何恢复文本视图滚动位置?

为什么这个不是很完美。

在 "纵向 "中,线条是被包裹的。

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 (在屏幕上方)。因为它是第三行)。

一个完美的是,在Landscape中,显示了 Line_1_Word_A (以及 Line_1_Word_E)在屏幕顶部。


请你提出一个完美的方法?


编辑。

几经思索,方法(3)与方法(1)其实是否相同?


编辑2.请问你的方法(3)是否和方法(1)一样?

好吧,我刚刚想到了另一个 不太完美,但更完美 比以上三种方法。

(4) 基于段落的存储

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

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

然后还原并向下滚动到该段(或块)。Bingo!

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

嗯,其实我们可以 "改进 "这个方法。把它变成字级,一个字一个TextView。这样在逻辑上就 "完美 "了。但是,我想,这不是一个明智的选择。

P.S. 卫生间永远是头脑风暴的最佳场所(-。


我是... 寻找您的完美答案!

android android-layout textview android-orientation android-scrollview
1个回答
13
投票

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

Sh.... (对不起,我太激动了。如果你发现它的任何错误bugsweakness,请DO给我你的宝贵建议,请随时纠正我。:-)

废话少说。给你!!!。

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

就这样吧 :-)

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

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

© www.soinside.com 2019 - 2024. All rights reserved.