我想让飞的手势检测工作在我的Android应用程序。
我有一个GridLayout,包含9个ImageViews。来源可以在这里找到:罗曼家伙的网格布局。
我从Romain Guy的Photostream应用程序中获取的文件只做了轻微的修改。
对于简单的点击情况,我只需要为每个ImageView设置onClickListener,我添加为实现View.OnClickListener的主要活动。实现能够识别投掷的东西似乎要复杂得多。我猜这是因为它可能跨越不同的观点?
If my activity implements
OnGestureListener I don't know how to
set that as the gesture listener for
the Grid or the Image views that I
add.
public class SelectFilterActivity extends Activity implements
View.OnClickListener, OnGestureListener { ...
If my activity implements
OnTouchListener then I have no
onFling method to override (it has
two events as parameters allowing me
to determine if the fling was
noteworthy).
public class SelectFilterActivity extends Activity implements
View.OnClickListener, OnTouchListener { ...
If I make a custom View, like GestureImageView that extends ImageView I don't know how to tell the activity that a fling has occurred from the view. In any case, I tried this and the methods weren't called when I touched the screen.
我真的需要一个跨视图工作的具体例子。我应该在什么时候以及如何附加这个侦听器?我还需要能够检测单个点击。
// Gesture detection
mGestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
int dx = (int) (e2.getX() - e1.getX());
// don't accept the fling if it's too short
// as it may conflict with a button push
if (Math.abs(dx) > MAJOR_MOVE && Math.abs(velocityX) > Math.absvelocityY)) {
if (velocityX > 0) {
moveRight();
} else {
moveLeft();
}
return true;
} else {
return false;
}
}
});
是否有可能在我的屏幕上方放置一个透明的视图来捕捉投掷?
如果我选择不从XML膨胀我的子图像视图,我可以通过手势检测器作为构造函数参数到我创建的ImageView的新子类吗?
这是一个非常简单的活动,我试图让飞动检测工作:SelectFilterActivity(改编自photostream)。
我一直在看这些资料:
检测手势-教程
SDK文档
计算器的代码
到目前为止,什么都没用,我希望能得到一些指导。
您可以使用droidQuery库来处理投掷、单击、长时间单击和自定义事件。实现是建立在我之前的答案下面,但droidQuery提供了一个光滑的,简单的语法:
//global variables private boolean isSwiping = false;
private SwipeDetector.Direction swipeDirection = null;
private View v;//must be instantiated before next call.
//swipe-handling code
$.with(v).swipe(new Function() {
@Override
public void invoke($ droidQuery, Object... params) {
if (params[0] == SwipeDetector.Direction.START)
isSwiping = true;
else if (params[0] == SwipeDetector.Direction.STOP) {
if (isSwiping) { isSwiping = false;
if (swipeDirection != null) {
switch(swipeDirection) {
case DOWN : //TODO: Down swipe complete, so do something
break;
case UP :
//TODO: Up swipe complete, so do something
break;
case LEFT :
//TODO: Left swipe complete, so do something
break;
case RIGHT :
//TODO: Right swipe complete, so do something
break;
default : break;
}
} }
}
else {
swipeDirection = (SwipeDetector.Direction) params[0];
}
}
});
原来的答案
这个答案使用了其他答案的组合。它由SwipeDetector类组成,该类有一个用于监听事件的内部接口。我还提供了一个RelativeLayout来展示如何覆盖一个视图的onTouch方法,以允许滑动事件和其他检测到的事件(如单击或长时间单击)。
SwipeDetector
package self.philbrown;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
/**
* Detect Swipes on a per-view basis. Based on original code by Thomas Fankhauser on StackOverflow.com,
* with adaptations by other authors (see link).
* @author Phil Brown
* @see <a href="http://stackoverflow.com/questions/937313/android-basic-gesture-detection">android-basic-gesture-detection</a>
*/
public class SwipeDetector implements View.OnTouchListener
{
/**
* The minimum distance a finger must travel in order to register a swipe event.
*/
private int minSwipeDistance;
/** Maintains a reference to the first detected down touch event. */
private float downX, downY;
/** Maintains a reference to the first detected up touch event. */
private float upX, upY;
/** provides access to size and dimension contants */
private ViewConfiguration config;
/**
* provides callbacks to a listener class for various swipe gestures.
*/
private SwipeListener listener;
public SwipeDetector(SwipeListener listener)
{
this.listener = listener;
}
/**
* {@inheritDoc}
*/
public boolean onTouch(View v, MotionEvent event)
{
if (config == null)
{
config = ViewConfiguration.get(v.getContext());
minSwipeDistance = config.getScaledTouchSlop();
}
switch(event.getAction())
{
case MotionEvent.ACTION_DOWN:
downX = event.getX();
downY = event.getY();
return true;
case MotionEvent.ACTION_UP:
upX = event.getX();
upY = event.getY();
float deltaX = downX - upX;
float deltaY = downY - upY;
// swipe horizontal?
if(Math.abs(deltaX) > minSwipeDistance)
{
// left or right
if (deltaX < 0)
{
if (listener != null)
{
listener.onRightSwipe(v);
return true;
}
}
if (deltaX > 0)
{
if (listener != null)
{
listener.onLeftSwipe(v);
return true;
}
}
}
// swipe vertical?
if(Math.abs(deltaY) > minSwipeDistance)
{
// top or down
if (deltaY < 0)
{
if (listener != null)
{
listener.onDownSwipe(v);
return true;
}
}
if (deltaY > 0)
{
if (listener != null)
{
listener.onUpSwipe(v);
return true;
}
}
}
}
return false;
}
/**
* Provides callbacks to a registered listener for swipe events in {@link SwipeDetector}
* @author Phil Brown
*/
public interface SwipeListener
{
/** Callback for registering a new swipe motion from the bottom of the view toward its top. */
public void onUpSwipe(View v);
/** Callback for registering a new swipe motion from the left of the view toward its right. */
public void onRightSwipe(View v);
/** Callback for registering a new swipe motion from the right of the view toward its left. */
public void onLeftSwipe(View v);
/** Callback for registering a new swipe motion from the top of the view toward its bottom. */
public void onDownSwipe(View v);
}
}
Swipe Interceptor视图
package self.philbrown;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.widget.RelativeLayout;
import com.npeinc.module_NPECore.model.SwipeDetector;
import com.npeinc.module_NPECore.model.SwipeDetector.SwipeListener;
/**
* View subclass used for handling all touches (swipes and others)
* @author Phil Brown
*/
public class SwipeInterceptorView extends RelativeLayout
{
private SwipeDetector swiper = null;
public void setSwipeListener(SwipeListener listener)
{
if (swiper == null)
swiper = new SwipeDetector(listener);
}
public SwipeInterceptorView(Context context) {
super(context);
}
public SwipeInterceptorView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SwipeInterceptorView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onTouchEvent(MotionEvent e)
{
boolean swipe = false, touch = false;
if (swiper != null)
swipe = swiper.onTouch(this, e);
touch = super.onTouchEvent(e);
return swipe || touch;
}
}
我做的有点不同,并编写了一个额外的检测器类来实现View.onTouchListener
onCreateis简单地把它添加到最低的布局,就像这样:
ActivitySwipeDetector activitySwipeDetector = new ActivitySwipeDetector(this);
lowestLayout = (RelativeLayout)this.findViewById(R.id.lowestLayout);
lowestLayout.setOnTouchListener(activitySwipeDetector);
在id。lowestLayout是id。在布局层次结构中最低的视图使用了xxx, lowestLayout被声明为RelativeLayout
然后是实际的活动滑动检测器类:
public class ActivitySwipeDetector implements View.OnTouchListener {
static final String logTag = "ActivitySwipeDetector";
private Activity activity;
static final int MIN_DISTANCE = 100;
private float downX, downY, upX, upY;
public ActivitySwipeDetector(Activity activity){
this.activity = activity;
}
public void onRightSwipe(){
Log.i(logTag, "RightToLeftSwipe!");
activity.doSomething();
}
public void onLeftSwipe(){
Log.i(logTag, "LeftToRightSwipe!");
activity.doSomething();
}
public void onDownSwipe(){
Log.i(logTag, "onTopToBottomSwipe!");
activity.doSomething();
}
public void onUpSwipe(){
Log.i(logTag, "onBottomToTopSwipe!");
activity.doSomething();
}
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN: {
downX = event.getX();
downY = event.getY();
return true;
}
case MotionEvent.ACTION_UP: {
upX = event.getX();
upY = event.getY();
float deltaX = downX - upX;
float deltaY = downY - upY;
// swipe horizontal?
if(Math.abs(deltaX) > Math.abs(deltaY))
{
if(Math.abs(deltaX) > MIN_DISTANCE){
// left or right
if(deltaX > 0) { this.onRightSwipe(); return true; }
if(deltaX < 0) { this.onLeftSwipe(); return true; }
}
else {
Log.i(logTag, "Horizontal Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
return false; // We don't consume the event
}
}
// swipe vertical?
else
{
if(Math.abs(deltaY) > MIN_DISTANCE){
// top or down
if(deltaY < 0) { this.onDownSwipe(); return true; }
if(deltaY > 0) { this.onUpSwipe(); return true; }
}
else {
Log.i(logTag, "Vertical Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
return false; // We don't consume the event
}
}
return true;
}
}
return false;
}
}
对我来说真的很好!
感谢幕府将军,他的代码我适应了我的情况。
让你的活动像往常一样实现onclicklistener:
public class SelectFilterActivity extends Activity implements OnClickListener {
private static final int SWIPE_MIN_DISTANCE = 120;
private static final int SWIPE_MAX_OFF_PATH = 250;
private static final int SWIPE_THRESHOLD_VELOCITY = 200;
private GestureDetector gestureDetector;
View.OnTouchListener gestureListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* ... */
// Gesture detection
gestureDetector = new GestureDetector(this, new MyGestureDetector());
gestureListener = new View.OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
};
}
class MyGestureDetector extends SimpleOnGestureListener {
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
try {
if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH)
return false;
// right to left swipe
if(e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(SelectFilterActivity.this, "Left Swipe", Toast.LENGTH_SHORT).show();
} else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE && Math.abs(velocityX) > SWIPE_THRESHOLD_VELOCITY) {
Toast.makeText(SelectFilterActivity.this, "Right Swipe", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
// nothing
}
return false;
}
@Override
public boolean onDown(MotionEvent e) {
return true;
}
}
}
将你的手势监听器附加到你添加到主布局中的所有视图上;
// Do this for each view added to the grid
imageView.setOnClickListener(SelectFilterActivity.this);
imageView.setOnTouchListener(gestureListener);
敬畏地看着你被覆盖的方法被击中,包括activity的onClick(View v)和手势监听器的onFling。
public void onClick(View v) {
Filter f = (Filter) v.getTag();
FilterFullscreenActivity.show(this, input, f);
}
“抛舞”后的舞蹈是可选的,但也是鼓励的。
我稍微修改和修复了Thomas Fankhauser的解决方案
整个系统由两个文件组成,SwipeInterface和ActivitySwipeDetector
SwipeInterface.java
import android.view.View;
public interface SwipeInterface {
public void bottom2top(View v);
public void left2right(View v);
public void right2left(View v);
public void top2bottom(View v);
}
探测器
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
public class ActivitySwipeDetector implements View.OnTouchListener {
static final String logTag = "ActivitySwipeDetector";
private SwipeInterface activity;
static final int MIN_DISTANCE = 100;
private float downX, downY, upX, upY;
public ActivitySwipeDetector(SwipeInterface activity){
this.activity = activity;
}
public void onRightToLeftSwipe(View v){
Log.i(logTag, "RightToLeftSwipe!");
activity.right2left(v);
}
public void onLeftToRightSwipe(View v){
Log.i(logTag, "LeftToRightSwipe!");
activity.left2right(v);
}
public void onTopToBottomSwipe(View v){
Log.i(logTag, "onTopToBottomSwipe!");
activity.top2bottom(v);
}
public void onBottomToTopSwipe(View v){
Log.i(logTag, "onBottomToTopSwipe!");
activity.bottom2top(v);
}
public boolean onTouch(View v, MotionEvent event) {
switch(event.getAction()){
case MotionEvent.ACTION_DOWN: {
downX = event.getX();
downY = event.getY();
return true;
}
case MotionEvent.ACTION_UP: {
upX = event.getX();
upY = event.getY();
float deltaX = downX - upX;
float deltaY = downY - upY;
// swipe horizontal?
if(Math.abs(deltaX) > MIN_DISTANCE){
// left or right
if(deltaX < 0) { this.onLeftToRightSwipe(v); return true; }
if(deltaX > 0) { this.onRightToLeftSwipe(v); return true; }
}
else {
Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
}
// swipe vertical?
if(Math.abs(deltaY) > MIN_DISTANCE){
// top or down
if(deltaY < 0) { this.onTopToBottomSwipe(v); return true; }
if(deltaY > 0) { this.onBottomToTopSwipe(v); return true; }
}
else {
Log.i(logTag, "Swipe was only " + Math.abs(deltaX) + " long, need at least " + MIN_DISTANCE);
v.performClick();
}
}
}
return false;
}
}
它是这样使用的:
ActivitySwipeDetector swipe = new ActivitySwipeDetector(this);
LinearLayout swipe_layout = (LinearLayout) findViewById(R.id.swipe_layout);
swipe_layout.setOnTouchListener(swipe);
在实现Activity时,你需要实现来自SwipeInterface的方法,你可以找到在哪个视图上调用了Swipe事件。
@Override
public void left2right(View v) {
switch(v.getId()){
case R.id.swipe_layout:
// do your stuff here
break;
}
}