仿iphone快速导航悬浮球

简介: <p style="margin-top:0px; margin-bottom:0px; padding-top:0px; padding-bottom:0px; font-family:Arial; font-size:14px; line-height:26px"> 用过iphone的朋友都知道,iPhone有个圆球辅助工具,<span style="font-family:aria

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

[html]  view plain copy print ?
  1. package com.tyd.floatball.util;  
  2.   
  3. import android.app.Application;  
  4. import android.view.WindowManager;  
  5.   
  6. public class MyApplication extends Application {  
  7.   
  8.     private WindowManager.LayoutParams wmParams = new WindowManager.LayoutParams();  
  9.   
  10.     public WindowManager.LayoutParams getMywmParams() {  
  11.         return wmParams;  
  12.     }  
  13.       
  14. }  



MainActivity.java:

[html]  view plain copy print ?
  1. package com.tyd.floatball.ui;  
  2.   
  3. import com.tyd.floatball.R;  
  4. import com.tyd.floatball.R.layout;  
  5. import com.tyd.floatball.service.TopFloatService;  
  6. import android.app.Activity;  
  7. import android.content.Intent;  
  8. import android.os.Bundle;  
  9.   
  10. public class MainActivity extends Activity {  
  11.     @Override  
  12.     public void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         setContentView(R.layout.main);  
  15.         Intent service = new Intent();  
  16.         service.setClass(this, TopFloatService.class);  
  17.         //启动服务  
  18.         startService(service);  
  19.     }  
  20. }  


TopFloatService.java:

