使用WindowManager创建可拖动的悬浮按钮

场景描述:
界面上有一个浮动按钮,可以用手指拖动,点击该按钮触发事件,我这里是启动扫描,留了一个空实现。

private WindowManager wm;
private View view;// 浮动按钮

/**
* 添加悬浮View
* @param paddingBottom 悬浮View与屏幕底部的距离
*/
protected void createFloatView(int paddingBottom) {
int w = 200;// 大小
wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
view = getLayoutInflater().inflate(R.layout.floatview, null);
final WindowManager.LayoutParams params = new WindowManager.LayoutParams();
params.type = LayoutParams.TYPE_BASE_APPLICATION;// 所有程序窗口的“基地”窗口,其他应用程序窗口都显示在它上面。
params.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
params.format = PixelFormat.TRANSLUCENT;// 不设置这个弹出框的透明遮罩显示为黑色
params.width = w;
params.height = w;
params.gravity = Gravity.TOP | Gravity.LEFT;
int screenWidth = getResources().getDisplayMetrics().widthPixels;
int screenHeight = getResources().getDisplayMetrics().heightPixels;
params.x = screenWidth - w;
params.y = screenHeight - w - paddingBottom;
view.setBackgroundColor(Color.TRANSPARENT);
view.setVisibility(View.VISIBLE);
view.setOnTouchListener(new OnTouchListener() {
// 触屏监听
float lastX, lastY;
int oldOffsetX, oldOffsetY;
int tag = 0;// 悬浮球 所需成员变量

@Override
public boolean onTouch(View v, MotionEvent event) {
final int action = event.getAction();
float x = event.getX();
float y = event.getY();
if (tag == 0) {
oldOffsetX = params.x; // 偏移量
oldOffsetY = params.y; // 偏移量
}
if (action == MotionEvent.ACTION_DOWN) {
lastX = x;
lastY = y;
} else if (action == MotionEvent.ACTION_MOVE) {
params.x += (int) (x - lastX) / 3; // 减小偏移量,防止过度抖动
params.y += (int) (y - lastY) / 3; // 减小偏移量,防止过度抖动
tag = 1;
wm.updateViewLayout(view, params);
} else if (action == MotionEvent.ACTION_UP) {
int newOffsetX = params.x;
int newOffsetY = params.y;
// 只要按钮一动位置不是很大,就认为是点击事件
if (Math.abs(oldOffsetX - newOffsetX) <= 20
&& Math.abs(oldOffsetY - newOffsetY) <= 20) {
onFloatViewClick();
} else {
tag = 0;
}
}
return true;
}
});
wm.addView(view, params);
}

/**
* 点击浮动按钮触发事件,需要override该方法
*/
protected void onFloatViewClick() {

}

/**
* 将悬浮View从WindowManager中移除,需要与createFloatView()成对出现
*/
protected void removeFloatView() {
if (wm != null && view != null) {
wm.removeViewImmediate(view);
// wm.removeView(view);//不要调用这个,WindowLeaked
view = null;
wm = null;
}
}
/**
* 隐藏悬浮View
*/
protected void hideFloatView() {
if (wm != null && view != null&&view.isShown()) {
view.setVisibility(View.GONE);
}
}
/**
* 显示悬浮View
*/
protected void showFloatView(){
if (wm != null && view != null&&!view.isShown()) {
view.setVisibility(View.VISIBLE);
}
}



或者使用Service
只要启动这个 Service,就会创建一个随手指移动的悬浮窗,关闭 Service 会移除悬浮窗。另外由于这里设置了 Window 的 type 为 TYPE_PHONE, 所以需要 SYSTEM_ALERT_WINDOW 权限,也可以使用 TYPE_TOAST。

public class WindowService extends Service {
WindowManager windowManager;
ImageView imageView;

public WindowService() {
}

@Override
public void onCreate() {
super.onCreate();
windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
}

@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (imageView == null) {
installWindow();
}
return START_STICKY;
}

@Override
public void onDestroy() {
super.onDestroy();
if (imageView != null) {
windowManager.removeView(imageView);
}
}

