android桌面悬浮窗仿QQ手机管家加速效果

android桌面悬浮窗仿QQ手机管家加速效果

主要还是用到了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();
            }
        });
        
    }
}
开启服务. 
 
 
上一篇:Core Text 入门


下一篇:android桌面悬浮窗实现