Android - Movable/Draggable Floating Action Button (FAB)

后端 未结 9 1644
温柔的废话
温柔的废话 2020-12-28 14:47

I am using a FloatingActionButton in my app. Occasionally, it overlaps essential content, so I would like to make it so the user can drag the FAB out of the way.

No

相关标签:
9条回答
  • 2020-12-28 15:33

    All proposed answers used OnTouch listener, which is not recommended by recent Android API because of the Accessibility implementations. Note also that startDrag() method is obsolete. Developers shoud use startDragAndDrop() instead. My implementation uses OnDragListener() as follows:

    1. Define two global float variables dX and dY;
    2. Put the below snippet inside onCreatView() method, where root is root view, taken by the inflater (or any other view, which can receive Drop events);

      final FloatingActionButton fab = root.findViewById(R.id.my_fab);
      
      fab.setOnClickListener(new View.OnClickListener() {
          @Override
          public void onClick(View view) {
              // Do whatever this button will do on click event
          }
      });
      
      root.setOnDragListener(new View.OnDragListener() {
          @Override
          public boolean onDrag(View v, DragEvent event) {
              switch (event.getAction()) {
                  case DragEvent.ACTION_DRAG_LOCATION:
                      dX = event.getX();
                      dY = event.getY();
                      break;
                  case DragEvent.ACTION_DRAG_ENDED:
                      fab.setX(dX-fab.getWidth()/2);
                      fab.setY(dY-fab.getHeight()/2);
                      break;
              }
              return true;
          }
      });
      
      
      fab.setOnLongClickListener(new View.OnLongClickListener() {
          @Override
          public boolean onLongClick(View v) {
              View.DragShadowBuilder myShadow = new View.DragShadowBuilder(fab);
              v.startDragAndDrop(null, myShadow, null, View.DRAG_FLAG_GLOBAL);
              return true;
          }
      });
      
    0 讨论(0)
  • 2020-12-28 15:40

    You can try this code XML

     <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:id="@+id/dashboardShowActionsFab"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
    

    JAVA

    fab.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
    
    
                ViewGroup.MarginLayoutParams layoutParams = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
    
                int action = motionEvent.getAction();
                if (action == MotionEvent.ACTION_DOWN) {
    
                    downRawX = motionEvent.getRawX();
                    downRawY = motionEvent.getRawY();
                    dX = view.getX() - downRawX;
                    dY = view.getY() - downRawY;
    
                    return true; // Consumed
    
                } else if (action == MotionEvent.ACTION_MOVE) {
    
                    int viewWidth = view.getWidth();
                    int viewHeight = view.getHeight();
    
                    View viewParent = (View) view.getParent();
                    int parentWidth = viewParent.getWidth();
                    int parentHeight = viewParent.getHeight();
    
                    float newX = motionEvent.getRawX() + dX;
                    newX = Math.max(layoutParams.leftMargin, newX); // Don't allow the FAB past the left hand side of the parent
                    newX = Math.min(parentWidth - viewWidth - layoutParams.rightMargin, newX); // Don't allow the FAB past the right hand side of the parent
    
                    float newY = motionEvent.getRawY() + dY;
                    newY = Math.max(layoutParams.topMargin, newY); // Don't allow the FAB past the top of the parent
                    newY = Math.min(parentHeight - viewHeight - layoutParams.bottomMargin, newY); // Don't allow the FAB past the bottom of the parent
    
                    view.animate()
                            .x(newX)
                            .y(newY)
                            .setDuration(0)
                            .start();
    
                    return true; // Consumed
    
                } else if (action == MotionEvent.ACTION_UP) {
    
                    float upRawX = motionEvent.getRawX();
                    float upRawY = motionEvent.getRawY();
    
                    float upDX = upRawX - downRawX;
                    float upDY = upRawY - downRawY;
    
                    if (Math.abs(upDX) < CLICK_DRAG_TOLERANCE && Math.abs(upDY) < CLICK_DRAG_TOLERANCE) { // A click
                        // return performClick();
                        Toast.makeText(MainActivity.this, "clicked", Toast.LENGTH_SHORT).show();
    
                    } else { // A drag
                        return true; // Consumed
                    }
    
                } else {
                    //return super.onTouchEvent(motionEvent);
                }
    
                return true;
            }
    
    0 讨论(0)
  • 2020-12-28 15:46

    actually you can just use android.support.design.widget.CoordinatorLayout instead of Relative layout or any other layout and this will work(moving FAB)

    0 讨论(0)
提交回复
热议问题