2017-09-22 3 views
2

Ich verwende eine FloatingActionButton in meiner App. Gelegentlich überlappt es wesentliche Inhalte, deshalb möchte ich es so einrichten, dass der Benutzer die FAB aus dem Weg räumen kann.Android - Bewegliche/schleppbare Floating Action Button (FAB)

Es ist keine Drag-and-Drop-Funktionalität an sich erforderlich. Es muss nur beweglich sein. Die Dokumentation erwähnt dies nicht, aber ich bin mir sicher, dass ich diese Funktionalität in anderen Apps gesehen habe.

Können Sie jemanden beraten/bieten ein Code-Snippet, wie es zu tun ist (vorzugsweise in XML).

Antwort

8

Basierend auf this answer for another SO question ist dies der Code ich habe erstellt. Es scheint gut zu funktionieren (mit Klick-Funktionalität in Betrieb) und ist nicht abhängig von dem übergeordneten Layout des FAB oder Positionierung ...

package com.example; 

import android.content.Context; 
import android.support.design.widget.FloatingActionButton; 
import android.util.AttributeSet; 
import android.view.MotionEvent; 
import android.view.View; 

public class MovableFloatingActionButton extends FloatingActionButton implements View.OnTouchListener { 

    private final static float CLICK_DRAG_TOLERANCE = 10; // Often, there will be a slight, unintentional, drag when the user taps the FAB, so we need to account for this. 

    private float downRawX, downRawY; 
    private float dX, dY; 

    public MovableFloatingActionButton(Context context) { 
     super(context); 
     init(); 
    } 

    public MovableFloatingActionButton(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     init(); 
    } 

    public MovableFloatingActionButton(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     init(); 
    } 

    private void init() { 
     setOnTouchListener(this); 
    } 

    @Override 
    public boolean onTouch(View view, MotionEvent motionEvent){ 

     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(0, newX); // Don't allow the FAB past the left hand side of the parent 
      newX = Math.min(parentWidth - viewWidth, newX); // Don't allow the FAB past the right hand side of the parent 

      float newY = motionEvent.getRawY() + dY; 
      newY = Math.max(0, newY); // Don't allow the FAB past the top of the parent 
      newY = Math.min(parentHeight - viewHeight, 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(); 
      } 
      else { // A drag 
       return true; // Consumed 
      } 

     } 
     else { 
      return super.onTouchEvent(motionEvent); 
     } 

    } 

} 

Und hier ist die XML ...

<com.example.MovableFloatingActionButton 
     android:id="@+id/fab" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_gravity="bottom|end" 
     android:layout_margin="@dimen/fab_margin" 
     android:src="@drawable/ic_navigate_next_white_24dp"/> 

Grundsätzlich Sie müssen nur android.support.design.widget.FloatingActionButton durch com.example.MovableFloatingActionButton in Ihrem XML ersetzen.

0

Sie wie unten durch nur impletementing onTouch auf jedem View versuchen können,

xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:id="@+id/rootlayout" 
    android:layout_height="match_parent" 
    android:orientation="vertical"> 

    <android.support.design.widget.FloatingActionButton 
     android:id="@+id/fab" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" /> 

</FrameLayout> 

java

public class dragativity extends AppCompatActivity implements View.OnTouchListener{ 

    FloatingActionButton fab; 

    FrameLayout rootlayout; 

    int _xDelta; 
    int _yDelta; 

    @Override 
    protected void onCreate(@Nullable Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.drag); 

     rootlayout = (FrameLayout) findViewById(R.id.rootlayout); 

     fab = (FloatingActionButton) findViewById(R.id.fab); 

     FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(150, 150); 
     fab.setLayoutParams(layoutParams); 
     fab.setOnTouchListener(dragativity.this); 
    } 

    public boolean onTouch(View view, MotionEvent event) { 
     final int X = (int) event.getRawX(); 
     final int Y = (int) event.getRawY(); 
     switch (event.getAction() & MotionEvent.ACTION_MASK) { 
      case MotionEvent.ACTION_DOWN: 
       FrameLayout.LayoutParams lParams = (FrameLayout.LayoutParams) view.getLayoutParams(); 
       _xDelta = X - lParams.leftMargin; 
       _yDelta = Y - lParams.topMargin; 
       break; 
      case MotionEvent.ACTION_UP: 
       break; 
      case MotionEvent.ACTION_POINTER_DOWN: 
       break; 
      case MotionEvent.ACTION_POINTER_UP: 
       break; 
      case MotionEvent.ACTION_MOVE: 
       FrameLayout.LayoutParams layoutParams = (FrameLayout.LayoutParams) view 
         .getLayoutParams(); 
       layoutParams.leftMargin = X - _xDelta; 
       layoutParams.topMargin = Y - _yDelta; 
       layoutParams.rightMargin = -250; 
       layoutParams.bottomMargin = -250; 
       view.setLayoutParams(layoutParams); 
       break; 
     } 
     rootlayout.invalidate(); 
     return true; 
    } 


} 
+0

Danke Omar. Ich habe diesen Ansatz versucht, hatte aber kein Glück damit. Ich habe etwas Code, der funktioniert, aber es wird in einer Sekunde gepostet. Danke trotzdem. –

Verwandte Themen