web-dev-qa-db-ja.com

android:ViewPagerおよびHorizo​​ntalScrollVIew

HorizontalScrollViewの中にViewPagerがあります。 HorizontalScrollViewrequestDisallowInterceptTouchEvent(true);を設定しましたが、ViewPagerは依然としてタッチイベントをインターセプトしていることがあります。ビューの親と祖先がタッチイベントをインターセプトするのを防ぐために使用できる別のコマンドはありますか?

注:HorizontalScrollViewは画面の半分しか占有しません。

30
Android Noob

同じ問題がありました。私の解決策は:

  1. ViewPagerのサブクラスを作成し、childIdというプロパティを追加します。
  2. childIdプロパティのセッターを作成し、HorizontalScrollViewのIDを設定します。
  3. ViewPagerのサブクラスでonInterceptTouchEvent()をオーバーライドし、childIdプロパティが0より大きい場合はその子を取得し、イベントがHorizontalScrollViewエリアにある場合はfalseを返します。

コード

_public class CustomViewPager extends ViewPager {

    private int childId;    

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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (childId > 0) {
            View scroll = findViewById(childId);
            if (scroll != null) {
                Rect rect = new Rect();
                scroll.getHitRect(rect);
                if (rect.contains((int) event.getX(), (int) event.getY())) {
                    return false;
                }
            }
        }
        return super.onInterceptTouchEvent(event);
    }

    public void setChildId(int id) {
        this.childId = id;
    }
}
_

onCreate()メソッド

_viewPager.setChildId(R.id.horizontalScrollViewId);
adapter = new ViewPagerAdapter(this);
viewPager.setAdapter(adapter);
_

この助けを願っています

35
Fede

返信いただきありがとうございます。ソリューションを少し変更し、ネストされたViewPagersを機能させることができました。

public class CustomViewPager extends ViewPager {
    private int childId;

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
     @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (childId > 0) {          
            ViewPager pager = (ViewPager)findViewById(childId);

            if (pager != null) {           
                pager.requestDisallowInterceptTouchEvent(true);
            }

        }

        return super.onInterceptTouchEvent(event);
    }

    public void setChildId(int id) {
        this.childId = id;
    }
}
8
Android Noob

したがって、この質問はかなり古いことはわかっていますが、ここに投稿されたものよりもいくつかの特別な利点があると思う解決策があります。発生する可能性のある状況の1つは、ViewPager内に複数のHorizo​​ntalScrollViewを含めることができます(これを行う)。その後、子タッチの競合を常に確認できるように、ViewPagerに大量のIDを提供する必要があります。

ViewPagerのソースを分析したところ、「canScroll」と呼ばれるこのメソッドを使用して、子ビューをスクロールできるかどうかを判断しました。幸いなことに、静的でも最終でもなかったので、単にオーバーライドすることができました。そのメソッド内で、「boolean ViewCompat.canScrollHorizo​​ntally(View、int)」が呼び出されました(SDK <14に対して常にfalseを返すメソッド)。私の解決策は次のとおりです。

public class CustomViewPager extends ViewPager {

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    public CustomViewPager(Context context) {
        super(context);
    }
    protected boolean canScroll(View v, boolean checkV, int dx, int x, int y) {
        return super.canScroll(v, checkV, dx, x, y) || (checkV && customCanScroll(v));
    }
    protected boolean customCanScroll(View v) {
        if (v instanceof HorizontalScrollView) {
            View hsvChild = ((HorizontalScrollView) v).getChildAt(0);
            if (hsvChild.getWidth() > v.getWidth())
                return true;
        }
        return false;
   }
}

したがって、ViewPager内に別のクラスのViewがあり、水平方向のドラッグも受け取る必要がある場合は、customCanScroll(View)を変更するだけで、タッチをインターセプトしないかどうかを返すことができます。

現在のビューでも「スクロール可能性」をチェックする必要がある場合、ブール値checkVはtrueです。そのため、これもチェックする必要があります。

これがこのような将来の問題に役立つことを願っています(またはより良い解決策がある場合、またはAndroidプラットフォーム、私に知らせてください)。

7
Victor Elias

すでに問題を解決したかどうかはわかりません。しかし、上記の答えはどれも適切に機能しません。ですから、苦しみを持って解決策を模索している人々にとって必要だと思います。

実際、ViewGroupでのタッチイベントの処理に関する公式ドキュメントを読むと、ソリューションは非常に簡単です。

まず、の使用法を理解する必要があります

ViewParent.requestDisallowInterceptTouchEvent(boolean) 、親Viewでこれを呼び出して、 onInterceptTouchEvent(MotionEvent) でタッチイベントをインターセプトしないことを示します。

次に、イベントをインターセプトし、Horizo​​ntalScrollViewの親ViewGroupがそれ以上イベントをディスパッチしないようにする必要があります。

そのため、Horizo​​ntalScrollViewのOnToushListenerを設定します。タッチダウンおよび移動イベントを検出し、requestDisallowInterceptTouchEvent(true)をその親に設定します(ViewPagerまたはsth else)イベントがHorizo​​ntalScrollViewによって処理されることを確認します。

もちろん、これらのコードをCustomHorizo​​ntalScrollViewコンポーネントに入れて再利用できるようにすることもできます。

それが役に立てば幸いです。 ;-)

