【问题标题】:Android Custom Rectangle DrawingAndroid 自定义矩形绘图
【发布时间】:2015-03-27 10:47:23
【问题描述】:

我希望在我的 Android UI 中创建一个拼字游戏板类型视图。为此,我目前已决定(仍在尝试最好的方法)使用带有自定义 BoardCell 视图的 TableLayout 和 TableRow 视图作为板的各个单元格。

我还是 Android 新手,之前从未创建过自定义视图。我在绘制矩形时遇到了问题。我可以绘制一行的第一个单元格,但我无法绘制该行中剩余的 14 个单元格。在调试期间,所有 BoardCell 对象都被初始化,并为每个对象调用“onDraw”。测量值和左、上、右和底部位置似乎也是正确的。所以我的问题是......我做错了什么?那一定是我缺少的一些简单的东西?

我尝试简单地绘制一些单元格的笔画(如下面的代码),但缺少右行和底行。我知道这与它有关,但我不明白为什么不绘制单元格的右侧和底部?

以下是所有相关代码,删除无关代码以缩短这篇文章。

activity_game.xml

<!-- Game Board --> <TableLayout android:id="@+id/board_grid" android:layout_width="355dp" android:layout_height="355dp" android:layout_below="@+id/score_container" android:layout_marginRight="2dp" android:layout_marginLeft="2dp" android:background="@color/white" android:stretchColumns="*"> <!-- Row 1 --> <TableRow android:layout_weight="1"> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp" custom:cellType="doubleWord"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp" custom:cellType="doubleLetter"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp" custom:cellType="doubleLetter"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp"/> <BoardCellView android:layout_height="21dp" android:layout_width="0dp" android:layout_margin="1dp" custom:cellType="doubleWord"/> </TableRow> </TableLayout>

BoardCellView.java

public class BoardCellView extends View {

    private static final String TAG = BoardCellView.class.getName();

    private static final int STANDARD_CELL_COLOUR       = Color.rgb(234, 234, 234);
    private static final int DOUBLE_LETTER_CELL_COLOUR  = Color.rgb(200, 175, 224);
    private static final int TRIPLE_LETTER_CELL_COLOUR  = Color.rgb(132, 217, 168);
    private static final int DOUBLE_WORD_CELL_COLOUR    = Color.rgb(255, 181, 131);
    private static final int TRIPLE_WORD_CELL_COLOUR    = Color.rgb(146, 205, 251);

    private Paint standardCellPaint;
    private Paint doubleLetterPaint;
    private Paint tripleLetterPaint;
    private Paint doubleWordPaint;
    private Paint tripleWordPaint;

    private CellType cellType;

    private Rect cellRectangle;

    public BoardCellView(Context context, AttributeSet attrs) {
        super(context, attrs);

        init();

        TypedArray typedArray = context.getTheme().obtainStyledAttributes(
            attrs,
            R.styleable.BoardCellView,
            0, 0);

        try {
            this.cellType =     CellType.fromInt(typedArray.getInt(R.styleable.BoardCellView_cellType, 0));

        } finally {
            typedArray.recycle();
        }
    }

