android⾃动悬浮窗代码,Android实现桌⾯悬浮窗、蒙板效果实
例代码
现在很多安全类的软件,⽐如360⼿机助⼿,百度⼿机助⼿等等,都有⼀个悬浮窗,可以飘浮在桌⾯上,⽅便⽤户使⽤⼀些常⽤的操作。
今天这篇⽂章,就是介绍如何实现桌⾯悬浮窗效果的。
⾸先,看⼀下效果图。
悬浮窗⼀共分为两个部分,⼀个是平常显⽰的⼩窗⼝,另外⼀个是点击⼩窗⼝显⽰出来的⼆级悬浮窗⼝。
⾸先,先看⼀下这个项⽬的⽬录结构。
最关键的就是红框内的四个类。
⾸先,FloatWindowService是⼀个后台的服务类,主要负责在后台不断的刷新桌⾯上的⼩悬浮窗⼝,否则会导致更换界⾯之后,悬浮窗⼝
也会随之消失,因此需要不断的刷新。下⾯是实现代码。
indow;
;
ask;
e;
t;
;
r;
r;
/**
*悬浮窗后台服务
*
*@authorzhaokaiqiang
*
*/
publicclassFloatWindowServiceextendsService{
publicstaticfinalStringLAYOUT_RES_ID="layoutResId";
publicstaticfinalStringROOT_LAYOUT_ID="rootLayoutId";
//⽤于在线程中创建/移除/更新悬浮窗
privateHandlerhandler=newHandler();
privateContextcontext;
privateTimertimer;
//⼩窗⼝布局资源id
privateintlayoutResId;
//布局根布局id
privateintrootLayoutId;
@Override
publicintonStartCommand(Intentintent,intflags,intstartId){
context=this;
layoutResId=Extra(LAYOUT_RES_ID,0);
rootLayoutId=Extra(ROOT_LAYOUT_ID,0);
if(layoutResId==0||rootLayoutId==0){
thrownewIllegalArgumentException(
"layoutResIdorrootLayoutIdisillegal");
}
if(timer==null){
timer=newTimer();
//每500毫秒就执⾏⼀次刷新任务
leAtFixedRate(newRefreshTask(),0,500);
}
tCommand(intent,flags,startId);
}
@Override
publicvoidonDestroy(){
roy();
//Service被终⽌的同时也停⽌定时器继续运⾏
();
timer=null;
}
privateclassRefreshTaskextendsTimerTask{
@Override
publicvoidrun(){
//当前界⾯没有悬浮窗显⽰,则创建悬浮
if(!tance(context).isWindowShowing()){
(newRunnable(){
@Override
publicvoidrun(){
tance(context)
.createSmallWindow(context,layoutResId,
rootLayoutId);
}
});
}
}
}
@Override
publicIBinderonBind(Intentintent){
returnnull;
}
}
除了后台服务之外,我们还需要两个⾃定义的布局,分别是FloatWindowSmallView和FloatWindowBigView,这两个⾃定义的布局,主
要负责悬浮窗的前台显⽰,我们分别看⼀下代码实现。
⾸先是FloatWindowSmallView类的实现。
indow;
;
ssLint;
t;
ormat;
y;
Inflater;
Event;
;
Manager;
Layout;
ew;
Utils;
ngwindow.R;
/**
*⼩悬浮窗,⽤于初始显⽰
*
*@authorzhaokaiqiang
*
*/
publicclassFloatWindowSmallViewextendsLinearLayout{
//⼩悬浮窗的宽
publicintviewWidth;
//⼩悬浮窗的⾼
publicintviewHeight;
//系统状态栏的⾼度
privatestaticintstatusBarHeight;
//⽤于更新⼩悬浮窗的位置
privateWindowManagerwindowManager;
//⼩悬浮窗的布局参数
ParamssmallWindowParams;
//记录当前⼿指位置在屏幕上的横坐标
privatefloatxInScreen;
//记录当前⼿指位置在屏幕上的纵坐标
privatefloatyInScreen;
//记录⼿指按下时在屏幕上的横坐标,⽤来判断单击事件
privatefloatxDownInScreen;
//记录⼿指按下时在屏幕上的纵坐标,⽤来判断单击事件
privatefloatyDownInScreen;
//记录⼿指按下时在⼩悬浮窗的View上的横坐标
privatefloatxInView;
//记录⼿指按下时在⼩悬浮窗的View上的纵坐标
privatefloatyInView;
//单击接⼝
privateOnClickListenerlistener;
/**
*构造函数
*
*@paramcontext
*上下⽂对象
*@paramlayoutResId
*布局资源id
*@paramrootLayoutId
*根布局id
*/
publicFloatWindowSmallView(Contextcontext,intlayoutResId,
introotLayoutId){
super(context);
windowManager=(WindowManager)context
.getSystemService(_SERVICE);
(context).inflate(layoutResId,this);
Viewview=findViewById(rootLayoutId);
viewWidth=outParams().width;
viewHeight=outParams().height;
statusBarHeight=getStatusBarHeight();
TextViewpercentView=(TextView)findViewById(t);
t("悬浮窗");
smallWindowParams=Params();
//设置显⽰类型为phone
=_PHONE;
//显⽰图⽚格式
=_8888;
//设置交互模式
=_NOT_TOUCH_MODAL
|_NOT_FOCUSABLE;
//设置对齐⽅式为左上
y=|;
=viewWidth;
=viewHeight;
smallWindowParams.x=eenWidth(context);
smallWindowParams.y=eenHeight(context)/2;
}
@SuppressLint("ClickableViewAccessibility")
@Override
publicbooleanonTouchEvent(MotionEventevent){
switch(ion()){
//⼿指按下时记录必要的数据,纵坐标的值都减去状态栏的⾼度
_DOWN:
//获取相对与⼩悬浮窗的坐标
xInView=();
yInView=();
//按下时的坐标位置,只记录⼀次
xDownInScreen=X();
yDownInScreen=Y()-statusBarHeight;
break;
_MOVE:
//时时的更新当前⼿指在屏幕上的位置
xInScreen=X();
yInScreen=Y()-statusBarHeight;
//⼿指移动的时候更新⼩悬浮窗的位置
updateViewPosition();
break;
_UP:
//如果⼿指离开屏幕时,按下坐标与当前坐标相等,则视为触发了单击事件
if(xDownInScreen==X()
&&yDownInScreen==(Y()-getStatusBarHeight())){
if(listener!=null){
();
}
}
break;
}
returntrue;
}
/**
*设置单击事件的回调接⼝
*/
publicvoidtOnClickListener(OnClickListenerlistener){
er=listener;
}
/**
*更新⼩悬浮窗在屏幕中的位置
*/
privatevoidupdateViewPosition(){
smallWindowParams.x=(int)(xInScreen-xInView);
smallWindowParams.y=(int)(yInScreen-yInView);
ViewLayout(this,smallWindowParams);
}
/**
*获取状态栏的⾼度
*
*@return
*/
privateintgetStatusBarHeight(){
try{
Class>c=e("al.R$dimen");
Objecto=tance();
Fieldfield=ld("status_bar_height");
intx=(Integer)(o);
returngetResources().getDimensionPixelSize(x);
}catch(Exceptione){
tackTrace();
}
return0;
}
/**
*单击接⼝
*
*@authorzhaokaiqiang
*
*/
publicinterfaceOnClickListener{
publicvoidclick();
}
}
在这个类⾥⾯,主要的⼯作是实现悬浮窗⼝在桌⾯前端的实现,还有就是位置的移动和单击事件的判断以及处理。这⾥使⽤的是主要是
WindowManager类的⼀些⽅法和属性,下⼀篇会详细说明,这篇只说实现。
除了⼩悬浮窗之外,点击之后弹出的⼆级悬浮窗也是类似的⽅式添加到桌⾯上,下⾯是⼆级悬浮窗的代码。
indow;
t;
ormat;
y;
Inflater;
;
Manager;
Layout;
ew;
Utils;
ngwindow.R;
publicclassFloatWindowBigViewextendsLinearLayout{
//记录⼤悬浮窗的宽
publicintviewWidth;
//记录⼤悬浮窗的⾼
publicintviewHeight;
ParamsbigWindowParams;
privateContextcontext;
publicFloatWindowBigView(Contextcontext){
super(context);
t=context;
(context).inflate(_window_big,this);
Viewview=findViewById(_window_layout);
viewWidth=outParams().width;
viewHeight=outParams().height;
bigWindowParams=Params();
//设置显⽰的位置,默认的是屏幕中⼼
bigWindowParams.x=eenWidth(context)/2-viewWidth
/2;
bigWindowParams.y=eenHeight(context)/2
-viewHeight/2;
=_PHONE;
=_8888;
//设置交互模式
=_NOT_TOUCH_MODAL
|_NOT_FOCUSABLE;
y=|;
=viewWidth;
=viewHeight;
initView();
}
privatevoidinitView(){
TextViewtv_back=(TextView)findViewById(_back);
tv_lickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewv){
tance(context).removeBigWindow();
}
});
}
}
这些基本的类建⽴起来之后,剩下的就是最重要的类FloatWindowManager的实现。这个类实现的就是对悬浮窗的操作。
indow;
t;
;
Manager;
/**
*悬浮窗管理器
*
*@authorzhaokaiqiang
*
*/
publicclassFloatWindowManager{
//⼩悬浮窗对象
privateFloatWindowSmallViewsmallWindow;
//⼤悬浮窗对象
privateFloatWindowBigViewbigWindow;
//⽤于控制在屏幕上添加或移除悬浮窗
privateWindowManagermWindowManager;
//FloatWindowManager的单例
privatestaticFloatWindowManagerfloatWindowManager;
//上下⽂对象
privateContextcontext;
privateFloatWindowManager(Contextcontext){
t=context;
}
publicstaticFloatWindowManagergetInstance(Contextcontext){
if(floatWindowManager==null){
floatWindowManager=newFloatWindowManager(context);
}
returnfloatWindowManager;
}
/**
*创建⼩悬浮窗
*
*@paramcontext
*必须为应⽤程序的Context.
*/
publicvoidcreateSmallWindow(Contextcontext,intlayoutResId,
introotLayoutId){
WindowManagerwindowManager=getWindowManager();
if(smallWindow==null){
smallWindow=newFloatWindowSmallView(context,layoutResId,
rootLayoutId);
w(smallWindow,indowParams);
}
}
/**
*将⼩悬浮窗从屏幕上移除
*
*@paramcontext
*/
publicvoidremoveSmallWindow(){
if(smallWindow!=null){
WindowManagerwindowManager=getWindowManager();
View(smallWindow);
smallWindow=null;
}
}
publicvoidtOnClickListener(kListenerlistener){
if(smallWindow!=null){
lickListener(listener);
}
}
/**
*创建⼤悬浮窗
*
*@paramcontext
*必须为应⽤程序的Context.
*/
publicvoidcreateBigWindow(Contextcontext){
WindowManagerwindowManager=getWindowManager();
if(bigWindow==null){
bigWindow=newFloatWindowBigView(context);
w(bigWindow,dowParams);
}
}
/**
*将⼤悬浮窗从屏幕上移除
*
*@paramcontext
*/
publicvoidremoveBigWindow(){
if(bigWindow!=null){
WindowManagerwindowManager=getWindowManager();
View(bigWindow);
bigWindow=null;
}
}
publicvoidremoveAll(){
rvice(newIntent(context,));
removeSmallWindow();
removeBigWindow();
}
/**
*是否有悬浮窗显⽰(包括⼩悬浮窗和⼤悬浮)
*
*@return有悬浮窗显⽰在桌⾯上返回true,没有的话返回fal
*/
publicbooleanisWindowShowing(){
returnsmallWindow!=null||bigWindow!=null;
}
/**
*如果WindowManager还未创建,则创建新的WindowManager返回。否则返回当前已创建的WindowManager
*
*@paramcontext
*@return
*/
privateWindowManagergetWindowManager(){
if(mWindowManager==null){
mWindowManager=(WindowManager)context
.getSystemService(_SERVICE);
}
returnmWindowManager;
}
}
还有个获取屏幕宽⾼的帮助类。
;
t;
Manager;
/**
*屏幕帮助类
*
*@authorzhaokaiqiang
*
*/
publicclassScreenUtils{
/**
*获取屏幕宽度
*
*@return
*/
@SuppressWarnings("deprecation")
publicstaticintgetScreenWidth(Contextcontext){
return((WindowManager)context
.getSystemService(_SERVICE)).getDefaultDisplay()
.getWidth();
}
/**
*获取屏幕宽度
*
*@return
*/
@SuppressWarnings("deprecation")
publicstaticintgetScreenHeight(Contextcontext){
return((WindowManager)context
.getSystemService(_SERVICE)).getDefaultDisplay()
.getHeight();
}
}
完成这些,我们就可以直接⽤了。
;
ty;
t;
;
;
nt;
;
ngwindow.R;
indowManager;
indowService;
kListener;
/**
*⽰例
*
*@ClassName:tivity
*@Description:
*@authorzhaokaiqiang
*@date2014-10-23下午11:30:13
*
*/
publicclassMainActivityextendsActivity{
privateFloatWindowManagerfloatWindowManager;
privateContextcontext;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
te(savedInstanceState);
tContentView(ty_main);
context=this;
floatWindowManager=tance(context);
}
/**
*显⽰⼩窗⼝
*
*@paramview
*/
publicvoidshow(Viewview){
//需要传递⼩悬浮窗布局,以及根布局的id,启动后台服务
Intentintent=newIntent(context,);
ra(_RES_ID,
_window_small);
ra(_LAYOUT_ID,
_window_layout);
startService(intent);
}
/**
*显⽰⼆级悬浮窗
*
*@paramview
*/
publicvoidshowBig(Viewview){
//设置⼩悬浮窗的单击事件
lickListener(newOnClickListener(){
@Override
publicvoidclick(){
BigWindow(context);
}
});
}
/**
*移除所有的悬浮窗
*
*@paramview
*/
publicvoidremove(Viewview){
All();
}
@Override
publicbooleanonKeyDown(intkeyCode,KeyEventevent){
//返回键移除⼆级悬浮窗
if(keyCode==E_BACK
&&ion()==_DOWN){
BigWindow();
returntrue;
}
own(keyCode,event);
}
}
在上⾯⽂章中,我们介绍了如何实现桌⾯悬浮窗⼝,在这个效果的实现过程中,最重要的⼀个类就是WindowManager,今天这篇⽂章,将
对WindowManager的使⽤进⾏介绍,并且实现⼀个使⽤WindowManager来实现⽤户打开APP,显⽰⾸次使⽤教学蒙板的效果。
WindowManager类实现了ViewManager接⼝,ViewManager接⼝允许我们在Activity上添加或者是移除view,因此WindowManager
也允许我们在Activity上进⾏View的添加和移除操作。
我们可以通过下⾯的⽅法获取⼀个WindowManager对象
temService(_SERVICE)
在Activity之中,我们可以直接通过getWindowManager()获取到⼀个WindowManager对象。
每⼀个WindowManager实例都被绑定到⼀个独有的Display对象上⾯,如果我们想获取不同Display的WindowManager对象,我们可以
通过createDisplayContext(Display)获取到这个Display的Context对象,然后使⽤上⾯的⽅法,也可以获取到⼀个WindowManager对
象。
我们在使⽤WindowManager类的时候,通常使⽤下⾯的⼏个⽅法:
w(View,Param);
View();
aultDisplay();
w()⽅法⽤来向当前的窗⼝上添加View对象,需要接受两个参数,View是要添加到窗⼝的View对象,⽽
Param则是添加的窗⼝的参数,在上⼀篇添加悬浮窗的操作的时候,需要对LayoutParam设置很多参数,下⾯
我们看⼀下常⽤的设置
//设置LayoutParams参数
LayoutParamsparams=Params();
//设置显⽰的类型,TYPE_PHONE指的是来电话的时候会被覆盖,其他时候会在最前端,显⽰位置在stateBar下⾯,其他更多的值请查阅
⽂档
=_PHONE;
//设置显⽰格式
=_8888;
//设置对齐⽅式
y=|;
//设置宽⾼
=eenWidth(this);
=eenHeight(this);
//设置显⽰的位置
params.x;
params.y;
设置好LayoutParam之后,我们就可以通过w(View,Param)将View添加到窗⼝之
上,不过,我们需要申明权限
添加完成之后,我们就可以在窗⼝上看到我们添加的View对象了。如果我们想将添加的View移除,我们只需要调⽤
View()即可,参数就是我们前⾯使⽤的View对象,使⽤很简单。除了这个⽅法,还有个
ViewImmediate(),也可以将View移除,但是⽂档中说,这个⽅法并不是给⼀般程序调⽤的,因此需要⼩⼼使
⽤,我们开发的都属于⼀般程序,建议不要使⽤这个⽅法。
除了这两个⽅法之外,我们最常⽤的另外⼀个⽅法就是aultDisplay(),通过这个⽅法,我们可以获取到当前界⾯
的Display的⼀个对象,然后我们就可以获取到当前屏幕的⼀些参数,⽐如说宽⾼。
下⾯是我常⽤的⼀个⼯具类。
ask;
t;
Manager;
/**
*屏幕帮助类
*
*@authorzhaokaiqiang
*
*/
publicclassScreenUtils{
/**
*获取屏幕宽度
*
*@return
*/
@SuppressWarnings("deprecation")
publicstaticintgetScreenWidth(Contextcontext){
return((WindowManager)context
.getSystemService(_SERVICE)).getDefaultDisplay()
.getWidth();
}
/**
*获取屏幕宽度
*
*@return
*/
@SuppressWarnings("deprecation")
publicstaticintgetScreenHeight(Contextcontext){
return((WindowManager)context
.getSystemService(_SERVICE)).getDefaultDisplay()
.getHeight();
}
}
知道上⾯这些之后,我们就可以实现教学模板效果了,⾸先看效果图。
下⾯是代码实现
ask;
ty;
ormat;
;
y;
;
kListener;
Manager;
Params;
iew;
ype;
publicclassMainActivityextendsActivity{
privateImageViewimg;
privateWindowManagerwindowManager;
@Override
protectedvoidonCreate(BundlesavedInstanceState){
te(savedInstanceState);
tContentView(ty_main);
windowManager=getWindowManager();
//动态初始化图层
img=newImageView(this);
outParams(newLayoutParams(
_PARENT,
_PARENT));
leType(_XY);
geResource();
//设置LayoutParams参数
LayoutParamsparams=Params();
//设置显⽰的类型,TYPE_PHONE指的是来电话的时候会被覆盖,其他时候会在最前端,显⽰位置在stateBar下⾯,其他更多的值请查阅
⽂档
=_PHONE;
//设置显⽰格式
=_8888;
//设置对齐⽅式
y=|;
//设置宽⾼
=eenWidth(this);
=eenHeight(this);
//添加到当前的窗⼝上
w(img,params);
//点击图层之后,将图层移除
lickListener(newOnClickListener(){
@Override
publicvoidonClick(Viewarg0){
View(img);
}
});
}
}
以上所述是⼩编给⼤家介绍的Android实现桌⾯悬浮窗、蒙板效果实例代码,希望对⼤家有所帮助!
本文发布于:2023-03-08 12:39:41,感谢您对本站的认可!
本文链接:https://www.wtabcd.cn/fanwen/zuowen/1678250382183805.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文word下载地址:悬浮窗口怎么设置.doc
本文 PDF 下载地址:悬浮窗口怎么设置.pdf
留言与评论(共有 0 条评论) |