Canvas 'drawLine и drawRect не включают конечную позицию?
К моему удивлению, я только что обнаружил, что drawLine и drawRect не включают конечную позицию, то есть:
canvas.drawLine(100, 100, 100, 100, paint);
или
RectF rect = new RectF(100, 100, 100, 100);
canvas.drawRect(rect, paint);
ничего не рисует.
Моя краска определяется следующим образом:
Paint paint = new Paint();
paint.setAntiAlias(false);
paint.setStyle(Paint.Style.FILL);
return paint;
Я попытался определить мою краску как FILL_AND_STROKE, но это не помогло.
Android drawPaint() javadoc даже не перечисляет параметры stopX и stopY!
Итак, если я хочу нарисовать вертикальную линию, которая идет именно от beginY до endY (включительно), я должен сделать следующее:
canvas.drawLine(constX, beginY, constX, endY + 1)
Обратите внимание, что я не добавлял 1 к конечной позиции X, а только к концу Y (xstays то же самое, что и вертикальная линия).
Мое устройство - HTC SENSE.
Изменить: Саймон, вы правы, вместо того, чтобы задавать вопрос, который я только что пытался поделиться своим чувством удивления, что Android не делает то, что говорят его документы в таком фундаментальном случае, как основной рисунок, и убедитесь, что Я не делал глупой ошибки на моем пути.
Чтобы сделать себя яснее: drawRect javadoc говорит:
public void drawRect (float left, float top, float right, float bottom, Paint paint)
Нарисуйте указанный Rect с помощью указанной краски. Прямоугольник будет заполнен или обрамлен на основе стиля в краске.
left - левая сторона рисунка прямоугольника
top - верхняя сторона рисунка прямоугольника
right - правая сторона рисунка прямоугольника
bottom - нижняя сторона рисунка прямоугольника
краска - краска, используемая для рисования прямоугольника
Итак, при написании
canvas.drawRect(x1, y1, x2, y2)
Вы ожидаете прямоугольник с углами (x1, y1); (x1, y2); (x2, y1) и (x2, y2).
Android говорит: неправильно! Они будут находиться в точке (x1, y1); (x1, y2-1); (x2-1, y1) и (x2-1, y2-1).
Для любопытных: установите ограничение на холст:
canvas.clipRect(x1, y1, x2, y2)
Затем попробуйте нарисовать точку:
canvas.drawPoint(x1, y1, paint);
и вы получите точку на экране.
Затем попробуйте в противоположном углу:
canvas.drawPoint(x2, y2, paint);
ничего не появляется. в остальных двух углах ничего не появится:
canvas.drawPoint(x1, y2, paint);
canvas.drawPoint(x2, y2, paint);
Все еще неудивительно для вас, ребята?
Таким образом, вывод заключается в том, что Android рассматривает правые и нижние координаты как исключительные, что означает, что, например, при написании:
canvas.clipRect(x1, y1, x2, y2)
Вы получите границы отсечения (x1, y1, x2 - 1, y2 - 1). То же самое происходит с каждым методом, который принимает координаты справа и внизу или Rect/RectF.
Ответы
Ответ 1
В вашем вопросе обнаруживается несогласованность в API чертежей Android. Вы говорите
Итак, если я хочу нарисовать вертикальную линию, которая идет именно от beginY до endY (включительно), я должен сделать следующее:
canvas.drawLine(constX, beginY, constX, endY + 1)
Обратите внимание, что я не добавлял 1 к конечной позиции X, а только к концу Y (xstays то же самое, что и вертикальная линия).
Предложение в скобках - это, на мой взгляд, ключ к пониманию природы несогласованности:
Вы также можете добавить 1 к конечной позиции X (или даже к началу X-позиции!), и вы получите точно такую же пиксельную идентичную строку. Почему это? Поскольку базовый алгоритм преобразования из "левого пикселя вправо/правый пиксель" от Android, как и "начальный и конечный пиксель в", является следующим: (показано только для x, для y это одно и то же):
int left, top, right, bottom; // left/top pixel inclusive, right/bottom pixel exclusive
int x1, y1, x2, y2; // x1/y1 and x2/y2 pixels inclusive
if ( left == right ) {
x1 = x2 = left;
} else if ( left < right ) {
x1 = left;
x2 = right - 1;
} else {
x1 = right;
x2 = left - 1;
}
Результатом этого (на мой взгляд, субоптимального) преобразования является то, что строка
canvas.drawLine(150, 150, 149, 160, paint);
точно параллельна
canvas.drawLine(150, 150, 151, 160, paint);
Я думаю, что все ожидали бы вид обратного V, поскольку конечные точки разделены по крайней мере на 1 пиксель (их расстояние составляет два пикселя), а начальные точки идентичны.
Но тестировавшись на разных устройствах и версиях Android, первая совершенно вертикальная линия находится в пиксельном столбце 149 и втором в столбце 150.
BTW: правильное преобразование для использования "начального и конечного пикселей в" -концепте:
int x1, y1, x2, y2; // x1/y1 and x2/y2 pixels inclusive
if ( x1 <= x2 )
++x2;
else
++x1;
if ( y1 <= y2 )
++y2;
else
++y1;
canvas.drawLine(x1, y1, x2, y2, paint);
Ответ 2
Ваш вопрос по существу является ответом для этого. Спасибо.
Я, например, не удивлен этим и не хотел бы этого другим способом. Вот почему:
-
Это согласуется с java.awt
, javax.swing
и другими API-интерфейсами, а также с основными Java-методами, такими как String.substring(int, int)
и List<?>.get(int)
.
-
Он совместим с android.graphics.RectF
, который не заботится о пикселях - как вы можете иметь долю пикселя?
-
API удобен:
-
Для прямоугольника 40 × 30 выполните экземпляр Rect(0, 0, 40, 30)
-
Rect.right - Rect.left == Rect.width()
-
Математика и геометрия проще. Например, если вы хотите нарисовать прямоугольник, центрированный внутри холста:
Rect clipBounds = canvas.getClipBounds()
int myRectWidth = 20;
int myRectHeight = 10;
int left = (clipBounds.width() - myRectWidth) / 2;
int top = (clipBounds.height() - myRectHeight) / 2;
int right = clipBounds.width() - left; // See how nice this is?
int bottom = clipBounds.height() - top; // This wouldn't work if bottom was inclusive!
canvas.drawRect(left, top, right, bottom);
API прав; документация API, к сожалению, просто не хватает деталей.
(На самом деле в подробно описывается метод Rect.contains(int, int)
. К сожалению, Google выпустил API вне двери без однако сами переменные поля документируются.)
Ответ 3
если ваш фон черный, добавьте одно утверждение paint.setColor(Color.RED);
а также вы прошли RectF rect = new RectF(100, 100, 100, 100);
все точки одинаковы, попробуйте RectF rect = new RectF(100, 100, 200, 200);
ИЛИ для строки canvas.drawLine(10, 10, 10, 10 + 15, paint);
Ответ 4
Ваш rect должен работать с плавниками, попробуйте добавить некоторый фон, ваша линия теперь кустает пиксель, два последних параметра - это не длина, а конечная позиция.