主要还是用到了WindowManager对桌面悬浮进行管理.
需要一个火箭的悬浮窗 一个发射台悬浮窗 ,判断火箭是否放到了发射台,如果放上了,则使用AsyTask 慢慢将火箭的图片往上移.结束后., 返回原位.
1.打开activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.windowmanagerdemo1.MainActivity" >
<Button
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/btn_start"
android:text="start"
/>
</RelativeLayout>
就一个Button.
2.新建一个小悬浮窗的视图small_view.xml
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<LinearLayout
android:layout_width="60dp"
android:layout_height="20dp"
android:id="@+id/ll_smallView"
android:background="#000000"
android:orientation="vertical"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/tv_percent"
android:textColor="#ffffff"
/>
</LinearLayout>
<ImageView
android:id="@+id/iv_recketImg"
android:layout_width="45dp"
android:layout_height="90dp"
android:src="@drawable/rocket"
android:visibility="gone"
/>
</FrameLayout>
在帧布局中放入一个LinearLayout,这个主要用来显示当前手机内存, 同时放入一个ImageView ,这个用于手指按下时显示出小火箭,平常小悬浮窗显示时则小火箭隐藏,当按住了小悬浮窗,则显示小火箭,隐藏悬浮窗.
3.新建 大悬浮窗视图 big_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="200dp"
android:layout_height="100dp"
android:id="@+id/ll_bigView"
android:background="#000000"
android:orientation="vertical" >
<Button
android:id="@+id/btn_close"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:text="关闭悬浮窗"
android:textColor="#ffffff"
/>
<Button
android:id="@+id/btn_back"
android:layout_width="100dp"
android:layout_height="40dp"
android:layout_gravity="center_horizontal"
android:text="返回"
android:textColor="#ffffff"
/>
</LinearLayout>
大悬浮窗 是在点击了小悬浮窗后显示的,里面就放了两个按钮.
4.新建发射台的视图 luncher.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<ImageView
android:id="@+id/iv_luncher"
android:layout_width="200dp"
android:layout_height="88dp"
android:src="@drawable/launcher_bg_hold"
/>
</LinearLayout>
发射台视图只有一个ImageView.
5,新建一个FloatBigView.java 大悬浮窗的实体类
public class FloatBigView extends LinearLayout {
//记录大悬浮窗的高度
public static int ViewHeight;
//记录大悬浮窗的宽度
public static int ViewWidth;
public FloatBigView(final Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.big_view, this);
View view=findViewById(R.id.ll_bigView);
ViewHeight=view.getLayoutParams().height;
ViewWidth=view.getLayoutParams().width;
Button btn_close=(Button) findViewById(R.id.btn_close);
Button btn_back=(Button) findViewById(R.id.btn_back);
btn_close.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MyWindowManager.removeBigView(context);
MyWindowManager.removeSmallWindow(context);
Intent intent=new Intent(getContext(), WindowService.class);
context.stopService(intent);
}
});
btn_back.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
MyWindowManager.removeBigView(context);
MyWindowManager.createSmallWindow(context);
}
});
}
}
大悬浮窗的实体类 里面就是绑定刚才的大悬浮窗视图,并找到两个按钮,监听一个 关闭 和一个 返回的事件, MyWindowManager将在下面创建
6,小悬浮窗的实体类
public class FloatSmallView extends LinearLayout {
public static int ViewHeight;
public static int ViewWidth;
//系统状态栏的高度
private static int statusHeight;
private WindowManager mWindowManager;
//小悬浮窗布局
private LinearLayout smallViewLayout;
//小火箭
private ImageView rocketImg;
//小悬浮窗参数
private WindowManager.LayoutParams mLayoutParams;
//记录手指在屏幕按下时的横坐标
private float xDown;
//记录手指在屏幕按下时的纵坐标
private float yDown;
//记录手指在屏幕移动时的横坐标
private float xMove;
//记录手指在屏幕移动时的纵坐标
private float yMove;
//记录手指按下时在小悬浮窗的横坐标
private float xInView;
//记录手指按下时在小悬浮窗的纵坐标
private float yInView;
//记录小火箭的高度
private int rocketHeight;
//记录小火箭的宽度
private int rocketWidth;
//记录当前手指是否在悬浮窗按下
private boolean isPressed;
public FloatSmallView(Context context) {
super(context);
mWindowManager=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
LayoutInflater.from(context).inflate(R.layout.small_view,this);
smallViewLayout=(LinearLayout) findViewById(R.id.ll_smallView);
ViewHeight=smallViewLayout.getLayoutParams().height;
ViewWidth=smallViewLayout.getLayoutParams().width;
rocketImg=(ImageView) findViewById(R.id.iv_recketImg);
rocketHeight=rocketImg.getLayoutParams().height;
rocketWidth=rocketImg.getLayoutParams().width;
TextView tv_percent=(TextView) findViewById(R.id.tv_percent);
tv_percent.setText(MyWindowManager.getUsedPercentValue(context));
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isPressed = true;
// 手指按下时记录必要数据,纵坐标的值都需要减去状态栏高度
xInView = event.getX();
yInView = event.getY();
xDown = event.getRawX();
yDown= event.getRawY() - getStatusBarHeight();
xMove = event.getRawX();
yMove = event.getRawY() - getStatusBarHeight();
break;
case MotionEvent.ACTION_MOVE:
xMove=event.getRawX();
yMove=event.getRawY()-getStatusBarHeight();
updateViewStatus();
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
isPressed=false;
if(MyWindowManager.isReadyToLuncher()){
luncherRocket();
}
else{
updateViewStatus();
if(xDown==xMove&&yDown==yMove){
Log.e("info","进入1");
openBigWindow();
}
}
break;
}
return true;
}
//打开大悬浮窗口,关闭小悬浮窗
private void openBigWindow(){
Log.e("info","进入2");
MyWindowManager.createBigView(getContext());
MyWindowManager.removeSmallWindow(getContext());
}
//开始发射小火箭
private void luncherRocket(){
MyWindowManager.removeRocketLuncher(getContext());
new LuncherTask().execute();
}
//传入小悬浮窗的参数, 用于更新位置
public void setParams(WindowManager.LayoutParams mParams){
this.mLayoutParams=mParams;
}
//更新小悬浮窗的位置
private void updateViewPosition(){
mLayoutParams.x=(int) (xMove-xInView);
mLayoutParams.y=(int) (yMove-yInView);
mWindowManager.updateViewLayout(this, mLayoutParams);
//检查小火箭是否到了发射台
MyWindowManager.updateLuncher();
}
//更新悬浮窗的显示样式 ,如果是按下状态 则显示为小火箭 否则为普通悬浮窗
private void updateViewStatus(){
if(isPressed&&rocketImg.getVisibility()!=View.VISIBLE){
mLayoutParams.width=rocketWidth;
mLayoutParams.height=rocketHeight;
mWindowManager.updateViewLayout(this, mLayoutParams);
smallViewLayout.setVisibility(View.GONE);
rocketImg.setVisibility(View.VISIBLE);
MyWindowManager.createLuncher(getContext());
}
else if(!isPressed){
mLayoutParams.width=ViewWidth;
mLayoutParams.height=ViewHeight;
mWindowManager.updateViewLayout(this, mLayoutParams);
smallViewLayout.setVisibility(View.VISIBLE);
rocketImg.setVisibility(View.GONE);
MyWindowManager.removeRocketLuncher(getContext());
}
}
//开始执行发射小火箭的任务
class LuncherTask extends AsyncTask<Void,Void, Void>{
@Override
protected Void doInBackground(Void... arg0) {
while(mLayoutParams.y>0){
mLayoutParams.y=mLayoutParams.y-20;
publishProgress();
try {
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Void... values) {
mWindowManager.updateViewLayout(FloatSmallView.this, mLayoutParams);
}
@Override
protected void onPostExecute(Void result) {
//小火箭升空后 回归悬浮窗状态
updateViewStatus();
mLayoutParams.x=(int) (xDown-xInView);
mLayoutParams.y=(int) (yDown-yInView);
mWindowManager.updateViewLayout(FloatSmallView.this, mLayoutParams);
}
}
//获取状态栏的高度
private int getStatusBarHeight() {
if (statusHeight == 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);
statusHeight = getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
}
return statusHeight;
}
}
小悬浮窗中方法较多,注释较多
7.创建发射台实体类RocketLuncher.java
//火箭发射台
public class RocketLuncher extends LinearLayout {
public static int width;
public static int height;
private ImageView luncherImg;
public RocketLuncher(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.luncher, this);
luncherImg=(ImageView) findViewById(R.id.iv_luncher);
width=luncherImg.getLayoutParams().width;
height=luncherImg.getLayoutParams().height;
}
//更新火箭发射台的显示状态
public void updateLuncherState(boolean isReadyToLuncher){
if(isReadyToLuncher){
luncherImg.setImageResource(R.drawable.launcher_bg_fire);
}
else{
luncherImg.setImageResource(R.drawable.launcher_bg_hold);
}
}
}
8,新建一个MyWindowManager.java用来管理这几个悬浮窗
public class MyWindowManager {
//小悬浮窗的实例
private static FloatSmallView mSmallView;
//大悬浮窗的实例
private static FloatBigView mBigView;
//火箭发射台的实例
private static RocketLuncher rocketLuncher;
//小悬浮窗的参数
private static LayoutParams mSmallViewParams;
//大悬浮窗的参数
private static LayoutParams mBigViewParams;
//火箭发射台的参数
private static LayoutParams rocketLuncherParams;
//用于在屏幕上添加或移除窗口
private static WindowManager mWindowManager;
//获取手机可用内存
private static ActivityManager mActivityManager;
//创建小悬浮窗
public static void createSmallWindow(Context context){
WindowManager windowManager=getWindowManager(context);
int screenWidth=windowManager.getDefaultDisplay().getWidth();
int screenHeight=windowManager.getDefaultDisplay().getHeight();
if(mSmallView==null){
mSmallView=new FloatSmallView(context);
if(mSmallViewParams==null){
mSmallViewParams=new LayoutParams();
mSmallViewParams.type=LayoutParams.TYPE_SYSTEM_ALERT;
mSmallViewParams.format=PixelFormat.RGBA_8888;
mSmallViewParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL
| LayoutParams.FLAG_NOT_FOCUSABLE;
mSmallViewParams.gravity=Gravity.LEFT|Gravity.TOP;
mSmallViewParams.width=FloatSmallView.ViewWidth;
mSmallViewParams.height=FloatSmallView.ViewHeight;
mSmallViewParams.x=screenWidth;
mSmallViewParams.y=screenHeight/2;
}
mSmallView.setParams(mSmallViewParams);
windowManager.addView(mSmallView, mSmallViewParams);
}
}
//将小悬浮窗从屏幕上移除
public static void removeSmallWindow(Context context){
if(mSmallView!=null){
WindowManager windowManager=getWindowManager(context);
windowManager.removeView(mSmallView);
mSmallView=null;
}
}
//创建大悬浮窗
public static void createBigView(Context context){
WindowManager windowManager=getWindowManager(context);
int screenWidth=windowManager.getDefaultDisplay().getWidth();
int screenHeight=windowManager.getDefaultDisplay().getHeight();
if(mBigView==null){
mBigView=new FloatBigView(context);
if(mBigViewParams==null){
mBigViewParams=new LayoutParams();
mBigViewParams.x=screenWidth/2-FloatBigView.ViewWidth/2;
mBigViewParams.y=screenHeight/2-FloatBigView.ViewHeight/2;
mBigViewParams.type=LayoutParams.TYPE_PHONE;
mBigViewParams.format= PixelFormat.RGBA_8888;
mBigViewParams.gravity=Gravity.LEFT|Gravity.TOP;
mBigViewParams.width=FloatBigView.ViewWidth;
mBigViewParams.height=FloatBigView.ViewHeight;
}
windowManager.addView(mBigView, mBigViewParams);
}
}
//将大悬浮窗移除
public static void removeBigView(Context context){
if(mBigView!=null){
WindowManager windowManager=getWindowManager(context);
windowManager.removeView(mBigView);
mBigView=null;
}
}
//创建一个火箭发射台
public static void createLuncher(Context context){
WindowManager windowManager=getWindowManager(context);
int screenWidht=windowManager.getDefaultDisplay().getWidth();
int screenHeight=windowManager.getDefaultDisplay().getHeight();
if(rocketLuncher==null){
rocketLuncher=new RocketLuncher(context);
if(rocketLuncherParams==null){
rocketLuncherParams=new LayoutParams();
rocketLuncherParams.x=screenWidht/2-RocketLuncher.width/2;
rocketLuncherParams.y=screenHeight-RocketLuncher.height;
rocketLuncherParams.type=LayoutParams.TYPE_PHONE;
rocketLuncherParams.format=PixelFormat.RGBA_8888;
rocketLuncherParams.gravity=Gravity.LEFT|Gravity.TOP;
rocketLuncherParams.width=RocketLuncher.width;
rocketLuncherParams.height=RocketLuncher.height;
}
windowManager.addView(rocketLuncher, rocketLuncherParams);
}
}
//移除火箭发射台
public static void removeRocketLuncher(Context context){
if(rocketLuncher!=null){
WindowManager wm=getWindowManager(context);
wm.removeView(rocketLuncher);
rocketLuncher=null;
}
}
//更新火箭发射台的显示状态
public static void updateLuncher(){
if(rocketLuncher!=null){
rocketLuncher.updateLuncherState(isReadyToLuncher());
}
}
//更新小悬浮窗TextView的内存占比
public static void updateUserPercent(Context context){
if(mSmallView!=null){
TextView percent=(TextView) mSmallView.findViewById(R.id.tv_percent);
percent.setText(getUsedPercentValue(context));
}
}
//是否有悬浮窗
public static boolean isWindowShow(){
return mSmallView!=null||mBigView!=null;
}
/**
* 计算已使用内存的百分比,并返回。
*
* @param context
* 可传入应用程序上下文。
* @return 已使用内存的百分比,以字符串形式返回。
*/
public static String getUsedPercentValue(Context context) {
String dir = "/proc/meminfo";
try {
FileReader fr = new FileReader(dir);
BufferedReader br = new BufferedReader(fr, 2048);
String memoryLine = br.readLine();
String subMemoryLine = memoryLine.substring(memoryLine
.indexOf("MemTotal:"));
br.close();
long totalMemorySize = Integer.parseInt(subMemoryLine.replaceAll(
"\\D+", ""));
long availableSize = getAvailableMemory(context) / 1024;
int percent = (int) ((totalMemorySize - availableSize)
/ (float) totalMemorySize * 100);
return percent + "%";
} catch (IOException e) {
e.printStackTrace();
}
return "悬浮窗";
}
/**
* 获取当前可用内存,返回数据以字节为单位。
*
* @param context
* 可传入应用程序上下文。
* @return 当前可用内存。
*/
private static long getAvailableMemory(Context context) {
ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
getActivityManager(context).getMemoryInfo(mi);
return mi.availMem;
}
//判断小火箭是否准备好发射
public static boolean isReadyToLuncher(){
if ((mSmallViewParams.x > rocketLuncherParams.x && mSmallViewParams.x
+ mSmallViewParams.width < rocketLuncherParams.x
+ rocketLuncherParams.width)
&& (mSmallViewParams.y + mSmallViewParams.height > rocketLuncherParams.y)) {
return true;
}
return false;
}
//得到WindowManager的单例
private static WindowManager getWindowManager(Context context){
if(mWindowManager==null){
mWindowManager=(WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
}
return mWindowManager;
}
//得到ActivityManager的单例
private static ActivityManager getActivityManager(Context context){
if(mActivityManager==null){
mActivityManager=(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
}
return mActivityManager;
}
}
9.悬浮窗的服务WindowService.java,用来时刻检查当前视图是否该显示悬浮窗还是隐藏.
public class WindowService extends Service {
//在线程中创建或移除悬浮窗
private Handler handler=new Handler();
//定时器 检查当前是应该创建还是移除悬浮窗
private Timer mTimer;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(mTimer==null){
mTimer=new Timer();
mTimer.scheduleAtFixedRate(new RefreshTaks(), 0, 500);
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel();
mTimer=null;
}
class RefreshTaks extends TimerTask{
@Override
public void run() {
//如果当前是桌面且没有窗口显示,则创建小悬浮窗
if(isHome()&&!MyWindowManager.isWindowShow()){
handler.post(new Runnable() {
@Override
public void run() {
MyWindowManager.createSmallWindow(getApplicationContext());
}
});
}
//如果不是桌面,且有悬浮窗显示,则移除悬浮窗
else if(!isHome()&&MyWindowManager.isWindowShow()){
handler.post(new Runnable() {
@Override
public void run() {
MyWindowManager.removeBigView(getApplicationContext());
MyWindowManager.removeSmallWindow(getApplicationContext());
}
});
}
//当前是桌面 且有悬浮窗显示 则更新内存
else if(isHome()&&MyWindowManager.isWindowShow()){
handler.post(new Runnable() {
@Override
public void run() {
MyWindowManager.updateUserPercent(getApplicationContext());
}
});
}
}
}
/**
* 判断当前界面是否是桌面
*/
private boolean isHome() {
ActivityManager mActivityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> rti = mActivityManager.getRunningTasks(1);
return getHomes().contains(rti.get(0).topActivity.getPackageName());
}
/**
* 获得属于桌面的应用的应用包名称
*
* @return 返回包含所有包名的字符串列表
*/
private List<String> getHomes() {
List<String> names = new ArrayList<String>();
PackageManager packageManager = this.getPackageManager();
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
List<ResolveInfo> resolveInfo = packageManager.queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
for (ResolveInfo ri : resolveInfo) {
names.add(ri.activityInfo.packageName);
}
return names;
}
@Override
public IBinder onBind(Intent arg0) {
return null;
}
}
10.打开MainActivity.java
public class MainActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn_start=(Button) findViewById(R.id.btn_start);
btn_start.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Intent intent=new Intent(MainActivity.this, WindowService.class);
MainActivity.this.startService(intent);
MainActivity.this.finish();
}
});
}
}
开启服务.