web-dev-qa-db-ja.com

親ビューにタッチイベントを渡す

タッチスクリーンを使用して画面をスクロールできるように、タッチイベントを実装したカスタムViewSwitcherがあります。

私のレイアウト階層は次のようになります。

<ViewSwitcher>

    <LinearLayout>
        <ListView />
    </LinearLayout>

    <LinearLayout>
        <ListView />
    </LinearLayout>

</ViewSwitcher>

現在、問題は、タッチイベントがListViewsによって消費されており、ビューを切り替えることができないことです。 ListViewsがなくても正常に動作します。ビューをスクロールして、ListViewをスクロールできるようにする必要があります。

これをどうやって解決しますか?

[〜#〜] edit [〜#〜]ListViewアイテムもクリック可能にする必要があります。

前もって感謝します!

35
Srichand Yella

質問に答えてくれてありがとう。しかし、はるかに簡単な方法でそれを理解することができました。 ViewSwitcherはタッチイベントを検出していなかったため、onTouchEvent()と呼ばれるタッチイベントをインターセプトし、falseを返しました。ここに:

_@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
    onTouchEvent(ev);
    return false;
}
_

onInterceptTouchEvent()をオーバーライドすることで、アクティビティのタッチイベントをインターセプトすることができました。次に、ViewSwitcherの切り替えを処理するListViewsonTouchEvent()を呼び出しました。そして最後にfalseを返すことにより、ViewGroupがイベントを消費しないようにします。

79
Srichand Yella

子ビュータッチイベントを親ビューに渡す最も簡単な方法は、これを子ビューに追加することです。

@Override
public boolean onTouchEvent(MotionEvent event) { 
    super.onTouchEvent(event);
    return false;
}
10
macio.Jun

親レイアウトで、子がタッチイベントをキャプチャできないようにする唯一の方法は、onInterceptTouchEventをオーバーライドしてtrueを返すことです。

@Override
public boolean onInterceptTouchEvent(MotionEvent ev)
{
    return true;
}
2
luca992

これを行う簡単な方法はないと思います。

それほど複雑ではありませんが、ListViewを拡張する独自のビューを作成する必要があります。その後、onTouchハンドラーをオーバーライドし、(タッチイベントに応じて)処理する(およびtrueを返す)か、親ビューに渡すかを決定できます。

また、問題は、ビューがタッチイベントを処理すると、残りのすべてを取得することになるということです...

Androidドキュメント から:

onTouch()-これは、リスナーがこのイベントを消費するかどうかを示すブール値を返します。重要なことは、このイベントが互いに続く複数のアクションを持つことができるということです。したがって、ダウンアクションイベントを受信したときにfalseを返す場合、イベントを消費しておらず、このイベントからの後続のアクションにも関心がないことを示します。したがって、指ジェスチャや最終的なアップアクションイベントなど、イベント内の他のアクションに対して呼び出されることはありません。

したがって、たとえば、同じタッチイベント中に(指を離さずに)リストをスクロールするために垂直方向に移動したい場合、ビューを切り替えるために水平方向に移動する必要があります。これは非常に難しいことです。

しかし、たとえばジェスチャーを使用したり、カスタムビューですべてを処理したり、MotionEventが何であるかに応じて、ViewSwitcherにコマンドを送信したりすることができます。

1
Matthieu

toucheventdispatchTouchEventを処理する呼び出しを挿入することもできますが、この場合は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;
}
0
Zanna

ビューでイベントを渡したい場合は、onTouchEventでfalseを返すようにしてください。それ以外の場合、プラットフォームはイベントを消費したと見なし、それ以上の処理は不要です。

0
Steve Prentice

私がやったことは、viewswitcherのリストビューにtoucheventlistenerを設定し、イベントを処理し、flingアクションを検出し、viewswitcherのmetchodを呼び出すことです。できます。

0
Zephyr Yang

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);これにより、クリックイベントが上方に伝播します。

0
SBerg413