2013-06-23 17 views
10

Tworzę niestandardowy widok, który jest rodzajem widoku postępu suwaka łuku. Mogę rysować mniej więcej łuku w oparciu o miejsce, w którym użytkownik dotyka (na x oś) przez obliczenie przeciągnięcia, robię to przez pierwsze obliczenie wartości procentowej, w której użytkownik dotknął osi X.,0% byłoby całkowicie na lewo, a 100% byłoby na całej linii w prawo.Widok niestandardowy drawArc, wykryj dotyk użytkownika na ścieżce rysowania łuku

Chcę zrobić to o krok dalej, zamiast rysować łuk na podstawie współrzędnej x, którą użytkownik naciśnie, chcę ją przesunąć tylko wtedy, gdy użytkownik dotknie rzeczywistej ścieżki rysowania łuku, aby było bardziej realistyczne . Jestem wciąż nowe do własnych poglądów i moje matematyki jest ograniczone, ale jeśli dostanę jakieś wskazówki byłbym wdzięczny dzięki

how it looks when user moves there finger on the area of the rectangle as a percentage along the x axis

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

Odpowiedz

9

Czy to praca dla Ciebie? Nie potrzebujesz dużo matematyki. Możesz obliczyć odległość punktu dotyku od środka łuku (jest to okrąg, więc jest to łatwe) i porównać to z promieniem, którego używasz. Dzięki temu dowiesz się, czy punkt znajduje się na łuku (prawie, patrz poniżej dla pełnego przypadku).

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 

} 
+0

Chciałbym wybrać 2 najlepsze odpowiedzi, będę klikał, dziękuję miliony – brux

+0

nie martw się, z przyjemnością pomogę :) – Plato

+0

Zmieniłem zdanie i zrobiłem to poprawnie, ponieważ wciąż mam w pełni w głowie to wokół, ale twój Kod działa, czy jesteś na IRC przypadkiem? – brux

11

Chcę aby poruszać się tylko wtedy, gdy użytkownik dotyka rzeczywistej łuk ścieżce holowniczej

Na początku onTouchEvent() trzeba sprawdzić czy xPosition i yPosition spełniają pewne warunki . Jeśli tak, robisz rzeczy, które teraz robisz. Jeśli nie, return true.

Stan:

Chcemy sprawdzić, czy x, y są w tym szarym łukiem tle:

enter image description here

Policzmy odległość od (x, y) do tego punktu (a, b) w środku:

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

distance() jest prosty euklidesowa DISTA NCE pomiędzy punktów (x, y) i (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 są w tym szarym tle łukowego, jeśli y > Y && dist >= r && dist <= R.

+3

+1 za rysunek :) – Plato

Powiązane problemy