Подтвердить что ты не робот

Android: ViewPager и HorizontalScrollVIew

У меня есть HorizontalScrollView внутри моего ViewPager. Я установил requestDisallowInterceptTouchEvent(true); для HorizontalScrollView, но ViewPager по-прежнему иногда перехватывает события касания. Есть ли еще одна команда, которую я могу использовать, чтобы предотвратить перехват событий "Просмотр" родителями и предками?

Примечание: HorizontalScrollView занимает только половину экрана.

4b9b3361

Ответ 1

У меня была та же проблема. Мое решение было:

  • Создайте подкласс ViewPager и добавьте свойство под названием childId.
  • Создайте сеттер для свойства childId и установите идентификатор HorizontalScrollView.
  • Переопределить onInterceptTouchEvent() в подклассе ViewPager, и если свойство 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);

Надеемся на эту помощь

Ответ 2

Спасибо за ответ. Я немного изменил ваше решение и смог создать вложенные функции 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;
    }
}

Ответ 3

Итак, я знаю, что этот вопрос довольно старый, но я пришел с решением, которое, по моему мнению, имеет некоторые дополнительные преимущества по сравнению с опубликованным здесь. Одна из ситуаций, которая может произойти, заключается в том, что у меня может быть более одного HorizontalScrollView внутри моего ViewPager (что я и делаю), а затем мне нужно будет предоставить тонны идентификаторов в ViewPager, чтобы он всегда мог проверять конфликты с детским контактом.

Я проанализировал источник из ViewPager и обнаружил, что они используют этот метод под названием "canScroll", чтобы определить, можно ли прокручивать дочернее представление. К счастью, он не был статичным и окончательным, поэтому я мог просто переопределить его. Внутри этого метода вызывается "boolean ViewCompat.canScrollHorizontally(View, int)" (тот, который всегда возвращает false для SDK < 14). Тогда мое решение было следующим:

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

Итак, если у вас есть другой класс View внутри вашего ViewPager, который также должен получать горизонтальные перетаскивания, просто измените customCanScroll (View), чтобы вы могли вернуться, если касание не должно быть перехвачено или нет.

Логическая проверка V истинна, если текущий вид также должен быть проверен для "прокрутки", поэтому мы также должны это проверить.

Надеюсь, что это поможет будущим проблемам (или если есть лучшее решение или официальное из платформы Android, сообщите мне).

Ответ 4

Я не знаю, решила ли вы проблему уже или нет. Но ни один из ответов выше не работает должным образом. Поэтому я думаю, что это необходимо для тех людей, которые могут искать решения со страданиями.

На самом деле, решение довольно просто, если вы читаете официальный документ об обработке сенсорных событий в ViewGroup.

Сначала вам нужно понять использование

ViewParent.requestDisallowInterceptTouchEvent(boolean), назовите это на родительском представлении, чтобы указать, что он не должен перехватывать события касания с помощью onInterceptTouchEvent (MotionEvent).

Затем вам нужно перехватить события и убедиться, что родительская ViewGroup вашего HorizontalScrollView больше не будет отправлять события.

Итак, установите OnToushListener для вас HorizontalScrollView. Обнаружение касания и перемещения событий, затем установите для параметра requestDisallowInterceptTouchEvent (true) родительский (ViewPager или sth else), чтобы убедиться, что события будут обрабатываться с помощью HorizontalScrollView.

Конечно, вы можете поместить этот код в свои компоненты CustomHorizontalScrollView, чтобы его можно было повторно использовать.

Надеясь, что это помогает.; -)

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

Ответ 5

Вот еще одно решение, которое сработало для меня,

Создайте собственный 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 к вашему элементу, будь то HorizontalScrollView или 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;
    }

});

Ответ 6

Решение Fede не очень хорошо для меня. У моего HorizontalScrollVIew были области, где он не попадал ни в какие входы (щелкните, проведите по экрану..). Я думаю, getHitRect() должен что-то сделать с этим. После замены его на следующий код все работало нормально.

Можно добавить несколько представлений HorizontalScrollView или любые другие виды, требующие фокуса.

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

Ответ 7

У меня возникли проблемы с небольшим представлением галереи на ноге моей первой страницы в группе viewpager. При просмотре фокуса в галерее будет перемещаться между перемещением элементов галереи или viewpager.

Переопределение ViewPager, как указано выше, и установка requestDisallowInterceptTouchEvent решили мою проблему. Страницы не изменяются при просмотре галереи. Подумайте, что это важное решение для тех, кто использует галереи с помощью viewpager.

Ответ 9

Я узнал, что если у вас есть ViewPager в ScrollView, и вы хотите, чтобы он всегда оставался в фокусе, когда вы касаетесь его, а 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;
        }
    });

Ответ 10

после теста много решения, я нахожу это. в MyPagerView:

@Override
public boolean onTouchEvent(MotionEvent event) {
    if (childId > 0) {
        View scroll = findViewById(childId);
        if (scroll != null && mGestureDetector.onTouchEvent(event)) {
            return false;
    }
}
return super.onTouchEvent(event);
}

@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
    if (childId > 0) {
            HorizontalScrollView scroll = (HorizontalScrollView)findViewById(childId);
            if (scroll != null && mGestureDetector.onTouchEvent(event)) {
                return false;
            }
    }
    return super.onInterceptTouchEvent(event);
}

Ответ 11

Итак, я изменил ответ Fede, потому что он отключил прикосновение в той же области на страницах вокруг той, которую я хотел. Кроме того, я сделал это, чтобы добавить несколько просмотров, потому что я имею дело с большим количеством графики и интерактивных представлений, которые используют горизонтальную интерактивность перетаскивания. Таким образом вы можете добавить

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

}