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

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

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

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

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

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

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

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

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

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

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

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

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

Мне также пришлось внести некоторые дополнения в код Swathi, чтобы получить то, что я хотел. В GestureListener.onTouch , помимо делегирования детектору жестов, мне также пришлось возвращать true для ACTION_UP и ACTION_CANCEL . Это успешно отключило функцию блокировки центра, но также отключило движение. Я смог снова включить fling, предоставив свой собственный делегат onFling методу onFling в галерее. Если вы хотите попробовать, зайдите в свой примерный образец ApiDemos и замените class 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  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); } } } 

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

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

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

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

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

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

Я немного изменил свой HorizontalListView-Class (кстати, у Paul есть опечатка в вашем имени classа, ваше имя classа – «HorizontialListView», а не «HorizontalListView», «i» – это слишком много), чтобы обновлять дочерние представления при выборе.

UPDATE: мой код, который я опубликовал здесь, был неправильным, я полагаю, поскольку у меня возникли проблемы с выбором (я думаю, что это связано с переходом на просмотр), мне нужно вернуться к чертежной доске …

UPDATE 2: Ok Проблема решена, я просто прокомментировал «removeNonVisibleItems (dx);» в “onLayout (..)”, я думаю, это повредит производительности, но поскольку я использую только очень маленькие списки, это не проблема для меня.

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

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

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

Вы заглянули в компонент ViewFlipper? Может быть, это может вам помочь.

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

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

Мое приложение использует 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); } 

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

    

и код:

  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); } } 
Давайте будем гением компьютера.