Android:App在AndroidPlot中的触摸事件期间崩溃

时间:2013-06-11 10:46:47

标签: android multi-touch motionevent androidplot

我被认为是Android编程的新手,这只是我的第二个应用程序,我正在学习他们来的东西。所以如果有明显的疏忽,请耐心等待。

作为更大应用程序的一部分,我正在尝试使用AndroidPlot实现图形页面。现在我正在使用图表的手动输入值,因为我只是测试。我在AndroidPlot网站上使用了该教程,以便在我的图形页面中实现缩放和平移。但是,无论何时发生触摸事件,都会在模拟器和实际手机上发生。

以下是图表页面的代码:

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

   }

这是错误的logcat

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)

我一直在读书,没有任何帮助。这可能是因为我在动议事件方面很可怕,因此我可能错过了可能的解决方案。 在此先感谢任何帮助或指导。

3 个答案:

答案 0 :(得分:3)

好吧我决定采用另一种方式,使用由 Marcin Lepicki 制作的定制缩放和平移功能,他们非常友好地分享他的作品。只要编码正在考虑,他的缩放功能的方式就更容易理解和更整洁。

以下是其他任何可能遇到相同问题或希望使用 AndroidPlot

的代码的链接

AndroidPlot multitouch zoom & scroll

希望这有用。

答案 1 :(得分:2)

当没有两个时,您正在访问错误的索引event.getX(1)getY(1)

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

之前使用event.getPointerCount
  

MotionEvent在Android 2.0(Eclair)中进行了扩展,以报告有关多个指针的数据,并添加了新的操作来描述多点触控事件。 MotionEvent.getPointerCount()返回活动指针的数量。 getX和getY现在接受一个索引来指定要检索的指针数据。

查看Making Sense of Multitouch

答案 2 :(得分:0)

spacing()中的异常发生,因为切换案例块中缺少break。因此,即使您只使用一根手指,第二根手指的case MotionEvent.ACTION_POINTER_DOWN:也会被执行。

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