Возможный дубликат:
Horizontal ListView в Android?
Как и многие другие вещи в Android, вы не подумаете, что это такая сложная проблема, но, черт возьми, вы ошибаетесь. И, как и многое другое в Android, API даже не предоставляет достаточно расширяемой отправной точки. Будь я проклят, если собираюсь свернуть свой собственный ListView, когда все, что мне нужно, - это взять его и перевернуть на бок. \ rant
Хорошо, теперь, когда я перестал злиться, давайте поговорим о самой проблеме. Мне нужно что-то вроде Gallery
, но без функции блокировки по центру. Мне действительно не нужен listSelector ListView
, но он полезен. В основном, я мог бы делать то, что хочу, с LinearLayout
внутри ScrollView
, но мне нужно, чтобы дочерние представления исходили от ListAdapter
, и мне бы очень хотелось иметь переработчик представлений. И я действительно не хочу писать код макета.
Я заглянул в исходный код некоторых из этих классов ...
Галерея: Похоже, я мог бы использовать Галерею, если бы переопределил большинство методов onXyz, скопировал весь их исходный код, но воздержался от вызова scrollIntoSlots()
. Но я уверен, что если я это сделаю, я наткнусь на какое-то недоступное поле для членов или с другими непредвиденными последствиями.
AbsSpinner: Поскольку поле mRecycler
является закрытым для пакета, я сомневаюсь, что смогу расширить этот класс.
AbsListView: Похоже, этот класс предназначен только для вертикальной прокрутки, поэтому здесь нет никакой помощи.
AdapterView: Мне никогда не приходилось напрямую расширять этот класс. Если вы скажете мне, что это легко сделать, и что легко раскатать свой RecycleBin
, я буду очень скептически настроен, но я попробую.
Полагаю, я мог бы скопировать оба AbsSpinner
и Gallery
, чтобы получить то, что я хочу ... надеюсь, эти классы не используют какую-то частную переменную пакета, к которой я не могу получить доступ. Вы все думаете, что это хорошая практика? Есть ли у кого-нибудь учебные пособия или сторонние решения, которые могут направить меня в правильном направлении?
Обновление:
Единственное решение, которое я нашел до сих пор, - это делать все самостоятельно. Задав этот вопрос, я переопределил AdapterView
и реализовал свой собственный HorizontalListView с нуля. Единственный способ по-настоящему переопределить функцию блокировки центра галереи - это переопределить частный метод scrollIntoSlots
, который, как мне кажется, потребует создания подкласса во время выполнения. Если у вас хватит смелости сделать это, это, пожалуй, лучшее решение, но я не хочу полагаться на недокументированные методы, которые могут измениться.
Swathi EP ниже предложил мне присвоить Gallery
OnTouchListener
и переопределить функцию прокрутки. Если вам не важна поддержка меток в вашем списке, или если представления могут привязываться к центру в конце анимации метания, то это будет работать для вас! Однако, в конце концов, по-прежнему невозможно удалить центральную блокировку без снятия откидной опоры. И я спрашиваю вас, в какой список не выкидывают?
Так что, увы, у меня это не сработало. :-( Но если вам интересен такой подход, читайте дальше ...
Мне также пришлось внести некоторые дополнения в код Swathi, чтобы получить то, что я хотел. В GestureListener.onTouch
, помимо делегирования детектору жестов, мне также приходилось возвращать истину для событий ACTION_UP
и ACTION_CANCEL
. Это успешно отключило функцию блокировки по центру, но также отключило подбрасывание. Мне удалось снова включить бросок, имея моего собственного делегата 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);
}
}
}