タッチスクリーンを使用して画面をスクロールできるように、タッチイベントを実装したカスタムViewSwitcher
があります。
私のレイアウト階層は次のようになります。
<ViewSwitcher>
<LinearLayout>
<ListView />
</LinearLayout>
<LinearLayout>
<ListView />
</LinearLayout>
</ViewSwitcher>
現在、問題は、タッチイベントがListViews
によって消費されており、ビューを切り替えることができないことです。 ListViews
がなくても正常に動作します。ビューをスクロールして、ListView
をスクロールできるようにする必要があります。
これをどうやって解決しますか?
[〜#〜] edit [〜#〜]:ListView
アイテムもクリック可能にする必要があります。
前もって感謝します!
質問に答えてくれてありがとう。しかし、はるかに簡単な方法でそれを理解することができました。 ViewSwitcher
はタッチイベントを検出していなかったため、onTouchEvent()
と呼ばれるタッチイベントをインターセプトし、false
を返しました。ここに:
_@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
onTouchEvent(ev);
return false;
}
_
onInterceptTouchEvent()
をオーバーライドすることで、アクティビティのタッチイベントをインターセプトすることができました。次に、ViewSwitcher
の切り替えを処理するListViews
でonTouchEvent()
を呼び出しました。そして最後にfalse
を返すことにより、ViewGroup
がイベントを消費しないようにします。
子ビュータッチイベントを親ビューに渡す最も簡単な方法は、これを子ビューに追加することです。
@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
return false;
}
親レイアウトで、子がタッチイベントをキャプチャできないようにする唯一の方法は、onInterceptTouchEventをオーバーライドしてtrueを返すことです。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
return true;
}
これを行う簡単な方法はないと思います。
それほど複雑ではありませんが、ListViewを拡張する独自のビューを作成する必要があります。その後、onTouch
ハンドラーをオーバーライドし、(タッチイベントに応じて)処理する(およびtrueを返す)か、親ビューに渡すかを決定できます。
また、問題は、ビューがタッチイベントを処理すると、残りのすべてを取得することになるということです...
Androidドキュメント から:
onTouch()-これは、リスナーがこのイベントを消費するかどうかを示すブール値を返します。重要なことは、このイベントが互いに続く複数のアクションを持つことができるということです。したがって、ダウンアクションイベントを受信したときにfalseを返す場合、イベントを消費しておらず、このイベントからの後続のアクションにも関心がないことを示します。したがって、指ジェスチャや最終的なアップアクションイベントなど、イベント内の他のアクションに対して呼び出されることはありません。
したがって、たとえば、同じタッチイベント中に(指を離さずに)リストをスクロールするために垂直方向に移動したい場合、ビューを切り替えるために水平方向に移動する必要があります。これは非常に難しいことです。
しかし、たとえばジェスチャーを使用したり、カスタムビューですべてを処理したり、MotionEventが何であるかに応じて、ViewSwitcherにコマンドを送信したりすることができます。
touchevent
のdispatchTouchEvent
を処理する呼び出しを挿入することもできますが、この場合はonTouchEvent
をオーバーライドしてtrueを返す必要があります。そうでない場合は、最初のMotionEvent
ジェスチャのDOWNが渡されます。
これはタッチ可能なラッパーコンテナーです。
<?xml version="1.0" encoding="utf-8"?>
<view xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:id="@+id/pager"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
class="com.example.myapp.FragmentContainer$TouchableWrapper" />
そしてクラス:
public static class TouchableWrapper extends FrameLayout {
private GestureDetector gestureDetector;
public void setGestureDetector(GestureDetector gestureDetector) {
this.gestureDetector = gestureDetector;
}
// these constructors for the XML inflater
public TouchableWrapper(Context context) {
super(context);
}
public TouchableWrapper(Context context, AttributeSet attrs) {
super(context, attrs);
}
public TouchableWrapper(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
Log.d(TAG, "onInterceptTouchEvent " + event.toString());
return false; // true for intercept, false è default and pass on to children View
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
Log.d(TAG, "dispatchTouchEvent " + event.toString());
gestureDetector.onTouchEvent(event);
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
Log.d(TAG, "onTouchEvent " + event.toString());
return true; //return super.onTouchEvent(event);
}
}
これはGestureDetector
参照です:
private GestureDetector gestureDetector;
これはGestureListener
:
private GestureDetector.SimpleOnGestureListener sOGL = new GestureDetector.SimpleOnGestureListener() {
private static final int SWIPE_THRESHOLD = 100;
private static final int SWIPE_VELOCITY_THRESHOLD = 100;
@Override
public boolean onDown(MotionEvent e) {
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
boolean result = false;
try {
float diffY = e2.getY() - e1.getY();
float diffX = e2.getX() - e1.getX();
if (Math.abs(diffX) > Math.abs(diffY)) {
if (Math.abs(diffX) > SWIPE_THRESHOLD && Math.abs(velocityX) > SWIPE_VELOCITY_THRESHOLD) {
if (diffX > 0) {
goToRight(); // onSwipeRight();
} else {
goToLeft(); // onSwipeLeft();
}
}
result = true;
} else if (Math.abs(diffY) > SWIPE_THRESHOLD && Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD) {
if (diffY > 0) {
// onSwipeBottom();
} else {
// onSwipeTop();
}
}
result = true;
} catch (Exception exception) {
exception.printStackTrace();
}
return result; // return false indicate event not handled
}
};
これをタッチして、タッチ可能なコンテナフラグメントと含まれるフラグメントをロードします。
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "onCreateView()");
View view = inflater.inflate(R.layout.fragmentcontainer, container, false);
gestureDetector = new GestureDetector(view.getContext(), sOGL);
((FragmentContainer.TouchableWrapper) view).setGestureDetector(gestureDetector);
FragmentManager fm = this.getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.pager, frag).commit();
return view;
}
ビューでイベントを渡したい場合は、onTouchEventでfalseを返すようにしてください。それ以外の場合、プラットフォームはイベントを消費したと見なし、それ以上の処理は不要です。
私がやったことは、viewswitcherのリストビューにtoucheventlistenerを設定し、イベントを処理し、flingアクションを検出し、viewswitcherのmetchodを呼び出すことです。できます。
AutoLink = "three"で親ビューのTextViewのタッチを処理する必要がありました。
private LinearLayout mParentView;
private TextView mTextView;
private View.OnTouchListener mParentListener = new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
......
return false;
}
};
mParentView.setOnTouchListener(mParentListener);
mTextView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
mParentListener.onTouch(mParentView, event);
return false;
}
};
次のように、ListViewアイテムをクリック不可として設定しようとしましたか:listView.setClickable(false);これにより、クリックイベントが上方に伝播します。