6

カスタム ビューを動的にレイアウト (つまり、FrameLayout) に追加していtouch eventsます。CustomViewコーナーでポイントをプルするための touchListeners を持つカスタム ビュー (下の画像に示されています)。それに加えて、画面上のビュー全体をドラッグ アンド ドロップする必要があります。ユーザーがそれらのコーナー ポイント (画像の色の領域) 以外に触れた場合は、ビューをドラッグ アンド ドロップする必要があります。ビュー私はタッチリスナーをトリガーしたくありません。

この画像をチェック

このコードを使用して、これらのポイントを引き出すことができます

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN:

        if (topTouchArea.contains(event.getX(), event.getY())) {                
            currentTouch = TOUCH_TOP;
        } else if (RightTouchArea.contains(event.getX(),event.getY())) {                
            currentTouch = TOUCH_RIGHT;
        } else if (LeftTouchArea.contains(event.getX(),event.getY())) {            
            currentTouch = TOUCH_LEFT;
        } else {
            return false; //Return false if user touches none of the corners
        }
        return true; 
    case MotionEvent.ACTION_MOVE:

        switch (currentTouch) {
        case TOUCH_TOP:              
             top.x = event.getX();
             top.y = event.getY();                            
             invalidate();
             return true;
        case TOUCH_RIGHT:                
             Right.x = event.getX();
             Right.y = event.getY();                
             invalidate();
             return true;
        case TOUCH_LEFT:                 
             Left.x = event.getX();
             Left.y = event.getY();             
             invalidate();
             return true;       
        }         

    case MotionEvent.ACTION_UP:

        switch (currentTouch) {
        case TOUCH_TOP:
             top.x = event.getX();
             top.y = event.getY();                
             invalidate();
             currentTouch = NONE;
             return true;
        case TOUCH_RIGHT:
             Right.x = event.getX();
             Right.y = event.getY();             
             invalidate();
             currentTouch = NONE;
             return true;
        case TOUCH_LEFT:
            Left.x = event.getX();
             Left.y = event.getY();               
             invalidate();
             currentTouch = NONE;
             return true;      
        }         
        return false;
    }
    return false;
}

CustomViewの上記の文字と一緒にこのドラッグアンドドロップを実現するにはどうすればよいですか....

4

2 に答える 2

7

この問題を解決するには、線形代数を使用します。線の一部ではない点が 3 つ以上あります (線形独立)。この事実を使用して、タッチ ポイントが領域内にあるかどうかを判断できます。これは、ポイントが多いほど難しくなります。そのため、次の手順を適用して、角が 3 つを超えるポリゴンを一連の三角形に変換する必要があります。

したがって、三角形を定義する 3 つの点 A、B、C があります。次に、タッチ ポイントを使用して 3 つの線を定義し、方向ベクトル AT、BT、CT を取得します。A、B、C は、これら 3 つのタッチ ラインの基点を示します。

次に、基点 A で境界線ABを定義し、基点 A で境界線 AC (基点が A か C かは関係ありません) を定義し、最後に基点 C で線 CB を定義します。ベクトルを表し、小文字はスカラーまたは係数を表します):

境界線:

a:X=A+f1*AB
b:X=B+f2*BC
c:X=C+f3*AC

タッチライン:

ta:X=A+t1*AT
tb:X=B+t2*BT
tc:X=C+t3*CT

タッチ ラインと交点を含む結果の三角形

ここで、タッチ ライン (図のピンク) と、タッチ ラインの基点の反対側にある境界線 (緑/赤) を交差させます。たとえば、交点 I3 を取得するには、ライン 'ta' とライン b を交差させる必要があります。ベクトル AT を係数t1だけ拡張すると、この点に到達します。

この係数t1が 1 より大きい場合、接触点 T は A と I3 の間の線「ta」にあります。係数t1が 1 より小さい場合 T は線分 A-I3 の外側にあります。

行 tb と c と tc と a でこれを 3 回行う必要があります。毎回、I(n) ポイントは 1 未満である必要があります (n は {1,2,3} です)。

この条件が 3 つの交点すべてに当てはまる場合、タッチ ポイントは三角形の内側にあります。

次の単純な連立方程式を解くことで、交点が得られます。

最初

A+t1*AT = B+f2*BC
<=>
0 = A+t1*AT - B - f2*BC

このシステムは次のようになります (ここで、x、y は特定の座標コンポーネントを提供します)。

0 = xA + t1*(xT-xA) - xB - f2*(xC-xB)
0 = yA + t1*(yT-yA) - yB - f2*(yC-yB)

