わかりました。私が実現しようとしているのは、Excel の固定ペインと同じ効果を実現するレイアウトです。つまり、メインの ListView とともに水平にスクロールするヘッダー行と、メインの ListView とともに垂直にスクロールする左側の ListView が必要です。ヘッダー行と左側のリストビューは、他の次元でスクロールするときには静止したままである必要があります。
XML レイアウトは次のとおりです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/recordViewLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<LinearLayout android:layout_width="160dp"
android:layout_height="match_parent"
android:orientation="vertical">
<CheckBox
android:id="@+id/checkBoxTop"
android:text="Check All"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ListView android:id="@+id/engNameList"
android:layout_width="160dp"
android:layout_height="wrap_content"/>
</LinearLayout>
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout android:id="@+id/scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/record_view_line" android:id="@+id/titleLine" />
<ListView
android:id="@android:id/list"
android:layout_height="wrap_content"
android:layout_width="match_parent"/>
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
次に、ListActivityでこのコードを使用します
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
View v = recordsListView.getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
((ListView)findViewById(R.id.engNameList)).setSelectionFromTop(firstVisibleItem, top);
}
これにより、ユーザーが右側の ListView をスクロールすると、左側の ListView もスクロールするはずです。残念ながら、そうはなりません。
グーグルで少し調べてみたところ、setSelectionFromTop() 関数は、複数のレイアウト内にネストされた ListView では機能しないようです。
このような場合、一緒にスクロールする方法、レイアウトを設定する別の方法、またはまったく別のテクニックを提案できる人はいますか。
ベストアンサー1
リライト
ある ListView のスクロール アクションを別の ListView に渡すことはあまりうまくいきませんでした。そこで、 を渡すという別の方法を選択しました。これにより、それぞれが独自のスムーズ スクロール、高速スクロール、その他の計算を実行できるMotionEvent
ようになります。ListView
初め、いくつかのクラス変数が必要になります:
ListView listView;
ListView listView2;
View clickSource;
View touchSource;
int offset = 0;
に追加するすべてのメソッドはlistView
とほぼ同じになりますがlistView2
、唯一の違いは が(それ自体ではなく)listView2
を参照することですlistView
。繰り返しコードは含めませんでしたlistView2
。
2番、OnTouchListenerから始めましょう:
listView = (ListView) findViewById(R.id.engNameList);
listView.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if(touchSource == null)
touchSource = v;
if(v == touchSource) {
listView2.dispatchTouchEvent(event);
if(event.getAction() == MotionEvent.ACTION_UP) {
clickSource = v;
touchSource = null;
}
}
return false;
}
});
循環ロジックを防ぐために、listView
を呼び出しlistView2
、呼び出し、呼び出し...をいつ渡すかを決定するためにlistView
クラス変数を使用しました。行のクリックが 内でもクリックされることは望ましくないと思われるため、これを防ぐために別のクラス変数を使用しました。touchSource
MotionEvent
listView
listView2
clickSource
三番目、OnItemClickListener:
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(parent == clickSource) {
// Do something with the ListView was clicked
}
}
});
第4、すべてのタッチ イベントを渡すのは、不一致が時々発生するため完璧ではありません。OnScrollListener は、これらの不一致を排除するのに最適です。
listView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(view == clickSource)
listView2.setSelectionFromTop(firstVisibleItem, view.getChildAt(0).getTop() + offset);
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
});
(オプション)最後に、レイアウトの異なる高さから始まるlistView
ので問題が発生するとおっしゃっていましたが...listView2
非常にListView のバランスをとるためにレイアウトを変更することを推奨しますが、私はこれに対処する方法を見つけました。ただし、少しトリッキーです。
レイアウト全体がレンダリングされるまで、2 つのレイアウト間の高さの差を計算することはできませんが、この時点ではコールバックはありません... そのため、単純なハンドラーを使用します。
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Set listView's x, y coordinates in loc[0], loc[1]
int[] loc = new int[2];
listView.getLocationInWindow(loc);
// Save listView's y and get listView2's coordinates
int firstY = loc[1];
listView2.getLocationInWindow(loc);
offset = firstY - loc[1];
//Log.v("Example", "offset: " + offset + " = " + firstY + " + " + loc[1]);
}
};
私仮定するレイアウトをレンダリングしてタイマーを開始するには、0.5 秒の遅延で十分ですonResume()
。
handler.sendEmptyMessageDelayed(0, 500);
オフセットを使用する場合、listView2
OnScroll メソッドはオフセットを追加するのではなく、減算することを明確にしておきます。
listView2.setSelectionFromTop(firstVisibleItem, view.getChildAt(0).getTop() - offset);
お役に立てれば幸いです!