[html]  view plain copy print ?
  1. package com.tyd.floatball.service;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.graphics.PixelFormat;  
  6. import android.graphics.Rect;  
  7. import android.graphics.drawable.BitmapDrawable;  
  8. import android.os.IBinder;  
  9. import android.util.DisplayMetrics;  
  10. import android.view.Gravity;  
  11. import android.view.KeyEvent;  
  12. import android.view.LayoutInflater;  
  13. import android.view.MotionEvent;  
  14. import android.view.View;  
  15. import android.view.View.OnClickListener;  
  16. import android.view.View.OnKeyListener;  
  17. import android.view.View.OnTouchListener;  
  18. import android.view.WindowManager;  
  19. import android.widget.Button;  
  20. import android.widget.LinearLayout;  
  21. import android.widget.PopupWindow;  
  22. import android.widget.RelativeLayout;  
  23. import android.widget.Toast;  
  24. import com.tyd.floatball.R;  
  25. import com.tyd.floatball.util.MyApplication;  
  26.   
  27. public class TopFloatService extends Service implements OnClickListener,OnKeyListener{  
  28.     WindowManager wm = null;  
  29.     WindowManager.LayoutParams ballWmParams = null;  
  30.     private View ballView;  
  31.     private View menuView;  
  32.     private float mTouchStartX;  
  33.     private float mTouchStartY;  
  34.     private float x;  
  35.     private float y;  
  36.     private RelativeLayout menuLayout;  
  37.     private Button floatImage;  
  38.     private PopupWindow pop;  
  39.     private RelativeLayout menuTop;  
  40.     private boolean ismoving = false;  
  41.       
  42.     @Override  
  43.     public void onCreate() {  
  44.         super.onCreate();  
  45.         //加载辅助球布局  
  46.         ballView = LayoutInflater.from(this).inflate(R.layout.floatball, null);  
  47.         floatImage = (Button)ballView.findViewById(R.id.float_image);  
  48.         setUpFloatMenuView();  
  49.         createView();  
  50.     }  
  51.       
  52.     /**  
  53.      * 窗口菜单初始化  
  54.      */  
  55.     private void setUpFloatMenuView(){  
  56.         menuView = LayoutInflater.from(this).inflate(R.layout.floatmenu, null);  
  57.         menuLayout = (RelativeLayout)menuView.findViewById(R.id.menu);  
  58.         menuTop = (RelativeLayout)menuView.findViewById(R.id.lay_main);  
  59.         menuLayout.setOnClickListener(this);  
  60.         menuLayout.setOnKeyListener(this);  
  61.         menuTop.setOnClickListener(this);  
  62.     }  
  63.   
  64.     /**  
  65.      * 通过MyApplication创建view,并初始化显示参数  
  66.      */  
  67.     private void createView() {  
  68.         wm = (WindowManager) getApplicationContext().getSystemService("window");  
  69.         ballWmParams =  ((MyApplication) getApplication()).getMywmParams();  
  70.         ballWmParams.type = WindowManager.LayoutParams.TYPE_PHONE;  
  71.         ballWmParams.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;  
  72.         ballWmParams.gravity = Gravity.LEFT | Gravity.TOP;  
  73.         ballWmParams.x = 0;  
  74.         ballWmParams.y = 0;  
  75.         ballWmParams.width = WindowManager.LayoutParams.WRAP_CONTENT;  
  76.         ballWmParams.height = WindowManager.LayoutParams.WRAP_CONTENT;  
  77.         ballWmParams.format = PixelFormat.RGBA_8888;  
  78.         //添加显示层  
  79.         wm.addView(ballView, ballWmParams);  
  80.         //注册触碰事件监听器  
  81.         floatImage.setOnTouchListener(new OnTouchListener() {  
  82.             public boolean onTouch(View v, MotionEvent event) {  
  83.                 x = event.getRawX();  
  84.                 y = event.getRawY();   
  85.                 switch (event.getAction()) {  
  86.                 case MotionEvent.ACTION_DOWN:  
  87.                     ismoving = false;  
  88.                     mTouchStartX = (int)event.getX();  
  89.                     mTouchStartY = (int)event.getY();  
  90.                     break;  
  91.                 case MotionEvent.ACTION_MOVE:  
  92.                     ismoving = true;  
  93.                     updateViewPosition();  
  94.                     break;  
  95.                 case MotionEvent.ACTION_UP:  
  96.                     mTouchStartX = mTouchStartY = 0;  
  97.                     break;  
  98.                 }  
  99.                 //如果拖动则返回false,否则返回true  
  100.                 if(ismoving == false){  
  101.                     return false;  
  102.                 }else{  
  103.                     return true;  
  104.                 }  
  105.             }  
  106.   
  107.         });  
  108.         //注册点击事件监听器  
  109.         floatImage.setOnClickListener(new View.OnClickListener() {  
  110.             @Override  
  111.             public void onClick(View v) {  
  112.                 DisplayMetrics dm = getResources().getDisplayMetrics();  
  113.                 pop = new PopupWindow(menuView, dm.widthPixels, dm.heightPixels);  
  114.                 pop.showAtLocation(ballView, Gravity.CENTER, 0, 0);  
  115.                 pop.update();  
  116.             }  
  117.         });  
  118.     }  
  119.       
  120.     /**  
  121.      * 更新view的显示位置  
  122.      */  
  123.     private void updateViewPosition() {  
  124.         ballWmParams.x = (int) (x - mTouchStartX);  
  125.         ballWmParams.y = (int) (y - mTouchStartY);  
  126.         wm.updateViewLayout(ballView, ballWmParams);  
  127.     }  
  128.   
  129.     @Override  
  130.     public IBinder onBind(Intent intent) {  
  131.         return null;  
  132.     }  
  133.   
  134.     @Override  
  135.     public void onClick(View v) {  
  136.         switch (v.getId()) {  
  137.         case R.id.lay_main:  
  138.             Toast.makeText(getApplicationContext(), "111", 1000).show();  
  139.             break;  
  140.   
  141.         default:  
  142.             if(pop!=null && pop.isShowing()){  
  143.                 pop.dismiss();  
  144.             }  
  145.             break;  
  146.         }  
  147.           
  148.     }  
  149.   
  150.     @Override  
  151.     public boolean onKey(View v, int keyCode, KeyEvent event) {  
  152.         Toast.makeText(getApplicationContext(), "keyCode:"+keyCode, 1000).show();  
  153.         switch (keyCode) {  
  154.         case KeyEvent.KEYCODE_HOME:  
  155.             pop.dismiss();  
  156.             break;  
  157.         default:  
  158.             break;  
  159.         }  
  160.         return true;  
  161.     }  
  162.       
  163. }  

