用过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