Canvas 'drawLine y drawRect no incluye la posición final?

Para mi sorpresa, acabo de descubrir que drawLine y drawRect no incluyen la posición final, es decir:

canvas.drawLine(100, 100, 100, 100, paint); 

o

 RectF rect = new RectF(100, 100, 100, 100); canvas.drawRect(rect, paint); 

No dibujará nada.

Mi pintura se define como sigue:

 Paint paint = new Paint(); paint.setAntiAlias(false); paint.setStyle(Paint.Style.FILL); return paint; 

He intentado definir mi pintura como FILL_AND_STROKE, pero no ayudaría.

DrawPaint de Android () javadoc ni siquiera la lista stopX y stopY params!

Por lo tanto, si quiero dibujar una línea vertical que va exactamente desde beginY hasta endY (inclusive), tengo que hacer lo siguiente:

 canvas.drawLine(constX, beginY, constX, endY + 1) 

Note que no he añadido 1 a la posición final de X, sólo para terminar Y (xstays lo mismo que quiero una línea vertical).

Mi dispositivo es HTC SENSE.

Editar: Simon, tienes razón, en lugar de hacer una pregunta Acabo de tratar de compartir mi sentimiento de sorpresa de que Android no hace lo que sus documentos dicen en un caso tan fundamental como el dibujo básico, y asegúrese de que yo didn ' No hago ningún error estúpido en mi camino.

Para hacerme más claro: javadoc de drawRect dice:

Public void drawRect (flotador a la izquierda, flotador superior, flotante a la derecha, fondo flotante, pintura)

Dibuja el Rect especificado usando la pintura especificada. El rectángulo se rellenará o enmarcará según el estilo de la pintura.

Left – El lado izquierdo del rectángulo a dibujar

Top – La parte superior del rectángulo a dibujar

Derecha – El lado derecho del rectángulo a dibujar

Bottom – La parte inferior del rectángulo a dibujar

Paint – La pintura usada para dibujar el rect

Por lo tanto, al escribir

 canvas.drawRect(x1, y1, x2, y2) 

Usted espera un rectángulo cuyas esquinas están en (x1, y1); (X _ {1}, y _ {2}); (X2, y1) y (x2, y2).

Android dice: ¡mal! Estarán en (x1, y1); (X _ {1}, y _ {2-1}); (X2-1, y1) y (x2-1, y2-1).

Para los curiosos: poner el recorte de lienzo:

 canvas.clipRect(x1, y1, x2, y2) 

Luego trate de dibujar un punto:

 canvas.drawPoint(x1, y1, paint); 

Y usted consigue un punto en la pantalla.

Luego intente en la esquina opuesta:

 canvas.drawPoint(x2, y2, paint); 

Nada aparece Nada aparecerá en las 2 esquinas restantes:

 canvas.drawPoint(x1, y2, paint); canvas.drawPoint(x2, y2, paint); 

¿Todavía no te sorprende a la gente?

Así que la conclusión es que Android trata las coordenadas derecha e inferior como exclusivas, lo que significa que al escribir:

 canvas.clipRect(x1, y1, x2, y2) 

Obtendrá los límites de recorte de (x1, y1, x2 – 1, y2 – 1). Lo mismo ocurre con cada método que toma las coordenadas derecha e inferior o los objetos Rect / RectF .

Su pregunta revela una inconsistencia en la API de dibujo de Android. Tu dices

Por lo tanto, si quiero dibujar una línea vertical que va exactamente desde beginY hasta endY (inclusive), tengo que hacer lo siguiente:

 canvas.drawLine(constX, beginY, constX, endY + 1) 

Note que no he añadido 1 a la posición final de X, sólo para terminar Y (xstays lo mismo que quiero una línea vertical).

La frase entre corchetes es en mi opinión la clave para entender la naturaleza de la inconsistencia:

También podría añadir 1 a la posición final X (o incluso a la posición inicial X!), Y obtendría exactamente la línea idéntica en píxeles. ¿Porqué es eso? Debido a que el algoritmo subyacente para transformar desde el concepto de "píxel izquierdo en / píxeles a la izquierda" de Android -concepto al "píxel de inicio y fin en" -concepto es el siguiente (mostrado sólo para x, para y es lo mismo):

 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; } 

El resultado de esto (en mi opinión sub-óptimo) la conversión es que la línea

 canvas.drawLine(150, 150, 149, 160, paint); 

Es exactamente paralelo a

 canvas.drawLine(150, 150, 151, 160, paint); 

Creo que todo el mundo espera una especie de V inversa, ya que los puntos finales están separados por al menos 1 píxel (su distancia es de dos píxeles) y los puntos de partida son idénticos.

Pero probado en varios dispositivos y versiones de Android, la 1ª línea perfectamente vertical está en la columna de píxeles 149 y la 2ª en la columna 150.

BTW: La transformación correcta para usar el "inicio y final del píxel en" -concept es:

 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); 

Su pregunta es esencialmente la respuesta para esto . Gracias.

Yo, por una parte, no estoy sorprendido por esto, y no lo querría de otra manera. Este es el por qué:

  • Es consistente con java.awt , javax.swing y otras APIs, así como los métodos Java básicos como String.substring(int, int) y List<?>.get(int) .

  • Es compatible con android.graphics.RectF , que no se preocupa por píxeles, ¿cómo puede tener una fracción de un píxel?

  • El API es conveniente:

    • Para un rectángulo de 40 × 30, instanciar Rect(0, 0, 40, 30)

    • Rect.right - Rect.left == Rect.width()

  • Las matemáticas y la geometría son más fáciles de esta manera. Por ejemplo, si desea dibujar un rectángulo centrado en el lienzo:

  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 () - izquierda;  // ¿Ves lo bonito que es esto?
     Int bottom = clipBounds.height () - arriba;  // ¡Esto no funcionaría si el fondo fuera inclusivo!
     Canvas.drawRect (izquierda, arriba, derecha, abajo); 

El API es correcto; La documentación de la API , por desgracia, sólo carece de detalle.

(En realidad, se menciona en el detalle para el Rect.contains(int, int) . Es lamentable que Google deje que el API salga por la puerta sin que las propias variables de campo estén documentadas.)

Si su fondo es negro, agregue una declaración paint.setColor(Color.RED); Y también tuviste un pase RectF rect = new RectF(100, 100, 100, 100); Todos los puntos son iguales, intente RectF rect = new RectF(100, 100, 200, 200);

O para line canvas.drawLine(10, 10, 10, 10 + 15, paint);

Su rect debe trabajar aletas, trate de añadir un poco de fondo, su línea es ahora kust un píxel, el último parámetro dos no es la longitud, es la posision final.

  • La capa de sombra funciona con el emulador pero no en un dispositivo real
  • android: Efecto de grabación de imágenes / Animación
  • Cómo establecer un punto de inicio utilizando path () en onDraw () utilizando canvas ..?
  • Android: colorea debajo del gráfico de líneas
  • Cómo obtener el ancho del texto cuando el ajuste de varios spannable
  • Android conjunto de la fuente personalizada a una pintura
  • Extraño dibujo de choque en lienzo en Android 4.0.3. A / libc: Señal fatal 11 (SIGSEGV)
  • Opacidad incremental, que desea una opacidad constante Vista de imagen con Drawable
  • Cómo dibujar texto con diferentes trazos y colores de relleno?
  • Color de fondo de relleno de lienzo de Android (aplicación de lona)
  • Línea dinámicamente generada con brillo efectivo
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.