package
com.lonshine.d_touchdemo;
import
java.util.ArrayList;
import
java.util.List;
import
android.content.Context;
import
android.os.Handler;
import
android.os.Message;
import
android.view.MotionEvent;
import
android.view.VelocityTracker;
import
android.view.ViewConfiguration;
/**
* 实现多点消息拦截,用于多个物体拖动等效果
* @author zeng
*/
public
class
MultiTouchGestureDetector
{
@SuppressWarnings
(
"unused"
)
private
static
final
String MYTAG =
"Alan"
;
public
static
final
String CLASS_NAME =
"MultiTouchGestureDetector"
;
/**
* 事件信息类 <br/>
* 用来记录一个手势
*/
private
class
EventInfo
{
private
MultiMotionEvent mCurrentDownEvent;
private
MultiMotionEvent mPreviousUpEvent;
private
boolean
mStillDown;
private
boolean
mInLongPress;
private
boolean
mAlwaysInTapRegion;
private
boolean
mAlwaysInBiggerTapRegion;
private
boolean
mIsDoubleTapping;
private
float
mLastMotionY;
private
float
mLastMotionX;
private
EventInfo(MotionEvent e)
{
this
(
new
MultiMotionEvent(e));
}
private
EventInfo(MultiMotionEvent me)
{
mCurrentDownEvent = me;
mStillDown =
true
;
mInLongPress =
false
;
mAlwaysInTapRegion =
true
;
mAlwaysInBiggerTapRegion =
true
;
mIsDoubleTapping =
false
;
}
public
void
recycle()
{
if
(mCurrentDownEvent !=
null
)
{
mCurrentDownEvent.recycle();
mCurrentDownEvent =
null
;
}
if
(mPreviousUpEvent !=
null
)
{
mPreviousUpEvent.recycle();
mPreviousUpEvent =
null
;
}
}
@Override
public
void
finalize()
{
this
.recycle();
}
}
/**
* 多点事件类 <br/>
* 将一个多点事件拆分为多个单点事件,并方便获得事件的绝对坐标 <br/>
* 绝对坐标用以在界面中找到触点所在的控件
*
* @author ray-ni
*/
public
class
MultiMotionEvent
{
private
MotionEvent mEvent;
private
int
mIndex;
private
MultiMotionEvent(MotionEvent e)
{
mEvent = e;
mIndex = (e.getAction() & MotionEvent.ACTION_POINTER_ID_MASK) >> MotionEvent.ACTION_POINTER_ID_SHIFT;
}
private
MultiMotionEvent(MotionEvent e,
int
idx)
{
mEvent = e;
mIndex = idx;
}
public
int
getAction()
{
int
action = mEvent.getAction() & MotionEvent.ACTION_MASK;
switch
(action)
{
case
MotionEvent.ACTION_POINTER_DOWN:
action = MotionEvent.ACTION_DOWN;
break
;
case
MotionEvent.ACTION_POINTER_UP:
action = MotionEvent.ACTION_UP;
break
;
}
return
action;
}
public
float
getX()
{
return
mEvent.getX(mIndex) + mEvent.getRawX() - mEvent.getX();
}
public
float
getY()
{
return
mEvent.getY(mIndex) + mEvent.getRawY() - mEvent.getY();
}
public
long
getEventTime()
{
return
mEvent.getEventTime();
}
public
int
getIndex()
{
return
mIndex;
}
public
int
getId()
{
return
mEvent.getPointerId(mIndex);
}
public
void
recycle()
{
if
(mEvent !=
null
)
{
mEvent.recycle();
mEvent =
null
;
}
}
}
public
interface
MultiTouchGestureListener
{
boolean
onDown(MultiMotionEvent e);
void
onShowPress(MultiMotionEvent e);
boolean
onSingleTapUp(MultiMotionEvent e);
void
onLongPress(MultiMotionEvent e);
boolean
onScroll(MultiMotionEvent e1, MultiMotionEvent e2,
float
distanceX,
float
distanceY);
boolean
onFling(MultiMotionEvent e1, MultiMotionEvent e2,
float
velocityX,
float
velocityY);
}
public
interface
MultiTouchDoubleTapListener
{
boolean
onSingleTapConfirmed(MultiMotionEvent e);
boolean
onDoubleTap(MultiMotionEvent e);
boolean
onDoubleTapEvent(MultiMotionEvent e);
}
private
static
List<EventInfo> sEventInfos =
new
ArrayList<EventInfo>(
10
);
private
static
List<EventInfo> sEventForDoubleTap =
new
ArrayList<EventInfo>(
5
);
private
int
mBiggerTouchSlopSquare =
20
*
20
;
private
int
mTouchSlopSquare;
private
int
mDoubleTapSlopSquare;
private
int
mMinimumFlingVelocity;
private
int
mMaximumFlingVelocity;
private
static
final
int
LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
private
static
final
int
TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
private
static
final
int
DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
private
static
final
int
DOUBLE_TAP_SLAP =
64
;
private
static
final
int
SHOW_PRESS =
1
;
private
static
final
int
LONG_PRESS =
2
;
private
static
final
int
TAP_SINGLE =
3
;
private
static
final
int
TAP_DOUBLE =
4
;
private
final
GestureHandler mHandler;
private
final
MultiTouchGestureListener mListener;
private
MultiTouchDoubleTapListener mDoubleTapListener;
private
boolean
mIsLongpressEnabled;
private
VelocityTracker mVelocityTracker;
private
class
GestureHandler
extends
Handler
{
GestureHandler()
{
super
();
}
GestureHandler(Handler handler)
{
super
(handler.getLooper());
}
@Override
public
void
handleMessage(Message msg)
{
int
idx = (Integer) msg.obj;
switch
(msg.what)
{
case
SHOW_PRESS:
{
if
(idx >= sEventInfos.size())
{
break
;
}
EventInfo info = sEventInfos.get(idx);
if
(info ==
null
)
{
break
;
}
mListener.onShowPress(info.mCurrentDownEvent);
break
;
}
case
LONG_PRESS:
{
if
(idx >= sEventInfos.size())
{
break
;
}
EventInfo info = sEventInfos.get(idx);
if
(info ==
null
)
{
break
;
}
dispatchLongPress(info, idx);
break
;
}
case
TAP_SINGLE:
{
if
(idx >= sEventInfos.size())
{
break
;
}
EventInfo info = sEventInfos.get(idx);
if
(info ==
null
)
{
break
;
}
if
(mDoubleTapListener !=
null
&& !info.mStillDown)
{
mDoubleTapListener.onSingleTapConfirmed(info.mCurrentDownEvent);
}
break
;
}
case
TAP_DOUBLE:
{
if
(idx >= sEventForDoubleTap.size())
{
break
;
}
EventInfo info = sEventForDoubleTap.get(idx);
if
(info ==
null
)
{
break
;
}
sEventForDoubleTap.set(idx,
null
);
break
;