android实现可自由移动、监听点击事件的悬浮窗
最近因为项目需要,自己实现了个可以自由移动,并且长按可以跳出一个控制播放的,大的悬浮窗。
好,开始吧。首先我们先聊权限,悬浮窗需要在manifest中声明一个权限:
然后呢,嗯,我们来讲讲关于悬浮窗实现的原理。
在Andriod中,所有的界面元素都要通过windowmanger来实现,像Activity、Fragment等等这些也是在其上实现。因此,我们的悬浮窗自然要通过这个实现。
这个项目中,我们自定义了两个悬浮窗view。我们以其中一个比较简单的为例:
我们自定义一个管理可以统一管理悬浮窗的类MyWindowManager,负责创建,删除悬浮窗
/** *Createdbyshiweon2017/3/7. *悬浮窗管理 *创建,移除 *单例模式 */ publicclassMyWindowManager{ privateFloatNormalViewnormalView; privateFloatControlViewcontrolView; privatestaticMyWindowManagerinstance; privateMyWindowManager(){ } publicstaticMyWindowManagergetInstance(){ if(instance==null) instance=newMyWindowManager(); returninstance; } /** *创建小型悬浮窗 */ publicvoidcreateNormalView(Contextcontext){ if(normalView==null) normalView=newFloatNormalView(context); } /** *移除悬浮窗 * *@paramcontext */ publicvoidremoveNormalView(Contextcontext){ if(normalView!=null){ WindowManagerwindowManager=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE); windowManager.removeView(normalView); normalView=null; } } /** *创建小型悬浮窗 */ publicvoidcreateControlView(Contextcontext){ if(controlView==null) controlView=newFloatControlView(context); } /** *移除悬浮窗 * *@paramcontext */ publicvoidremoveControlView(Contextcontext){ if(controlView!=null){ WindowManagerwindowManager=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE); windowManager.removeView(controlView); controlView=null; } } }
然后看看我们自定义的一个view,其继承自LinearLayout,我们在initLayoutParams初始化这个控件的位置等其他参数;在initEvent方法中定义随手指移动的监听事件以及长按的监听事件。
publicclassFloatNormalViewextendsLinearLayout{ privateContextcontext=null; privateViewview=null; privateImageViewivShowControlView=null; privateWindowManager.LayoutParamslp=newWindowManager.LayoutParams(); privatestaticWindowManagerwindowManager; privatefloatmTouchStartX; privatefloatmTouchStartY; privatefloatx; privatefloaty; privatebooleaninitViewPlace=false; privateMyWindowManagermyWindowManager; privatebooleanisControlViewShowing=false; publicFloatNormalView(Contextcontext){ super(context); this.context=context; myWindowManager=MyWindowManager.getInstance(); LayoutInflater.from(context).inflate(R.layout.float_normal_view,this); view=findViewById(R.id.ll_float_normal); ivShowControlView=(ImageView)findViewById(R.id.iv_show_control_view); windowManager=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE); initLayoutParams(); initEvent(); } /** *初始化参数 */ privatevoidinitLayoutParams(){ //屏幕宽高 intscreenWidth=windowManager.getDefaultDisplay().getWidth(); intscreenHeight=windowManager.getDefaultDisplay().getHeight(); //总是出现在应用程序窗口之上。 lp.type=WindowManager.LayoutParams.TYPE_PHONE; //FLAG_NOT_TOUCH_MODAL不阻塞事件传递到后面的窗口 //FLAG_NOT_FOCUSABLE悬浮窗口较小时,后面的应用图标由不可长按变为可长按,不设置这个flag的话,home页的划屏会有问题 lp.flags=WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE |WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; //悬浮窗默认显示的位置 lp.gravity=Gravity.START|Gravity.TOP; //指定位置 lp.x=screenWidth-view.getLayoutParams().width*2; lp.y=screenHeight/2+view.getLayoutParams().height*2; //悬浮窗的宽高 lp.width=WindowManager.LayoutParams.WRAP_CONTENT; lp.height=WindowManager.LayoutParams.WRAP_CONTENT; lp.format=PixelFormat.TRANSPARENT; windowManager.addView(this,lp); } /** *设置悬浮窗监听事件 */ privatevoidinitEvent(){ ivShowControlView.setOnLongClickListener(newOnLongClickListener(){ @Override publicbooleanonLongClick(Viewview){ if(!isControlViewShowing){ myWindowManager.createControlView(context); isControlViewShowing=true; }else{ myWindowManager.removeControlView(context); isControlViewShowing=false; } returntrue; } }); view.setOnTouchListener(newOnTouchListener(){ @Override publicbooleanonTouch(Viewv,MotionEventevent){ switch(event.getAction()){ caseMotionEvent.ACTION_DOWN: if(!initViewPlace){ initViewPlace=true; //获取初始位置 mTouchStartX+=(event.getRawX()-lp.x); mTouchStartY+=(event.getRawY()-lp.y); }else{ //根据上次手指离开的位置与此次点击的位置进行初始位置微调 mTouchStartX+=(event.getRawX()-x); mTouchStartY+=(event.getRawY()-y); } break; caseMotionEvent.ACTION_MOVE: //获取相对屏幕的坐标,以屏幕左上角为原点 x=event.getRawX(); y=event.getRawY(); updateViewPosition(); break; caseMotionEvent.ACTION_UP: break; } returntrue; } }); } /** *更新浮动窗口位置 */ privatevoidupdateViewPosition(){ lp.x=(int)(x-mTouchStartX); lp.y=(int)(y-mTouchStartY); windowManager.updateViewLayout(this,lp); }
最后,只需要在Activity中调用mywindowManager中调用createxxx方法就可以。
publicclassMainActivityextendsAppCompatActivity{ MyWindowManagermyWindowManager; @Override protectedvoidonCreate(@NullableBundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); myWindowManager=MyWindowManager.getInstance(); myWindowManager.createNormalView(this.getApplicationContext()); } }
最后,附上demo项目的下载地址:android实现悬浮窗
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。