添加可拖动悬浮窗口到桌面
先说一下权限问题,一般权限比较容易忘记:
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
MainActivity.java
public class MainActivity extends Activity {
private Button button1;
private Button button2;
private Context context;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
button1 = (Button) findViewById(R.id.button1);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, FloatButtonService.class);
intent.setAction("1");
startService(intent);
}
});
button2 = (Button) findViewById(R.id.button2);
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(context, FloatButtonService.class);
intent.setAction("0");
startService(intent);
}
});
}
FloatButtonService.java
public class FloatButtonService extends Service {
/** 悬浮窗口 */
private CustomView customView;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
customView = new CustomView(getApplicationContext());
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(intent.getAction().equals("1")){
//# 显示悬浮视图
customView.createWinPop();
}else{
// # 移出悬浮视图
customView.closeWinPop();
}
return super.onStartCommand(intent, flags, startId);
}
}
CustomView.java
import java.lang.reflect.Field;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.WindowManager;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class CustomView extends LinearLayout {
/** 窗口管理器(用于更新小悬浮窗的位置) */
private WindowManager winManager;
/** 记录系统状态栏的高度 */
private int statusBarHeight;
/** 记录当前手指位置在屏幕上的横坐标值 */
private float xInScreen;
/** 记录当前手指位置在屏幕上的纵坐标值 */
private float yInScreen;
/** 记录手指按下时在屏幕上的横坐标的值 */
private float xDownInScreen;
/** 记录手指按下时在屏幕上的纵坐标的值 */
private float yDownInScreen;
/** 记录手指按下时在小悬浮窗的View上的横坐标的值 */
private float xInView;
/** 记录手指按下时在小悬浮窗的View上的纵坐标的值 */
private float yInView;
/** 悬浮窗的参数 */
private WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
private String tag = "CustomView";
public CustomView(Context context) {
super(context);
winManager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater.from(context).inflate(R.layout.custom_view, this);
TextView textView1 = (TextView) findViewById(R.id.textView1);
textView1.setText("hello");
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// #手指按下,记录数值就好(但是不能忽略状态栏)
xInView = event.getX();
yInView = event.getY();
xDownInScreen = event.getRawX();
yDownInScreen = event.getRawY() - getStatusBarHeight();
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
break;
case MotionEvent.ACTION_MOVE:
// #手指移动的时候,需要更新悬浮窗口的位置
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
// #手指抬起的时候,判断是不是按下事件
if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) {
Toast.makeText(getContext(), "#Click Event is called",
Toast.LENGTH_SHORT).show();
// BackFuntion.getIns().back();
}
break;
default:
break;
}
// # 返回true
return true;
}
/**
* 更新悬浮窗在设备屏幕上的位置
*/
private void updateViewPosition() {
mParams.x = (int) (xInScreen - xInView);
mParams.y = (int) (yInScreen - yInView);
winManager.updateViewLayout(this, mParams);
}
/**
* @return 返回状态栏高度的像素值。
*/
private int getStatusBarHeight() {
if (statusBarHeight == 0) {
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object o = c.newInstance();
Field field = c.getField("status_bar_height");
int x = (Integer) field.get(o);
statusBarHeight = getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
}
return statusBarHeight;
}
/**
* 创建悬浮窗
*/
public void createWinPop() {
Point outSize = new Point();
winManager.getDefaultDisplay().getSize(outSize);
int screenWidth = outSize.x;
int screenHeight = outSize.y;
// #新版SDK不建议使用下面getWidth和getHeight获取
// int screenWidth = winManager.getDefaultDisplay().getWidth();
// int screenHeight = winManager.getDefaultDisplay().getHeight();
mParams.x = screenWidth / 2 - 100;
mParams.y = screenHeight / 2 - 100;
mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
mParams.format = PixelFormat.RGBA_8888;
mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mParams.gravity = Gravity.LEFT | Gravity.TOP;
mParams.width = 150;
mParams.height = 50;
try {
winManager.addView(this, mParams);
} catch (Exception e) {
Log.e("MainActivity", "#e=" + e.toString());
Toast.makeText(getContext(), "#已经存在了", Toast.LENGTH_LONG).show();
}
}
/**
* 关闭悬浮窗
*/
public void closeWinPop() {
try {
winManager.removeView(this);
} catch (Exception e) {
Log.e("MainActivity", "#e=" + e.toString());
Toast.makeText(getContext(), "#不存在", Toast.LENGTH_SHORT).show();
}
}
}
在添加和移出悬浮窗口的时候,会抛出相应的异常,没有窗口存在的时候移出会异常,有窗口存在的时候还去创建,就会异常,都进行捕抓就好。
本文来自CSDN博客,转载请联系作者注明出处http://blog.csdn.net/dreamintheworld