【问题标题】:Android, canScrollVertically never called for ImageViewAndroid,canScrollVertically 从未调用 ImageView
【发布时间】:2015-11-18 20:29:48
【问题描述】:

我正在使用 Mike Ortiz 的 TouchImageView

在其中,canScrollHorizontally 被覆盖:

@Override
public boolean canScrollHorizontally(int direction) {
    matrix.getValues(m);
    float x = m[Matrix.MTRANS_X];
    float y = m[Matrix.MTRANS_Y];

    if (getImageWidth() < viewWidth) {
        return false;

    } else if (x >= -1 && direction < 0) {
        return false;

    } else if (Math.abs(x) + viewWidth + 1 >= getImageWidth() && direction > 0) {
        return false;
    }

    return true;
}

这按预期工作。我可以将 TouchImageView 放在 ViewPager 中,然后滚动缩放的图像,但当我到达图像的边缘时,也可以在 ViewPager 中向右/向左滑动。

但我想要的是嵌套在常规 ViewPager 中的垂直 ViewPager。垂直 ViewPager 仿照this SO post:

public class VerticalViewPager extends ViewPager {

    public VerticalViewPager(Context context) {
        super(context);
        init();
    }

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

    private void init() {
        // The majority of the magic happens here
        setPageTransformer(true, new VerticalPageTransformer());
        // The easiest way to get rid of the overscroll drawing that happens on the left and right
        setOverScrollMode(OVER_SCROLL_NEVER);
    }

    private class VerticalPageTransformer implements ViewPager.PageTransformer {

        @Override
        public void transformPage(View view, float position) {

            if (position < -1) { // [-Infinity,-1)
                // This page is way off-screen to the left.
                view.setAlpha(0);

            } else if (position <= 1) { // [-1,1]
                view.setAlpha(1);

                // Counteract the default slide transition
                view.setTranslationX(view.getWidth() * -position);

                //set Y position to swipe in from top
                float yPosition = position * view.getHeight();
                view.setTranslationY(yPosition);

            } else { // (1,+Infinity]
                // This page is way off-screen to the right.
                view.setAlpha(0);
            }
        }
    }

    /**
     * Swaps the X and Y coordinates of your touch event.
     */
    private MotionEvent swapXY(MotionEvent ev) {
        float width = getWidth();
        float height = getHeight();

        float newX = (ev.getY() / height) * width;
        float newY = (ev.getX() / width) * height;

        ev.setLocation(newX, newY);

        return ev;
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev){
        boolean intercepted = super.onInterceptTouchEvent(swapXY(ev));
        swapXY(ev); // return touch coordinates to original reference frame for any child views
        return intercepted;
    }

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

}

使用常规的 ImageView,效果很好。我可以在水平 ViewPager 中向左/向右滑动,同时也可以根据需要在嵌套的 ViewPager 中垂直滚动。对垂直 ViewPager 的一种修改(允许从垂直 ViewPager 中的任何位置进行水平滚动)是:

@Override
public boolean canScrollHorizontally(int direction) {
    return false;
}

小改动,效果很好。

当垂直 ViewPager 的内容是自定义的 TouchImageViews 时,问题就来了。向右/向左滑动仍然很有效,但垂直滑动仅在图像的右边缘与设备屏幕的右侧对齐时才有效。这是由于 TouchImageView 类中的 canScrollHorizontally 覆盖造成的。

int direction 参数不考虑 x 或 y。 y 正向滑动与 x 正向滑动无法区分。

我想做的是覆盖canScrollVertically 方法,以检测何时发生垂直滑动,但该方法永远不会被调用。即使只是一个快速测试,例如:

@Override
public boolean canScrollVertically(int direction) {
    matrix.getValues(m);

    Toast.makeText(context, "vertical", Toast.LENGTH_SHORT).show();


    return true;
}

永远不会被调用。将相同的 Toast 消息放入 canScrollHorizontally 方法中会在每次滑动(水平或垂直)时显示该消息。

为什么从未调用过canScrollVertically

我想检测图像何时在视图中触底,以及用户何时向上滑动。当满足这两个条件时,我可以从canScrollHorizontally 返回 false 并允许垂直 ViewPager 正确滚动。

提前感谢您的帮助。有人认识迈克·奥尔蒂斯吗?

【问题讨论】:

    标签: android android-viewpager android-imageview android-scroll touchimageview


    【解决方案1】:

    所以我想出的解决方案如下。

    TouchImageView 中,Mike 有一个自定义类

    private class PrivateOnTouchListener implements OnTouchListener
    

    其中有以下块:

        case MotionEvent.ACTION_MOVE:
            if (state == State.DRAG) {
                float deltaX = curr.x - last.x;
                float deltaY = curr.y - last.y;
    
                ... etc ... 
            }
            break;
    

    我所做的是设置一个全局boolean verticalDrag;。使用上面的块,我检查以确保 deltaY 比 deltaX 足够大(即垂直拖动/滑动)

    if(Math.abs(deltaY) > (Math.abs(deltaX) * sensitivity)){
        verticalDrag = true;
    }else{
        verticalDrag = false;
    }
    

    灵敏度由编码人员自行决定分配。真正的垂直滑动通常会有几个像素的左/右偏差 - 很难仅在一个方向或另一个方向上滑动。因此,灵敏度可能非常高(即 5 到 10,或更高,具体取决于测试),并且仍会触发。

    回到canScrollHorizontally 方法内,我只是添加:

    float y = m[Matrix.MTRANS_Y];
    
    else if(Math.abs(y) + viewHeight + 1 >= getImageHeight() && verticalDrag){
        return false;
    }
    

    它允许垂直 ViewPager 根据需要滑动。

    【讨论】:

      【解决方案2】:

      在我的例子中,我正在检查我的 scrollView(包含文本)是否可以垂直滚动在初始化活动时。在手机上,它会滚动,但在平板电脑上却不能。 canScrollVertically 正在返回我不正确的值,因为它还无法确定。我通过在OnGlobalLayoutListener 中调用它解决了这个问题。

      (科特林)

      override fun onActivityCreated(savedInstanceState: Bundle?) {
          super.onActivityCreated(savedInstanceState)
      
              // Must use onGlobalLayout or else canScrollVertically will not return the correct value because the layout hasn't been made yet
              scrollView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
      
                  override fun onGlobalLayout() {
                      // If the scrollView can scroll, disable the accept menu item button
                      if ( scrollView.canScrollVertically(1) || scrollView.canScrollVertically(-1) )
                          acceptMenuItem?.isEnabled = false
      
                      // Remove itself after onGlobalLayout is first called or else it would be called about a million times per second
                      scrollView.viewTreeObserver.removeOnGlobalLayoutListener(this)
                  }
              })
        }
      

      我的用例是显示使用条款。在用户滚动到底部之前,我不希望启用接受按钮。我知道这已经晚了,但我希望这能解决一些关于 canScrollVertically 的困惑

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-06-18
        • 2023-04-06
        • 2011-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多