二番目

B+t2*BT = C+f3*AC
<=>
0 = B+t2*BT - C - f3*AC

第3

C+t3*CT = A+f1*AB
<=>
0 = C+t3*CT - A - f1*AB

これら 3 つのシステムを解くと、点が領域内にあるかどうかの答えが得られます。解は 0 とは明確に異なる必要があります (0 が唯一の解である場合、ポイントは同じ線上にあります ->線形従属)!

それに基づいて、オブジェクトのすべての座標を変換できます。

上記のように、三角形に縮小し、このメソッドをポリゴンのすべての部分三角形に適用する必要があります。条件に 1 つ (またはマルチタッチを実装する場合は 2 つ以上) 一致する場合、タッチはオブジェクト領域内にあります。

これは 3 つの小さな計算にすぎず、「Touch-Down」イベント ハンドラで 1 回呼び出す必要があります。領域に触れたことはわかっているので、指を動かしながらこれらすべての計算を行う必要はありません。

三角化について これは、一文では答えられない、より複雑な問題です。単純なポリゴンを処理したくないという他の回答に対するコメントによると、ポリゴンで構成されるより複雑な形状を処理したいと考えています。たとえば、あなたの星の形。ここでは、上記の方法を使用できます。三角形を自分で定義する必要があります。どのコーナーが面に属し、どのコーナーが面に属していないかを知るのはそれほど簡単ではないからです。

別の解決策は、いわゆる Quick Hull アルゴリズムを使用して、点セットから凸包を生成することです。これにより、三角形化に使用する必要がある形状の輪郭が得られます。可能なすべてのポイント セットを本当に処理したい場合は、「シェーディングされていない」面がいくつかある場合は、それらもタッチされたものとして処理します。

あなたのスターケースでの私の解決策:

  • スパイク三角形を定義する

  • 上記の方法を使用して (いくつかの LSE を解決することによって)、1 つが触れられているかどうかを判断します。

他のすべての場合

三角形の外接円を使って三角形化します。他の輪郭点を含まない円を定義する 3 つの点を見つけることによって。いわゆるドロネー三角形分割。このメソッドで三角形を見つけます。影のない領域がいくつかある場合は、「タッチ可能」などのプロパティを使用して三角形オブジェクトを定義し、タッチを処理する必要があるかどうかをアルゴリズムに知らせることができます。

三角形のセットを適切に処理および更新すれば、凹型の形状を処理する方法についてこれ以上質問する必要はありません。

五角形については、次のようにしてください。

  • クイックハルと三角測量法を使用します。

  • ユーザーがポイントの位置を変更した場合、三角形を更新します

  • 利益

于 2012-06-26T10:20:37.753 に答える
3

まず、View.dispatchTouchEvent() をオーバーライドして、三角形から外れたタッチをフィルタリングする必要があります。それを行う方法と、ビューの一部をタッチ透過にするために OnTouchListener ではなくその特定のメソッドを使用する必要がある理由については、こちらの回答をご覧ください。

次に、OnTouchListener で、タッチ座標を三角形のポイントの座標と比較して、ユーザーがポイントの 1 つまたは三角形の内側にヒットしたかどうかを判断します。また、ポイントに少し余裕を持たせることをお勧めします。タッチ スクリーンで小さなオブジェクトをポイントするのは非常に難しいため、ユーザーに 4 ~ 8 ピクセルのミス バッファーを持たせます。

したがって、ユーザーがポイントをヒットした場合 - ポイントをドラッグし、ポイントの 1 つではなく三角形の内側にヒットした場合 (つまり、タッチ ポイントが三角形内にあるが、ポイントのローカリティの 1 つに含まれていない場合) - 全体をドラッグします。見る。また、三角形が小さすぎてポイント マージンがオーバーラップする場合 (複数のポイント ローカリティに一致するタッチが発生します)、最も近いものを選択します。

ドラッグ アンド ドロップ API に慣れていない場合は、ここにすばらしいチュートリアルがあります。アクションが ACTION_DOWN で、タッチ ポイントが三角形の内側にある場合は、OnTouchListener から startDrag() を呼び出す必要があります。

ハニカム以前の API には、 android-dragareaというドラッグ アンド ドロップ ライブラリがあります。ドキュメントにサンプルアプリへのリンクがあります。

UPDああ、あなたがアルゴリズムも探していることに気づきませんでした。Point-in-Polygon アルゴリズムが必要です。ここにいくつかの優れたソリューションがあります。それらはほとんどすべての複雑なポリゴンで機能します。

于 2012-06-26T09:57:18.443 に答える