触摸/拖动某些视图时禁用viewpager

时间:2016-08-29 16:01:54

标签: android android-fragments android-viewpager mpandroidchart

使用与this question的答案类似的内容,我尝试在用户滑过特定项目时禁用ViewPager滑动操作。有问题的视图是来自MPAndroidChart库的可滚动图表,所以我自然不希望视图寻呼机干扰图表的滚动。

我遇到的问题是ViewPager经常会有" onInterceptTouch"在我想要的视图上调用onTouchListener之前调用。

在这段代码中,我在按下/未按下视图时进行录制:

private long lastDown;

private long lastUp;

...

public void foo(){

    barChart.setOnTouchListener(new View.OnTouchListener() {
      @Override
      public boolean onTouch(View v, MotionEvent event) {

        System.out.println("AAA");

        if(event.getAction() == MotionEvent.ACTION_DOWN){
          lastDown = System.currentTimeMillis();
        }else if(event.getAction() == MotionEvent.ACTION_UP){
          lastUp = System.currentTimeMillis();
        }

    return false;
      }
    });
}

在这段代码中,我确定是否选择了视图:

  public boolean isGraphTouched(){
    return lastDown > lastUp;
  }

在这段代码中,我重写了onInterceptTouchEvent方法:

  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    System.out.println("BBB");
    return isGraphSelected() ? super.onInterceptTouchEvent(ev) : false;
  }

如果您注意到printlines,则会在之前调用onInterceptTouchEvent方法...

Println

我能想到解决这个问题的唯一方法是制作一个方法来检查图形是否存在于运动事件的坐标处(虽然我不确定这是否可能)然后使用它确定寻呼机是否可以转换。

2 个答案:

答案 0 :(得分:1)

我设法通过合并其他帖子中的this answer来解决我的问题。该代码允许您获取给定视图的坐标并将它们与您自己的坐标进行比较。

在我的CustomViewPager类中,我实现了上面提到的:

  private boolean isPointInsideView(float x, float y, View view) {
    int location[] = new int[2];
    view.getLocationOnScreen(location);
    int viewX = location[0];
    int viewY = location[1];

    return ((x > viewX && x < (viewX + view.getWidth())) && (y > viewY && y < (viewY + view.getHeight())));
  }

然后我有一个方法返回一个布尔值,它检查几个条件并返回true / false,如果寻呼机应该能够被刷过:

  public boolean canSwipe(float x, float y) {
    boolean canSwipe = true;
    if (launchActivity.isReady(MainScreenPagerAdapter.STAT_PAGE)) {
      FragmentStatistics fragmentStatistics = (FragmentStatistics) launchActivity.getPageAdapter().instantiateItem(this, MainScreenPagerAdapter.STAT_PAGE);
      View chart = fragmentStatistics.getView().findViewById(R.id.chart);
      canSwipe = !isPointInsideView(x, y, chart) || !fragmentStatistics.isGraphPannable();
    }
    return canSwipe;
  }

然后,当然,我覆盖了onInterceptTouchEvent,如下所示:

  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    return canSwipe(ev.getX(), ev.getY()) ? super.onInterceptTouchEvent(ev) : false;
  }

现在,图表可以完全平移,而传感器根本不会干扰它。

完整的CustomViewPager代码:

public class CustomViewPager extends ViewPager {

  /** Reference to the launch activity */
  private LaunchActivity launchActivity;

  /**
   * Constructor to call the super constructor
   *
   * @param context The application context
   * @param attrs   The attributes
   */
  public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
  }

  /**
   * Sets object reference for the {@code launchActivity}
   *
   * @param launchActivity The LaunchActivity to be set
   */
  public void set(LaunchActivity launchActivity) {
    this.launchActivity = launchActivity;
  }

  /**
   * Determines if the pager can be swiped based off the x and y inputs provided, as well as if the
   * barchart can be panned or not.
   *
   * @param x The x coordinate to check
   * @param y The y coordinate to check
   * @return True if the ViewPager will continue with normal swiping action.
   */
  public boolean canSwipe(float x, float y) {
    boolean canSwipe = true;
    if (launchActivity.isReady(MainScreenPagerAdapter.STAT_PAGE)) {
      FragmentStatistics fragmentStatistics = (FragmentStatistics) launchActivity.getPageAdapter().instantiateItem(this, MainScreenPagerAdapter.STAT_PAGE);
      View chart = fragmentStatistics.getView().findViewById(R.id.chart);
      canSwipe = !isPointInsideView(x, y, chart) || !fragmentStatistics.isGraphPannable();
    }
    return canSwipe;
  }

  /**
   * Takes x and y coordinates and compares them to the coordinates of the passed view. Returns true if the passed coordinates
   * are within the range of the {@code view}
   *
   * @param x    The x coordinate to compare
   * @param y    The y coordinate to compare
   * @param view The view to check the coordinates of
   * @return True if the x and y coordinates match that of the view
   */
  private boolean isPointInsideView(float x, float y, View view) {
    int location[] = new int[2];
    view.getLocationOnScreen(location);
    int viewX = location[0];
    int viewY = location[1];

    // point is inside view bounds
    return ((x > viewX && x < (viewX + view.getWidth())) && (y > viewY && y < (viewY + view.getHeight())));
  }

  /**
   * Override of the onInterceptTouchEvent which allows swiping to be disabled when chart is selected
   *
   * @param ev The MotionEvent object
   * @return Call to super if true, otherwise returns false
   */
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    return canSwipe(ev.getX(), ev.getY()) ? super.onInterceptTouchEvent(ev) : false;
  }

}

答案 1 :(得分:1)

我设法通过将函数parent.requestDisallowInterceptTouchEvent(true);放置在子视图onTouchEvent()内使其工作。这样,如果发生滚动并由ViewPager处理,则View不允许他的任何父母隐瞒他的触摸事件。

但是,在我的情况下,我有一个ViewPager,其中带有可拖动的自定义视图,我希望在不改变ViewPager更改页面的情况下进行移动。

我在代码方面的解决方案:(Kotlin)

view.setOnTouchListener { v, event ->
    parent.requestDisallowInterceptTouchEvent(true);
    //Drag and drop handling is here and the rest of the event logic
}

希望这对您也有帮助。