public HotSpotNodeView( Context context ) { super( context ); this.setClickable( true ); this.setFocusable( false ); this.setWillNotDraw( false ); // Layouts have onDraw() disabled by default. rectPaint = new Paint( Paint.ANTI_ALIAS_FLAG ); rectPaint.setColor( otherColor ); rectPaint.setStyle( Paint.Style.STROKE ); rectPaint.setStrokeWidth( 1 ); rectPaint.setStrokeCap( Paint.Cap.ROUND ); rectPaint.setStrokeJoin( Paint.Join.ROUND ); rectPaint.setStrokeMiter( 1 ); rectPaint.setPathEffect( new DashPathEffect( new float[] {1f, 2f}, 0 ) ); gestureDetector = new GestureDetector( context, new SimpleOnGestureListener() { @Override public boolean onSingleTapUp( MotionEvent e ) { if ( hotspotNode != null ) { for ( ZoneHolder zoneHolder : zoneHolders ) { float paddedX = e.getX() + HotSpotNodeView.this.getPaddingLeft(); float paddedY = e.getY() + HotSpotNodeView.this.getPaddingTop(); if ( zoneHolder.currentZoneRect.contains( paddedX, paddedY ) ) { if ( zoneHolder.imageRef != null ) { zoneHolder.revealed = !zoneHolder.revealed; HotSpotNodeView.this.invalidate(); // Keep looping through layers? Sure. } else if ( zoneHolder.linkTarget != -1 ) { HotSpotNodeView.this.getNavCtrl().setReaderNode( zoneHolder.linkTarget ); break; } } } } return true; } @Override public boolean onScroll( MotionEvent e1, MotionEvent e2, float distanceX, float distanceY ) { handleScroll( distanceX, distanceY ); // Delta since last scroll, NOT since initial drag. return true; } @Override public boolean onDown( MotionEvent e ) { return true; // Necessary for all other gesture methods to work. } }); scaleDetector = new ScaleGestureDetector( context, new SimpleOnScaleGestureListener() { public boolean onScale( ScaleGestureDetector detector ) { float newScale = scale; newScale *= detector.getScaleFactor(); newScale = Math.max( minScale, Math.min( newScale, 2.0f ) ); handleScale( newScale ); return true; } }); this.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch( View v, MotionEvent e ) { if ( gestureDetector.onTouchEvent( e ) ) { return true; } else if ( scaleDetector.onTouchEvent( e ) ) { return true; } // Check MotionEvent.ACTION_UP here if interested in end-of-scroll. return false; } }); }