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

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

поскольку ширина экрана, вероятно, будет отличаться между портретом и пейзажем, ширина строки текста, что означает также ширину TextView и ScrollView, будет меняться. Таким образом, линейная обертка будет отличаться в разных конфигурациях экрана (портрет против пейзажа, большой против малого). Этот line-break будет находиться в разных местах в разных случаях.

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


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

(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 (at экран сверху). (из-за две-линии-смещение-в-пиксель сверху.)


тогда я придумываю подход,

(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) в верхней части экрана.


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


Edit:

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


Edit 2:

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

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

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

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

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

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

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

П. С. ванная комната-это всегда самое лучшее место для "мозговой атаки" ( -:


я еще ищу ваш идеальный ответ!!

1 ответов


ВАУ ВАУ ВАУ-Эй, ребята! я так горжусь тем, что у меня есть идеальное решение для этого сейчас * * * * *

ВГ.... (простите, я слишком взволнован. Если вы найдете какие-либо ошибки/ошибки/слабость на нем, пожалуйста, дайте мне ваши ценные предложения и, пожалуйста, не стесняйтесь исправить меня. :-)

завязывай. Вот, держи !!!

@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