0

さまざまな数のアイテムを持つ ListView があります。スクロールすることも、1 つの画面に収まるようにすることもできます。ユーザーがリストをタップしてドラッグし、オーバースクロールすると、素敵なオーバースクロール エッジ グロー効果が得られます。

要素が少ないためにリストがスクロールしない場合でも、項目の 1 つをタップしてドラッグすると、エッジ グロー効果が得られます。これはいいですし、私が欲しいものです。

問題は、最後の項目の下をクリックしてドラッグしても何も起こらないことです。その場合も「スクロールしてみる」ようにしたい。視覚的なフィードバックがなく、リストが固定されているように見えると混乱します。

+--------------------------+
| Item 1           (x)     |     Tap and drag here works.  The list
+--------------------------+     doesn't move, but the user gets a
| Item 2                   |     visual overscroll indicator on the
+--------------------------+     top or the bottom.
| Item 3                   |
+--------------------------+
|                          |
|                  (x)     |     Tap and drag here does nothing.
|                          |
|                          |
|                          |
|                          |
|                          |
+--------------------------+

ListView 全体をスクロール試行に反応させるにはどうすればよいですか?

アイテムに必要なスペースだけでなく、使用可能なすべてのスペースをカバーするようにしました (念のためandroid:layout_height="fill_parent"、別の BG カラーを設定して試しました)。スクロールを開始するコードはどこにありますか? 独自の ListView サブクラスを既に使用しているため、何かをオーバーライドする必要がある場合は問題ありません。

4

1 に答える 1

0

それを見つけた。ListView サブクラスの以下は、そのトリックを行います。Android 4.2.1 でテストしましたが、どの 4.x でも動作するはずです。

免責事項: このコードは、ListView の実装の詳細に依存し、リフレクションを使用してプライベート変数を変更します。これがどれほど悪いことか、私は誇張することはできません。これを本番コードで使用しないでください。

これは、概念の証明として、また好奇心を満たすために作成しました。このようなコードを使用したい場合 (残念ながら、特定の効果を得るために必要な場合があります)、以下で行うようにバージョン ガードを配置します。試してソースコードを確認したバージョンでのみ実行してください。それ以外の場合は、デフォルトの動作を呼び出すだけで使用する必要がありますreturn super.onTouchEvent(ev)

このコードを使用すると、最後の項目の下の空の部分で短いリストをスクロールできます (失敗します)。空白部分をクリックしてドラッグすると、オーバースクロールのグローが表示されます。これは、iPhone のようなオーバースクロール ラバーバンド効果を実装している場合に特に便利です。

それはどのように機能しますか?AbsListView.OnTouchEventを見てください。行 3397 で、motionPosition は現在選択されている項目のインデックスです。-1 (項目なし) の場合if、数行後が false であり、mTouchMode設定されません。その場合、ListView を手動でスクロール モードにします。

static final int TOUCH_MODE_DOWN = 0;
static final int TOUCH_MODE_SCROLL = 3;
static final int TOUCH_MODE_FLING = 4;

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN ||
        Build.VERSION.SDK_INT == Build.VERSION_CODES.JELLY_BEAN_MR1) {
        final int x = (int) ev.getX();
        final int y = (int) ev.getY();
        int motionPosition = pointToPosition(x, y);
        int action = (ev.getAction() & MotionEvent.ACTION_MASK);

        if (action == MotionEvent.ACTION_DOWN) {
            if (motionPosition == -1) {
                setFieldInt("mActivePointerId", ev.getPointerId(0));
                if (!getAdapterViewFieldBool("mDataChanged")) {
                    if ((getFieldInt("mTouchMode") != TOUCH_MODE_FLING)) {
                        setFieldInt("mTouchMode", TOUCH_MODE_DOWN);
                    }
                }

                setFieldInt("mMotionViewOriginalTop", 0);
                setFieldInt("mMotionX", x);
                setFieldInt("mMotionY", y);
                setFieldInt("mMotionPosition", motionPosition);
                setFieldInt("mLastY", Integer.MIN_VALUE);
            }
        }
    }
    return super.onTouchEvent(ev);
}

private void setFieldInt(String fieldName, int value) {
    try {
        Field field = AbsListView.class.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.setInt(this, value);
    }
    catch (NoSuchFieldException e) { Log.v(TAG, "exception", e); }
    catch (IllegalAccessException e) { Log.v(TAG, "exception", e); }
}

private int getFieldInt(String fieldName) {
    try {
        Field field = AbsListView.class.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.getInt(this);
    }
    catch (NoSuchFieldException e) { Log.v(TAG, "exception", e); }
    catch (IllegalAccessException e) { Log.v(TAG, "exception", e); }
    return 0;
}


private boolean getAdapterViewFieldBool(String fieldName) {
    try {
        Field field = AdapterView.class.getDeclaredField(fieldName);
        field.setAccessible(true);
        return field.getBoolean(this);
    }
    catch (NoSuchFieldException e) { Log.v(TAG, "exception", e); }
    catch (IllegalAccessException e) { Log.v(TAG, "exception", e); }
    return false;
}
于 2013-02-12T22:06:33.510 に答える