Movable extended floating action button

520 Views Asked by At

I am using ExtendedFloatingActionButton and make it movable on screen but it's view is missing from left side wen move it to the left of screen.

This is the image of screen where button is Working fine on right side: enter image description here

This is the image of screen where button is not working on left side: enter image description here here is the xml file:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:icon="@drawable/ic_baseline_4g_mobiledata_24"
    android:text=""
    app:iconTint="@color/white"
    android:textColor="@color/white"
    app:backgroundTint="@color/black"
    app:iconGravity="end"
    android:textAllCaps="false"
    android:layout_gravity="center|end"
    android:layout_marginBottom="20dp"
    android:layout_marginEnd="20dp"/>

And this is my main class code:

class MainActivity : AppCompatActivity(), View.OnTouchListener {
lateinit var fab: ExtendedFloatingActionButton

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


private var downRawX = 0f
private  var downRawY:kotlin.Float = 0f
private var dX = 0f
private  var dY:kotlin.Float = 0f

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val view: View = findViewById(R.id.fab);
    view.setOnTouchListener(this);

    fab = findViewById(R.id.fab)

    fab.shrink()

    fab.setOnClickListener {
        if (!fab.isExtended) {
            fab.extend()
            fab.text = "Boost: Off \nPing: 99 Jitter: 15"
            fab.maxLines = 2
            fab.background = applicationContext.getDrawable(R.drawable.fab_back)
        } else {
            fab.shrink()
            fab.background = applicationContext.getDrawable(R.drawable.circle_fab)

        }
    }
}

override fun onTouch(view: View?, motionEvent: MotionEvent): Boolean {

    val action = motionEvent.action
    return if (action == MotionEvent.ACTION_DOWN) {
        downRawX = motionEvent.rawX
        downRawY = motionEvent.rawY
        dX = view!!.x - downRawX
        dY = view!!.y - downRawY
        true // Consumed
    } else if (action == MotionEvent.ACTION_MOVE) {
        val viewWidth = view!!.width
        val viewHeight = view!!.height
        val viewParent = view!!.parent as View
        val parentWidth = viewParent.width
        val parentHeight = viewParent.height
        var newX = motionEvent.rawX + dX
        newX = Math.max(0f, newX) // Don't allow the FAB past the left hand side of the parent
        newX = Math.min(
            (parentWidth - viewWidth).toFloat(),
            newX)

        if (newX < 1.0) {
            fab.iconGravity = MaterialButton.ICON_GRAVITY_START
        } else {
            fab.iconGravity = MaterialButton.ICON_GRAVITY_END
        }
        Log.e("error", newX.toString())
        // Don't allow the FAB past the right hand side of the parent
        var newY = motionEvent.rawY + dY
        newY = Math.max(0f, newY) // Don't allow the FAB past the top of the parent
        newY = Math.min(
            (parentHeight - viewHeight).toFloat(),
            newY
        ) // Don't allow the FAB past the bottom of the parent
        view!!.animate()
            .x(newX)
            .y(newY)
            .setDuration(0)
            .start()
        true // Consumed
    } else if (action == MotionEvent.ACTION_UP) {
        val upRawX = motionEvent.rawX
        val upRawY = motionEvent.rawY
        val upDX = upRawX - downRawX
        val upDY = upRawY - downRawY
        if (Math.abs(upDX) < CLICK_DRAG_TOLERANCE && Math.abs(upDY) < CLICK_DRAG_TOLERANCE) { // A click
            performClick()
        } else { // A drag
            true // Consumed
        }
    } else {
        super.onTouchEvent(motionEvent)
    }
}

private fun performClick(): Boolean {

    if (!fab.isExtended) {
        fab.extend()
        fab.text = "Boost: Off \nPing: 99 Jitter: 15"
        fab.maxLines = 2
        fab.background = applicationContext.getDrawable(R.drawable.fab_back)
    } else {
        fab.shrink()
        fab.background = applicationContext.getDrawable(R.drawable.circle_fab)

    }
    return true
}

}

Can someone help me to figure out the problem? I don't know why it's happening like this.

1

There are 1 best solutions below

2
Simanjit On

Please check below class and its xml

package com.example.merchantdemo.customDesign;

import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;

import com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;

public class MovableFloatingActionButton extends ExtendedFloatingActionButton 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){

    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();
        }
        else { // A drag
            return true; // Consumed
        }

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

}

}

And here is the XML of MovableFloatingActionButton

<com.example.MovableFloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginEnd="@dimen/fab_margin"
    android:layout_marginBottom="16dp"
    app:icon="@android:drawable/ic_input_add"
    android:text="@string/extended_fab_label"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent" />

Hope this help you