У меня есть GridView в приложении, над которым я работаю. Я хотел бы иметь возможность изменять порядок элементов в GridView с помощью drag-and-drop. Я нашел много помощи для ListViews, но ничего не было в GridViews. Я хочу добиться такого поведения, как в этом приложении launcher http://www.youtube.com/watch?v=u5LISE8BU_E&t=5m30s. Любые идеи?
Android GridView переупорядочивает элементы с помощью Drag and Drop
Ответ 1
Если вы не решите эту проблему, я предоставил свой код. Но он работает на Android 3.0 и выше, потому что я использую инфраструктуру drag-n-drop для Android
grid = (GridView) findViewById(R.id.grid);
grid.setAdapter(new DragGridAdapter(items, getActivity()));
....
grid.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
GridView parent = (GridView) v;
int x = (int) event.getX();
int y = (int) event.getY();
int position = parent.pointToPosition(x, y);
if (position > AdapterView.INVALID_POSITION) {
int count = parent.getChildCount();
for (int i = 0; i < count; i++) {
View curr = parent.getChildAt(i);
curr.setOnDragListener(new View.OnDragListener() {
@Override
public boolean onDrag(View v, DragEvent event) {
boolean result = true;
int action = event.getAction();
switch (action) {
case DragEvent.ACTION_DRAG_STARTED:
break;
case DragEvent.ACTION_DRAG_LOCATION:
break;
case DragEvent.ACTION_DRAG_ENTERED:
v.setBackgroundResource(R.drawable.shape_image_view_small_gallery_selected);
break;
case DragEvent.ACTION_DRAG_EXITED:
v.setBackgroundResource(R.drawable.shape_image_view_small_gallery_unselected);
break;
case DragEvent.ACTION_DROP:
if (event.getLocalState() == v) {
result = false;
} else {
View droped = (View) event.getLocalState();
GridItem dropItem = ((DragGridItemHolder) droped.getTag()).item;
GridView parent = (GridView) droped.getParent();
DragGridAdapter adapter = (DragGridAdapter) parent.getAdapter();
List<GridItem> items = adapter.getItems();
View target = v;
GridItem targetItem = ((DragGridItemHolder) target.getTag()).item;
int index = items.indexOf(targetItem);
items.remove(dropItem);
items.add(index, dropItem);
adapter.notifyDataSetChanged();
}
break;
case DragEvent.ACTION_DRAG_ENDED:
v.setBackgroundResource(R.drawable.shape_image_view_small_gallery_unselected);
break;
default:
result = false;
break;
}
return result;
}
});
}
int relativePosition = position - parent.getFirstVisiblePosition();
View target = (View) parent.getChildAt(relativePosition);
DragGridItemHolder holder = (DragGridItemHolder) target.getTag();
GridItem currentItem = holder.item;
String text = currentItem.getFile().getAbsolutePath();
ClipData data = ClipData.newPlainText("DragData", text);
target.startDrag(data, new View.DragShadowBuilder(target), target, 0);
}
}
return false;
и DragGridAdapter
public class DragGridAdapter extends BaseAdapter{
private Context context;
private List<GridItem> items;
public DragGridAdapter(List<GridItem> items, Context context){
this.context = context;
this.items = items;
}
@Override
public int getCount() {
return items.size();
}
@Override
public Object getItem(int position) {
return items.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
DragGridItemHolder holder;
if (convertView == null) {
holder = new DragGridItemHolder();
ImageView img = new ImageView(context);
holder.image = img;
convertView = img;
convertView.setTag(holder);
} else {
holder = (DragGridItemHolder) convertView.getTag();
}
holder.item = items.get(position);
holder.image.setImageBitmap(items.get(position).getBitmap());
return convertView;
}
public List<GridItem> getItems() {
return items;
}
Надеюсь, это поможет вам.
Ответ 2
Моя версия для отображения сетки перетаскивания https://github.com/askerov/DynamicGrid.
Он расширяет оригинальный GridView, поддерживает перетаскивание, чтобы переупорядочить элементы, автоматически прокручивать, если перетащить экран. Он полностью работает на 3.0+ api, но поддерживает 2,2 и 2,3 с ограничениями (без анимации).
Ответ 3
Посмотрите на thquinn DraggableGridView, это было разработано с таргетингом на Android 2.2 (уровень API 8). Надеюсь, это поможет кому-то:)
Ответ 4
Используя фреймворк drag-n-drop, вместо этого, управляя дочерними элементами и устанавливая draglistener, я использую в качестве контейнера макета элемента сетки DragableLinearLayout, который расширяет LinearLayout и реализует метод onDragEvent (DragEvent).
Итак, вы можете заполнить свою сетку адаптером, как обычно, и большая часть кода перетаскивания находится на onDragEvent из DragableLinearLayout
public class DragableLinearLayout extends LinearLayout {
public DragableLinearLayout(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
}
public DragableLinearLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public DragableLinearLayout(Context context) {
super(context);
}
@Override
public boolean onDragEvent(DragEvent event) {
//in wich grid item am I?
GridView parent = (GridView) getParent();
Object item = parent.getAdapter().getItem(
parent.getPositionForView(this));
//if you need the database id of your item...
Cursor cur = (Cursor) item;
long l_id = cur.getLong(cur.getColumnIndex("youritemid"));
switch (event.getAction()) {
case DragEvent.ACTION_DRAG_STARTED:
return true;
case DragEvent.ACTION_DRAG_ENTERED:
setBackgroundColor(Color.GREEN);
invalidate();
return true;
case DragEvent.ACTION_DRAG_EXITED:
setBackgroundColor(Color.WHITE);
invalidate();
return false;
case DragEvent.ACTION_DROP:
ClipData cd = event.getClipData();
long l_id_start = Long.valueOf(cd.getItemAt(0).getText()
.toString());
//
Toast.makeText(getContext(), "DROP FROM " + l_id_start
+ " TO " + l_id, Toast.LENGTH_LONG);
//do your stuff
........
//the db requery will be on the onDragEvent.drop of the container
//see the listener
return false;
case DragEvent.ACTION_DRAG_ENDED:
setBackgroundColor(Color.WHITE);
invalidate();
//
return false;
}
return true;
}
}
private View.OnDragListener listenerOnDragEvent = new View.OnDragListener() {
public boolean onDrag(View v, DragEvent event) {
// Defines a variable to store the action type for the incoming
// event
final int action = event.getAction();
switch (action) {
case DragEvent.ACTION_DROP:
// REQUERY
updateDbView();
return false;
// break;
}
return true;
}
};
Ответ 5
Нелегко дать короткий ответ на этот вопрос, так как есть сотни строк кода: вам нужно перехватить начало перетаскивания, обычно на onLongClick, скрыть представление, инициировавшее действие, показать наложение, которое может перемещаться, пока пользователь все еще находится в касании вниз, и, наконец, совершает изменения при касании. Лучший способ - расширить стандартный GridView в android.widget. Результат выглядит следующим образом:
Вот видео-демонстрация youtube, которая может показаться вам полезной: http://www.youtube.com/watch?v=m4yktX3SWSs&feature=youtu.be
Я также собрал более подробный ответ в статье в своем блоге, вы можете найти ее полезной, поскольку она поставляется с полным примером исходного кода. Ссылка: http://www.pocketmagic.net/2013/11/complex-android-gridview-with-drag-and-drop-functionality/
Ответ 6
Недавно я нашел решение, на котором его автор провел довольно много времени здесь http://blahti.wordpress.com/2012/03/03/improved-drag-drop-for-gridview/ Есть 4 предыдущих связанных сообщения в блоге, объясняющих, что происходит более подробно там.
Ответ 7
Возможно, проект PagedDragDropGrid - это то, что вам нужно: https://github.com/mrKlar/PagedDragDropGrid
Он предоставляет пользовательский ViewGroup
(аналогичный GridView) с функцией плавного переупорядочения (точно так же, как в вашем видео). Вероятно, для этого потребуется немного настроек, но это стоит.
Надеюсь, что это поможет.
Ответ 8
Здесь библиотека из h6ah4i, которая использует преимущества Recycler Views, чтобы предложить gridview с функцией перетаскивания с возможностями переупорядочения.
Ответ 9
Google недавно выпустил несколько лабораторий кода несколько месяцев назад. https://codelabs.developers.google.com/codelabs/android-training-adaptive-layouts/index.html?index=..%2F..%2Fandroid-training#0
Вы можете проверить решение этого здесь https://github.com/google-developer-training/android-fundamentals-apps-v2/tree/master/MaterialMe-Resource
Они создают сетку с подвижными карточками, которые можно перетаскивать в любое место макета с помощью itemTouchHandler.
Более подробный код о том, как выполнять перетаскивание, находится здесь. Вам нужно изучить задачу 3: сделать раздел CardView смахивающим, подвижным и интерактивным.