您的位置:首页 > 移动开发 > Android开发

Android 悬浮窗的创建与移除

2015-08-05 14:11 471 查看
本文主要是介绍悬浮窗的创建与移除,并能通过点击悬浮窗图标回到应用主界面。本文是通过参考网上的文章并通过自己修改完成的。本文主要参考的文章是:http://blog.csdn.net/guolin_blog/article/details/8689140

1.MainActivity.java

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity implements OnClickListener {  
	private Button  startFloatWindow;
	private Button stopFloatWindow;
	private  TextView tv;
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        
        startFloatWindow = (Button) findViewById(R.id.start_float_window);  
        stopFloatWindow = (Button) findViewById(R.id.stop_float_window); 
        
         tv= (TextView) findViewById(R.id.show_txt);
         
         String str=new StringBuilder()
         .append("\n")
         .append("说明:").append("\n")
         .append("1.点击开启悬浮窗按钮可以看到悬浮窗;").append("\n")
         .append("2.点击关闭悬浮窗按钮可以移除悬浮窗;").append("\n")     
         .append("3.点击悬浮窗图标可以进入应用主界面.").append("\n")
 		.toString();
         tv.setText(str); 
         
        startFloatWindow.setOnClickListener(this);
        stopFloatWindow.setOnClickListener(this);
    }
    
    public void onClick(View v) {
		switch(v.getId()) {
		case R.id.start_float_window:
			Intent serviceStart  = new Intent(MainActivity.this, FloatWindowService.class);  
            startService(serviceStart );  
            finish();  
			break;
		case R.id.stop_float_window:
			  Intent serviceStop  = new Intent(MainActivity.this, FloatWindowService.class);  
              stopService(serviceStop );  
              finish();  
			break;
		}
	}
}


2.FloatWindowService.java

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
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.IBinder;

public class FloatWindowService extends Service {

	/**
	 * 用于在线程中创建或移除悬浮窗。
	 */
	private Handler handler = new Handler();

	/**
	 * 定时器,定时进行检测当前应该创建还是移除悬浮窗。
	 */
	private Timer timer;

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

	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// 开启定时器,每隔0.5秒刷新一次
		if (timer == null) {
			timer = new Timer();
			timer.scheduleAtFixedRate(new RefreshTask(), 0, 500);
		}
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		super.onDestroy();
		// Service被终止的同时也停止定时器继续运行
		timer.cancel();
		timer = null;
	}

	class RefreshTask extends TimerTask {

		@Override
		public void run() {
			// 当前界面是桌面,且没有悬浮窗显示,则创建悬浮窗。
			if (isHome() && !MyWindowManager.isWindowShowing()) {
				handler.post(new Runnable() {
					@Override
					public void run() {
						MyWindowManager.createSmallWindow(getApplicationContext());
					}
				});
			}
			// 当前界面不是桌面,且有悬浮窗显示,则移除悬浮窗。
			else if (!isHome() && MyWindowManager.isWindowShowing()) {
				handler.post(new Runnable() {
					@Override
					public void run() {
						MyWindowManager.removeSmallWindow(getApplicationContext());
						
					}
				});
			}
		}

	}

	/**
	 * 判断当前界面是否是桌面
	 */
	@SuppressWarnings("deprecation")
	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;
	}
}


3.FloatWindowSmallView.java

import java.lang.reflect.Field;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;

@SuppressLint("ClickableViewAccessibility") 
public class FloatWindowSmallView extends LinearLayout {  
	  
    /** 
     * 记录小悬浮窗的宽度 
     */  
    public static int viewWidth;  
  
    /** 
     * 记录小悬浮窗的高度 
     */  
    public static int viewHeight;  
  
    /** 
     * 记录系统状态栏的高度 
     */  
     private static int statusBarHeight;  
  
    /** 
     * 用于更新小悬浮窗的位置 
     */  
    private WindowManager windowManager;  
  
    /** 
     * 小悬浮窗的参数 
     */  
    private WindowManager.LayoutParams mParams;  
  
    /** 
     * 记录当前手指位置在屏幕上的横坐标值 
     */  
    private float xInScreen;  
  
    /** 
     * 记录当前手指位置在屏幕上的纵坐标值 
     */  
    private float yInScreen;  
  
    /** 
     * 记录手指按下时在屏幕上的横坐标的值 
     */  
    private float xDownInScreen;  
  
    /** 
     * 记录手指按下时在屏幕上的纵坐标的值 
     */  
    private float yDownInScreen;  
  
    /** 
     * 记录手指按下时在小悬浮窗的View上的横坐标的值 
     */  
    private float xInView;  
  
    /** 
     * 记录手指按下时在小悬浮窗的View上的纵坐标的值 
     */  
    private float yInView;  
    private ImageView mfloat;
    public static int sViewWidth;
    public static int sViewHeight;
    public FloatWindowSmallView(Context context) {  
        super(context);  
        windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);  
        LayoutInflater.from(context).inflate(R.layout.float_window, this);  
        View view = findViewById(R.id.float_window_layout);  
        viewWidth = view.getLayoutParams().width;  
        viewHeight = view.getLayoutParams().height;  
        mfloat = (ImageView) findViewById(R.id.iv_btn);
        mfloat.setBackgroundResource(R.drawable.float_ic);
        sViewWidth = view.getLayoutParams().width;
        sViewHeight = view.getLayoutParams().height;
    }  
  
    @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:  
            // 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。  
            if (xDownInScreen == xInScreen && yDownInScreen == yInScreen) {  
            	Intent intent = new Intent(getContext(),MainActivity.class);
            	intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            	getContext().startActivity(intent);
            }  
            break;  
        default:  
            break;  
        }  
        return true;  
    }  
  
    /** 
     * 将小悬浮窗的参数传入,用于更新小悬浮窗的位置。 
     *  
     * @param params 
     *            小悬浮窗的参数 
     */  
    public void setParams(WindowManager.LayoutParams params) {  
        mParams = params;  
    }  
  
    /** 
     * 更新小悬浮窗在屏幕中的位置。 
     */  
    private void updateViewPosition() {  
        mParams.x = (int) (xInScreen - xInView);  
        mParams.y = (int) (yInScreen - yInView);  
        windowManager.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;  
    }  
}


