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

Глядя на стену (GridView?), которая выходит за пределы экрана, и пользователь может коснуться ее, чтобы переместить ее

Желаемый эффект У меня есть куча небольших изображений, которые я хотел бы показать на "стене", а затем позволить пользователю выбрасывать эту стену в любом направлении и выбирать изображение.

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

Вопрос Каков лучший виджет для реализации желаемого эффекта? Пример кода был бы особенно полезен.

ИЗМЕНИТЬ... если у кого-то есть пример кода, который позволит мне разместить около 30 изображений на "стене" (таблица будет хорошей), тогда я буду принимать это как ответ. Обратите внимание, что "стена" должна выглядеть так, как будто она выходит за пределы экрана и позволяет пользователю использовать палец для перетаскивания "стены" вверх по левому краю. Перетаскивание должно быть в режиме "свободной формы". Один щелчок на изображении выбирает его, и обратный вызов должен быть обнаружен. Я создал щедрость для этого решения.

4b9b3361

Ответ 1

Решение на самом деле довольно простое, но боль. Мне пришлось реализовать именно это в рамках программы, которую я недавно сделал. Однако есть несколько сложных вещей, которые вам нужно преодолеть. Следует отметить, что разные версии ОС имеют разные впечатления. Этот метод иногда отрицательно влияет на определенную специализацию или кладку, чтобы сделать эту работу как рисунок. Хотя I имеет рабочую копию, код, который я предоставляю, не для всех и зависит от любых других изменений или настроек в вашем коде.

  • установите android:layout_width в wrap_content
  • установите android:layout_height в wrap_content
  • В вашем коде:
    • определите, сколько строк у вас будет.
    • разделите количество элементов на количество строк.
    • добавить gridView. setStretchMode(NO_STRETCH);
    • добавить gridView. setNumColumns( количество столбцов );
    • добавить gridView. setColumnWidth( явная ширина в пикселях );
  • Прокрутить:
    • Вы можете просто использовать gridView. scrollBy() в onTouchEvent()

Это шаги. Все они необходимы, чтобы заставить его работать. Ключ представляет собой NO_STRETCH с явным количеством столбцов с определенной шириной. Если вам требуется уточнение, можно предоставить дополнительную информацию. Вы можете даже использовать VelocityTracker или onFling для обработки flinging. У меня есть snappingToPage включен в мой. Используя это решение, даже не требуется переопределять onDraw() или onLayout(). Эти три строки кода избавляются от необходимости использования WebView или любого другого встраивания или вложения.

Двунаправленная прокрутка также довольно проста в применении. Вот простое решение для кода:

  • Во-первых, в вашем классе начните отслеживать позиции X и Y, создав два члена класса. Также добавьте отслеживание состояния;

    // Holds the last position of the touch event (including movement)
    int myLastX;
    int myLastY;
    
    // Tracks the state of the Touch handling
    final static private int TOUCH_STATE_REST = 0;
    final static private int TOUCH_STATE_SCROLLING = 1;
    int myState = TOUCH_STATE_REST;
    
  • Во-вторых, убедитесь, что вы проверяете прокрутку, таким образом вы можете щелкнуть или долго щелкнуть сами изображения.

    @Override public boolean onInterceptTouchEvent(final MotionEvent ev)
    {//User is already scrolling something. If we haven't interrupted this already,
    // then something else is handling its own scrolling and we should let this be.
    // Once we return TRUE, this event no longer fires and instead all goes to 
    // onTouch() until the next TouchEvent begins (often beginning with ACTION_DOWN).
        if ((ev.getAction() == MotionEvent.ACTION_MOVE)
        &&  (myState != TOUCH_STATE_REST))
            return false;
    
    // Grab the X and Y positions of the MotionEvent
        final float _x = ev.getX();
        final float _y = ev.getY();
        switch (ev.getAction())
        {   case MotionEvent.ACTION_MOVE:
                final int _diffX = (int) Math.abs(_x - myLastX);
                final int _diffY = (int) Math.abs(_y - myLastY);
    
                final boolean xMoved = _diffX > 0;
                final boolean yMoved = _diffY > 0;
                if (xMoved || yMoved)
                   myState = TOUCH_STATE_SCROLLING;
                break;
            case MotionEvent.ACTION_DOWN:
            // Remember location of down touch
                myLastX = _x;
                myLastY = _y;
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if (myState == TOUCH_STATE_SCROLLING)
                // Release the drag
                    myState = TOUCH_STATE_REST;
    
        }
        //If we are not At Rest, start handling in our own onTouch()
        return myState != TOUCH_STATE_REST;
    }
    
  • После того, как GridView знает, что вы прокручиваете, он отправит все сенсорные события в onTouch. Сделайте свою прокрутку здесь.

    @Override public boolean onTouchEvent(final MotionEvent ev)
    {
        final int action = ev.getAction();
        final float x = ev.getX();
        final float y = ev.getY();
        final View child;
    
        switch (action) 
        {
            case MotionEvent.ACTION_DOWN:
                //Supplemental code, if needed
                break;
            case MotionEvent.ACTION_MOVE:
                // This handles Scrolling only.
                if (myState == TOUCH_STATE_SCROLLING)
                {
                    // Scroll to follow the motion event
                    // This will update the vars as long as your finger is down.
                    final int deltaX = (int) (myLastX - x);
                    final int deltaY = (int) (myLastY - y);
                    myLastX = x;
                    myLastY = y;
                    scrollBy(deltaX, deltaY);
                }
                break;
            case MotionEvent.ACTION_UP:
            // If Scrolling, stop the scroll so we can scroll later.
                if (myState == TOUCH_STATE_SCROLLING)
                    myState = TOUCH_STATE_REST;
                break
            case MotionEvent.ACTION_CANCEL:
            // This is just a failsafe. I don't even know how to cancel a touch event
                 myState = TOUCH_STATE_REST;
        }
    
    return true;
    }
    

