Vista personalizada drawArc, detecta el tacto del usuario en la trayectoria de trazado del arco

Estoy creando una vista personalizada que es una especie de vista de progreso de arco deslizante. Puedo dibujar más o menos del arco basado en donde el usuario toca (en el eje x) calculando el barrido, lo hago calculando primero el percept Donde el usuario tocó a lo largo del eje x..0% sería todo el camino a la izquierda y el 100% sería todo el camino a la derecha.

Quiero llevar esto un paso más allá, en lugar de dibujar el arco basado en la coordenada x que el usuario presiona, quiero hacer que se mueva sólo cuando el usuario toca el camino de trazado de arco real, por lo que es más realista. Todavía soy nuevo a las vistas de encargo y mi matemáticas es limitado pero si consigo algunos extremidades agradecería agradecido

Cómo se ve cuando el usuario se mueve allí dedo sobre el área del rectángulo como un porcentaje a lo largo del eje x

class ArcProgress extends View { Context cx; float width; float height; float center_x, center_y; final RectF oval = new RectF(); final RectF touchArea = new RectF(); float sweep = 0; float left, right; int percent = 0; public ArcProgress(Context context) { super(context); cx = context; } public int getPercentage() { return percent; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); setBackgroundColor(0xfff0ebde); width = (float) getWidth(); height = (float) getHeight(); float radius; if (width > height) { radius = height / 3; } else { radius = width / 3; } Paint paint = new Paint(); paint.setAntiAlias(true); paint.setColor(0xffd2c8b6); paint.setStrokeWidth(35); paint.setStyle(Paint.Style.STROKE); center_x = width / 2; center_y = height / 2; left = center_x - radius; float top = center_y - radius; right = center_x + radius; float bottom = center_y + radius; oval.set(left, top, right, bottom); //this is the background arc, it remains constant canvas.drawArc(oval, 180, 180, false, paint); paint.setStrokeWidth(10); paint.setColor(0xffe0524d); //this is the red arc whichhas its sweep argument manipulated by on touch canvas.drawArc(oval, 180, sweep, false, paint); } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_MOVE) { float xPosition = event.getX(); float yPosition = event.getY(); if (oval.contains(xPosition, yPosition)) { float x = xPosition - left; float s = x * 100; float b = s / oval.width(); percent = Math.round(b); sweep = (180 / 100.0f) * (float) percent; invalidate(); } else { if (xPosition < left) { percent = 0; sweep = (180 / 100.0f) * (float) percent; invalidate(); } if (xPosition > right) { percent = 100; sweep = (180 / 100.0f) * (float) percent; invalidate(); } } } return true; } } 

¿Esto funciona para tí? No necesitas un montón de matemáticas. Puede calcular la distancia del punto de contacto desde el centro de su arco (es un círculo por lo que es fácil) y compararlo con el radio que está utilizando. Eso le dirá si el punto está en el arco (casi, ver abajo para el caso completo).

 Point touchEv = ...; Point circleCenter = ...; //the radius of the circle you used to draw the arc float circleRadius = ...; //how far from the arc should a touch point treated as it's on the arc float maxDiff = getResources().getDimension(R.dimen.max_diff_dp); //calculate the distance of the touch point from the center of your circle float dist = Math.pow(touchEv.x-circleCenter.x,2) + Math.pow(touchEv.y- circleCenter.y,2) dist = Math.sqrt(dist); //We also need the bounding rect of the top half of the circle (the visible arc) Rect topBoundingRect = new Rect(circleCenter.x - circleRadius, circleCenter.y - circleRadius, circleCenter.x + circleRadius, circleCenter.y); if (Math.abs(dist - circleRadius) <= maxDiff && topBoundingRect.contains(touchEv.x, touchEv.y)) { // the user is touching the arc } 

Quiero hacer que se mueva sólo cuando el usuario toca la trayectoria de trazado de arco real

Al principio de onTouchEvent() debe comprobar si xPosition y yPosition cumplen alguna condición. Si es así, usted hace las cosas, que está haciendo ahora. Si no, return true .

Condición:

Queremos comprobar si x, y están en ese fondo de arco gris:

Introduzca aquí la descripción de la imagen

Calculemos una distancia de (x, y) a ese punto (a, b) en el centro:

 final dist = distance(x, y, a, b) 

distance() es una distancia euclídea simple entre los puntos (x, y) y (a, b):

 double distance(int x, int y, int a, int b) { return Math.sqrt((x - a) * (x - a) + (y - b) * (y - b)); } 

X, y están en ese fondo de arco gris, si y > Y && dist >= r && dist <= R

  • Cómo ajustar el tamaño de los desplegables de azulejos
  • Qué es "serviceAccountKey.json" que se refiere en el tutorial de notificaciones de dispositivo a dispositivo de Firebase
  • Android elegir una imagen de la galería en PreferenceScreen?
  • ¿Cómo depurar el código fuente de java cuando implemento un detector personalizado para Lint?
  • ¿Cómo puedo usar Proguard en Eclipse para proyectos Java NO-Android?
  • Creando funciones globales en android
  • GetString fuera de un contexto o actividad
  • N-Puzzle pseudo-aleatorio barajar?
  • Comunicación asíncrona entre Javascript y Phonegap Plugin
  • Fuente impresionante en la vista de lista de Android no funciona
  • Retrofit GSON serialize Fecha de json string en java.util.date
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.