horizontalScrollView.setOnTouchListener(new View.OnTouchListener() {
float rawX;
int mTouchSlop =  ViewConfiguration.get(getActivity()).getScaledTouchSlop();

@Override
public boolean onTouch(View v, MotionEvent event) {
    switch (event.getActionMasked()) {
        case MotionEvent.ACTION_DOWN:
            v.getParent().requestDisallowInterceptTouchEvent(true);
            rawX = event.getRawX();
            break;
        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            v.getParent().requestDisallowInterceptTouchEvent(false);
            rawX = 0f;
            break;
        case MotionEvent.ACTION_MOVE:
            if (Math.abs(rawX - event.getRawX()) > mTouchSlop)
                v.getParent().requestDisallowInterceptTouchEvent(true);
            break;
    }
    return false;
}
6
Ryan Hoo

ここに私のために働いた別の解決策があります、

カスタムViewPagerを作成する

public class NoScrollViewPager extends ViewPager {

    private boolean scrollDisable = false;


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

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(scrollDisable) {
            return false;
        } else {
            return super.onInterceptTouchEvent(ev);
        }
    }

    public void disableScroll() {
        scrollDisable = true;
    }

    public void enableScroll() {
        scrollDisable = false;
    }



}

次に、OnTouchListenerをアイテムに追加します。これは、Horizo​​ntalScrollView、Gallery、またはタッチされたときにビューページャーにスクロールさせたくないものでした。

gf.setOnTouchListener(new OnTouchListener() {

    @Override
    public boolean onTouch(View arg0,
            MotionEvent ev) {
        switch(ev.getAction()) {
        case MotionEvent.ACTION_DOWN:
            viewPager.disableScroll();
            break;
        case MotionEvent.ACTION_UP:
            viewPager.enableScroll();
            break;
        }
        return false;
    }

});
5
Ali AlNoaimi

Fedeのソリューションは私にはあまりうまくいきませんでした。 Horizo​​ntalScrollVIewには、入力(クリック、スワイプ、..)をキャッチできない領域がありました。 getHitRect()はそれで何かをしなければならないと思います。次のコードで置き換えた後、すべてが正常に機能しました。

複数のHorizo​​ntalScrollVIewビューまたはフォーカスを必要とする他のビューを追加することもできます。

public class CustomViewPager extends ViewPager {

    private ArrayList<Integer> children; 

    public CustomViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
        children = new ArrayList<Integer>();
    }   

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (children.size() > 0) {
            for(int i=0; i<children.size(); i++){
                View scroll = findViewById(children.get(i));
                if (scroll != null & scroll.isPressed()) {
                    return false;
                }
            }
        }
        return super.onInterceptTouchEvent(event);
    }

    public void addChildId(int id) {
       children.add(id);
    }

}

XMLでは、次のようなものがあります。

<form.paginator.lib.CustomViewPager
      Android:id="@+id/pager"
      Android:layout_width="fill_parent"
      Android:layout_height="150dp" />

OnCreate()メソッドで:

mPager = (CustomViewPager) findViewById(R.id.pager);
mPager.setAdapter(mAdapter);
mPager.addChildId(R.id.avatarImageView);

ビューのOnTouchListener()メソッドで、CustomViewPagerの子に追加しました:

case MotionEvent.ACTION_DOWN:
     v.setPressed(true);
     .
     .
     .
case MotionEvent.ACTION_UP:
     v.setPressed(false);
2
milosjovac

これは、スクロールビュー内のビューページャーでも機能します。 https://stackoverflow.com/a/2655740/969325

1
Warpzit

ScrollViewにViewPagerがあり、常にフォーカスを維持したい場合、タッチしてScrollViewがフォーカスを取得しない場合、これがそれを行うことがわかりました。

    mViewPager= (ViewPager) findViewById(R.id.pager);
    mViewPager.setAdapter(adapter);
    mViewPager.setOnTouchListener(new View.OnTouchListener() {

        @Override
        public boolean onTouch(View v, MotionEvent event) {
            mViewPager.getParent().requestDisallowInterceptTouchEvent(true);
            return false;
        }
    });
1

ビューページャーグループの最初のページのふもとにある小さなギャラリービューで問題が発生していました。ギャラリービューをスワイプすると、ギャラリーアイテムまたはビューページャーの移動間でフォーカスが移動します。

上記のViewPagerをオーバーライドし、requestDisallowInterceptTouchEventを設定すると、問題が解決しました。ギャラリービューをスワイプしてもページは変更されなくなりました。 viewpagerでgalleryviewsを使用している人にとって、これは重要なソリューションだと考えてください。

1
App8ite

だから、私はフェードの答えを修正しました。なぜなら、それは私が欲しかったページの周りの同じ領域のタッチを無効にしていたからです。また、水平方向のドラッグ/ドロップインタラクティビティを使用する多くのグラフィックスとインタラクティブビューを扱っているため、複数のビューを追加できるようにしました。この方法で追加できます

public class CustomViewPager extends ViewPager {

private List<ViewFocus> lateralTouchViews = new ArrayList<>();
public CustomViewPager(Context context, AttributeSet attrs) {
    super(context, attrs);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    for(int i = 0; i< lateralTouchViews.size(); i++){
        View scroll = findViewById(lateralTouchViews.get(i).id);
        if (scroll != null && getCurrentItem() == lateralTouchViews.get(i).itemPosition) {
            Rect rect = new Rect();
            scroll.getHitRect(rect);
            if (rect.contains((int) event.getX(), (int) event.getY())) {
                return false;
            }
        }
    }
    return super.onInterceptTouchEvent(event);
}

public void addConflict(int id, int pageIndex) {
    lateralTouchViews.add(new ViewFocus(id, pageIndex));
}
public class ViewFocus{
    int id;
    int itemPosition;

    public ViewFocus(int id, int itemPosition){
        this.id = id;
        this.itemPosition = itemPosition;
    }
}

}

0