4.MyWindowManager.java

import android.app.ActivityManager;
import android.content.Context;
import android.graphics.PixelFormat;
import android.view.Gravity;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;

public class MyWindowManager {  
	  
    /** 
     * 小悬浮窗View的实例 
     */  
    private static FloatWindowSmallView smallWindow;  
 
    /** 
     * 小悬浮窗View的参数 
     */  
    private static LayoutParams smallWindowParams;  
  
    /** 
     * 用于控制在屏幕上添加或移除悬浮窗 
     */  
    private static WindowManager mWindowManager;  
  
    /** 
     * 用于获取手机可用内存 
     */  
    private static ActivityManager mActivityManager;  
  
    /** 
     * 创建一个小悬浮窗。初始位置为屏幕的右部中间位置。
     *  
     * @param context 
     *            必须为应用程序的Context. 
     */  
    @SuppressWarnings("deprecation")
	public static void createSmallWindow(Context context) {  
        WindowManager windowManager = getWindowManager(context);  
        int screenWidth = windowManager.getDefaultDisplay().getWidth();  
        int screenHeight = windowManager.getDefaultDisplay().getHeight();  
        if (smallWindow == null) {  
            smallWindow = new FloatWindowSmallView(context);  
            if (smallWindowParams == null) {  
                smallWindowParams = new LayoutParams();  
                smallWindowParams.type = LayoutParams.TYPE_PHONE;  
                smallWindowParams.format = PixelFormat.RGBA_8888;  
                smallWindowParams.flags = LayoutParams.FLAG_NOT_TOUCH_MODAL  
                        | LayoutParams.FLAG_NOT_FOCUSABLE;  
                smallWindowParams.gravity = Gravity.LEFT | Gravity.TOP;  
                smallWindowParams.width = FloatWindowSmallView.viewWidth;  
                smallWindowParams.height = FloatWindowSmallView.viewHeight;  
                smallWindowParams.x = screenWidth;  
                smallWindowParams.y = screenHeight / 2;  
            }  
            smallWindow.setParams(smallWindowParams);  
            windowManager.addView(smallWindow, smallWindowParams);  
        }  
    }  
  
    /** 
     * 将小悬浮窗从屏幕上移除。 
     *  
     * @param context 
     *            必须为应用程序的Context. 
     */  
    public static void removeSmallWindow(Context context) {  
        if (smallWindow != null) {  
            WindowManager windowManager = getWindowManager(context);  
            windowManager.removeView(smallWindow);  
            smallWindow = null;  
        }  
    }  
  
    /** 
     * 是否有悬浮窗(包括小悬浮窗和大悬浮窗)显示在屏幕上。 
     *  
     * @return 有悬浮窗显示在桌面上返回true,没有的话返回false。 
     */  
    public static boolean isWindowShowing() {  
        return smallWindow != null ;
    }  
  
    /** 
     * 如果WindowManager还未创建,则创建一个新的WindowManager返回。否则返回当前已创建的WindowManager。 
     *  
     * @param context 
     *            必须为应用程序的Context. 
     * @return WindowManager的实例,用于控制在屏幕上添加或移除悬浮窗。 
     */  
    private static WindowManager getWindowManager(Context context) {  
        if (mWindowManager == null) {  
            mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);  
        }  
        return mWindowManager;  
    }  
  
    /** 
     * 如果ActivityManager还未创建,则创建一个新的ActivityManager返回。否则返回当前已创建的ActivityManager。 
     *  
     * @param context 
     *            可传入应用程序上下文。 
     * @return ActivityManager的实例,用于获取手机可用内存。 
     */  
    @SuppressWarnings("unused")
	private static ActivityManager getActivityManager(Context context) {  
        if (mActivityManager == null) {  
            mActivityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);  
        }  
        return mActivityManager;  
    }  
  
}


5.布局文件1:activity_main.xml

<LinearLayout 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"  
    android:orientation="vertical">
    
     <TextView  
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_marginTop="60dip"  
        android:textStyle="bold"  
        android:textSize="24dip"  
        android:text="悬浮窗功能测试"   
        android:layout_gravity="center"/> 
         
    <Button  
        android:id="@+id/start_float_window"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="开启悬浮窗" >  
    </Button>  
    
    <Button  
        android:id="@+id/stop_float_window"  
        android:layout_width="fill_parent"  
        android:layout_height="wrap_content"  
        android:text="关闭悬浮窗" >  
    </Button> 
     
    <TextView 
        android:id="@+id/show_txt"   
        android:layout_width="wrap_content"  
        android:layout_height="wrap_content"  
        android:layout_marginTop="20dip"  
        android:text=""   
        />
</LinearLayout>


6.布局文件2:float_window.xml

<?xml version="1.0" encoding="UTF-8"?>  

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"  
    android:orientation="vertical"
    android:id="@+id/float_window_layout"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    
   <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/iv_btn"
        android:contentDescription="@null"/>
   
</LinearLayout>


7.配置文件AndroidManifest.xml

添加权限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
 	<uses-permission android:name="android.permission.GET_TASKS"/>


记得要注册相应的Activity和Service.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: