0

На основании следующих фрагментов кода мне было интересно, почему жест onFling не распознается для GridView кнопок (я использую кнопки вместо других представлений по личным причинам):onFly жест не распознан для GridView кнопок

Вот мой MainActivity:

public class MainActivity extends AppCompatActivity { 
    private GridView grid; 
    GestureDetector gDetector; 

    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; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 

     grid = (GridView)findViewById(R.id.grid); 

     // 4X4 grid. 
     grid.setNumColumns(4); 

     ArrayList<Button> mButtons = new ArrayList<Button>(); 
     Button button = null; 

     for (int i = 0; i < 16; i++) { 
      button = new Button(this); 
      button.setText(i + ""); 
      mButtons.add(button); 
     } 

     grid.setAdapter(new CustomAdapter(this, mButtons)); 

     gDetector = new GestureDetector(this, new SimpleOnGestureListener() { 
      @Override 
      public boolean onDown(MotionEvent event) { 
       return true; 
      } 

      @Override 
      public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
           float velocityY) { 
       final int position = grid.pointToPosition(Math.round(e1.getX()), Math.round(e1.getY())); 

       if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) { 
        if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH 
         || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) { 
         return false; 
        } 
        if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE) { 
         Toast.makeText(MainActivity.this, "top at index " + position, Toast.LENGTH_SHORT).show(); 
        } else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE) { 
         Toast.makeText(MainActivity.this, "bottom at index " + position, Toast.LENGTH_SHORT).show(); 
        } 
       } else { 
        if (Math.abs(velocityX) < SWIPE_THRESHOLD_VELOCITY) { 
         return false; 
        } 
        if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE) { 
         Toast.makeText(MainActivity.this, "left at index " + position, Toast.LENGTH_SHORT).show(); 
        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE) { 
         Toast.makeText(MainActivity.this, "right at index " + position, Toast.LENGTH_SHORT).show(); 
        } 
       } 

       return super.onFling(e1, e2, velocityX, velocityY); 
      } 
     }); 
} 

@Override 
public boolean onTouchEvent(MotionEvent event) { 
    return gDetector.onTouchEvent(event); 
} 

... вот мой CustomAdapter:

public class CustomAdapter extends BaseAdapter { 
    private ArrayList<Button> mButtons = null; 
    private Context ctx; 

    public CustomAdapter(Context ctx, ArrayList<Button> button) { 
     this.ctx = ctx; 
     this.mButtons = button; 
    } 

    @Override 
    public int getCount() { 
     return mButtons.size(); 
    } 

    @Override 
    public Object getItem(int position) {return (Object) mButtons.get(position);} 

    @Override 
    public long getItemId(int position) { 

     // Position and id are synonymous. 
     return position; 
    } 

    @Override 
    public View getView(int position, View convertView, ViewGroup parent) { 
     Button button; 

     // Assigns a view to convertView should it be null, otherwise, casts convertView to the 
     // correct View type. 
     if (convertView == null) { 
      button = mButtons.get(position); 
     } else { 
      button = (Button) convertView; 
     } 

     return button; 
    } 
} 

... и, видимо, красть, onFling, будет только получить признание на в нижней половине экрана, когда GridView настроен на wrap_content, тогда как салфетка не будет работать вообще, когда GridView настроен на match_parent. Вот сетка устанавливается на wrap_content с салфеткой работает только в замкнутом квадрате следующим образом:

enter image description here

Очень высокая оценка.

+1

Ваш 'onTouchEvent()' в Activity не был вызван для переходов по кнопкам, потому что кнопки потребляли события касания. Возможно, вам придется переопределить класс родительского представления (например, gridview) и указать ваш интерес к перехвату события касания, используя onInterceptTouchEvent(). См. Http://stackoverflow.com/questions/9181529/detect-fling-gesture-over-clickable-items – headuck

+0

@headuck Благодарим за комментарий. Хотя вы могли бы предоставить мне пример кода, который переопределит GridView на основе фрагментов, которые у меня выше? Я был бы очень признателен. – DaveNOTDavid

ответ

1

Поскольку кнопки потребляли события касания до достижения onTouchEvent() активности, детектор жестов никогда не получает событий над кнопками. Возможно, вам придется переопределить класс родительского представления кнопок, например. GridView, чтобы перехватить события касания.

Ниже приведен пример класса GestureDetectGridView, который распространяется на GridView.

public class GestureDetectGridView extends GridView { 
    private GestureDetector gDetector; 
    private boolean flingConfirmed = false; 
    private float mTouchX; 
    private float mTouchY; 

    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; 

    // Boiler plate view constructors 
    public GestureDetectGridView(Context context) { 
     super(context); 
     init(context); 
    } 

    public GestureDetectGridView(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(context); 
    } 

    public GestureDetectGridView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     init(context); 
    } 

    @TargetApi(21) 
    public GestureDetectGridView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { 
     super(context, attrs, defStyleAttr, defStyleRes); 
     init(context); 
    } 

    // Sets up gesture detector, moved from your original MainActivity 

    private void init(final Context context) { 
     gDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() { 
      @Override 
      public boolean onDown(MotionEvent event) { 
       return true; 
      } 

      @Override 
      public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
            float velocityY) { 
       final int position = GestureDetectGridView.this.pointToPosition(Math.round(e1.getX()), Math.round(e1.getY())); 

       if (Math.abs(e1.getY() - e2.getY()) > SWIPE_MAX_OFF_PATH) { 
        if (Math.abs(e1.getX() - e2.getX()) > SWIPE_MAX_OFF_PATH 
          || Math.abs(velocityY) < SWIPE_THRESHOLD_VELOCITY) { 
         return false; 
        } 
        if (e1.getY() - e2.getY() > SWIPE_MIN_DISTANCE) { 
         Toast.makeText(context, "top at index " + position, Toast.LENGTH_SHORT).show(); 
        } else if (e2.getY() - e1.getY() > SWIPE_MIN_DISTANCE) { 
         Toast.makeText(context, "bottom at index " + position, Toast.LENGTH_SHORT).show(); 
        } 
       } else { 
        if (Math.abs(velocityX) < SWIPE_THRESHOLD_VELOCITY) { 
         return false; 
        } 
        if (e1.getX() - e2.getX() > SWIPE_MIN_DISTANCE) { 
         Toast.makeText(context, "left at index " + position, Toast.LENGTH_SHORT).show(); 
        } else if (e2.getX() - e1.getX() > SWIPE_MIN_DISTANCE) { 
         Toast.makeText(context, "right at index " + position, Toast.LENGTH_SHORT).show(); 
        } 
       } 
       return super.onFling(e1, e2, velocityX, velocityY); 
      } 
     }); 
    } 

    @Override 
    public boolean onInterceptTouchEvent(MotionEvent ev) { 
     int action = ev.getActionMasked(); 
     gDetector.onTouchEvent(ev); 
     // Determine whether we need to start intercepting all touch events 
     // such that the buttons would no longer receive further touch events 
     // Return true if the fling gesture is confirmed 
     if (action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP) { 
      flingConfirmed = false; 
     } else if (action == MotionEvent.ACTION_DOWN) { 
      mTouchX = ev.getX(); 
      mTouchY = ev.getY(); 
     } else { 
      // short cut just in case 
      if (flingConfirmed) { 
       return true; 
      } 
      float dX = (Math.abs(ev.getX() - mTouchX)); 
      float dY = (Math.abs(ev.getY() - mTouchY)); 
      if ((dX > SWIPE_MIN_DISTANCE) || (dY > SWIPE_MIN_DISTANCE)) { 
       flingConfirmed = true; 
       return true; 
      } 
     } 
     return super.onInterceptTouchEvent(ev); 
    } 

    @Override 
    public boolean onTouchEvent(MotionEvent ev) { 
     return gDetector.onTouchEvent(ev); 
    } 

} 

Чтобы использовать это, изменить GridView макет/активность, чтобы использовать этот класс, вместо этого, и удалить коды обнаружения жеста от активности (которые были перемещены в этот класс). Возможно, вам придется использовать обратные вызовы и т. Д. Для обработки событий вне представления.