Подтвердить что ты не робот

Ненавязчивое всплывающее окно, которое не блокирует перетаскивание n в Android

Я работаю над приложением launcher для Android, похожим на nova launcher. У меня есть настройка OnItemLongClickListener и OnDragListener. Когда я долго нажимаю на значок, появляется всплывающее меню с меню, например "Удалить", "Изменить значок" и т.д. На следующем рисунке показано, как работает приложение с всплывающим окном, а затем Длительное нажатие.

введите описание изображения здесь

Проблема заключается в том, что всплывающее окно открывается, но переключение не работает. Кажется, что я не могу зарегистрировать позицию x, y, когда всплывающее окно открыто. Также при выполнении кавычек в logcat отображается следующее сообщение.

I/ViewRootImpl: Reporting drop result: false

Мой код выглядит примерно так в OnDragListener

public boolean onDrag(View v, DragEvent event) {
int dragEvent = event.getAction();
switch (dragEvent)
    {
        case DragEvent.ACTION_DRAG_LOCATION:
        //Open popup here; note: its opened only once. popup.show();
        //Log.i("Position x : ", Float.toString(event.getX())); log x or y

        /*code to detect x any y change amount and close the popup
          once user drags the icon little further and app knows that
          user is trying to drag instead of opening the popup
          and hence close the popup. popup.dismiss();
        */

        // other case like ACTION_DROP etx goes after this
    }
 }

Но кажется, что после всплывающего окна я не могу зарегистрировать x или y; также не может быть запущен код, определяющий, было ли действие предназначено для "перетаскивания" или "всплывающего окна".

Итак, как я могу решить эту проблему? Я хочу закрыть всплывающее окно, как только количество перетаскивания в любом из них достаточно, чтобы знать, что пользователь хочет перетащить. И если не остановить перетаскивание и отобразить всплывающее окно.

Edit

Я решил проблему с помощью всплывающего окна, используя как OnTouchListner, так и OnDragListner. Следующий показывает мой код для OnDragListner.

//bottomAppDrawer is a GridView
bottomAppDrawer.setOnDragListener(new View.OnDragListener() {
        @Override
        public boolean onDrag(View v, DragEvent event) {
            int dragEvent = event.getAction();
            LinearLayout draggedItem = (LinearLayout) event.getLocalState(); //dragged LinearLayout

            GridView targetItem = (GridView) v; /* How do i get this drop target as LinearLayout so that i can delete or swap data */

            switch (dragEvent)
            {
                case DragEvent.ACTION_DRAG_LOCATION:
                    if(reset==false) {
                        dragPositionStart = event.getX();
                        reset= true;
                    }

                    if(Math.abs(dragPositionStart - event.getX())>=20) {
                        Log.i("Position close : ", Float.toString(dragPositionStart));

                        if(isPopupOpen) {
                            popupMenu.dismiss();
                            v.startDrag(data, dragShadow, itemView, 0);
                            Toast.makeText(mContext, "popup closed", Toast.LENGTH_SHORT).show();
                            isPopupOpen = false;
                        }

                        reset = false;
                    }

                    break;

                case DragEvent.ACTION_DROP:



                    Toast.makeText(mContext, "drop" + Integer.toString(targetItem.getChildCount()), Toast.LENGTH_SHORT).show();

                    break;


            }

            return true;
        }
    });

Теперь проблема в том, что я получаю целевой объект "Gridview" , поскольку я бросаю LinearLayout в "Gridview" . Кроме того, этот "LinearLayout" является дочерним элементом "Gridview" . И я хочу, чтобы цель кавычки была другой "LinearLayout" внутри одного и того же "GridView", чтобы я мог менять данные или переупорядочивать. Как показано на рисунке ниже.

введите описание изображения здесь

4b9b3361

Ответ 1

Из того, что я понимаю, есть две вещи, которые вы хотите сделать. 1) Измените порядок просмотров после перетаскивания. и 2) Измените типы просмотра после изменения порядка.

Для проблемы 1, поскольку это сетка, это звучит так, будто мы просто хотим изменить порядок данных в адаптере и, возможно, изменить данные, чтобы они отображались по-разному. Но нам нужно выяснить позицию исходного пункта и целевой позиции назначения.

мы можем расширить GridView, чтобы сделать это:

public class DragAndDropGridView extends GridView {

    public void handleMove(int x, int y, int originalPosition) {


        Rect rect = new Rect();
        PushbackAdapter adapter = (PushbackAdapter) getAdapter();

        for (int visiblePosition = getFirstVisiblePosition(); visiblePosition <= getLastVisiblePosition(); visiblePosition++) {
            // TODO verify that there are no edge cases not covered by this

            View view = getChildAt(visiblePosition);
            int left = view.getLeft();
            int top = view.getTop();
            getChildVisibleRect(view, rect, null);
            rect.offsetTo(left, top);
            if (rect.contains(x, y)) {
                // yay the user tried drop the view at this location
                // determine if they wanted to drop it here or after this side
                int centerX = rect.centerX();
                if (x <= centerX) {
                    // we want to drop it here
                    adapter.move(originalPosition, visiblePosition);
                    adapter.notifyDataSetInvalidated();
                    break;
                } else {
                    // we want to drop it behind
                    adapter.move(originalPosition, visiblePosition + 1);
                    adapter.notifyDataSetInvalidated();
                    break;
                }
            }

        }
    }
}  

Это оставляет нам вызов handleMoveMethod. Мы делаем это из метода ACTION_DROP.

                 case DragEvent.ACTION_DROP:


                        handleMove((int)event.getX(), (int)event.getY(), getPositionForView(draggedItem));


                        Toast.makeText(mContext, "drop" + Integer.toString(targetItem.getChildCount()), Toast.LENGTH_SHORT).show();

                        break;

Наконец, проблема (2) кажется, что вы можете изменить либо содержимое объекта в позиции, либо тип вида, в котором он содержится. Я бы предложил использовать методы getItemViewType и getItemViewTypeCount, если вам нужно различные виды просмотров. Например. что-то вроде следующих:

    private static class PushbackAdapter extends ArrayAdapter {

    ArrayList<Object> mItems;

    public void move(int originalPosition, int targetPosition){
        // TODO verify that this move logic is correct
        Object item = mItems.remove(originalPosition);
        item.useLinearLayoutType(true);
        mItems.add(targetPosition, item);
    }

    ...

    @Override
    public int getItemViewType(int i) {
        return mItems.get(i).isLeanearLayoutType()? 1 : 0;
    }

Там могут быть ошибки, поэтому, пожалуйста, тщательно протестируйте

Ответ 2

Найдите позицию LinerLayout (которая перетаскивается) в Gridview с помощью targetItem.pointToPosition(..).

Проведите LinerLayout с помощью кода ниже:

int i =targetItem.pointToPosition((int)event.getX(), (int)event.getY());
int j = Integer.parseInt(event.getClipData().getItemAt(0).getText().toString());
Collections.swap(targetItem, i, j);//swap Linerlayout
Log.i(TAG, "Swapped " + i+ " with " + j);

Код не проверен. Надеюсь, это поможет вам.:)