先看效果
未扩展
扩展后
代码说明
AndroidManifest..xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cn.hpc.assistant"
android:versionCode="1"
android:versionName="1.0" >
<!--需要下面的权限-->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="14" />
<uses-permission android:name="android.permission.GET_TASKS" />
<application
android:name=".FloatApplication"
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="cn.hpc.assistant.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
App 类
package cn.hpc.assistant;
import android.app.Application;
import android.view.WindowManager;
public class FloatApplication extends Application {
private WindowManager.LayoutParams wmParams=new WindowManager.LayoutParams();
public WindowManager.LayoutParams getWmParams(){
return wmParams;
}
}
MainActivity 类
package cn.hpc.assistant;
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.graphics.Point;
import android.os.Bundle;
import android.view.Gravity;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
public class MainActivity extends Activity {
private WindowManager wm = null;
private WindowManager.LayoutParams wmParams = null;
private FloatFrame myFV = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 创建悬浮窗口
createFloatView();
this.finish(); // 显示悬浮窗口后,Activity自动退出
}
private void createFloatView() {
Point windowSize = new Point();
this.getWindowManager().getDefaultDisplay().getSize(windowSize);
myFV = new FloatFrame(getApplicationContext());
// 获取WindowManager
wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
// 设置LayoutParams(全局变量)相关参数
wmParams = ((FloatApplication) getApplication()).getWmParams();
/**
* 以下都是WindowManager.LayoutParams的相关属性 具体用途可参考SDK文档
*/
wmParams.type = 2003;//LayoutParams.TYPE_PHONE; // 设置window type
wmParams.format = PixelFormat.RGBA_8888; // 设置图片格式,效果为背景透明
// 设置Window flag
wmParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
/*
* 下面的flags属性的效果形同“锁定”。 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
* wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL |
* LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCHABLE;
*/
wmParams.gravity = Gravity.LEFT | Gravity.TOP; // 调整悬浮窗口至左上角
// wmParams.gravity = Gravity.CENTER_VERTICAL | Gravity.RIGHT; // 调整悬浮窗口至左上角
//设置默认显示位置
// wmParams.x = 0;// 以屏幕左上角为原点,设置x、y初始值
// wmParams.y = 0;
wmParams.x = windowSize.x;// 以屏幕右边, 距中
wmParams.y = windowSize.y / 2;
// 设置悬浮窗口长宽数据
wmParams.width = android.view.ViewGroup.LayoutParams.WRAP_CONTENT;// 40;
wmParams.height = android.app.ActionBar.LayoutParams.WRAP_CONTENT;// 40;
// 显示myFloatView图像
wm.addView(myFV, wmParams);
}
}
FloatFrame 类
package cn.hpc.assistant;
import java.util.ArrayList;
import java.util.List;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
import android.widget.LinearLayout;
public class FloatFrame extends LinearLayout {
private float mTouchRawX;
private float mTouchRawY;
private WindowManager wm = (WindowManager) getContext()
.getApplicationContext().getSystemService(Context.WINDOW_SERVICE);
// 此wmParams为获取的全局变量,用以保存悬浮窗口的属性
private WindowManager.LayoutParams wmParams = ((FloatApplication) getContext()
.getApplicationContext()).getWmParams();
private Context mContext;
View viewExtFrame;
Button btnExt;
public FloatFrame(Context context) {
super(context);
mContext = context;
gestureDetector = new GestureDetector(context, gestureListener);
View view = View.inflate(context, R.layout.float_layout_main, null);
viewExtFrame = view.findViewById(R.id.id_float_ext_frame);
btnExt = (Button)view.findViewById(R.id.id_btn_ext);
int ids[] = { R.id.id_btn_ext, R.id.id_btn_exit };
for (int id : ids) {
view.findViewById(id).setOnClickListener(onClick);
}
view.findViewById(R.id.id_btn_exit).setOnTouchListener(frameOnTouchListener);
this.addView(view);
}
private void clickView(int id) {
switch (id) {
case R.id.id_btn_ext:
int visible = viewExtFrame.getVisibility();
if (visible == View.VISIBLE) {
viewExtFrame.setVisibility(View.INVISIBLE);
btnExt.setText("<<");
} else {
viewExtFrame.setVisibility(View.VISIBLE);
btnExt.setText(">>");
}
break;
case R.id.id_btn_exit:
wm.removeView(FloatFrame.this);// 点击退出,销毁悬浮窗口
Log.e("float view", "exit");
break;
default:
}
}
// 响应悬浮窗口中的Button点击
View.OnClickListener onClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
clickView(v.getId());
}
};
final static int MESSAGE_MOVE = 0x1001;
final static int MESSAGE_DOWN = 0x1002;
final static int MESSAGE_UP = 0x1003;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_MOVE:
updateViewPosition();
break;
case MESSAGE_DOWN:
break;
case MESSAGE_UP:
break;
default:
}
}
};
// 点击Listener
OnTouchListener frameOnTouchListener = new OnTouchListener() {
public boolean onTouch(View v, MotionEvent event) {
if (null == gestureDetector || null == event) {
return false;
}
return gestureDetector.onTouchEvent(event);
}
};
// 手势识别
GestureDetector.OnGestureListener gestureListener = new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
// TODO Auto-generated method stub
Log.d("OnGestureListener", "onDown");
mTouchRawX = e.getX();
mTouchRawY = e.getY();
return false;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
float velocityY) {
return true;
}
@Override
public void onLongPress(MotionEvent e) {
// TODO Auto-generated method stub
// Log.d("OnGestureListener", "onLongPress");
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
mTouchRawX = e2.getRawX();
mTouchRawY = e2.getRawY();
mHandler.sendEmptyMessage(MESSAGE_MOVE);
return true;
}
@Override
public void onShowPress(MotionEvent e) {
// Log.d("OnGestureListener", "onShowPress");
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
// Log.d("OnGestureListener", "onSingleTapUp");
return false;
}
};
private GestureDetector gestureDetector;
private void updateViewPosition() {
// 更新浮动窗口位置参数
wmParams.x = (int) mTouchRawX;
wmParams.y = (int) mTouchRawY;
wm.updateViewLayout(this, wmParams);
}
}
悬浮窗口布局文件:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<!-- 显示、隐藏的扩展容器 -->
<LinearLayout
android:id="@+id/id_float_ext_frame"
android:layout_width="wrap_content"
android:layout_height="600dip"
android:background="@android:drawable/alert_dark_frame"
android:orientation="vertical"
android:visibility="gone" >
<ImageView
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:src="@drawable/ic_launcher" />
</LinearLayout>
<Button
android:id="@+id/id_btn_ext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="..."
android:background="@android:drawable/ic_dialog_dialer"
android:textColor="#FF00FF00" />
<Button
android:id="@+id/id_btn_exit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="exit"
android:textColor="#FF0000FF" />
</LinearLayout>