вторник, 3 мая 2011 г.

Чем заменить Gallery

Каждый раз, когда мне приходится использовать компонент Gallery, я поражаюсь его бестолковости. Кое с чем мириться просто невозможно:

Реализация листания

Жест fling пролистывает сразу кучу элементов, а чаще хочется, чтобы происходил переход на один элемент (как в андроидовском home screen). Конечно, можно унаследоваться от галереи и добиться нужного поведения с помощью вот такой перегрузки onFling:

CustomGallery.java

public class CustomGallery extends Gallery {
    public CustomGallery(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    public CustomGallery(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }
    
    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return true;
    }
}

Это несколько спасает положение, но не очень. Теперь жест пролистывания далеко не всегда листает:

Жест пролистывания в модифицированной галерее

И с этим уже не побороться.

Проблемы с размещением интерактивных элементов

Gallery обычно используется для размещения изображений, и тогда проблем нет. Но вот понадобилось положить в галерею кнопки, или другой компонент, обрабатывающий нажатия. И тут скроллинг галереи перестает работать вовсе, потому что срабатывает onTouch ее детей. Само собой, так жить нельзя.

Что делать?

Как ни печально, у меня так и не получилось победить эти особенности Gallery, так что пришлось от нее отказаться. Зато удалось найти копипасту класса DragableSpace, который решает все проблемы. Я не буду приводить здесь его реализацию, просто дам ссылку: http://pastebin.com/CgK8TCQS. Работает отлично: и листает хорошо, и с интерактивными компонентами никаких вопросов.

На всякий случай вот исходники. Там приведены примеры работы стандартной галереи, галереи с перегруженным onFling и собственно DragableSpace.

Если есть другие решения — рассказывайте, будет очень полезно.

4 комментария:

Антон комментирует...

Дарья, здравствуйте. Я бы ещё предложил использовать жесты. Сейчас попробовал - всё достаточно просто и работает.

Alex Korovyansky комментирует...

Можно использовать компонент Workspace, работает красиво.
Но фишка в том, что в отличии от Gallery ни DragableSpace, ни Workspace не являются адаптируемыми виджетами... В ситуации когда мы хотим показывать 10000 картинок, нам просто не хватит памяти на 10000 статических вьюшек. Здесь очень бы пригодился механизм convertView.

JLab13 комментирует...

Можно посмотреть в сторону https://github.com/pakerfeldt/android-viewflow
Сам не тестировал но пример там работает отлично.

А по поводу стандартной Gallery чтоб много не скролилось у меня решение таким костылем:

public class GalleryOneSlide extends Gallery {
public GalleryOneSlide(Context context, AttributeSet attrs) {
super(context, attrs);
}

@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
if (e2.getX() > e1.getX()) {
onKeyDown(KeyEvent.KEYCODE_DPAD_LEFT, null);
} else {
onKeyDown(KeyEvent.KEYCODE_DPAD_RIGHT, null);
}
return true;
}

}

const комментирует...

ViewFlipper: http://developer.android.com/reference/android/widget/ViewFlipper.html

android.support.v4.view.ViewPager
http://developer.android.com/reference/android/support/v4/view/ViewPager.html