15

私が望むのは、デバイスの向きが変わると、縦向きのときの画面の一番上の行が横向きの画面の一番上の行のままになることです。およびその逆。

縦と横では画面の幅が異なる可能性が高いため、文字の線幅、つまり と の幅もTextView異なりScrollViewます。したがって、ライン ラップは、異なる画面構成 (ポートレートとランドスケープ、大と小) で異なります。改行は、場合によって異なる位置にあります。

参考までに、完璧ではない解決策が 3 つあります。また、それらの欠点についても説明しました。


まず、最も基本的なアプローチ:

(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(画面上部に)表示されます。(上から 2 ライン オフセット イン ピクセルのため。)


それから私はアプローチを思いつきます、

(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(画面上部に)表示されます。(3行目なので。)

完璧なものは、Landscape でLine_1_Word_A(および をLine_1_Word_E) 画面上部に表示することです。


完璧なアプローチを提案していただけますか?


編集:

いくつか考えてみた結果、(3) の方法は (1) の方法と本当に同じでしょうか? :-/


編集2:

さて、私は上記の 3 つよりも完璧ではないが、より完璧な別のアプローチを思いついたところです。

(4) 段落ごとの格納

段落 (またはテキストのブロック) を異なる TextView オブジェクトに分割します。

次に、方法 (3) のようなコード、またはその他の方法で、どの段落 (またはブロック)、つまりどの TextView オブジェクトが現在画面の上部にあるかを検出することは難しくありません。

次に、その段落 (またはブロック) まで復元して下にスクロールします。ビンゴ!

私が言ったように、それはそれほど完璧ではありません。しかし、少なくともユーザーは、読んでいた段落 (またはブロック) に戻ることができます。彼/彼女はその特定の行を見つけるために少し下をのぞく必要があります. (または、読者に前の行をいくつか思い出させる、つまり、段落の最初から読む方が良いかもしれません。)長い長い長い段落があると、ひどく悪いかもしれないことはわかっています :-/

実は、この方法を「改善」することができます。単語レベル、単語を TextView にします。したがって、論理的には「完全」です。しかし、それは賢明な選択ではないと思います。

PS バスルームは常にブレインストーミングに最適な場所です (-:


私はまだあなたの完璧な答えを探しています!!

4

1 に答える 1

15

私は今、これに対する完璧な解決策を得たことを誇りに思っています。

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

それでおしまい。:-)

役に立ったら、手を叩いてください。<--ここ重要!!

必要に応じて、その小さな直角三角形をクリックします。(最初に手を叩いてください!)

于 2013-03-28T16:03:21.737 に答える