¿Cómo puedo pasar Touch Listeners a la vista personalizada para arrastrar y soltar?

Tengo una pregunta sobre el manejo de touch events para CustomView Estoy agregando vistas personalizadas dinámicamente al diseño (es decir, FrameLayout). Esas vistas personalizadas que tienen TouchListeners para tirar de puntos en las esquinas (se muestra en la imagen de abajo). Junto con eso tengo que arrastrar y soltar la vista total en la pantalla, si el usuario toca otros que los puntos de esquina (área de color en la imagen) tiene que arrastrar y soltar de la vista de lo contrario no, y también si el usuario toca fuera de ese Vista no quiero activar ningún oyente táctil.

Compruebe esta imagen

Puedo sacar esos puntos usando este código

 @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: if (topTouchArea.contains(event.getX(), event.getY())) { currentTouch = TOUCH_TOP; } else if (RightTouchArea.contains(event.getX(),event.getY())) { currentTouch = TOUCH_RIGHT; } else if (LeftTouchArea.contains(event.getX(),event.getY())) { currentTouch = TOUCH_LEFT; } else { return false; //Return false if user touches none of the corners } return true; case MotionEvent.ACTION_MOVE: switch (currentTouch) { case TOUCH_TOP: top.x = event.getX(); top.y = event.getY(); invalidate(); return true; case TOUCH_RIGHT: Right.x = event.getX(); Right.y = event.getY(); invalidate(); return true; case TOUCH_LEFT: Left.x = event.getX(); Left.y = event.getY(); invalidate(); return true; } case MotionEvent.ACTION_UP: switch (currentTouch) { case TOUCH_TOP: top.x = event.getX(); top.y = event.getY(); invalidate(); currentTouch = NONE; return true; case TOUCH_RIGHT: Right.x = event.getX(); Right.y = event.getY(); invalidate(); currentTouch = NONE; return true; case TOUCH_LEFT: Left.x = event.getX(); Left.y = event.getY(); invalidate(); currentTouch = NONE; return true; } return false; } return false; } 

¿Cómo puedo lograr este arrastrar y soltar junto con los caracteres anteriores de la CustomView ….

Utilizaría algún álgebra lineal para resolver este problema. Tiene 3 o más puntos que no forman parte de una línea ( independiente lineal ). Usted podría utilizar este hecho para determinar si el punto de contacto se encuentra dentro de la zona. Esto se hace más difícil cuanto más puntos tienes, así que necesitas transformar polígonos con más esquinas de 3 a un conjunto de triángulos, aplicando el siguiente procedimiento.

Así que tiene tres puntos A, B, C que definen un triángulo. A continuación, se definen tres líneas con su punto de contacto para obtener los vectores de dirección AT, BT, CT mientras que los A, B, Cs denotan los puntos de base de estas tres líneas de contacto .

A continuación, se definen las líneas de límite AB con el punto base A, AC con el punto base A (no importa si A o C es el punto base) y finalmente la línea CB con el punto base C. Así que permite resumir (letras grandes Denotando vectores mientras que las letras pequeñas indican escalares o factores):

Líneas fronterizas :

 a:X=A+f1*AB b:X=B+f2*BC c:X=C+f3*AC 

Líneas de contacto :

 ta:X=A+t1*AT tb:X=B+t2*BT tc:X=C+t3*CT 

Triángulo resultante con líneas de contacto e intersecciones

Ahora intersecar las líneas de contacto (rosa en la figura) con las líneas de borde (verde / rojo) en opuesto al punto base de la línea de contacto. Por ejemplo, usted necesita cruzar la línea 'ta' con la línea b para obtener el punto de intersección I3. Este punto alcanzará si se extiende el vector AT por el factor t1 .

Si este factor t1 es mayor que 1, el punto de contacto T se encuentra entre A e I3, la línea 'ta'. Si El factor t1 es menor que 1 T se encuentra fuera de la parte de línea A-I3.

Tendrás que hacer esto tres veces con la línea tb yc y tc y a. Cada vez que los puntos I (n) necesitarán ser menores que uno (donde es n está en {1,2,3}).

Si esta condición se aplica para las tres intersecciones, su punto de contacto está dentro del triángulo.

Usted obtendrá la Intersección resolviendo estos simples sistemas de ecuaciones:

El primero

 A+t1*AT = B+f2*BC <=> 0 = A+t1*AT - B - f2*BC 

Este sistema se parece a esto (donde x, y donar el componente de coordenadas específico):

 0 = xA + t1*(xT-xA) - xB - f2*(xC-xB) 0 = yA + t1*(yT-yA) - yB - f2*(yC-yB) 

El segundo

 B+t2*BT = C+f3*AC <=> 0 = B+t2*BT - C - f3*AC 

El tercero

 C+t3*CT = A+f1*AB <=> 0 = C+t3*CT - A - f1*AB 

Resolver estos tres sistemas le dará la respuesta si un punto se encuentra dentro de la zona o no. La solución necesita ser distintamente de 0 (¡Si 0 es la única solución, sus puntos están en la misma línea -> lineal dependiente )!

Basado en eso usted puede traducir sus todas las coordenadas de su objeto.

Como se mencionó anteriormente, tendrá que reducir hasta triángulos y aplicar este método a todos los subtriangles de un polígono. Si uno coincide con la condición (o dos o más si desea implementar multitáctil), su toque se encuentra dentro del área del objeto.

Esto es sólo tres cálculos pequeños y debe ser llamado en el controlador de eventos "Touch-Down" una vez. Puesto que usted sabe que usted tocó el área no hay necesidad de hacer todos estos cálculos mientras que mueve su dedo (s).

Acerca de la triangulación Esta es una cuestión más compleja que no ha sido contestada en una sola oración. De acuerdo con sus comentarios sobre la otra respuesta que no desea manejar polígonos simples, desea manejar formas más complejas que consisten en polígonos. Como por ejemplo su forma de estrella. Aquí sólo puede utilizar el método anterior, debe definir sus propios triángulos. Porque no es tan simple saber qué esquina pertenece a una cara y cuál no.

Una solución alternativa sería utilizar el llamado algoritmo Quick Hull para generar un casco convexo a partir de un conjunto de puntos. Esto le dará el contorno de la forma que los puntos de la esquina que debe utilizar para trianglelize. Si usted tiene algunas caras "unshaded" sólo manejarlos como tocado, así, si realmente desea manejar todos los puntos posibles.

Mi solución en tu caso estrella:

  • Definir triángulos de espiga

  • Utilice el método que mencioné anteriormente (resolviendo algunos LSEs) para determinar si uno es tocado o no.

Para todo lo demás :

Trianglize por el uso circuncircle de un triángulo. Hallando tres puntos que definen un círculo que no contiene otros puntos de contorno. La llamada Triangulación de Delaunay . Deje que este método encuentre sus triángulos. Si usted tiene algunas áreas sin sombra se puede definir un objeto de triángulo con la propiedad "táctil" o algo así, para que su algoritmo saber si el toque debe ser manejado o no.

Si usted maneja y actualiza el conjunto de triángulos correctamente no debe haber más preguntas sobre cómo manejar una forma cóncava.

Para su pentágono, pruebe lo siguiente:

  • Utilice el método de casco rápido y triangulación.

  • Si un usuario cambia una posición de puntos, actualiza los triángulos

  • lucro

En primer lugar, debe anular View.dispatchTouchEvent () para filtrar los toques fuera de triángulo. Echa un vistazo a mi respuesta aquí para obtener explicaciones sobre cómo hacer eso y por qué necesita utilizar ese método en particular y no OnTouchListener para hacer partes de la vista táctil transparente.

Entonces, en su OnTouchListener, usted deseará comparar coordenadas del tacto a las de sus puntos del triángulo para figurar fuera si el usuario golpea uno de los puntos o el interior del triángulo. También le sugiero que dé los puntos un poco de margen allí – es bastante difícil apuntar objetos pequeños en las pantallas táctiles, así que deje que el usuario tenga como un búfer de error de 4-8 píxeles para eso.

Por lo tanto, si el usuario golpea un punto – arrastrar el punto, si golpean el interior del triángulo y no uno de los puntos (es decir, el punto de contacto está dentro del triángulo, pero no está dentro de una de las localidades puntos) ver. Además, si el triángulo es tan pequeño que los bordes de los puntos se superponen (lo que resultará en un toque que coincida con más de una localidad puntual), escoja el más cercano.

En caso de que no estés familiarizado con la función de arrastrar y soltar api, he aquí un buen tutorial . Tendrá que llamar a startDrag () de su OnTouchListener si la acción es ACTION_DOWN y el punto de contacto está dentro del triángulo.

Para pre-honeycomb APIs, hay una biblioteca de arrastrar y soltar llamada android-dragarea . Hay un enlace a la aplicación de ejemplo en la documentación.

UPD Oh, no me di cuenta que estabas buscando algoritmos también. Usted quiere un algoritmo de punto en polígono, aquí hay algunas buenas soluciones, que van a trabajar para casi cualquier polígono complejo :

  • Ver movido pero aún en la esquina superior izquierda
  • Problema de renderización de ViewPager personalizado en ciertos dispositivos:
  • ¿Android View.postDelayed referencia de la fuga?
  • Android ViewPropertyAnimator no se escala al mismo tiempo
  • ImageView ser un cuadrado con ancho dinámico?
  • Agregar Haga clic en Evento en la lista expandible Vea al nino mientras extiende la actividad en lugar de la actividad?
  • Recepción de la barra de estado oculta / entrada de un evento de actividad de pantalla completa en un servicio
  • Arrastrar y soltar en android 3.x causa illegalStateException después de pequeño número en arrastra
  • Animación giratoria androide
  • Tabla de Donuts Android
  • FilePicker desde android webview trabajando sólo una vez
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.