在java中拖动多个按钮视图

Posted

技术标签:

【中文标题】在java中拖动多个按钮视图【英文标题】:Dragging multiple button views in java 【发布时间】:2015-11-23 12:20:34 【问题描述】:

我有一个应用程序,我需要在其中移动一堆按钮(就像将一堆卡片的一部分从一堆移动到另一堆一样)。我已经在 xml 布局中定义了所有按钮,并为所有人设置了触摸和拖动侦听器。 我可以单独在屏幕上拖放任何按钮。但在某些情况下,我需要做的是拖动堆叠在我同时单击的原始按钮顶部的其他按钮。 有没有办法“欺骗”或模拟按下另一个按钮(以便侦听器注册它)? 谢谢 ***编辑于 2015 年 9 月 8 日 @覆盖 public boolean onTouch(View v, MotionEvent e) // tosty("mclicking: "+mClicking); int startpos = 0; switch (e.getAction() & MotionEvent.ACTION_MASK)

    case MotionEvent.ACTION_DOWN:

        isWastePile=false;

        get_selected_deck(v); // determines which of 7 decks or layouts in the tablau you have
                                // clicked
        FromDeck = selecteddeck;
        FromDeckCard = deckcard;
        FromDeckButton = deckbutton;
        // if (!mClicking) 
        mClicking = true;
        //String piecetag = (String) v.getTag();

        // // IDEA!!!/ ///
        /*
         * I wrote a function that finds all the ImageButtons below where
         * the user clicked, and set them all to invisible. I then created a
         * new Linear Layout within the Linear Layout that the user clicked (during the ACTION_DOWN event),
         * and passed that into the Drag Shadow builder during the ACTION_MOVE event.
         * 
         * Once into the ACTION_DROP portion, I simply referenced global
         * variables to figure out if the user dropped in one or multiple
         * ImageButtons, and dealt with them accordingly.
         */

        //if (!isWastePile) 
        //draglayout.setClipChildren(false);
        lltemp = new LinearLayout(this);
        lltemp.setOrientation(LinearLayout.VERTICAL);
        LinearLayout.LayoutParams llparams = new LinearLayout.LayoutParams(
                LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);

        llparams.setMargins(0, -52, 0, 0);
        lltemp.setLayoutParams(llparams);
        draglayout.addView(lltemp);


        for (int i = 0; i < deckstack_list[selecteddeck].size(); i++) 
            if (v == (draglayout.getChildAt(i))) 
                startpos = i;
                for (int o = i; o < deckstack_list[selecteddeck].size(); o++) 
                    // layout5.removeViewAt(o);
                    draglayout.getChildAt(o).setVisibility(View.GONE); // all
                                                                            // buttons
                                                                            // being
                    dragtempstack.push((Integer) deckstack_list[selecteddeck].get(o))   ;                                                   // dragged
                                                                            // to
                                                                            // invisible
                    // then recreate another linear layout within layout5
                    // and pass to dragshadow builder
                    // to do

                    // also set a GLOBAL variable with stack count (number
                    // of cards dragged)
                    lltemp.setClipChildren(false);
                    lltemp.addView(createtempButtons(o, startpos));


                

            
        
        // // end if wastepile check statement

        //tosty("dragtempstack size: "+dragtempstack.size());

        break;

    case MotionEvent.ACTION_MOVE:

        //tosty("Action MOVE");
        Log.i("ACTION Event: ", "ACTION MOVE");
        // v = layout5;


        v = lltemp;


        v.setVisibility(View.INVISIBLE);
        v.bringToFront();
        v.invalidate();
        v.setVisibility(View.VISIBLE);

        //DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(v);
        DeckDragShadow shadowBuilder = new DeckDragShadow(v);
        v.startDrag(null, shadowBuilder, v, 0);


        correctDrag = false;

        break;

    private Button createtempButtons(final int i, final int startpos) 
    final Button b = new Button(this);

    b.setOnTouchListener(this);
    b.setOnDragListener(new DeckDragListener());

    b.setBackgroundResource(cardimagearray[dragdeckstack.get(i)]);

    float width = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            45, getResources().getDisplayMetrics());
    float height = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            61, getResources().getDisplayMetrics());

    LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
            (int) width, (int) height);
    float margTop = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
            -36, getResources().getDisplayMetrics());

    if (i > startpos) 
        params.setMargins(0, -57, 0, 0);
    

    b.setLayoutParams(params);

    // b.bringToFront();
    // b.invalidate();
    b.setVisibility(View.VISIBLE);

    return b;

