Android自定义可拖拽的悬浮按钮DragFloatingActionButton

悬浮按钮FloatingActionButton是Android 5.0系统添加的新控件,FloatingActionButton是继承至ImageView,所以FloatingActionButton拥有ImageView的所有属性。本文讲解的是一个实现了可拖拽的悬浮按钮,并为此添加了类似于qq的吸附边框的功能。在此之前,先了解下其简单的使用方式吧:

首先你得添加其依赖

compile 'com.android.support:design:25.3.1'

然后在布局文件中使用。

<android.support.design.widget.FloatingActionButton
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_gravity="right|bottom"
   android:src="@drawable/ic_launcher"
   />

如图:

FloatingActionButton正常显示的情况下有个填充的颜色,有个阴影;点击的时候会有一个rippleColor,并且阴影的范围可以增大。其中:

1、填充的颜色默认使用就是style当中的colorAccent。

2、rippleColor默认取的是Theme当中的colorControlHighlight。

3、elevation和pressedTranslationZ,前者用户设置正常显示的阴影大小;后者是点击时显示的阴影大小。

好了,现在介绍本文的重点:可拖拽的,有吸附功能的悬浮按钮

先上代码。

import android.animation.ObjectAnimator;
import android.content.Context;
import android.support.design.widget.FloatingActionButton;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.animation.DecelerateInterpolator;
public class DragFloatActionButton extends FloatingActionButton {
 private int screenWidth;
 private int screenHeight;
 private int screenWidthHalf;
 private int statusHeight;
 private int virtualHeight;
 public DragFloatActionButton(Context context) {
  super(context);
  init();
 }
 public DragFloatActionButton(Context context, AttributeSet attrs) {
  super(context, attrs);
  init();
 }
 public DragFloatActionButton(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  init();
 }
 private void init() {
  screenWidth = ScreenUtils.getScreenWidth(getContext());
  screenWidthHalf = screenWidth / 2;
  screenHeight = ScreenUtils.getScreenHeight(getContext());
  statusHeight = ScreenUtils.getStatusHeight(getContext());
  virtualHeight=ScreenUtils.getVirtualBarHeigh(getContext());
 }
 private int lastX;
 private int lastY;
 private boolean isDrag;
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  int rawX = (int) event.getRawX();
  int rawY = (int) event.getRawY();
  switch (event.getAction() & MotionEvent.ACTION_MASK) {
   case MotionEvent.ACTION_DOWN:
    isDrag = false;
    getParent().requestDisallowInterceptTouchEvent(true);
    lastX = rawX;
    lastY = rawY;
    Log.e("down---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf);
    break;
   case MotionEvent.ACTION_MOVE:
    isDrag = true;
    //计算手指移动了多少
    int dx = rawX - lastX;
    int dy = rawY - lastY;
    //这里修复一些手机无法触发点击事件的问题
    int distance= (int) Math.sqrt(dx*dx+dy*dy);
    Log.e("distance---->",distance+"");
    if(distance<3){//给个容错范围,不然有部分手机还是无法点击
     isDrag=false;
     break;
    }
    float x = getX() + dx;
    float y = getY() + dy;
    //检测是否到达边缘 左上右下
    x = x < 0 ? 0 : x > screenWidth - getWidth() ? screenWidth - getWidth() : x;
    // y = y < statusHeight ? statusHeight : (y + getHeight() >= screenHeight ? screenHeight - getHeight() : y);
    if (y<0){
     y=0;
    }
    if (y>screenHeight-statusHeight-getHeight()){
     y=screenHeight-statusHeight-getHeight();
    }
    setX(x);
    setY(y);
    lastX = rawX;
    lastY = rawY;
    Log.e("move---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf + " " + isDrag+" statusHeight="+statusHeight+ " virtualHeight"+virtualHeight+ " screenHeight"+ screenHeight+" getHeight="+getHeight()+" y"+y);
    break;
   case MotionEvent.ACTION_UP:
    if (isDrag) {
     //恢复按压效果
     setPressed(false);
     Log.e("ACTION_UP---->", "getX=" + getX() + ";screenWidthHalf=" + screenWidthHalf);
     if (rawX >= screenWidthHalf) {
      animate().setInterpolator(new DecelerateInterpolator())
        .setDuration(500)
        .xBy(screenWidth - getWidth() - getX())
        .start();
     } else {
      ObjectAnimator oa = ObjectAnimator.ofFloat(this, "x", getX(), 0);
      oa.setInterpolator(new DecelerateInterpolator());
      oa.setDuration(500);
      oa.start();
     }
    }
    Log.e("up---->",isDrag+"");
    break;
  }
  //如果是拖拽则消耗事件,否则正常传递即可。
  return isDrag || super.onTouchEvent(event);
 }
}

ScreenUtils.Java

package com.example.cmos.retrofitdemo;
import android.app.Activity;
import android.content.Context;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;
import java.lang.reflect.Method;
/**
 * Created by gongwq on 2017/6/14 0014.
 */
public class ScreenUtils {
 private ScreenUtils() {
  /* cannot be instantiated */
  throw new UnsupportedOperationException("cannot be instantiated");
 }
 /**
  * 获得屏幕高度
  *
  * @param context
  * @return
  */
 public static int getScreenWidth(Context context) {
  WindowManager wm = (WindowManager) context
    .getSystemService(Context.WINDOW_SERVICE);
  DisplayMetrics outMetrics = new DisplayMetrics();
  wm.getDefaultDisplay().getMetrics(outMetrics);
  return outMetrics.widthPixels;
 }
 /**
  * 获得屏幕宽度
  *
  * @param context
  * @return
  */
 public static int getScreenHeight(Context context) {
  WindowManager wm = (WindowManager) context
    .getSystemService(Context.WINDOW_SERVICE);
  DisplayMetrics outMetrics = new DisplayMetrics();
  wm.getDefaultDisplay().getMetrics(outMetrics);
  return outMetrics.heightPixels;
 }
 /**
  * 获得状态栏的高度
  *
  * @param context
  * @return
  */
 public static int getStatusHeight(Context context) {
  int statusHeight = -1;
  try {
   Class<?> clazz = Class.forName("com.android.internal.R$dimen");
   Object object = clazz.newInstance();
   int height = Integer.parseInt(clazz.getField("status_bar_height")
     .get(object).toString());
   statusHeight = context.getResources().getDimensionPixelSize(height);
  } catch (Exception e) {
   e.printStackTrace();
  }
  return statusHeight;
 }
 /**
  * 获取虚拟功能键高度
  */
 public static int getVirtualBarHeigh(Context context) {
  int vh = 0;
  WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
  Display display = windowManager.getDefaultDisplay();
  DisplayMetrics dm = new DisplayMetrics();
  try {
   @SuppressWarnings("rawtypes")
   Class c = Class.forName("android.view.Display");
   @SuppressWarnings("unchecked")
   Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
   method.invoke(display, dm);
   vh = dm.heightPixels - windowManager.getDefaultDisplay().getHeight();
  } catch (Exception e) {
   e.printStackTrace();
  }
  return vh;
 }
 public static int getVirtualBarHeigh(Activity activity) {
  int titleHeight = 0;
  Rect frame = new Rect();
  activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
  int statusHeight = frame.top;
  titleHeight = activity.getWindow().findViewById(Window.ID_ANDROID_CONTENT).getTop() - statusHeight;
  return titleHeight;
 }
}

上面的代码也很简单,相信看代码中的注释就可以看的明白了。但是这里还是讲下其实现原理:这个自定义的悬浮按钮,我们主要是重写了其onTouch事件,捕捉触摸事件,然后利用setX(),setY()方法将其移动。而吸附效果,主要是利用的属性动画,最后,不要忘了return 是否还在拖拽的结果,免得无法触发点击事件。

PS

最后贴一个弹出框。推荐用popmenu,相比于popwindow,这个会自动调整显示的位置,这在拖拽的悬浮按钮中很有用,因为如果用后者,你将按钮移到屏幕上方,而当你的弹出框也是设置在显示的悬浮按钮的上方,那么就有可能会遮挡弹出框的内容。

dragFloatActionButton= (DragFloatActionButton) findViewById(R.id.floatBtn);
  dragFloatActionButton.setOnClickListener(this);
....
 @Override
 public void onClick(View view) {
  switch (view.getId()) {
   case R.id.floatBtn:
    PopupMenu popupMenu=new PopupMenu(this,view);
    getMenuInflater().inflate(R.menu.pop_item,popupMenu.getMenu());
    popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
     @Override
     public boolean onMenuItemClick(MenuItem menuItem) {
      switch (menuItem.getItemId()){
       case R.id.action_last:
        Toast.makeText(TestActivity.this,""+menuItem.getItemId(),Toast.LENGTH_SHORT).show();
        break;
       case R.id.action_next:
        Toast.makeText(TestActivity.this,""+menuItem.getItemId(),Toast.LENGTH_SHORT).show();
        break;
      }
      return false;
     }
    });
    popupMenu.show();
    Log.e("****--->","float");
    // Toast.makeText(this,"flaot---",Toast.LENGTH_SHORT).show();
    break;
  }
 }