Если курс, это решение перемещается в X и Y одновременно. Если вы хотите перемещать только одно направление за раз, вы можете легко отличить, проверив большую разницу X и Y. (т.е. Math.abs(deltaX) > Math.abs(deltaY)) Ниже приведена частичная выборка для одной направленной прокрутки, но она может переключаться между X или Y.

3b. Измените это в OnTouch(), если вы хотите обрабатывать одно направление за раз:

            case MotionEvent.ACTION_MOVE:
                if (myState == TOUCH_STATE_SCROLLING)
                {
                    //This will update the vars as long as your finger is down.
                    final int deltaX = (int) (myLastX - x);
                    final int deltaY = (int) (myLastY - y);
                    myLastX = x;
                    myLastY = y;

                    // Check which direction is the bigger of the two
                    if (Math.abs(deltaX) > Math.abs(deltaY))
                        scrollBy(deltaX, 0);
                    else if (Math.abs(deltaY) > Math.abs(deltaX))
                        scrollBy(0, deltaY);
                    // We do nothing if they are equal.
                }
                break;

FuzzicalLogic

Ответ 2

A GridView может иметь контент, который выходит за пределы размера экрана, но только в вертикальном направлении.

Вопрос: Каков наилучший виджет для реализации желаемого эффекта?
Не являются виджетами по умолчанию (по крайней мере до 3.0), которые реализуют 2D-прокрутку. Все они реализуют только 1D (прокрутка в одном направлении). К сожалению, решение вашей проблемы не так просто.

Вы можете:

  • Поместите TableLayout внутри пользовательского класса ScrollView и обработайте события касания самостоятельно. Это позволит вам сделать правильное 2D-панорамирование, но не будет настолько хорошим для больших наборов данных, поскольку не будет никакой утилизации просмотра.
  • Измените GridView, если возможно, чтобы включить функцию горизонтальной прокрутки (возможно, лучшее решение, если вы можете это сделать)
  • Попробуйте помещать TableLayout внутри ScrollViewlayout_width="wrap_content), который вы помещаете внутри HorizontalScrollView - хотя это может работать, это не было бы оптимальным решением
  • Сделайте что-нибудь с OpenGL и нарисуйте прямо на холсте - вот как по умолчанию Галерея 3D-приложения делает это "стена картин"

Ответ 3

Я думаю, что единственное решение для Android для Android - это иметь встроенный WebView, в котором вы можете иметь этот двумерный свиток (и, кстати, это единственное, что имеет эту возможность).

Нажимая изображение, вы можете управлять поведением посредством обратного вызова с JavaScript на JAva.

Это не очень "красиво", но... это единственный жизнеспособный способ сделать то, что вы хотите "из коробки".

Ответ 4

Я реализовал GridView, который переопределяет методы onInterceptTouchEvent. Я установил OnTouchListener, как описано Fuzzical Logic. Моя проблема заключается в том, что установка пользовательского OnTouchListener, объекты моего gridView больше не доступны для кликов. Это потому, что по умолчанию OnTouchListener из GridView вызывает onItemClickListener?

Я хотел бы иметь прокручиваемый GridView 2 направления, но у него все еще есть cliackable объекты. Должен ли я реализовать свой собственный метод, чтобы проверить, соответствует ли касание элементу или есть ли более простой способ достичь этого?

Grodak