Duplicata possible :
ListView horizontal dans Android ?
Comme beaucoup de choses dans Android, vous ne penseriez pas qu'il s'agisse d'un problème si difficile à résoudre, mais vous auriez tort. Et, comme beaucoup de choses dans Android, l'API ne fournit même pas un point de départ raisonnablement extensible. Que je sois damné si je dois créer ma propre ListView, alors que tout ce que je veux, c'est prendre la chose et la retourner. \rant
Bon, maintenant que j'ai fini de m'énerver, parlons du problème lui-même. Ce dont j'ai besoin, c'est quelque chose qui ressemble exactement à l'image suivante Gallery
mais sans la fonction de verrouillage central. Je n'ai pas vraiment besoin ListView
mais c'est un élément indispensable. En général, je pourrais faire ce que je veux avec une fonction LinearLayout
à l'intérieur d'un ScrollView
mais j'ai besoin que les vues enfant proviennent d'un fichier ListAdapter
et j'aimerais vraiment avoir un recycleur de vues. Et je vraiment ne veulent pas écrire de code de mise en page.
J'ai jeté un coup d'oeil au code source de certaines de ces classes...
Galerie : Il semble que je puisse utiliser la Gallery si je surcharge la plupart des méthodes 'onXyz', que je copie tout leur code source, mais que je m'abstiens d'appeler scrollIntoSlots()
. Mais je suis sûr que si je fais cela, je me heurterai à un champ membre inaccessible ou à une autre conséquence imprévue.
AbsSpinner : Depuis le mRecycler
est package-private, je doute que je puisse étendre cette classe.
AbsListView : Il semble que cette classe ne soit destinée qu'au défilement vertical, donc aucune aide ici.
AdapterView : Je n'ai jamais eu à étendre cette classe directement. Si vous me dites que c'est facile à faire, et qu'il est facile de mettre en place ma propre RecycleBin
Je serai très sceptique, mais je vais essayer.
Je suppose que je pourrais éventuellement copier les deux AbsSpinner
y Gallery
pour obtenir ce que je veux... en espérant que ces classes n'utilisent pas une variable privée du paquet à laquelle je ne peux pas accéder. Pensez-vous que c'est une bonne pratique ? Quelqu'un a-t-il des tutoriels ou des solutions tierces qui pourraient me mettre sur la bonne voie ?
Mise à jour :
La seule solution que j'ai trouvée jusqu'à présent est de tout faire moi-même. Depuis que j'ai posé cette question, j'ai modifié les paramètres suivants AdapterView
et j'ai implémenté mon propre "HorizontalListView" à partir de rien. La seule façon d'outrepasser réellement la fonction de verrouillage central de la galerie est d'outrepasser le paramètre privé scrollIntoSlots
ce qui, je crois, nécessiterait de générer une sous-classe au moment de l'exécution. Si vous êtes assez audacieux pour le faire, c'est sans doute la meilleure solution, mais je ne veux pas me fier à des méthodes non documentées qui pourraient changer.
Swathi EP ci-dessous a suggéré que je donne le Gallery
un OnTouchListener
et remplacer la fonctionnalité de défilement. Si vous ne vous souciez pas de la prise en charge du défilement dans votre liste, ou si vous êtes d'accord pour que les vues reviennent au centre à la fin de l'animation du défilement, alors cette option est la suivante sera travailler pour vous ! Cependant, au final, il s'avère toujours impossible de supprimer la fonction de verrouillage central sans supprimer le support du fling. Et je vous le demande, quel genre de liste n'a pas de fling ?
Donc, hélas, cela n'a pas fonctionné pour moi :-( Mais si cette approche vous intéresse, lisez la suite...
J'ai également dû faire quelques ajouts au code de Swathi pour obtenir ce que je voulais. Dans GestureListener.onTouch
en plus de déléguer au détecteur de gestes, je devais également renvoyer true pour les éléments suivants ACTION_UP
y ACTION_CANCEL
événements. Cela a permis de désactiver la fonction de verrouillage central, mais aussi de désactiver le flingage. J'ai pu réactiver le flottement en faisant en sorte que mon propre GestureListener soit délégué à l'événement onFling
méthode. Si vous voulez l'essayer, allez dans votre code d'exemple ApiDemos et remplacez la classe Gallery1.java par le code suivant :
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);
}
}
}