辅助球的布局文件 floatball.xml:

[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="wrap_content"  
  5.     android:orientation="vertical"  
  6.     android:layout_gravity="center_vertical">  
  7.       
  8.     <Button  
  9.         android:id="@+id/float_image"  
  10.         android:layout_width="50dp"  
  11.         android:layout_height="50dp"  
  12.         android:background="@drawable/selector_btn_assistive"   
  13.         />  
  14.   
  15. </FrameLayout>  

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

[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/menu"  
  4.     android:layout_width="fill_parent"  
  5.     android:layout_height="fill_parent"  
  6.     android:background="@drawable/transparent" >  
  7.   
  8.     <LinearLayout  
  9.         android:layout_width="@dimen/size_dialog"  
  10.         android:layout_height="@dimen/size_dialog"  
  11.         android:layout_centerInParent="true"  
  12.         android:background="@drawable/shape_background_assistivetouch"  
  13.         android:orientation="vertical" >  
  14.   
  15.         <RelativeLayout  
  16.             android:id="@+id/lay_main"  
  17.             android:layout_width="fill_parent"  
  18.             android:layout_height="fill_parent"  
  19.             android:orientation="vertical"  
  20.             android:padding="4.0px"  
  21.             android:visibility="visible" >  
  22.   
  23.             <TextView  
  24.                 android:id="@+id/btn_apps"  
  25.                 style="@style/Icon"  
  26.                 android:layout_centerInParent="true"  
  27.                 android:drawableTop="@drawable/selector_ic_apps"  
  28.                 android:text="@string/apps" />  
  29.   
  30.             <TextView  
  31.                 android:id="@+id/btn_home_screen"  
  32.                 style="@style/Icon"  
  33.                 android:layout_alignParentBottom="true"  
  34.                 android:layout_centerHorizontal="true"  
  35.                 android:drawableTop="@drawable/selector_ic_home"  
  36.                 android:text="@string/home_screen" />  
  37.   
  38.             <TextView  
  39.                 android:id="@+id/btn_setting"  
  40.                 style="@style/Icon"  
  41.                 android:layout_alignParentRight="true"  
  42.                 android:layout_centerVertical="true"  
  43.                 android:drawableTop="@drawable/selector_ic_phone"  
  44.                 android:text="@string/setting" />  
  45.   
  46.             <TextView  
  47.                 android:id="@+id/btn_lock_screen"  
  48.                 style="@style/Icon"  
  49.                 android:layout_centerHorizontal="true"  
  50.                 android:drawableTop="@drawable/selector_ic_power_down"  
  51.                 android:text="@string/lock_screen" />  
  52.   
  53.             <TextView  
  54.                 android:id="@+id/btn_favor"  
  55.                 style="@style/Icon"  
  56.                 android:layout_alignParentLeft="true"  
  57.                 android:layout_centerVertical="true"  
  58.                 android:drawableTop="@drawable/selector_ic_star"  
  59.                 android:text="@string/favor" />  
  60.         </RelativeLayout>  
  61.     </LinearLayout>  
  62.   
  63. </RelativeLayout>  

AndroidManifest.xml:

[html]  view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     package="com.tyd.floatball"  
  4.     android:versionCode="1"  
  5.     android:versionName="1.0" >  
  6.     <uses-sdk android:minSdkVersion="14" />  
  7.   
  8.     <application  
  9.         android:icon="@drawable/ic_launcher"  
  10.         android:label="@string/app_name"   
  11.         android:name=".util.MyApplication">  
  12.         <activity  
  13.             android:label="@string/app_name"  
  14.             android:name=".ui.MainActivity" >  
  15.             <intent-filter >  
  16.                 <action android:name="android.intent.action.MAIN" />  
  17.   
  18.                 <category android:name="android.intent.category.LAUNCHER" />  
  19.             </intent-filter>  
  20.         </activity>  
  21.         <service   
  22.                 android:name=".service.TopFloatService"    
  23.                 android:enabled="true"  
  24.                 android:exported="true"  
  25.             />  
  26.     </application>  
  27.       
  28.     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />  
  29.     <uses-permission android:name="android.permission.DISABLE_KEYGUARD"/>  
  30. </manifest>  


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

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

目录
相关文章
|
存储 数据采集 分布式计算
从 0 到 1 搭建大数据平台之数据采集系统
从 0 到 1 搭建大数据平台之数据采集系统
1492 0
|
Linux Shell 文件存储
|
11月前
|
JSON API 开发者
闲鱼商品详情API接口(闲鱼API系列)
闲鱼商品详情API为开发者提供便捷、高效且合规的途径,获取闲鱼平台上特定商品的详细信息,如标题、价格、描述和图片等。该接口采用GET请求方式,需传入app_key、item_id、timestamp和sign等参数,返回JSON格式数据。示例代码展示了如何使用Python调用此API,包括生成签名和处理响应。开发者需替换实际的app_key、app_secret和商品ID,并关注官方文档以确保接口使用的准确性。
3417 1
|
11月前
|
人工智能 自然语言处理 供应链
《DeepSeek:工业互联网与人工智能融合的“催化剂”》
在工业4.0和智能制造的浪潮下,DeepSeek技术作为工业互联网与人工智能融合的“催化剂”,通过智能数据处理、精准建模预测、智能决策支持及智能交互,全面优化生产流程,提升企业竞争力。它能高效处理多源异构数据,挖掘关键信息,预测设备故障,提供科学决策建议,并简化操作流程,推动制造业向智能化、高效化、绿色化方向迈进,引领工业互联网新时代的发展潮流。
317 5
《DeepSeek:工业互联网与人工智能融合的“催化剂”》
|
存储 缓存 NoSQL
【赵渝强老师】MongoDB的WiredTiger存储引擎
MongoDB WiredTiger存储引擎自3.2版本起成为默认选择,提供文档级别的并发控制、检查点、数据压缩和本地加密等功能。本文详细介绍了WiredTiger的并发控制机制、预写日志与检查点、内存使用、数据压缩及磁盘空间回收等特性。
590 0
|
存储 开发工具 git
Git 远程仓库地址管理:添加、修改和验证
Git 远程仓库地址管理:添加、修改和验证
1238 4
|
Kubernetes 开发工具 容器
k8s搭建集群—部署CNI网络插件——2023.02
k8s搭建集群—部署CNI网络插件——2023.02
889 0
|
机器学习/深度学习 数据采集 算法
大数据与机器学习:数字时代的强大动力
在当今数字化时代,数据已经成为了一项宝贵的资源,而大数据和机器学习则是将其转化为实际价值的关键工具。本文将探讨大数据与机器学习的关系,以及它们如何共同推动技术、企业和社会的发展。
1009 0
|
监控 druid Java
Springboot用JUnit测试接口时报错Failed to determine a suitable driver class configure a DataSource: ‘url‘
Springboot用JUnit测试接口时报错Failed to determine a suitable driver class configure a DataSource: ‘url‘
584 0
|
存储 安全 数据挖掘
性能30%↑|阿里云AnalyticDB X AMD EPYC,数据分析步入Next Level
阿里云原生数仓 AnalyticDB for PostgreSQL 与 AMD 新一代硬件深度优化,结合全自研计算引擎及行列混合存储实现性能升级,综合性能提升30%。结合丰富的企业级能力帮助企业构建离在线一体、流批一体综合数据分析平台,采用同一引擎即可满足离线批处理、流式加工,交互式分析三种场景,在开发运维、时效性及成本上具备更高的性价比。
792 0