【问题讨论】:

进一步澄清,纸牌是我需要做的一个很好的例子。单击卡片堆中任意位置的卡片,然后将所有卡片拖动到单击的原始按钮的顶部。我可以通过循环更改所有其他卡片的背景、可见性等,但似乎无法拖动所有卡片。 我假设您已经有了要移动视图的东西,那么为什么不移动按钮,而是创建并移动包含按钮的布局呢? 是的,正确我有线性布局的按钮。如果我将线性布局视图传递到拖动阴影生成器中,所有按钮都会移动。但是当我尝试使用我想要移动的按钮重新创建一个临时线性布局时,例如一半的按钮,我遇到了拖动问题。这是我一直在尝试的一些代码 【参考方案1】:

我不会尝试为每个按钮复制侦听器,而是将按钮视为组。当您单击组中的按钮时,它会分成两组:上面有按钮的按钮和您留下的按钮。然后将该组拖放到其他组上。

正如 Templerschaf 所建议的,这些组可以是 LinearLayouts:

你点击LinearLayout 它注册了哪个项目 创建一个新的 LinearLayout,在正确位置包含该项目下方的项目 删除点击项下的项并相应调整大小 然后布局可以继续拖拽 然后可以将其放到另一个 LinearLayout 上,这会将项目添加到自己的列表中

这很像 ListView 动画。见:

https://www.youtube.com/watch?v=_BZIvjMgH-Q

https://www.youtube.com/watch?v=mwE61B56pVQ

https://github.com/bauerca/drag-sort-listview/blob/master/library/src/com/mobeta/android/dslv/DragSortListView.java

【讨论】:

我有点理解你的意思,我在创建新的 LinearLayout 后卡住了(dragshadow 不会随着新布局更新),因为我已经点击了按钮,它开始了你建议的过程1.单击布局,2.我检测/注册哪个按钮,3.我创建一个新的临时线性布局,顶部附加按钮并将其传递给dragshadow,但是如何让图像更新为新的线性当我还在触摸按钮时布局?在拖动过程中,它仍然只拖动我点击的原始按钮。 一旦我完成拖动,新的线性布局就会被绘制到屏幕上。我也需要在拖动前的第一次按下或长按时发生这一切。希望这是有道理的 您可能希望在 Button 和包含该按钮的行布局上将 clickable 设置为 false,以便 LinearLayout 处理拖动。您需要分别响应初始单击和拖动,因此您可能需要 onTouchEvent。我认为这是在我链接到的第一个视频中完成的。我不相信您需要像该视频中那样创建 BitmapDrawable:使用 LinearLayout 应该是可能的。 感谢大家的帮助,我终于找到工作了,也许不太理想,性能会告诉我是否会保留这种方法。但最大的不同在于 onTouch 方法,我将创建另一个布局和使用新布局创建拖动阴影这两个动作分开。我使用 ACTION_DOWN 事件来执行所有视图的创建和删除等操作。然后在 ACTION_MOVE 部分中,我将新创建的布局传递给 dragshadow 构建器。 然后使用一些额外的命令,比如bringToFront(新布局出现在预先存在的图像后面)和invalidate() 来重绘。我现在可以将多个图像从一个布局拖放到另一个布局。

以上是关于在java中拖动多个按钮视图的主要内容,如果未能解决你的问题,请参考以下文章

可以拖动到视图控制器中的任何位置的浮动按钮?

跨多个子视图的 SwiftUI 拖动手势

滚动视图,按钮事件交换

如何检查拖动视图的位置是不是位于另一个视图之上

xcode / storyboard:无法将栏按钮拖动到顶部的工具栏

从控制多个场景的视图控制器中禁用 uibutton