首页 > 代码库 > 仿iphone快速导航悬浮球

仿iphone快速导航悬浮球

用过iphone的朋友都知道,iPhone有个圆球辅助工具,它漂浮在你的手机屏幕(在任何APP之上),你可以将它移动到任何地方,它叫做AssistiveTouch,本篇模拟该软件实现一个小案例,主要是实现它的界面,首先来看看实现的效果吧:

技术分享


拖动小圆球:

技术分享


点击弹出pop窗口:

技术分享


为了让辅助工具一直悬浮在窗口之上,这里使用的机制是通过在程序初始化是,启动一个service,在service的onCreate() 函数中使用LayoutInflater来加载一个view,而这个view就是辅助球的布局文件:floatball.xml,然后对它进行onclick事件的监听,setOnClickListener监听到辅助球点击事件之后,就创建一个PopupWindow,弹出如上的菜单界面,大体的实现就是这样。

其实,实现窗口悬浮于最前面的一个重要属性是:WindowManager.LayoutParams.TYPE_PHONE

我们只要将WindowManager.LayoutParams的type属性设置为 WindowManager.LayoutParams.TYPE_PHONE就可以实现悬浮最前面。


工程目录结构:

技术分享


部分代码解析:

MyApplication.java:

package com.tyd.floatball.util;  
import android.app.Application;  
import android.view.WindowManager;  
public class MyApplication extends Application {  
    private WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();  
    public WindowManager.LayoutParams getMywmParams() {  
        return wmParams;  
    }     
}  


MainActivity.java:

package com.tyd.floatball.ui;  
  
import com.tyd.floatball.R;  
import com.tyd.floatball.R.layout;  
import com.tyd.floatball.service.TopFloatService;  
import android.app.Activity;  
import android.content.Intent;  
import android.os.Bundle;  
  
public class MainActivity extends Activity {  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
        Intent service = new Intent();  
        service.setClass(this, TopFloatService.class);  
        //启动服务  
        startService(service);  
    }  
}  

TopFloatService.java:

package com.tyd.floatball.service;  
  
import android.app.Service;  
import android.content.Intent;  
import android.graphics.PixelFormat;  
import android.graphics.Rect;  
import android.graphics.drawable.BitmapDrawable;  
import android.os.IBinder;  
import android.util.DisplayMetrics;  
import android.view.Gravity;  
import android.view.KeyEvent;  
import android.view.LayoutInflater;  
import android.view.MotionEvent;  
import android.view.View;  
import android.view.View.OnClickListener;  
import android.view.View.OnKeyListener;  
import android.view.View.OnTouchListener;  
import android.view.WindowManager;  
import android.widget.Button;  
import android.widget.LinearLayout;  
import android.widget.PopupWindow;  
import android.widget.RelativeLayout;  
import android.widget.Toast;  
import com.tyd.floatball.R;  
import com.tyd.floatball.util.MyApplication;  
  
public class TopFloatService extends Service implements OnClickListener,OnKeyListener{  
    WindowManager wm = null;  
    WindowManager.LayoutParams ballWmParams = null;  
    private View ballView;  
    private View menuView;  
    private float mTouchStartX;  
    private float mTouchStartY;  
    private float x;  
    private float y;  
    private RelativeLayout menuLayout;  
    private Button floatImage;  
    private PopupWindow pop;  
    private RelativeLayout menuTop;  
    private boolean ismoving = false;  
      
    @Override  
    public void onCreate() {  
        super.onCreate();  
        //加载辅助球布局  
        ballView = LayoutInflater.from(this).inflate(R.layout.floatball, null);  
        floatImage = (Button)ballView.findViewById(R.id.float_image);  
        setUpFloatMenuView();  
        createView();  
    }  
      
    /**  
     * 窗口菜单初始化  
     */  
    private void setUpFloatMenuView(){  
        menuView = LayoutInflater.from(this).inflate(R.layout.floatmenu, null);  
        menuLayout = (RelativeLayout)menuView.findViewById(R.id.menu);  
        menuTop = (RelativeLayout)menuView.findViewById(R.id.lay_main);  
        menuLayout.setOnClickListener(this);  
        menuLayout.setOnKeyListener(this);  
        menuTop.setOnClickListener(this);  
    }  
  
