Back to project page custom-touch-examples.
The source code is released under:
Copyright (c) 2012 Wireless Designs, LLC Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in ...
If you think the Android project custom-touch-examples listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.
package com.examples.customtouch.widget; // w w w . ja va2 s . c o m import android.content.Context; import android.util.AttributeSet; import android.view.GestureDetector; import android.view.GestureDetector.SimpleOnGestureListener; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; import android.widget.FrameLayout; import android.widget.OverScroller; public class TwoDimensionGestureScrollView extends FrameLayout { private GestureDetector mDetector; private OverScroller mScroller; /* Positions of the last motion event */ private float mInitialX, mInitialY; /* Drag threshold */ private int mTouchSlop; public TwoDimensionGestureScrollView(Context context) { super(context); init(context); } public TwoDimensionGestureScrollView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public TwoDimensionGestureScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context); } private void init(Context context) { mDetector = new GestureDetector(context, mListener); mScroller = new OverScroller(context); //Get system constants for touch thresholds mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); } /* * Override the measureChild... implementations to guarantee that the child view * gets measured to be as large as it wants to be. The default implementation will * force some children to be only as large as this view. */ @Override protected void measureChild(View child, int parentWidthMeasureSpec, int parentHeightMeasureSpec) { int childWidthMeasureSpec; int childHeightMeasureSpec; childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } @Override protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( lp.leftMargin + lp.rightMargin, MeasureSpec.UNSPECIFIED); final int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec( lp.topMargin + lp.bottomMargin, MeasureSpec.UNSPECIFIED); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { // This is called at drawing time by ViewGroup. We use // this method to keep the fling animation going through // to completion. int x = mScroller.getCurrX(); int y = mScroller.getCurrY(); scrollTo(x, y); // Keep on drawing until the animation has finished. postInvalidate(); } } //Override scrollTo to do bounds checks on any scrolling request @Override public void scrollTo(int x, int y) { // we rely on the fact the View.scrollBy calls scrollTo. if (getChildCount() > 0) { View child = getChildAt(0); x = clamp(x, getWidth() - getPaddingRight() - getPaddingLeft(), child.getWidth()); y = clamp(y, getHeight() - getPaddingBottom() - getPaddingTop(), child.getHeight()); if (x != getScrollX() || y != getScrollY()) { super.scrollTo(x, y); } } } /* * Utility method to initialize the Scroller and start redrawing */ public void fling(int velocityX, int velocityY) { if (getChildCount() > 0) { int height = getHeight() - getPaddingBottom() - getPaddingTop(); int width = getWidth() - getPaddingLeft() - getPaddingRight(); int bottom = getChildAt(0).getHeight(); int right = getChildAt(0).getWidth(); mScroller.fling(getScrollX(), getScrollY(), velocityX, velocityY, 0, Math.max(0, right - width), 0, Math.max(0, bottom - height)); invalidate(); } } /* * Utility method to assist in doing bounds checking */ private int clamp(int n, int my, int child) { if (my >= child || n < 0) { /* my >= child is this case: * |--------------- me ---------------| * |------ child ------| * or * |--------------- me ---------------| * |------ child ------| * or * |--------------- me ---------------| * |------ child ------| * * n < 0 is this case: * |------ me ------| * |-------- child --------| * |-- mScrollX --| */ return 0; } if ((my+n) > child) { /* this case: * |------ me ------| * |------ child ------| * |-- mScrollX --| */ return child-my; } return n; } //Listener to handle all the touch events private SimpleOnGestureListener mListener = new SimpleOnGestureListener() { public boolean onDown(MotionEvent e) { //Cancel any current fling if (!mScroller.isFinished()) { mScroller.abortAnimation(); } return true; } public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { //Call a helper method to start the scroller animation fling((int)-velocityX/2, (int)-velocityY/2); return true; } public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { //Any view can be scrolled by simply calling its scrollBy() method scrollBy((int)distanceX, (int)distanceY); return true; } }; /* * Monitor touch events passed down to the children and * intercept as soon as it is determined we are dragging */ @Override public boolean onInterceptTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mInitialX = event.getX(); mInitialY = event.getY(); //Feed the down event to the detector so it has // context when/if dragging begins mDetector.onTouchEvent(event); break; case MotionEvent.ACTION_MOVE: final float x = event.getX(); final float y = event.getY(); final int yDiff = (int) Math.abs(y - mInitialY); final int xDiff = (int) Math.abs(x - mInitialX); //Verify that either difference is enough to be a drag if (yDiff > mTouchSlop || xDiff > mTouchSlop) { //Start capturing events return true; } break; } return super.onInterceptTouchEvent(event); } /* * Feed all touch events we receive to the detector for * processing. */ @Override public boolean onTouchEvent(MotionEvent event) { return mDetector.onTouchEvent(event); } }