2010-10-06 3 views
181

Можно создать дубликат:
Horizontal ListView in Android?Как сделать горизонтальный ListView в Android?

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

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

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

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

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

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

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

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

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

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

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

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

} 
+0

Я пробовал этот пост и работал на меня ... http://whats-online.info/science-and-tutorials/87/Android-tutorial-Horizontal-RecyclerView-with-images-and-text-example/ –

ответ

12

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

+25

Две причины, по которым я не придерживаюсь такого подхода: (1) Он не расширяет «AdapterView», поэтому я не могу использовать его взаимозаменяемо с моими списками «ListView» и «ListAdapter» и (2) Нет переработка видов. Возможно, можно было бы применить эту функциональность в представлении прокрутки, но мне кажется, что это будет беспорядочно работать с прокруткой, и это будет почти такая же работа, как просто расширение «AdapterView». –

+0

Вы пробовали горизонтальный recyclerView? Эта библиотека упрощает код для ориентации вашего списка, используя очень минимальный код. Проверьте этот обработанный пример с демонстрацией http://whats-online.info/science-and-tutorials/87/Android-tutorial-Horizontal-RecyclerView-with-images-and-text-example/ –

2

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

+0

Что вы подразумеваете под " Я включил прослушиватель жестов для галереи? " Вы просто переопределили метод «onScroll» Gallery и прокрутили себя? Если да, то как вы рассказали детям галереи о перестановке? –

+0

Я написал класс, расширяющий SimpleOnGestureListener, в котором у меня есть переопределенный метод onfling(). В приведенном ниже коде показано обнаружение жестов и жестикулятор моей галереи: –

+1

// Обнаружение жеста \t \t gestureDetector = new GestureDetector (новый MyGestureDetector()); \t \t gestureListener = новый View.OnTouchListener() { \t \t \t общественного логический onTouch (View v, MotionEvent событие) { \t \t \t \t если (gestureDetector.onTouchEvent (событие)) { \t \t \t \t \t return true; \t \t \t \t} \t \t \t \t возвращение ложным; \t \t \t} \t \t}; \t \t myGallery.setOnTouchListener (gestureListener); –

-1

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

<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); 
     } 
    } 
+0

Насколько я вижу, это все равно будет иметь эффект блокировки центра. Что делает метод 'onScroll()' вашей активности? –

+0

На самом деле я удалил часть кода здесь, прежде чем вызывать onScroll(), поскольку он не охватывает вопрос. Если вам интересно, я вызываю getLastVisiblePosition(), который используется в onScroll, чтобы определить, является ли последний элемент видимым и выполняет некоторую логику. Что касается центра блокировки - да, это имеет такое поведение. – ackio

0

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

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

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

+0

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

4

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

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

+3

Ха-ха, мне нравится ваше отношение ... вроде бы боятся попробовать ... Я сначала попробую предложение Swathi EP. –

+0

Итак, я пошел вперед и внедрил свой собственный подкласс AdaptView, поскольку я полагал, что это будет такая же работа и меньший риск. Тем не менее, попытка вашего предложения будет интересным экспериментом. :-) –

+0

С дополнительным бонусом, что техника может работать для любого вида вида. Жесткий бит - найти практические приложения! :) –

48

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

+0

спасибо ... замечательная работа! –

+0

Это .... Фантастическая работа –

+0

Один вопрос: почему вы выполняете синхронизацию потоков в своей реализации? Все работает на 100% на потоке пользовательского интерфейса. –

3

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

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

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

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

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

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

+0

Приятно, что он заработал, но он не перерабатывает представления, данные статичны, порядок предметов не гарантируется, и это действительно трудно настроить/исправить, не зная точно, что вы делаете из-за отсутствия комментариев в нем. Если вы точно знаете, что делаете, вам не нужно это решение в первую очередь. Я хочу, чтобы команда разработчиков Android уже реализовала это. Я сохраняю несколько элементов в прокрутке, чтобы поддерживать их быстро, используя LinkedList, чтобы гарантировать позиционирование при перерисовке. Он не идеален, но функционирует достаточно хорошо. –

4

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

+1

Галерея устарела и заменена HorizontalScrollView в API, поскольку это было опубликовано. Просто нанесите LinearLayout на него, и теперь вы можете добавлять элементы через код. Отлично работает, хотя и не перерабатывает огромное количество предметов. –

Смежные вопросы