Лучший способ: сохранить и восстановить позицию TextView в ScrollView

Я хочу, чтобы при изменении ориентации устройства верхняя строка на экране, когда в Portrait остается верхней строкой на экране в Landscape. И наоборот.

Поскольку ширина экрана может быть разной между Portrait и Landscape, ширина строки текста, а это означает также ширину TextView и ScrollView , будет отличаться. Таким образом, перенос строк будет различным в разных конфигурациях экрана (Portrait and Landscape, large vs. small). В разных случаях разрыв линии будет в другом положении.

Для вашей справки есть три не очень совершенных решения. Также объяснили их недостатки.


Во-первых, самый простой подход:

(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 (вверху экрана) в Portrait при сохранении. Когда он будет изменен на Landscape, он Line_3_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 (вверху экрана) в Portrait при сохранении. Когда он будет изменен на Landscape, он Line_3_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 (вверху экрана) в Portrait при сохранении. Когда он будет изменен на Landscape, он Line_3_Word_A (на верхней Line_3_Word_A экрана). (Потому что это третья строка.)

Идеально было бы в Пейзаже, показывая Line_1_Word_A (а также Line_1_Word_E ) на экране.


Не могли бы вы предложить идеальный подход?


Редактировать:

После нескольких мыслей, действительно ли метод (3) идентичен методу (1)? : – /


Изменить 2:

Ну, я только что придумал еще один не очень совершенный, но более совершенный подход, чем три:

(4) Сохранение на основе абзаца

Разделение абзацев (или блоков текстов) на разные объекты TextView.

Затем по кодам, подобным методу (3), или любым другим способом, нетрудно определить, какой абзац (или блок), т. Е. Какой объект TextView, в настоящее время находится в верхней части экрана.

Затем восстановите и прокрутите список до этого абзаца (или блока). Бинго!

Как я уже сказал, это не так прекрасно . Но по крайней мере пользователи могут вернуться к тому абзацу (или блоку), который он читал. Ему / ей просто нужно немного подглядеть, чтобы найти эту конкретную линию. (Или может быть даже лучше напомнить читателям несколько предыдущих строк, то есть прочитать с начала абзаца.) Я знаю, что это может быть ужасно плохо, если у нас длинный длинный абзац: – /

Ну, мы можем «улучшить» этот метод. Сделайте это до уровня слова, слово TextView. Поэтому он логически «совершенен». Но, я думаю, это не разумный выбор.

PS ванная всегда лучшее место для мозгового штурма (-:


Я все еще ищу твой идеальный ответ!

WOW WOW WOW – эй, ребята! Я так горжусь, что могу сказать, что у меня теперь есть СОВЕРШЕННОЕ решение * * * * *

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