新建menu文件夹,在里面添加pop_item.xml文件

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto">
 <item
  android:id="@+id/action_delete"
  android:orderInCategory="100"
  android:title="删除"
  app:showAsAction="never" />
 <item
  android:id="@+id/action_save"
  android:orderInCategory="200"
  android:title="保存"
  app:showAsAction="never" />
 <item
  android:id="@+id/action_last"
  android:orderInCategory="300"
  android:title="上一步"
  app:showAsAction="never" />
 <item
  android:id="@+id/action_next"
  android:icon="@null"
  android:orderInCategory="400"
  android:title="下一步"
  app:showAsAction="never" />
</menu>

以上所述是小编给大家介绍的Android自定义可拖拽的悬浮按钮DragFloatingActionButton,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • Android利用悬浮按钮实现翻页效果

    今天给大家分享下自己用悬浮按钮点击实现翻页效果的例子. 首先,一个按钮要实现悬浮,就要用到系统顶级窗口相关的WindowManager,WindowManager.LayoutParams.那么在AndroidManifest.xml中添加权限: <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> 然后,我们要对WindowManager,WindowManager.Layout

  • Android中FloatingActionButton实现悬浮按钮实例

    Android中FloatingActionButton(悬浮按钮) 使用不是特别多,常规性APP应用中很少使用该控件. 当然他的使用方法其实很简单.直接上代码: xml: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="

  • Android开发模仿qq视频通话悬浮按钮(实例代码)

    模仿qq视频通话的悬浮按钮的实例代码,如下所示: public class FloatingWindowService extends Service{ private static final String TAG="OnTouchListener"; private static View mView = null; private static WindowManager mWindowManager = null; private static Context mContext

  • Android实现让图片在屏幕上任意移动的方法(拖拽功能)

    本文实例讲述了Android实现让图片在屏幕上任意移动的方法.分享给大家供大家参考,具体如下: public class DragExampleActivity extends Activity { Bitmap mBitmap; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInst

  • Android实现系统级悬浮按钮

    本文实例为大家分享了Android系统级悬浮按钮的具体代码,供大家参考,具体内容如下 具体的需求 1.就是做一个系统级的悬浮按钮,就像iPhone 桌面的那个悬浮按钮效果一样,能随意拖动,并且手一放开,悬浮按钮就自动靠边. 2.可以点击并且可以随意拖动. 3.悬浮按钮自动靠边的时候,或者移动到边上的时候,自动隐藏半边. 4.横竖屏切换都兼容 1.就在WindowManager 里面添加View,这个View通过自定义控件来实现. 2.在onTouch里的MotionEvent.ACTION_MO

  • Android悬浮按钮点击返回顶部FloatingActionButton

    先看一下Android悬浮按钮点击回到顶部的效果: FloatingActionButton是Design Support库中提供的一个控件,这个控件可以轻松实现悬浮按钮的效果 首先,要在项目中使用这个悬浮按钮就要先把design这个包导入项目 gradle中加入依赖 compile 'com.android.support:design:25.0.0' 接下来就是在xml中使用: 我这里是放置一个listView模拟返回顶部 <?xml version="1.0" encodi

  • Android开发悬浮按钮 Floating ActionButton的实现方法

    一.介绍 这个类是继承自ImageView的,所以对于这个控件我们可以使用ImageView的所有属性 android.support.design.widget.FloatingActionButton 二.使用准备, 在as 的 build.grade文件中写上 compile 'com.android.support:design:22.2.0' 三.使用说明 xml文件中,注意蓝色字体部分 <android.support.design.widget.FloatingActionButt

  • Android自定义可拖拽的悬浮按钮DragFloatingActionButton

    悬浮按钮FloatingActionButton是Android 5.0系统添加的新控件,FloatingActionButton是继承至ImageView,所以FloatingActionButton拥有ImageView的所有属性.本文讲解的是一个实现了可拖拽的悬浮按钮,并为此添加了类似于qq的吸附边框的功能.在此之前,先了解下其简单的使用方式吧: 首先你得添加其依赖 compile 'com.android.support:design:25.3.1' 然后在布局文件中使用. <andro

  • Android 自定义可拖拽View界面渲染刷新后不会自动回到起始位置

    以自定义ImageView为例: /** * 可拖拽ImageView * Created by admin on 2017/2/21. */ public class FloatingImageView extends ImageView{ public FloatingImageView(Context context) { super(context); } public FloatingImageView(Context context, AttributeSet attrs) { su

  • android自定义可拖拽的仪表盘

    本文实例为大家分享了android自定义可拖拽的仪表盘的具体代码,供大家参考,具体内容如下 因为项目最近需要用到仪表盘,又不想使用之前使用的背景图的方式.主要是想自己写一点代码.觉得绘制要比图片好.于是有了下面这张图: 面从弧度,刻度,文字,指针都是canvas绘制出来的. /** * Created by xulc on 2018/7/18. */ public class DashboardView extends View { private int minWidthDP = 200; p

  • Android实现可拖拽列表和多选功能

    本文实例为大家分享了Android实现可拖拽列表和多选的具体代码,供大家参考,具体内容如下 这是我已经完成的一个已经上线的OA软件的一个模块,这个模块的功能不多,已经放到GitHub上面开源了,有感兴趣的朋友可以看看UIFrame 主窗口JAVA代码 /** * 编辑状态下长按拖动条目 * 1.通过ItemTouchHelper.Callback实现长按拖动 * 2.通过isEditable的值判断是否编辑状态,初值是false * 3.切换编辑状态要把isEditable的值取反,并改变复选框

  • C#自定义鼠标拖拽Drag&Drop效果之基本原理及基本实现代码

    目录 一.前言 二.基本原理 1,设计界面 2,拖拽发起方 3,拖拽接收方 4,实际演示 三.自定义拖拽时鼠标效果 1,界面设计 2,拖拽发起方 3,拖拽接收方 4,GiveFeedback实现鼠标样式切换 4,实际演示 四.源码下载 五.总结 一.前言 拖拽(Drag&Drop),属于是极其常用的基础功能.无论是在系统上.应用上.还是在网页上,拖拽随处可见.同时拖拽时的鼠标效果也很漂亮,像这样: 这样: 还有这样: 等等等等.这些拖拽时的鼠标效果,直观又美观.然后,在我们写程序时,程序确实是支

  • Android中RecyclerView拖拽、侧删功能的实现代码

    废话不多说,下面展示一下效果. 这是GridView主文件实现. public class GridViewActivity extends AppCompatActivity { RecyclerView mRecyclerView; List<String> mStringList; RecyclerAdapter mRecyAdapter; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { s

  • Vue自定义指令拖拽功能示例

    下面给大家分享vue自定义指令拖拽功能代码,具体代码如下所示: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>实例方法</title> <meta name="viewport" content="width=device-width, initial-scale=1

  • Android实现View拖拽跟随手指移动效果

    今天想实现这个功能,但是网上搜索代码,都是利用setPadding,setMargin 等方法去实现的,这在Android 4.0 以前是没问题的,但是,android 4.0 后系统已经提供了更简单的方法给我们用了,就是setTranslationX() 和setTranslationY() .这两个是View的属性方法.现在我就用这两个方法实现一个View可以跟着手指移动拖拽的效果.代码非常非常简单: public class DragView extends TextView { floa

  • Android TouchListener实现拖拽删实例代码

    Android TouchListener实现拖拽删实例代码 如果为一个控件设置了该触摸监听, 控件会随着用户的拖动而移动, 如果拖动的距离大过设置的临界值, 那么当松开手指时会有回调onDragComplete, 用户可在该方法中将该控件从父布局中删除, 或这进行其他操作. 如果用户拖拽的距离小于临界值, 那么当用户松开手指时控件会回谈到原来的初始位置.这时会触发onDragRebound回调. 如果用户触摸控件之后没有拖拽而是直接松开手指, 会触发onClick回调, 这样用户就不用为该控件

  • Android实现可拖拽的GridView效果长按可拖拽删除数据源

    Android 可拖拽的GridView效果实现, 长按可拖拽和item实时交换 简单修改,完成自己想要的功能:长按,移到垃圾桶,删除数据. 主要思路是: 1.获取到用户长按的操作 2.获取按下的图片的bitmap以及移动的时候动态刷新镜像 3 action_up的时候判断镜像的位置,进入是否删除逻辑 自定义控件 package com.leafact.GridView; import android.app.Activity; import android.content.Context; i

随机推荐