android 浮动窗口
场景:android 中上层浮动窗口
android 顶层浮动窗口
FloatFrame 类
悬浮窗口布局文件:
android 顶层浮动窗口
先看效果
未扩展
扩展后
代码说明
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>