0

画面に同じカスタム ビューをいくつか表示しようとしています。ここに私のビュークラスがあります:

public class DraggableText extends View {
private int cStart;
private int cEnd;
private Paint mTextPaint, mBgPaint;
private RectF mRect;
private Point mPos;

public DraggableText(Context context, AttributeSet attrs) {
    super(context, attrs);
    TypedArray a = context.getTheme().obtainStyledAttributes(attrs,
            R.styleable.DraggableText, 0, 0);

    try {
        cStart = Color.parseColor(a
                .getString(R.styleable.DraggableText_gradientStart));
        cEnd = Color.parseColor(a
                .getString(R.styleable.DraggableText_gradientEnd));
    } finally {
        a.recycle();
    }
    init();
}

private void init() {
    mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

    Shader s = new LinearGradient(0, 0, 0, getHeight(), cStart, cEnd,
            Shader.TileMode.CLAMP);
    mBgPaint.setShader(s);

    mRect = new RectF();
    mPos = new Point(0, 0);
}

public void setPos(Point p){
    mPos = p;
    invalidate();
    requestLayout();
}

public Point getPos(){
    return mPos;
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);

    int desiredWidth = (widthSize / 2) - 80;
    int desiredHeight = 65;

    int width;
    int height;

    if (widthMode == MeasureSpec.EXACTLY) {
        width = widthSize;
    } else if (widthMode == MeasureSpec.AT_MOST) {
        width = Math.min(desiredWidth, widthSize);
    } else {
        width = desiredWidth;
    }

    if (heightMode == MeasureSpec.EXACTLY) {
        height = heightSize;
    } else if (heightMode == MeasureSpec.AT_MOST) {
        height = Math.min(desiredHeight, heightSize);
    } else {
        height = desiredHeight;
    }

    setMeasuredDimension(width, height);
}

@Override
protected void onDraw(Canvas c) {
    super.onDraw(c);
     mRect.set(mPos.x, mPos.y, getWidth(), getHeight());
     c.drawRoundRect(mRect, 8, 8, mBgPaint);
}

}

onCreateコールバックのアクティビティでは、次のようにします。

    word1 = (DraggableText) findViewById(R.id.word1);
    word2 = (DraggableText) findViewById(R.id.word2);
    word3 = (DraggableText) findViewById(R.id.word3);
    word4 = (DraggableText) findViewById(R.id.word4);

    word1.post(new Runnable() {
        @Override
        public void run() {
            word1.setPos(new Point(20, 20));
            word2.setPos(new Point(word1.getWidth() + 20, 20));
            word3.setPos(new Point(20, word1.getHeight() + 10));
            word4.setPos(new Point(word1.getWidth() + 20, word1.getHeight() + 10));
        }
    });

getWidthビューにアクセスできるように、この実行可能ファイルを投稿しgetHeightます。ポイントではありません。このコードを削除してsetPos、どんな値でも使用すると、常に同じになります。画面上の 1 つのビューのみ (またはすべて、ただし前者の上)。

1 つのビューのみを描画するバグはどこにありますか?

4

1 に答える 1

0

問題は、post() ランナブルが実行されるまでに、ビューが実際にインフレーションと初期レイアウトを完了していないことです。代わりに ViewTreeObserver とやり取りしたい。アクティビティの onResume で、これを試してください:

@Override
public void onResume(){
    super.onResume();
    findViewById(R.id.word1).getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
                @Override public void onGlobalLayout() {
                        DraggableText word1 = (DraggableText) findViewById(R.id.word1);
                        DraggableText word2 = (DraggableText) findViewById(R.id.word2);
                        DraggableText word3 = (DraggableText) findViewById(R.id.word3);
                        DraggableText word4 = (DraggableText) findViewById(R.id.word4);
                        word1.setPos(new Point(20, 20));
                        word2.setPos(new Point(word1.getWidth() + 20, 20));
                        word3.setPos(new Point(20, word1.getHeight() + 10));
                        word4.setPos(new Point(word1.getWidth() + 20, word1.getHeight() + 10));
                        word1.getViewTreeObserver().removeGlobalOnLayoutListener(this);
                    }
                }
            });
}

ViewTreeObserverの詳細は次のとおりです。

フォローアップ: ああ、悪い。私はあなたのコードをあまり徹底的に読んでいないと思います。あなたが求めていることを行う便利な100%フレームワークの方法があるかどうかは実際にはわかりません。requestLayout() は、ビューの次のレイアウトをキューに入れるだけで、同期を強制しません。次の 2 つのことを試すことができます。

1 - 2 つの異なるランナブルを作成します。最初に位置変更を word1 にポストします。残りの位置の変更を投稿する 2 番目。

2 - フレームワークの getWidth\getHeight に依存する代わりに、カスタム ビュー内の独自のメンバー変数で位置とディメンションを追跡します。これにより、setPos() を呼び出すときに手動で更新できます。

また、別のレイアウト メカニズムを完全に使用することを検討することもできます。多くの詳細に入る代わりに、RelativeLayout コンテナーを使用してみてください。次に、たとえば、単語 1 のマージンを変更するだけで、他の単語がそれに応じて続きます。

于 2012-09-04T23:46:56.703 に答える