I'm considered a newbie in android programming, this is only my second application and i'm learning things as they come. So if there are obvious oversights, bear with me.

As a part of a larger application I'm trying to implement a graph page using AndroidPlot. For now I'm using manually input values for the graph as i'm only testing. I used the tutorial on the AndroidPlot website in order to implements zoom and pan in my graph page. However anytime a touch event occurs, on the emulator and on the actual phone.

Here is the code for the graph page:

public class Graph extends Activity implements OnTouchListener{

Campaign_Db myCamp = new Campaign_Db(this);
private XYPlot myXY;
private PointF minXY;
private PointF maxXY;
ArrayList<String> array_date;
ArrayList<Integer> array_cap;
Array arr_date;
Integer[] arr_cap;
float x,y;

@Override
protected void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    setContentView(R.layout.graph);

    myXY = (XYPlot) findViewById(R.id.myXYplot);
    myXY.setOnTouchListener(this);

    getdata();

    // Create a couple arrays of y-values to plot:
    Number[] series1Numbers = {978307200,  // 2001
            1009843200, // 2002
            1041379200, // 2003
            1072915200, // 2004
            1104537600  // 2005
            };
    Number[] series2 = {1,2,3,4,5};



    // Turn the above arrays into XYSeries':
    XYSeries series1 = new SimpleXYSeries(
            Arrays.asList(series1Numbers),
            Arrays.asList(series2),
            "cups of water");



    // Create a formatter to use for drawing a series using LineAndPointRenderer:
    @SuppressWarnings("deprecation")
    LineAndPointFormatter series1Format = new LineAndPointFormatter(
            Color.rgb(0, 200, 0),                   // line color
            Color.rgb(0, 100, 0),                   // point color
            null);                                  // fill color (none)

    // add a new series' to the xyplot:
    myXY.addSeries(series1, series1Format);


    // reduce the number of range labels
    myXY.setTicksPerRangeLabel(1);
    myXY.setTicksPerDomainLabel(2);

    // get rid of decimal points in our range labels:
    myXY.setRangeValueFormat(new DecimalFormat("0"));

    // customize our domain/range labels
    myXY.setDomainLabel("Date");
    myXY.setRangeLabel("# of cups");

    myXY.setDomainValueFormat(new Format() {

        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        // create a simple date format that draws on the year portion of our timestamp.
        // see http://download.oracle.com/javase/1.4.2/docs/api/java/text/SimpleDateFormat.html
        // for a full description of SimpleDateFormat.
        private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy");

        @Override
        public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {

            // because our timestamps are in seconds and SimpleDateFormat expects milliseconds
            // we multiply our timestamp by 1000:
            long timestamp = ((Number) obj).longValue() * 1000;
            Date date = new Date(timestamp);
            return dateFormat.format(date, toAppendTo, pos);
        }


        @Override
        public Object parseObject(String string, ParsePosition position) {
            // TODO Auto-generated method stub
            return null;
        }


    });


    // by default, AndroidPlot displays developer guides to aid in laying out your plot.
    // To get rid of them call disableAllMarkup():
    myXY.disableAllMarkup();

    myXY.redraw();  
  //Set of internal variables for keeping track of the boundaries
        myXY.calculateMinMaxVals();
        minXY=new PointF(myXY.getCalculatedMinX().floatValue(),myXY.getCalculatedMinY().floatValue());
        maxXY=new PointF(myXY.getCalculatedMaxX().floatValue(),myXY.getCalculatedMaxY().floatValue());

}
// Definition of the touch states
    static final int NONE = 0;
    static final int ONE_FINGER_DRAG = 1;
    static final int TWO_FINGERS_DRAG = 2;
    int mode = NONE;

    PointF firstFinger;
    float lastScrolling;
    float distBetweenFingers;
    float lastZooming;

    public boolean onTouch(View view, MotionEvent event) {

        switch (event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_DOWN: // Start gesture
            firstFinger = new PointF(event.getX(), event.getY());
            mode = ONE_FINGER_DRAG;
            break;
        case MotionEvent.ACTION_UP: 
        case MotionEvent.ACTION_POINTER_UP:
            //When the gesture ends, a thread is created to give inertia to the scrolling and zoom 
            Timer t = new Timer();
                t.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        while(Math.abs(lastScrolling)>1f || Math.abs(lastZooming-1)<1.01){ 
                        lastScrolling*=.8;
                        scroll(lastScrolling);
                        lastZooming+=(1-lastZooming)*.2;
                        zoom(lastZooming);
                        myXY.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
                            myXY.redraw();

                    }
                    }
                }, 0);


        case MotionEvent.ACTION_POINTER_DOWN: // second finger
            distBetweenFingers = spacing(event);
            // the distance check is done to avoid false alarms
            if (distBetweenFingers > 5f) {
                mode = TWO_FINGERS_DRAG;
            }
            break;
        case MotionEvent.ACTION_MOVE:
            if (mode == ONE_FINGER_DRAG) {
                PointF oldFirstFinger=firstFinger;
                firstFinger=new PointF(event.getX(), event.getY());
                lastScrolling=oldFirstFinger.x-firstFinger.x;
                scroll(lastScrolling);
                lastZooming=(firstFinger.y-oldFirstFinger.y)/myXY.getHeight();
                if (lastZooming<0)
                    lastZooming=1/(1-lastZooming);
                else
                    lastZooming+=1;
                zoom(lastZooming);
                myXY.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
                myXY.redraw();

            } else if (mode == TWO_FINGERS_DRAG) {
                float oldDist =distBetweenFingers; 
                distBetweenFingers=spacing(event);
                lastZooming=oldDist/distBetweenFingers;
                zoom(lastZooming);
                myXY.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
                myXY.redraw();
            }
            break;
        }
        return true;
    }




    private void zoom(float scale) {
        float domainSpan = maxXY.x  - minXY.x;
        float domainMidPoint = maxXY.x  - domainSpan / 2.0f;
        float offset = domainSpan * scale / 2.0f;
        minXY.x=domainMidPoint- offset;
        maxXY.x=domainMidPoint+offset;
    }

    private void scroll(float pan) {
        float domainSpan = maxXY.x  - minXY.x;
        float step = domainSpan / myXY.getWidth();
        float offset = pan * step;
        minXY.x+= offset;
        maxXY.x+= offset;
    }

    private float spacing(MotionEvent event) {

        x = event.getX(0) - event.getX(1);
        y = event.getY(0) - event.getY(1);


        return FloatMath.sqrt(x * x + y * y);
    }

     public boolean onInterceptTouchEvent(MotionEvent ev) {
            try {
                return super.onTouchEvent(ev);
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
                return false;
            } catch (ArrayIndexOutOfBoundsException e) {
                e.printStackTrace();
                return false;
            }
        }

   }

