Como posso fazer um ListView horizontal no Android? [duplicado]

Possível duplicado:
ListView horizontal no Android?

Como muitas coisas no Android, você não pensaria que esse seria um problema tão difícil, mas ohhh, por Deus, você estaria errado. E, como muitas coisas no Android, a API nem fornece um ponto de partida razoavelmente extensível. Dane-se se vou rolar meu próprio ListView, quando tudo o que quero é pegar o objeto e virar de lado. \ rant

Certo, agora que eu acabei de fumegar, vamos falar sobre o problema em si. O que eu preciso é basicamente algo exatamente como oGallery, mas sem o recurso de travamento central. Eu realmente não precisoListViewé listSelector, mas é bom de ter. Principalmente, eu poderia fazer o que eu queria com umLinearLayout dentro de umScrollView, mas preciso que as visualizações filho sejam provenientes de umListAdapter e eu realmente gostaria de ter um reciclador de visualizações. E eurealmente não quer escrever nenhum código de layout.

Eu espiei o código fonte para algumas dessas classes ...

Galeria: Parece que eu poderia usar a Galeria se substituir a maioria dos métodos 'onXyz', copiar todo o código-fonte, mas abster-me de chamarscrollIntoSlots(). Mas tenho certeza de que, se fizer isso, encontrarei algum campo de membro inacessível ou outra conseqüência imprevista.

AbsSpinner: Desde omRecycler O campo é package-private. Duvido que seja capaz de estender essa classe.

AbsListView: Parece que esta classe é apenas para rolagem vertical, então não há ajuda lá.

AdapterView: Eu nunca tive que estender essa classe diretamente. Se você me disser que é fácil de fazer, e que é fácil criar minhas própriasRecycleBin, Vou ser muito cético, mas vou tentar.

Suponho que eu poderia copiarambos AbsSpinner eGallery para obter o que eu quero ... espero que essas classes não estejam usando alguma variável privada de pacote que não possa acessar. Vocês acham que é uma boa prática? Alguém tem algum tutorial ou solução de terceiros que pode me colocar na direção certa?

Atualizar:
A única solução que encontrei até agora é fazer tudo sozinha. Desde que fiz esta pergunta, eu substituíAdapterView e implementei meu próprio "HorizontalListView" do zero. A única maneira de substituir verdadeiramente o recurso de travamento central da Galeria é substituir oscrollIntoSlots método, que acredito que exigiria a geração de uma subclasse em tempo de execução. Se você for ousado o suficiente para fazer isso, é sem dúvida a melhor solução, mas não quero confiar em métodos não documentados que possam mudar.

O PE Swathi abaixo sugeriu que eu desseGallery aOnTouchListener e substitua a funcionalidade de rolagem. Se você não se importa em ter suporte a arremessar na sua lista ou se as exibições podem ser ajustadas no centro no final da animação de arremessar, então issovai Trabalho para você! No entanto, no final, ainda é impossível remover o recurso de travamento central sem remover o suporte para arremessar. E eu pergunto: que tipo de lista não é lançada?

Então, infelizmente, isso não funcionou para mim. :-( Mas se você estiver interessado nessa abordagem, continue a ler ...

Eu também tive que fazer algumas adições ao código de Swathi para conseguir o que queria. NoGestureListener.onTouch, além de delegar ao detector de gestos, eu também tive que retornar verdadeiro paraACTION_UP eACTION_CANCEL eventos. Isso desativou com êxito o recurso de travamento central, mas também desativou o lançamento. Consegui reativar o fling tendo meu próprio GestureListener delegado à GaleriaonFling método. Se você quiser experimentá-lo, entre no código de exemplo do ApiDemos e substitua a classe Gallery1.java pelo seguinte código:

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

}

questionAnswers(8)

yourAnswerToTheQuestion