最好的方法:保存并保存恢复 ScrollView 中的 TextView 位置 [英] Best Way: Save & Restore TextView Position in ScrollView

查看:24
本文介绍了最好的方法:保存并保存恢复 ScrollView 中的 TextView 位置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What i want is, upon the device changes orientation, the top line on the screen when in Portrait remains the top line on screen in Landscape. And vice versa.

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

As the width of the screen is likely to be different between Portrait and Landscape, the line width of the text, which means also the width of the TextView and the ScrollView, will vary. Thus, the line-wrap will be different in different screen configurations (Portrait vs. Landscape, large vs. small). The line-break will be at different position in different cases.

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

There are three not-so-perfect solutions for your reference. Also explained the shortcomings of them.

首先,最基本的方法:

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

为什么这不是那么完美:

在纵向中,线条被换行.

In Portrait, lines are wrapped.

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

在横向中,线条被包裹.

In Landscape, lines are not wrapped.

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(在屏幕顶部).(因为从顶部有两行像素偏移.)

Imagine reading Line_2_Word_A (at screen top) in Portrait while saving. When changed to Landscape, it will be showing Line_3_Word_A (at screen top). (Because of two-lines-offset-in-pixel from top.)

然后我想出一个方法,

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

这完美地工作当且仅当每行的长度相同.

This works perfectly if and only if the length of every line is the same.

为什么这不是那么完美:

在纵向中,线条被换行.

In Portrait, lines are wrapped.

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

在横向中,线条被包裹.

In Landscape, lines are not wrapped.

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%.)

Imagine reading Line_2_Word_A (at screen top) in Portrait while saving. When changed to Landscape, it will be showing Line_3_Word_A (at screen top). (Because it is scrolled by 50%.)

然后我发现这种方法确实

Then i found this approach which indeed

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

Please take a look at (first answer): How to restore textview scrolling position after screen rotation?

为什么这不是那么完美:

在纵向中,线条被换行.

In Portrait, lines are wrapped.

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

在横向中,线条被包裹.

In Landscape, lines are not wrapped.

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(在屏幕顶部).(因为是第三行.)

Imagine reading Line_1_Word_E (at screen top) in Portrait while saving. When changed to Landscape, it will be showing Line_3_Word_A (at screen top). (Because it is the third line.)

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

A perfect one would be, in Landscape, showing Line_1_Word_A (as well as Line_1_Word_E) at screen top.

您能推荐一个完美的方法吗?

Could you please suggest a perfect approach?

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

After a few thoughts, is method (3) identical to method (1) in fact? :-/

好吧,我刚刚想出了另一个不是那么完美但更完美的方法:

Well, i have just come up with another not-so-perfect-yet-more-perfect approach than the above three:

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

Separating paragraphs (or blocks of texts) into different TextView objects.

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

Then by the codes like method (3), or in any other ways, it is not hard to detect which paragraph (or block), i.e. which TextView object, is currently at the top of the screen.

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

Then restore and scroll down to that paragraph (or block). Bingo!

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

As i said, it is not-so-perfect. But at least the users can get back to that paragraph (or block) that he/she was reading. He/She just have to peek down a bit to find that particular line. (Or it might be even better to remind readers with a few previous lines, i.e. reading from the start of the paragraph.) i know it might be terribly bad if we have a long long long paragraph :-/

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

Well, we can actually "improve" this method. Make it down to word-level, a word a TextView. So it is logically "perfect". But, i guess, it is not a wise choice.

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

推荐答案

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

I am so proud to say, I got a perfect solution to this now.

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

Sh.... (sorry I am too excited about it. If you find any mistakes/bugs/weakness on it, please DO give me your valuable suggestions and please feel free to correct me. :-)

别废话了.给你!!!

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

就是这样.:-)

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

If it helps you, please clap your hands. <-- this is important!!

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

And if you wish to, click that little upright triangle. (make sure you have clapped your hands first!)

这篇关于最好的方法:保存并保存恢复 ScrollView 中的 TextView 位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