    /**
     * Setup the paint and rectangle objects
     */
    private void init() {
        // The rectangle we will use to draw
        this.cellRectangle = new Rect();

        // Setup the Paints for each cell type
        this.standardCellPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.standardCellPaint.setStyle(Paint.Style.STROKE);
        this.standardCellPaint.setColor(STANDARD_CELL_COLOUR);
        this.standardCellPaint.setStrokeWidth(5.0f);

        this.doubleLetterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.doubleLetterPaint.setStyle(Paint.Style.FILL);
        this.doubleLetterPaint.setColor(DOUBLE_LETTER_CELL_COLOUR);

        this.tripleLetterPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.tripleLetterPaint.setStyle(Paint.Style.FILL);
        this.tripleLetterPaint.setColor(TRIPLE_LETTER_CELL_COLOUR);

        this.doubleWordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.doubleWordPaint.setStyle(Paint.Style.STROKE);
        this.doubleWordPaint.setColor(DOUBLE_WORD_CELL_COLOUR);
        this.doubleWordPaint.setStrokeWidth(5.0f);

        this.tripleWordPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        this.tripleWordPaint.setStyle(Paint.Style.FILL);
        this.tripleWordPaint.setColor(TRIPLE_WORD_CELL_COLOUR);

    }

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        this.cellRectangle.set(left, top, right, bottom);
        Log.d(TAG, "---- " + left + ":"+ top + ":"+ right + ":"+ bottom);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        // Standard cell first as this is by far the most common
        switch (this.cellType) {
            case STANDARD:
                Log.d(TAG, "---- Drawing Standard: " + this.cellRectangle.toShortString());
                canvas.drawRect(this.cellRectangle, this.standardCellPaint);
                break;
            case DL:
                Log.d(TAG, "---- Drawing DL");
                canvas.drawRect(this.cellRectangle, this.doubleLetterPaint);
                break;
            case TL:
                Log.d(TAG, "---- Drawing TL");
                canvas.drawRect(this.cellRectangle, this.tripleLetterPaint);
                break;
            case DW:
                Log.d(TAG, "---- Drawing DW: " + this.cellRectangle.toShortString());
                canvas.drawRect(this.cellRectangle, this.doubleWordPaint);
                break;
            case TW:
                Log.d(TAG, "---- Drawing TW");
                canvas.drawRect(this.cellRectangle, this.tripleWordPaint);
                break;
        }
    }
}

Logcat的输出(第一个是onLayout的输出,第二个是onDraw的输出)

BoardCellView﹕ ---- 3:3:68:66
03-27 10:57:12.534  27810-27810/app D/BoardCellView﹕ ---- 74:3:139:66
03-27 10:57:12.534  27810-27810/app D/BoardCellView﹕ ---- 145:3:210:66
03-27 10:57:12.534  27810-27810/app D/BoardCellView﹕ ---- 216:3:281:66
03-27 10:57:12.534  27810-27810/app D/BoardCellView﹕ ---- 287:3:352:66
03-27 10:57:12.536  27810-27810/app D/BoardCellView﹕ ---- 358:3:423:66
....
---- Drawing DW: [3,3][68,66]
03-27 10:57:12.576  27810-27810/app D/BoardCellView﹕ ---- Drawing Standard: [74,3][139,66]
03-27 10:57:12.576  27810-27810/app D/BoardCellView﹕ ---- Drawing Standard: [145,3][210,66]
03-27 10:57:12.576  27810-27810/app D/BoardCellView﹕ ---- Drawing Standard: [216,3][281,66]
03-27 10:57:12.576  27810-27810/app D/BoardCellView﹕ ---- Drawing Standard: [287,3][352,66]

这是视图的绘制方式。前 2 行使用我的自定义视图。其余行使用带有背景颜色的简单 View 对象。

![棋盘视图]http://cl.ly/image/0T2F3i1l3y24

我花了几天时间尝试 Google 和这里​​ (Drawing multiple custom views) 提供的各种解决方案,但我没有找到任何可以解决我问题的方法。提前感谢您的帮助。

【问题讨论】:

    标签: android android-layout


    【解决方案1】:

    问题在于onLayout() 中的cellRectangle 设置。传入onLayout() 的矩形坐标是相对于父视图的,但是在调用drawRect() 时需要在onDraw() 中使用的坐标应该相对于视图本身,因为Canvas 是设置为使视图的左上角对应于 (0, 0)。

    因此,父视图中的 (left, top) 将对应于子视图中的 (0, 0),并且 (right, bottom) 将对应于 (right-left, bottom-top)。基本上你只需要从它们中减去(左,上)。

    考虑到这一点,像这样更改onLayout

    @Override
    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        super.onLayout(changed, left, top, right, bottom);
        this.cellRectangle.set(0, 0, right-left, bottom-top);
        Log.d(TAG, "---- " + left + ":"+ top + ":"+ right + ":"+ bottom);
    }
    

    【讨论】:

    • 谢谢!这完全有道理。我猜是因为在调试中打印出的坐标我假设 onDraw 中的 Canvas 实际上是要在其中绘制视图的父视图的坐标。我知道这一定是我在某个地方的简单疏忽。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 1970-01-01
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多