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实现悬浮窗
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。