Android: синхронизированная прокрутка двух разных видов - PullRequest
2 голосов
/ 04 января 2011

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

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

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

Все представления являются представлениями прокрутки, и я вместо этого включил плавную прокрутку и использовал smoothScrollTo и т. Д., Чтобы попытатьсяулучшить это, но это та же проблема, тем не менее.Эта проблема особенно заметна на больших экранах, таких как Samsung Galaxy Tab, тогда как на устройствах с экранами среднего размера она едва заметна.

Любая помощь приветствуется!Если есть простое исправление, замечательно ... если это означает новый дизайн (который соответствует приведенному выше сценарию с липким представлением), то пусть будет так.

Код для запуска прог.прокрутка, то же самое для горизонтальной

@Override  
protected void onScrollChanged(int x, int y, int oldx, int oldy) {  
   mListener.onScrollY(y);  
   super.onScrollChanged(x, y, oldx, oldy);  
}  
// which leads to,  
// Handle vertical scroll  
public void onScrollY(final int y) {  
   mCurrentY = y;  
   mVerticalScroll.smoothScrollTo(0, y);  
}  

макетов XML ниже, если это поможет

Фактическая сетка, которая представляет собой горизонтальную прокрутку, обернутую в вертикальную прокрутку, и элементы сеткидобавлено вертикально во вложенный линейный макет
>

  < com.....VerticalScrollView  
    android:id="@+id/gridscroll" 
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent" 
    android:layout_below="@id/timescroll"
    android:layout_toRightOf="@id/vertscroll"  
    android:layout_alignTop="@id/vertscroll"  
    android:layout_marginLeft="2dp" android:scrollbars="none"  
    android:fadingEdge="none">   

    < com....HorizScrollView
    android:id="@+id/horizscroll"
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"
    android:scrollbars="none"  
    android:fadingEdge="none">  

    < LinearLayout android:id="@+id/grid"  
      android:layout_width="fill_parent"  
      android:layout_height="fill_parent"  
      android:orientation="vertical">  

      < /LinearLayout>  

      < /com.....HorizScrollView>  

      < /com.....VerticalScrollView>  

Горизонтальное липкое изображение

 < com.....GridTimeScrollView
    android:id="@+id/timescroller" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:scrollbars="none"
    android:fadingEdge="none">

    < LinearLayout android:id="@+id/timelist"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" />
    < /com.....GridTimeScrollView>

Вертикальное липкое изображение

< com....GridVertListScrollView
android:id="@+id/vertscroller"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scrollbars="none" 
android:fadingEdge="none">

< LinearLayout
android:id="@+id/vertitemlist"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" />
< /com.....GridVertListScrollView>

Ответы [ 3 ]

6 голосов
/ 18 января 2011

Прежде всего, я думаю, вы должны знать об этом: ScrollView Inside ScrollView

Вкратце: использование скролл-обзоров внутри скролл-обзоров - плохая вещь, которая ломает многие оптимизации.

Теперь на ваш вопрос.

У меня была такая же потребность, как вы описали. В итоге я реализовал собственное представление и его метод onDraw. Это было отчасти потому, что я рисовал что-то не тривиальное, и вам, возможно, не придется это делать.

В любом случае, я считаю, что ваш лучший вариант:

  1. Реализация пользовательского представления, расширяющего относительное расположение
  2. создать компоновку этого вида с верхним, левым и "основным" видами, которые будут прокручиваемыми компонентами
  3. добавить OnGestureListener к этому представлению и передать сенсорные события в вашей деятельности в пользовательское представление
  4. когда ваш слушатель жестов обнаруживает бросок или прокрутку, вызывайте scrollBy в каждом из режимов прокрутки. При этом, если вы хотите, чтобы вид сверху прокручивался только горизонтально, передайте 0 в качестве расстояния вертикальной прокрутки.
  5. Чтобы реализовать плавные движения, вам нужно создать скроллер (в вашем собственном представлении). Когда слушатель жестов обнаружит событие броска, установите прокрутку вверх. Затем переопределите метод computeScroll() пользовательского представления и обновите прокрутку в каждом из дочерних представлений. Проверьте этот пример , чтобы узнать, как его реализовать. Прошу прощения, я постараюсь опубликовать лучший пример, когда это возможно. Проверьте мой код ниже ... это проще:)

Обновление: Пример кода

@Override
    public void computeScroll() {
        if (scroller.computeScrollOffset()) {
            if (!scrolledLastFrame) {
                lastX = scroller.getStartX();
                lastY = scroller.getStartY();
            }

            int dx = scroller.getCurrX() - lastX;
            int dy = scroller.getCurrY() - lastY;

            lastX = scroller.getCurrX();
            lastY = scroller.getCurrY();

            doScroll(dx, dy);
            scrolledLastFrame = true;
        } else {
            scrolledLastFrame = false;
        }

    }
3 голосов
/ 22 января 2011

Не используйте smoothScrollTo, вместо этого используйте scrollTo. smoothScrollTo будет анимировать прокрутку из текущей позиции в нужную вам позицию, потому что вы хотите, чтобы они были синхронизированы, вы хотите, чтобы другое представление прокрутки находилось точно в том же месте, что и другое представление прокрутки, scrollTo делает это.

2 голосов
/ 20 января 2011

Глядя на ответы.Почему бы вам не справиться с этим с помощью слушателя OnTouch.Когда сенсорное событие MOVE, вы звоните.

public void onScrollY(final int y) {  
   mCurrentY = y;  
   mVerticalScroll.smoothScrollTo(0, y);  
}  

со значением getVerticalScroll в другом ScrollView.Это довольно легко.И верните true, чтобы TouchEvents обрабатывался дальше.

Вот как это может выглядеть

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_MOVE:
            lv2.onScrollY(lv.getScrollY());
            break;
        default:
            break;
    }
    return false;
}

Простое право?

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...