private void installWindow() {
imageView = new ImageView(this.getBaseContext());
imageView.setImageResource(R.mipmap.ic_launcher_round);
final WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
layoutParams.format = PixelFormat.TRANSPARENT;
layoutParams.width = 200;
layoutParams.height = 200;
layoutParams.gravity = Gravity.LEFT | Gravity.TOP;
layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE;
layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_FULLSCREEN
| WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN;
windowManager.addView(imageView, layoutParams);
imageView.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
layoutParams.x = (int) event.getRawX() - 100;
layoutParams.y = (int) event.getRawY() - 100;
windowManager.updateViewLayout(imageView, layoutParams);
return true;
}

});
}
}



[url]http://blog.csdn.net/manymore13[/url]

import com.mobovip.bgr.R;

import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.ImageView;

/**
* @author manymore13
* @Blog <a
* href="http://blog.csdn.net/manymore13">http://blog.csdn.net/manymore13
* </a>
* @version 1.0 floatView = new FloatView(this); // 创建窗体
* floatView.setOnClickListener(this); //
* 设置事件,你需要实现FloatView里的onclick接口 floatView.show(); // 显示该窗体
* floatView.hide(); // 隐藏窗体
*/
public class FloatView extends ImageView {

private Context c;
private float mTouchX;
private float mTouchY;
private float x;
private float y;
private int startX;
private int startY;
private int imgId = R.drawable.ic_launcher;
private int controlledSpace = 20;
private int screenWidth;
private int screenHeight;
boolean isShow = false;
private OnClickListener mClickListener;

private WindowManager windowManager;

private WindowManager.LayoutParams windowManagerParams = new WindowManager.LayoutParams();

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

public FloatView(Context c) {
super(c);
initView(c);
}

// 初始化窗体
public void initView(Context c) {
windowManager = (WindowManager) c.getApplicationContext()
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm=getResources().getDisplayMetrics();
screenWidth = dm.widthPixels;
screenHeight = dm.heightPixels;
this.setImageResource(imgId);
windowManagerParams.type = LayoutParams.TYPE_PHONE;
windowManagerParams.format = PixelFormat.RGBA_8888; // 背景透明
windowManagerParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
// 调整悬浮窗口至左上角,便于调整坐标
windowManagerParams.gravity = Gravity.LEFT | Gravity.TOP;
// 以屏幕左上角为原点,设置x、y初始值
windowManagerParams.x = 0;
windowManagerParams.y = screenHeight>>1;
// 设置悬浮窗口长宽数据
windowManagerParams.width = LayoutParams.WRAP_CONTENT;
windowManagerParams.height = LayoutParams.WRAP_CONTENT;

}

public void setImgResource(int id) {
imgId = id;
}

@Override
public boolean onTouchEvent(MotionEvent event) {

x = event.getRawX();
y = event.getRawY();

switch (event.getAction()) {
case MotionEvent.ACTION_DOWN: {
mTouchX = event.getX();
mTouchY = event.getY();
startX = (int) event.getRawX();
startY = (int) event.getRawY();
break;

}
case MotionEvent.ACTION_MOVE: {
updateViewPosition();
break;
}
case MotionEvent.ACTION_UP: {

if (Math.abs(x - startX) < controlledSpace
&& Math.abs(y - startY) < controlledSpace) {
if (mClickListener != null) {
mClickListener.onClick(this);
}
}
// Log.i("tag", "x=" + x + " startX+" + startX + " y=" + y
// + " startY=" + startY);
if (x <= screenWidth / 2) {
x = 0;
} else {
x = screenWidth;
}

updateViewPosition();

break;
}
}

return super.onTouchEvent(event);
}

// 隐藏该窗体
public void hide() {
if (isShow) {
windowManager.removeView(this);
isShow = false;
}

}

// 显示该窗体
public void show() {
if (isShow == false) {
windowManager.addView(this, windowManagerParams);
isShow = true;
}

}

@Override
public void setOnClickListener(OnClickListener l) {
this.mClickListener = l;
}

private void updateViewPosition() {
// 更新浮动窗口位置参数
windowManagerParams.x = (int) (x - mTouchX);
windowManagerParams.y = (int) (y - mTouchY);
windowManager.updateViewLayout(this, windowManagerParams); // 刷新显示
}
}



一个Android布局可以拖动排序子控件:RearrangeableLayout
[url]https://github.com/rajasharan/RearrangeableLayout[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值