4

特にドラッグアンドドロップの状況で、作成したカスタムViewGroupにビュー要素を配置するのに問題があります。Android 2.2以降をターゲットにしているため、Android3で登場したドラッグアンドドロップAPIを実際に使用することはできません。

私のカスタムViewGroupは「NodeGrid」と呼ばれ、「RelativeLayout」を拡張します。そのonLayoutメソッドは、次のようにオーバーライドされます。

@Override
protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) 
{
    //pxConversion is a multiplier to convert 1 dip to x pixels.
    //We will use it to convert dip units into px units.
    Resources r = getResources();
    float pxConversion = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, r.getDisplayMetrics());

    //Layout the children of this viewgroup
    int childCount = this.getChildCount();
    for (int i = 0; i < childCount; i++)
    {
        NodeView view = (NodeView) this.getChildAt(i);

        if (view.DataContext != null)
        {
            int left = (int) (view.DataContext.get_left() * pxConversion);
            int top = (int) (view.DataContext.get_top() * pxConversion);
            int right = left + (int) (view.DataContext.get_width() * pxConversion);
            int bottom = top + (int) (view.DataContext.get_height() * pxConversion);

            view.layout(left, top, right, bottom);
        }
    }   
}

「NodeGrid」の子は「NodeView」タイプです(上記のコードで確認できます)。NodeViewは、私が作成したカスタムViewクラスです。これには、NodeGrid上のNodeViewインスタンスに関する位置情報を持ついくつかのゲッター/セッターを含むビューモデルクラスである「DataContext」と呼ばれるメンバーが含まれています。

私の「NodeView」クラスは、ユーザーによるタッチイベントをキャプチャするため、ユーザーはグリッド上の任意の場所にノードをドラッグアンドドロップするだけで済みます。イベントハンドラは次のようになります。

@Override
public boolean onTouchEvent(MotionEvent event) {

    if (event.getAction() == MotionEvent.ACTION_DOWN)
    {
        isBeingDragged = true;
    }
    else if (event.getAction() == MotionEvent.ACTION_UP)
    {
        isBeingDragged = false;
    }
    else if (event.getAction() == MotionEvent.ACTION_MOVE)
    {
        if (DataContext != null && isBeingDragged)
        {
            float xPosition = event.getRawX();
            float yPosition = event.getRawY();

            DataContext.set_left(xPosition);
            DataContext.set_top(yPosition);

            this.requestLayout();
        }
    }

    return true;
}

私の問題は、ドラッグされているビューが「NodeGrid」で期待するように配置されていないことです。ドラッグするとx軸の位置は正しいように見えますが、y軸の位置は常に一定量のピクセルによってオフセットされています。これを引き起こしているのは何ですか?getRawX()およびgetRawY()ではなくgetX()およびgetY()メソッドを使用しようとしましたが、それが原因で悪化するだけです。

getRawX()とgetRawY()がpx単位を返すのか、dip単位を返すのかわからなかったので、px単位が返されることを期待して、新しいx値とy値をに割り当てる前にそれらをdip単位に変換してみました。ノードですが、それはオフセットを減少させるだけで、それを排除しませんでした。

タッチしている場所とノードが配置されている場所の違いの原因は何ですか?

4

1 に答える 1

1

どうやら他の誰もこの種の状況に遭遇していないことに非常に驚いています...

いくつかの調査の後、私は部分的に問題を解決することができました。

getRawX()とgetRawY()が機能しなかった理由は、アプリの一部ではない画面上のもの(常に画面の上部にあるAndroidメニューなど)に関係なく、絶対的な画面位置で機能するためです。フルスクリーンモードでない限り)。これらの座標を使用することは、特にそれらを正当化して「私のアプリ」座標に変換する明確な方法がないため、ハックのように見えました。

getX()とgetY()は、私が知る限り、触れられているオブジェクトに関連しているようです。これを考慮に入れると、onTouchEventのコードを次のように変更しました。

float xPosition = event.getX();
float yPosition = event.getY();

DataContext.set_left(DataContext.get_left() + xPosition);
DataContext.set_top(DataContext.get_top() + yPosition);

this.requestLayout();

これは間違いなく役立ちます...しかし、それでも完璧な解決策ではないようです。一般に、ビューオブジェクトはマウスカーソル/指と一緒にドラッグされますが、非常にぎくしゃくしていて、画面から外れることがあります。

それで、「歴史的な座標」をメソッドに取り入れていないからかもしれないと思いました。上に表示したコードの直前にこのコードを配置して、メソッドに履歴座標を組み込んでみました。

int historySize = event.getHistorySize();
for (int i = 0; i < historySize; i++)
{
    float xPosition = event.getHistoricalX(i);
    float yPosition = event.getHistoricalY(i);

    DataContext.set_left(DataContext.get_left() + xPosition);
    DataContext.set_top(DataContext.get_top() + yPosition);

    this.requestLayout();
}

残念ながら...これは実際には悪化するので、履歴座標を正しく使用していないか、まったく使用しないでください。その件に関して別の質問を投稿しますが、上記の私の質問に対する部分的な回答としてはこれで十分です。

于 2011-12-24T01:43:31.830 に答える