Android,canScrollVertically从未调用过ImageView

时间:2015-11-18 20:29:49

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

我正在使用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;
}
永远不会打电话给

。在canScrollHorizontally方法中放置相同的Toast消息会在每次滑动(水平或垂直)上显示消息。

为什么canScrollVertically从未被调用?

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

提前感谢您的帮助。有人都知道Mike Ortiz!?

2 个答案:

答案 0 :(得分:0)

我提出的解决方案如下:

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根据需要滑动。

答案 1 :(得分:0)

就我而言,我正在检查我的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

的一些困惑