Как я могу сделать горизонтальный ListView в Android?

Возможный дубликат:
Горизонтальный ListView в Android?

Как и многие другие вещи в Android, вы не думаете, что это будет такой сложной проблемой, но, черт возьми, вы ошибаетесь. И, как и многие другие вещи в Android, API даже не обеспечивает разумно расширяемой отправной точки. Будь я проклят, если я собираюсь свернуть свой собственный ListView, когда все, что я хочу, это взять вещь и перевернуть ее на бок. \ декламация

Хорошо, теперь, когда я покончил с дурью, давайте поговорим о самой проблеме. Что мне нужно, так это то, что Gallery, но без центральной блокировки. Мне не нужно ListViewlistSelector, но это приятно иметь. В основном я мог делать то, что я хочу с LinearLayout внутри ScrollView, но мне нужно, чтобы взгляды ребенка исходили от ListAdapter и я действительно хотел бы иметь мнение переработчика. И я действительно не хочу писать код компоновки.

Я заглянул в исходный код для некоторых из этих классов...

Галерея: похоже, я мог бы использовать Галерею, если переопределил большинство методов onXyz, скопировал весь их исходный код, но воздержался от вызова scrollIntoSlots(), Но я уверен, что если я сделаю это, я столкнусь с каким-либо полем участника, которое недоступно, или каким-либо другим непредвиденным последствием.

AbsSpinner: так как mRecycler поле является закрытым для пакета, я сомневаюсь, что смогу расширить этот класс.

AbsListView: похоже, этот класс предназначен только для вертикальной прокрутки, так что тут никакой помощи.

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

Я полагаю, я мог бы скопировать оба AbsSpinner а также Gallery чтобы получить то, что я хочу... надеюсь, эти классы не используют какую-то частную переменную пакета, к которой у меня нет доступа. Вы думаете, что это хорошая практика? Есть ли у кого-нибудь учебники или сторонние решения, которые могут направить меня в правильном направлении?

Обновить:
Единственное решение, которое я нашел, это сделать все самому. С тех пор, как задал этот вопрос, я переопределил AdapterView и реализовал свой собственный "HorizontalListView" с нуля. Единственный способ по-настоящему переопределить функцию блокировки центра галереи, это переопределить частный scrollIntoSlots метод, который я считаю, потребует генерации подкласса во время выполнения. Если вы достаточно смелы, чтобы сделать это, возможно, это лучшее решение, но я не хочу полагаться на недокументированные методы, которые могут измениться.

Свати EP ниже предложил, чтобы я дал Gallery OnTouchListener и переопределить функциональность прокрутки. Если вас не волнует наличие поддержки fling в вашем списке, или если все в порядке, когда представления будут привязываться к центру в конце анимации fling, это будет работать для вас! Тем не менее, в конце концов, все еще оказывается невозможным удалить центральную блокировку, не удаляя подвижную опору. И я спрашиваю вас, какой список не бросает?

Так что, увы, это не сработало для меня.:-(Но если вам интересен такой подход, читайте дальше...

Мне также пришлось внести некоторые дополнения в код Swathi, чтобы получить то, что я хотел. В GestureListener.onTouchВ дополнение к делегированию детектору жестов, мне также пришлось вернуть true для ACTION_UP а также ACTION_CANCEL События. Это успешно отключило функцию блокировки по центру, но также отключило бросание. Я смог снова включить fling, имея своего собственного делегата GestureListener в галерее onFling метод. Если вы хотите попробовать это, перейдите в пример кода ApiDemos и замените класс Gallery1.java следующим кодом:

import com.example.android.apis.R;

import android.app.Activity;
import android.content.Context;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.GestureDetector;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.View.OnTouchListener;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Toast;
import android.widget.AdapterView.AdapterContextMenuInfo;
import android.widget.AdapterView.OnItemClickListener;

public class Gallery1 extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.gallery_1);

        // Reference the Gallery view
        final Gallery g = (Gallery) findViewById(R.id.gallery);

        // Set the adapter to our custom adapter (below)
        g.setAdapter(new ImageAdapter(this));

        // Set a item click listener, and just Toast the clicked position
        g.setOnItemClickListener(new OnItemClickListener() {
            public void onItemClick(AdapterView parent, View v, int position, long id) {
                Toast.makeText(Gallery1.this, "" + position, Toast.LENGTH_SHORT).show();
            }
        });

        // Gesture detection
        final GestureDetector gestureDetector = new GestureDetector(new MyGestureDetector(g));
        OnTouchListener gestureListener = new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                boolean retVal = gestureDetector.onTouchEvent(event);
                int action = event.getAction();
                if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
                    retVal = true;
                    onUp();
                }
                return retVal;
            }

            public void onUp() {
                // Here I am merely copying the Gallery's onUp() method.
                for (int i = g.getChildCount() - 1; i >= 0; i--) {
                    g.getChildAt(i).setPressed(false);
                }
                g.setPressed(false);
            }
        };
        g.setOnTouchListener(gestureListener);

        // We also want to show context menu for longpressed items in the gallery
        registerForContextMenu(g);
    }

    @Override
    public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
        menu.add(R.string.gallery_2_text);
    }

    @Override
    public boolean onContextItemSelected(MenuItem item) {
        AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
        Toast.makeText(this, "Longpress: " + info.position, Toast.LENGTH_SHORT).show();
        return true;
    }

    public class ImageAdapter extends BaseAdapter {
        int mGalleryItemBackground;

        public ImageAdapter(Context c) {
            mContext = c;
            // See res/values/attrs.xml for the <declare-styleable> that defines
            // Gallery1.
            TypedArray a = obtainStyledAttributes(R.styleable.Gallery1);
            mGalleryItemBackground = a.getResourceId(
                    R.styleable.Gallery1_android_galleryItemBackground, 0);
            a.recycle();
        }

        public int getCount() {
            return mImageIds.length;
        }

        public Object getItem(int position) {
            return position;
        }

        public long getItemId(int position) {
            return position;
        }

        public View getView(int position, View convertView, ViewGroup parent) {
            ImageView i = new ImageView(mContext);

            i.setImageResource(mImageIds[position]);
            i.setScaleType(ImageView.ScaleType.FIT_XY);
            i.setLayoutParams(new Gallery.LayoutParams(136, 88));

            // The preferred Gallery item background
            i.setBackgroundResource(mGalleryItemBackground);

            return i;
        }

        private Context mContext;

        private Integer[] mImageIds = {
                R.drawable.gallery_photo_1,
                R.drawable.gallery_photo_2,
                R.drawable.gallery_photo_3,
                R.drawable.gallery_photo_4,
                R.drawable.gallery_photo_5,
                R.drawable.gallery_photo_6,
                R.drawable.gallery_photo_7,
                R.drawable.gallery_photo_8
        };
    }

    public class MyGestureDetector extends SimpleOnGestureListener {

        private Gallery gallery;

        public MyGestureDetector(Gallery gallery) {
            this.gallery = gallery;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, 
                float velocityY) {
            return gallery.onFling(e1, e2, velocityX, velocityY);
        }
    }

}

