Desplaza la vista de cuadrícula mientras arrastra el elemento (como sombra)

Estoy desarrollando para api> 14 y he implementado la funcionalidad de arrastrar / soltar en un GridView .

Sin embargo, al arrastrar elementos a la parte superior o inferior de la pantalla, el GridView no se desplaza.

Me gustaría tenerlo desplazarse en la dirección en la que arrastra un elemento cada vez más rápido a medida que se mueve hacia el borde y lento como mover el elemento de nuevo hacia el centro vertical de la pantalla.

Seguramente este tipo de funcionalidad debe ser estándar en cualquier drag-n-drop?

De todos modos, ¿alguien sabe la mejor manera de abordar esto?

ACTUALIZACIÓN : En realidad no puedo encontrar un ejemplo en Internet que intente desplazarse con un elemento de cuadrícula arrastrado (¿me estoy perdiendo algo aquí?) Y mucho menos resolver mi problema.

¿Cómo se obtiene el elemento arrastrable (que aparece como una sombra) para desplazarse por la vista de cuadrícula? Estoy asignando el arrastre de la siguiente manera:

 int gridChildPosition = position - mGridView.getFirstVisiblePosition(); ViewFlipper gridItem = (ViewFlipper) mGridView.getChildAt(gridChildPosition); ClipData data = ClipData.newPlainText("", ""); DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(gridItem); if (mGridView.startDrag(data, shadowBuilder, gridItem, 0)) { int lastVisiblePosition = mGridView.getLastVisiblePosition() - mGridView.getFirstVisiblePosition(); for (int i=0; i<=lastVisiblePosition; i++) { if (i == gridChildPosition) { continue; } mGridView.getChildAt(i).setOnDragListener(new GridItemDragListener(position)); mGridView.getChildAt(i).setAlpha(0.4f); } } 

Por encima del código crea la sombra arrastrable y todos los demás elementos se atenúan. Pero no estoy seguro de cómo puedo obtener la sombra para desplazarse por la vista de cuadrícula.

Lo bueno de Drag Events es que también puedes escucharlos en el grupo de padres ViewGroup . Extienda GridView y onDragEvent para supervisar DragEvent.ACTION_DRAG_LOCATION . Allí, obtenga las coordenadas Y ( event.getY() ) de la resistencia. Asegúrese de devolver true de ACTION_DRAG_STARTED o no recibirá el evento en ACTION_DRAG_LOCATION .

Determine sus "hit boxes", tal vez usando la técnica que sugiere jaibatrik , o simplemente usando un porcentaje de la altura medida de GridView.

Probablemente tendría más sentido usar smoothScrollByOffset(int offset) , de esta manera puede implementar scroll escalonado / exponencial. Es decir, cuanto más tiempo el usuario mantiene el elemento arrastrado en el cuadro de resultados, mayor es el desplazamiento.

Suena como una idea genial para una biblioteca / componente de código abierto. D

EDITAR:

He aquí un ejemplo de cómo podría hacer esto:

 import android.app.Activity; import android.content.ClipData; import android.content.ClipData.Item; import android.content.Context; import android.os.Bundle; import android.util.Log; import android.view.DragEvent; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemLongClickListener; import android.widget.ArrayAdapter; import android.widget.GridView; public class GridDragActivity extends Activity implements OnItemLongClickListener { private static final String TAG = "GridDragActivity"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); MyGridView gridView = new MyGridView(this); gridView.setNumColumns(3); gridView.setOnItemLongClickListener(this); gridView.setAdapter(new ArrayAdapter<String>( this, android.R.layout.simple_list_item_1, COUNTRIES)); setContentView(gridView); } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { ClipData data = ClipData.newPlainText((String) view.getTag(), String.valueOf(position)); View.DragShadowBuilder shadow = new View.DragShadowBuilder(view); view.startDrag(data, shadow, null, 0); return true; } class MyGridView extends GridView { private static final int THRESHHOLD = 200; private static final int OFFSET = 10; public MyGridView(Context context) { super(context); } @Override public boolean onDragEvent(DragEvent event) { int height = getMeasuredHeight(); switch (event.getAction()) { case DragEvent.ACTION_DRAG_STARTED: return true; case DragEvent.ACTION_DRAG_LOCATION: float y = event.getY(); if (height - y < THRESHHOLD) { smoothScrollByOffset(OFFSET); } else if (height - y > height - THRESHHOLD) { smoothScrollByOffset(-OFFSET); } return true; case DragEvent.ACTION_DROP: ClipData data = event.getClipData(); Item item = data.getItemAt(0); int start = Integer.valueOf((String) item.getText()); int end = pointToPosition((int) event.getX(), (int) event.getY()); Log.i(TAG, "DROP started at = " + start + ", ended at = " + end); return true; } return super.onDragEvent(event); } } static final String[] COUNTRIES = new String[] { "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina", "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde", "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic", "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic", "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland", "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia", "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar", "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary" }; } 

Creo que necesitas usar los métodos smoothScrollToPosition(int position) o smoothScrollByOffset(int offset) de GridView . Tome dos rectángulos en la parte superior e inferior de la pantalla. Si el evento táctil se recibe en esos rectángulos mientras arrastra, desplácese por GridView . Puede obtener la última posición visible en cualquier momento utilizando el método getLastVisiblePosition() .

  • No se puede implementar Parcelable porque no puedo hacer que el campo CREATOR esté estático
  • Cómo almacenar Hashmap en Android para que se reutilice cuando la aplicación se reinicie con las preferencias compartidas?
  • ¿Por qué algunas bibliotecas Java utilizan funciones estáticas newInstance en lugar de constructores?
  • Unparseable date Exception Servicios móviles de Windows Azure
  • Eclipse "funciona como android" no hace nada
  • Android: ¿Una forma sencilla de hacer una geofence?
  • ¿Qué es Native Android con java?
  • Cómo leer atributos personalizados en Android
  • Android FileNotFound Exception - No se puede getInputStream desde la URL de la imagen que no tiene formato de archivo
  • Optimizaciones de Java: (Hotspot / Dalvik) Optimización del método final devolver una constante?
  • Arraylist de clasificación de Android por propiedades
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.