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

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

由于纵向和横向之间的屏幕宽度可能不同,因此文本的线宽(也就是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)存储第一条可见线

请看一下(第一个答案): 如何在屏幕旋转后恢复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 

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

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


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


编辑:

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


编辑2:

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

(4)基于段落的存储

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

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

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

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

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

PS浴室始终是头脑风暴的最佳场所( – :


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

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

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

切废话。 干得好 !!!

 @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