8 ответов

Прочитав этот пост, я реализовал свою собственную горизонталь ListView, Вы можете найти его здесь: http://dev-smart.com/horizontal-listview/ Дайте мне знать, если это поможет.

Вы рассматривали возможность использования HorizontalScrollView для обертывания элементов списка? Это позволит горизонтально прокручивать каждый из ваших элементов списка (то, что вы вставите, зависит от вас, и может сделать их динамическими элементами, похожими на ListView). Это будет хорошо работать, если вы только после одного ряда предметов.

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

Вы знаете, может быть возможно использовать существующий ListView с некоторым разумным переопределением dispatchDraw() (чтобы повернуть холст на 90 градусов), onTouch() (чтобы поменять X и Y координат MotionEvent) и, возможно, onMeasure() или что-то еще, чтобы обмануть его, думая, что это y по x, а не x по y...

Я понятия не имею, сработает ли это на самом деле, но было бы интересно узнать.:)

Я использовал Pauls (см. Его ответ) Реализацию HorizontalListview, и она работает, большое спасибо за обмен!

Я немного изменил его HorizontalListView-Class (кстати, у Пола есть опечатка в вашем имени класса, ваше имя класса "HorizontialListView" вместо "HorizontalListView", "i" слишком много) для обновления дочерних представлений при выборе.

ОБНОВЛЕНИЕ: мой код, который я разместил здесь, был неправильным, я полагаю, поскольку у меня возникли проблемы с выбором (я думаю, что это связано с переработкой представления), я должен вернуться к чертежной доске...

ОБНОВЛЕНИЕ 2: Хорошо, проблема решена, я просто прокомментировал "removeNonVisibleItems(dx);" в "onLayout(..)", я думаю, это ухудшит производительность, но так как я использую только очень маленькие списки, это не проблема для меня.

Я в основном использовал этот учебник здесь на developerlife и просто заменил ListView на Pauls HorizontalListView и внес изменения, чтобы сделать возможным "постоянный" выбор (дочерний элемент, который нажимает на изменение, меняет его внешний вид, а при повторном нажатии - снова меняет его).

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

Галерея - лучшее решение, я попробовал это. Я работал над одним почтовым приложением, в котором письма в папке "Входящие" отображались в виде списка, я хотел горизонтальный просмотр, я просто преобразовал просмотр списка в галерею, и все работало нормально, как мне было нужно, без каких-либо ошибок. Для эффекта прокрутки я включил функцию прослушивания жестов для галереи. Я надеюсь, что этот ответ может помочь вам.

Вы смотрели в компонент ViewFlipper? Может быть, это может помочь вам.

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

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

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

       setContentView(R.layout.somelayout);
       orientation = getResources().getConfiguration().orientation;

       if ( orientation == Configuration.ORIENTATION_LANDSCAPE )
       {

            Gallery gallery = (Gallery)findViewById( R.id.somegallery );

            gallery.setAdapter( someAdapter );

            gallery.setOnItemClickListener( new OnItemClickListener() {
            @Override
            public void onItemClick( AdapterView<?> parent, View view,
                    int position, long id ) {

                onClick( position );
            }
        });
       }
       else
       {
            setListAdapter( someAdapter );

            getListView().setOnScrollListener(this);
       }    

Для обработки событий прокрутки я унаследовал свой собственный виджет от Gallery и переопределил onFling(). Вот файл layout.xml:

    <view 
    class="package$somegallery"
    android:id="@+id/somegallery" 
    android:layout_height="fill_parent" 
    android:layout_width="fill_parent">
    </view>

и код:

    public static class somegallery extends Gallery
    {
        private Context mCtx;

        public somegallery(Context context, AttributeSet attrs)
        {
            super(context, attrs);
            mCtx = context;
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
                float velocityY) {

            ( (CurrentActivity)mCtx ).onScroll();

            return super.onFling(e1, e2, velocityX, velocityY);
        }
   }
Другие вопросы по тегам