0

私は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 は、このSO 投稿をモデルにしています。

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));
    }

}

通常の ImageViews では、うまく機能します。必要に応じて、ネストされた ViewPager を垂直方向にスクロールしながら、水平方向の ViewPager を左右にスワイプできます。垂直 ViewPager に対する 1 つの変更 (垂直 ViewPager 内の任意の場所からの水平スクロールを可能にするため) は、次のとおりです。

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

小さな変更で、うまく機能します。

垂直 ViewPager の内容がカスタム TouchImageView である場合に問題が発生します。左右のスワイプは引き続きうまく機能しますが、垂直方向のスワイプは、画像の右端がデバイス画面の右側に並んでいる場合にのみ機能します. これはcanScrollHorizontally、TouchImageView クラス内のオーバーライドが原因です。

引数はint directionx または 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呼び出されないのですか?

ビューで画像が底になっているときと、ユーザーが上にスワイプしているときの両方を検出したいと思います。これら 2 つの条件が満たされると、からfalsecanScrollHorizontallyを返し、垂直方向の ViewPager が適切にスクロールできるようになります。

助けてくれてありがとう。マイク・オルティス知ってる人いますか!?

4

2 に答える 2

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;

私がやったことは、 global を設定すること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 をスワイプできます。

于 2015-11-18T21:06:34.070 に答える
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

于 2019-09-10T15:46:30.050 に答える