    /**  
     * 通过MyApplication创建view,并初始化显示参数  
     */  
    private void createView() {  
        wm = (WindowManager) getApplicationContext().getSystemService("window");  
        ballWmParams =  ((MyApplication) getApplication()).getMywmParams();  
        ballWmParams.type = WindowManager.LayoutParams.TYPE_PHONE;  
        ballWmParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;  
        ballWmParams.gravity = Gravity.LEFT | Gravity.TOP;  
        ballWmParams.x = 0;  
        ballWmParams.y = 0;  
        ballWmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;  
        ballWmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;  
        ballWmParams.format = PixelFormat.RGBA_8888;  
        //添加显示层  
        wm.addView(ballView, ballWmParams);  
        //注册触碰事件监听器  
        floatImage.setOnTouchListener(new OnTouchListener() {  
            public boolean onTouch(View v, MotionEvent event) {  
                x = event.getRawX();  
                y = event.getRawY();   
                switch (event.getAction()) {  
                case MotionEvent.ACTION_DOWN:  
                    ismoving = false;  
                    mTouchStartX = (int)event.getX();  
                    mTouchStartY = (int)event.getY();  
                    break;  
                case MotionEvent.ACTION_MOVE:  
                    ismoving = true;  
                    updateViewPosition();  
                    break;  
                case MotionEvent.ACTION_UP:  
                    mTouchStartX = mTouchStartY = 0;  
                    break;  
                }  
                //如果拖动则返回false,否则返回true  
                if(ismoving == false){  
                    return false;  
                }else{  
                    return true;  
                }  
            }  
  
        });  
        //注册点击事件监听器  
        floatImage.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                DisplayMetrics dm = getResources().getDisplayMetrics();  
                pop = new PopupWindow(menuView, dm.widthPixels, dm.heightPixels);  
                pop.showAtLocation(ballView, Gravity.CENTER, 0, 0);  
                pop.update();  
            }  
        });  
    }  
      
    /**  
     * 更新view的显示位置  
     */  
    private void updateViewPosition() {  
        ballWmParams.x = (int) (x - mTouchStartX);  
        ballWmParams.y = (int) (y - mTouchStartY);  
        wm.updateViewLayout(ballView, ballWmParams);  
    }  
  
    @Override  
    public IBinder onBind(Intent intent) {  
        return null;  
    }  
  
    @Override  
    public void onClick(View v) {  
        switch (v.getId()) {  
        case R.id.lay_main:  
            Toast.makeText(getApplicationContext(), "111", 1000).show();  
            break;  
  
        default:  
            if(pop!=null && pop.isShowing()){  
                pop.dismiss();  
            }  
            break;  
        }  
          
    }  
  
    @Override  
    public boolean onKey(View v, int keyCode, KeyEvent event) {  
        Toast.makeText(getApplicationContext(), "keyCode:"+keyCode, 1000).show();  
        switch (keyCode) {  
        case KeyEvent.KEYCODE_HOME:  
            pop.dismiss();  
            break;  
        default:  
            break;  
        }  
        return true;  
    }  
      
} 


辅助球的布局文件 floatball.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="wrap_content"  
    android:orientation="vertical"  
    android:layout_gravity="center_vertical">  
      
    <Button  
        android:id="@+id/float_image"  
        android:layout_width="50dp"  
        android:layout_height="50dp"  
        android:background="@drawable/selector_btn_assistive"   
        />  
  
</FrameLayout>  


窗口菜单的布局文件floatmenu.xml:

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    android:id="@+id/menu"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
    android:background="@drawable/transparent" >  
  
    <LinearLayout  
        android:layout_width="@dimen/size_dialog"  
        android:layout_height="@dimen/size_dialog"  
        android:layout_centerInParent="true"  
        android:background="@drawable/shape_background_assistivetouch"  
        android:orientation="vertical" >  
  
        <RelativeLayout  
            android:id="@+id/lay_main"  
            android:layout_width="fill_parent"  
            android:layout_height="fill_parent"  
            android:orientation="vertical"  
            android:padding="4.0px"  
            android:visibility="visible" >  
  
            <TextView  
                android:id="@+id/btn_apps"  
                style="@style/Icon"  
                android:layout_centerInParent="true"  
                android:drawableTop="@drawable/selector_ic_apps"  
                android:text="@string/apps" />  
  
            <TextView  
                android:id="@+id/btn_home_screen"  
                style="@style/Icon"  
                android:layout_alignParentBottom="true"  
                android:layout_centerHorizontal="true"  
                android:drawableTop="@drawable/selector_ic_home"  
                android:text="@string/home_screen" />  
  
            <TextView  
                android:id="@+id/btn_setting"  
                style="@style/Icon"  
                android:layout_alignParentRight="true"  
                android:layout_centerVertical="true"  
                android:drawableTop="@drawable/selector_ic_phone"  
                android:text="@string/setting" />  
  
            <TextView  
                android:id="@+id/btn_lock_screen"  
                style="@style/Icon"  
                android:layout_centerHorizontal="true"  
                android:drawableTop="@drawable/selector_ic_power_down"  
                android:text="@string/lock_screen" />  
  
            <TextView  
                android:id="@+id/btn_favor"  
                style="@style/Icon"  
                android:layout_alignParentLeft="true"  
                android:layout_centerVertical="true"  
                android:drawableTop="@drawable/selector_ic_star"  
                android:text="@string/favor" />  
        </RelativeLayout>  
    </LinearLayout>  
  
</RelativeLayout> 

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
    package="com.tyd.floatball"  
    android:versionCode="1"  
    android:versionName="1.0" >  
    <uses-sdk android:minSdkVersion="14" />  
  
    <application  
        android:icon="@drawable/ic_launcher"  
        android:label="@string/app_name"   
        android:name=".util.MyApplication">  
        <activity  
            android:label="@string/app_name"  
            android:name=".ui.MainActivity" >  
            <intent-filter >  
                <action android:name="android.intent.action.MAIN" />  
  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
        <service   
                android:name=".service.TopFloatService"    
                android:enabled="true"  
                android:exported="true"  
            />  
    </application>  
      
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />  
    <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>  
</manifest>  


该实例我已经将源码整理打包,进行了上传,下面是资源的下载地址:

http://download.csdn.net/detail/wulianghuan/5364129

仿iphone快速导航悬浮球