Холст смещается путем установки матрицы идентичности в onDraw пользовательского представления
Я установил матрицу для моего холста в onDraw
метод пользовательского просмотра через canvas.setMatrix(matrix);
тогда я просто рисую сетку, используя предопределенные краски:
canvas.drawRect(0,0,viewWidth,viewHeight, background);
for(int i=0; i <= nRows; i++){
canvas.drawLine(0,i*cellHeight, nCols*cellWidth,i*cellHeight,lines);
canvas.drawLine(i*cellWidth, 0, i*cellWidth, nRows*cellHeight, lines);
if(i != nRows)
canvas.drawText(""+i, i*cellWidth, (i+1)*cellHeight, text);
}
и по какой-то причине весь холст смещается примерно в 1,5 раза выше высоты ячейки. Есть идеи, почему это происходит или как это исправить? Матрица не была инициализирована и, согласно документации, кстати, должна быть идентичностью.
Спасибо большое!
2 ответа
Я сузил это поведение до того, что оригинал Matrix
из View
Холст уже переведен по позиции вида. Это не очевидно, однако, если вы получаете Matrix
с помощью Canvas.getMatrix()
, или же View.getMatrix()
, Вы получите идентификационную матрицу из этих звонков.
Смещение холста, которое вы видите, скорее всего, точно такой же высоты, как View
смещение от верхней части экрана (строка состояния, строка заголовка и т. д.).
Вы правильно используете canvas.concat(matrix)
вместо canvas.setMatrix(matrix)
в этом случае использования, и большинство случаев использования. Если вам действительно нужна оригинальная матрица, которую я сделал при отладке, вы должны преобразовать ее вручную с помощью View
перевод в своем собственном Window
:
int[] viewLocation = new int[2];
mView.getLocationInWindow(viewLocation);
mOriginalMatrix.setTranslate(viewLocation[0], viewLocation[1]);
РЕДАКТИРОВАТЬ, чтобы ответить на дополнительный вопрос в комментариях:
Чтобы преобразовать сенсорные координаты (или любые экранные координаты) в соответствие с координатами Canvas
просто сделайте все преобразования в Matrix
вместо этого и Canvas.concat()
с этой матрицей каждый кадр перед рисованием. (Или вы можете продолжать делать все преобразования непосредственно в Canvas
как вы делаете сейчас, и использовать Canvas.getMatrix(mMyMatrix)
получить матрицу после каждого розыгрыша. Это устарело, но это работает.)
Затем матрицу можно использовать для преобразования ваших исходных границ сетки в те, которые нарисованы на экране. По сути, вы делаете то же самое, что и Canvas
делает, когда рисует сетку, преобразовывая угловые точки сетки в координаты экрана. Теперь сетка будет в той же системе координат, что и ваши сенсорные события:
private final Matrix mMyMatrix = new Matrix();
// Assumes that the grid covers the whole View.
private final float[] mOriginalGridCorners = new float[] {
0, 0, // top left (x, y)
getWidth(), getHeight() // bottom right (x, y)
};
private final float[] mTransformedGridCorners = new float[4];
@Override
public boolean onTouchEvent(MotionEvent event) {
if (/* User pans the screen */) {
mMyMatrix.postTranslate(deltaX, deltaY);
}
if (/* User zooms the screen */) {
mMyMatrix.postScale(deltaScale, deltaScale);
}
if (/* User taps the grid */) {
// Transform the original grid corners to where they
// are on the screen (panned and zoomed).
mMyMatrix.mapPoints(mTransformedGridCorners, mOriginalGridCorners);
float gridWidth = mTransformedGridCorners[2] - mTransformedGridCorners[0];
float gridHeight = mTransformedGridCorners[3] - mTransformedGridCorners[1];
// Get the x and y coordinate of the tap inside the
// grid, between 0 and 1.
float x = (event.getX() - mTransformedGridCorners[0]) / gridWidth;
float y = (event.getY() - mTransformedGridCorners[1]) / gridHeight;
// To get the tapped grid cell.
int column = (int)(x * nbrColumns);
int row = (int)(y * nbrRows);
// Or to get the tapped exact pixel in the original grid.
int pixelX = (int)(x * getWidth());
int pixelY = (int)(y * getHeight());
}
return true;
}
@Override
protected void onDraw(Canvas canvas) {
// Each frame, transform your canvas with the matrix.
canvas.save();
canvas.concat(mMyMatrix);
// Draw grid.
grid.draw(canvas);
canvas.restore();
}
Или устаревший способ получить матрицу, которая все еще работает и, возможно, потребует меньше изменений:
@Override
protected void onDraw(Canvas canvas) {
canvas.save();
// Transform canvas and draw the grid.
grid.draw(canvas);
// Get the matrix from canvas. Can be used to transform
// corners on the next touch event.
canvas.getMatrix(mMyMatrix);
canvas.restore();
}
Я нашел решение этой проблемы, если не причина проблемы.
Замена линии canvas.setMatrix(matrix);
с canvas.concat(matrix);
сделал трюк. Я думаю, что это частично связано с тем фактом, что установка матрицы изменяет происхождение холста, который будет рассчитываться относительно высоты и ширины экрана, а не вида. Но есть загадки, потому что это также волшебным образом решило некоторые другие проблемы, которые у меня были.
РЕДАКТИРОВАТЬ
Оказывается, одно из последствий таких действий заключается в том, что event.getX()
а также event.getY()
в onTouchEvent(MotionEvent event)
метод начать возвращать целые числа, с которыми трудно иметь дело. Мой пользовательский вид предназначен для создания масштабируемой, панорамируемой сетки квадратов, по которой я могу щелкнуть и получить координату квадрата. Используя этот метод, я пытаюсь получить (x,y) координату события клика (MotionEvent.ACTION_UP
дело в onTouchEvent
метод).
Я пытаюсь получить координату х, например, с помощью
int x = (int) ((start.x - dspl.x)/(cellWidth*scaleFactor));
Я учел сколько я панорамировал экран (dspl
дает общее смещение, которое произошло до сих пор) и сумму, которую я увеличил (scaleFactor
дает общее масштабирование, которое произошло). Но это не учитывает моменты, в которых происходило последовательное увеличение.
Любые хорошие идеи о том, как получить правильные координаты?