悬浮按钮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,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对网站的支持!
# android悬浮按钮
# 拖拽
# Android自定义悬浮按钮效果
# Android开发之FloatingActionButton悬浮按钮基本使用、字体、颜色用法示例
# Android悬浮按钮的使用方法
# Android自定义APP全局悬浮按钮
# Android 悬浮按钮之实现兔兔按钮示例
# 弹出
# 的是
# 有个
# 在此
# 自定义
# 小编
# 正常显示
# 主要是
# 会有
# 好了
# 还在
# 就有
# 将其
# 也很
# 给大家
# 写了
# 在里面
# 如图
# 这在
相关文章:
定制建站如何定义?其核心优势是什么?
大学网站设计制作软件有哪些,如何将网站制作成自己app?
免费公司网站制作软件,如何申请免费主页空间做自己的网站?
股票网站制作软件,网上股票怎么开户?
制作网站的软件下载免费,今日头条开宝箱老是需要下载怎么回事?
家具网站制作软件,家具厂怎么跑业务?
济南网站制作的价格,历城一职专官方网站?
如何制作网站标识牌,动态网站如何制作(教程)?
如何在宝塔面板中创建新站点?
网站制作难吗安全吗,做一个网站需要多久时间?
香港服务器租用每月最低只需15元?
广州营销型建站服务商推荐:技术优势与SEO优化解析
如何基于PHP生成高效IDC网络公司建站源码?
如何在橙子建站中快速调整背景颜色?
如何选择靠谱的建站公司加盟品牌?
制作充值网站的软件,做人力招聘为什么要自己交端口钱?
制作宣传网站的软件,小红书可以宣传网站吗?
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
建站之星安装步骤有哪些常见问题?
建站之星后台管理如何实现高效配置?
如何在Mac上搭建Golang开发环境_使用Homebrew安装和管理Go版本
建站主机选择指南:服务器配置与SEO优化实战技巧
,怎么用自己头像做动态表情包?
深圳防火门网站制作公司,深圳中天明防火门怎么编码?
香港服务器网站卡顿?如何解决网络延迟与负载问题?
GML (Geography Markup Language)是什么,它如何用XML来表示地理空间信息?
网站制作怎么样才能赚钱,用自己的电脑做服务器架设网站有什么利弊,能赚钱吗?
,南京靠谱的征婚网站?
如何快速辨别茅台真假?关键步骤解析
如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?
无锡制作网站公司有哪些,无锡优八网络科技有限公司介绍?
制作网站的过程怎么写,用凡科建站如何制作自己的网站?
巅云智能建站系统:可视化拖拽+多端适配+免费模板一键生成
如何确认建站备案号应放置的具体位置?
如何快速打造个性化非模板自助建站?
红河网站制作公司,红河事业单位身份证如何上传?
怎么将XML数据可视化 D3.js加载XML
建站之星安装模板失败:服务器环境不兼容?
焦点电影公司作品,电影焦点结局是什么?
为什么Go需要go mod文件_Go go mod文件作用说明
如何选择高效可靠的多用户建站源码资源?
专业公司网站制作公司,用什么语言做企业网站比较好?
如何在服务器上配置二级域名建站?
建站之星伪静态规则如何正确配置?
安徽网站建设与外贸建站服务专业定制方案
想学网站制作怎么学,建立一个网站要花费多少?
如何在万网自助建站中设置域名及备案?
制作表格网站有哪些,线上表格怎么弄?
大连网站制作公司哪家好一点,大连买房网站哪个好?
如何在建站之星绑定自定义域名?
*请认真填写需求信息,我们会在24小时内与您取得联系。