用過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.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.widget.button;
import android.widget.linearlayout;
import android.widget.popupwindow;
import android.widget.relativelayout;
import android.widget.toast;
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;
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();
case motionevent.action_up:
mtouchstartx = mtouchstarty = 0;
}
//如果拖動則傳回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);
public ibinder onbind(intent intent) {
return null;
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();
}
public boolean onkey(view v, int keycode, keyevent event) {
toast.maketext(getapplicationcontext(), "keycode:"+keycode, 1000).show();
switch (keycode) {
case keyevent.keycode_home:
pop.dismiss();
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:
<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" />
android:id="@+id/btn_home_screen"
android:layout_alignparentbottom="true"
android:layout_centerhorizontal="true"
android:drawabletop="@drawable/selector_ic_home"
android:text="@string/home_screen" />
android:id="@+id/btn_setting"
android:layout_alignparentright="true"
android:layout_centervertical="true"
android:drawabletop="@drawable/selector_ic_phone"
android:text="@string/setting" />
android:id="@+id/btn_lock_screen"
android:drawabletop="@drawable/selector_ic_power_down"
android:text="@string/lock_screen" />
android:id="@+id/btn_favor"
android:layout_alignparentleft="true"
android:drawabletop="@drawable/selector_ic_star"
android:text="@string/favor" />
</relativelayout>
</linearlayout>
</relativelayout>
androidmanifest.xml:
<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