And here is the logcat for the error

06-11 14:59:31.764: E/AndroidRuntime(2203): FATAL EXCEPTION: main
06-11 14:59:31.764: E/AndroidRuntime(2203): java.lang.IllegalArgumentException: pointerIndex out of range
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.MotionEvent.nativeGetAxisValue(Native Method)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.MotionEvent.getX(MotionEvent.java:1974)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at com.example.damavand.Graph.spacing(Graph.java:231)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at com.example.damavand.Graph.onTouch(Graph.java:176)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.View.dispatchTouchEvent(View.java:5559)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2058)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1827)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:1931)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1390)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.app.Activity.dispatchTouchEvent(Activity.java:2364)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:1879)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.View.dispatchPointerEvent(View.java:5766)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewRootImpl.deliverPointerEvent(ViewRootImpl.java:2890)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2466)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewRootImpl.processInputEvents(ViewRootImpl.java:845)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.view.ViewRootImpl.handleMessage(ViewRootImpl.java:2475)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.os.Handler.dispatchMessage(Handler.java:99)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.os.Looper.loop(Looper.java:137)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at android.app.ActivityThread.main(ActivityThread.java:4441)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at java.lang.reflect.Method.invokeNative(Native Method)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at java.lang.reflect.Method.invoke(Method.java:511)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
06-11 14:59:31.764: E/AndroidRuntime(2203):     at dalvik.system.NativeStart.main(Native Method)

I have been reading around and nothing have been helpful. This might be because I am horrible when it comes to motion events and because of that I might have missed on probable solutions. Thanks in advance for any help or guidance.

有帮助吗?

解决方案

Alright I decided to go about this another way and use a custom-built zoom and pan function made by Marcin Lepicki who had been kind enough to share his work. His way of approching the zoom function is much easier to follow and also tidier as long as coding is considering.

Here is the link to his code for anyone else who might be facing the same issue or looking to work with AndroidPlot

AndroidPlot multitouch zoom & scroll

Hope this has been helpful.

其他提示

You are accessing to a wrong index event.getX(1) and getY(1) when there are not two

private float spacing(MotionEvent event) {

    x = event.getX(0) - event.getX(1);
    y = event.getY(0) - event.getY(1);


    return FloatMath.sqrt(x * x + y * y);
}

Use event.getPointerCount before

MotionEvent was extended in Android 2.0 (Eclair) to report data about multiple pointers and new actions were added to describe multitouch events. MotionEvent.getPointerCount() returns the number of active pointers. getX and getY now accept an index to specify which pointer’s data to retrieve.

Take a look at Making Sense of Multitouch

The exception in spacing() occures because there is a break missing in the switch case block. So the follwing case MotionEvent.ACTION_POINTER_DOWN: for the second finger is executed even you use only one finger.

    case MotionEvent.ACTION_POINTER_UP:
        //When the gesture ends, a thread is created to give inertia to the scrolling and zoom 
        Timer t = new Timer();
            t.schedule(new TimerTask() {
                @Override
                public void run() {
                    while(Math.abs(lastScrolling)>1f || Math.abs(lastZooming-1)<1.01){ 
                    lastScrolling*=.8;
                    scroll(lastScrolling);
                    lastZooming+=(1-lastZooming)*.2;
                    zoom(lastZooming);
                    myXY.setDomainBoundaries(minXY.x, maxXY.x, BoundaryMode.AUTO);
                        myXY.redraw();

                }
                }
            }, 0);
            break;   // <== the MISSING break!

    case MotionEvent.ACTION_POINTER_DOWN: // second finger
        distBetweenFingers = spacing(event);
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top