Android中可自由移动悬浮窗口的实现
Android自定义悬浮按钮效果

Android⾃定义悬浮按钮效果本⽂实例为⼤家分享了Android⾃定义悬浮按钮效果的具体代码,供⼤家参考,具体内容如下以下:内容没有参考,写的也是⼀个⽐较简单的例⼦,主要就是应⽤切换前后台时会显⽰/隐藏悬浮窗。
内容仅⽤于⾃我记录学习使⽤。
项⽬的开发时应⽤在登陆后显⽰⼀个悬浮窗,同时显⽰在线⼈数等⼀些其他信息,点击悬浮按钮可以显⽰全局弹窗名单。
开发完成后,觉着需要记录⼀下这种实现⽅式。
所以写⼀个简单的Demo。
Demo思路是通过启动Service来添加/移除悬浮窗,因为是⼀个全局悬浮窗,所以选择依附于Service。
在MyAppliction中监听应⽤的前后台切换来添加或者隐藏悬浮窗。
其⾃定义的悬浮窗View在项⽬中是通过Canvas⼿动绘制的,这⾥图个省事直接加载⼀个布局⽂件。
主要是想理解这种添加全局悬浮窗的⽅式,所以Demo样式和功能能简则简。
MyApplictionpackage com.example.qxb_810.floatbuttondemo.application;import android.app.Activity;import android.app.ActivityManager;import android.app.Application;import android.content.Context;import android.content.Intent;import android.os.Bundle;import android.util.Log;import android.view.WindowManager;import com.example.qxb_810.floatbuttondemo.service.FloatingActionService;import java.util.List;import static android.content.ContentValues.TAG;/*** create 2018/12/1 13:31* desc ⾃定义Application*/public class MyApplication extends Application {private Intent mIntent;private youtParams mFloatingLayoutParams = new youtParams();public youtParams getmFloatingLayoutParams() {return mFloatingLayoutParams;}@Overridepublic void onCreate() {super.onCreate();this.monitorActivityLifecycle();}/*** 监听程序Activity声明周期*/private void monitorActivityLifecycle() {this.registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks() {@Overridepublic void onActivityCreated(Activity activity, Bundle savedInstanceState) {}@Overridepublic void onActivityStarted(Activity activity) {if (isRunningForeground()){mIntent = new Intent(MyApplication.this, FloatingActionService.class);startService(mIntent);}}@Overridepublic void onActivityResumed(Activity activity) {}@Overridepublic void onActivityPaused(Activity activity) {}@Overridepublic void onActivityStopped(Activity activity) {if (!isRunningForeground()){stopService(mIntent);}}@Overridepublic void onActivitySaveInstanceState(Activity activity, Bundle outState) {}@Overridepublic void onActivityDestroyed(Activity activity) {}});}/*** 判断应⽤运⾏在前后台*/public boolean isRunningForeground() {ActivityManager activityManager = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);List<ActivityManager.RunningAppProcessInfo> appProcessInfos = activityManager.getRunningAppProcesses(); // 枚举进程for (ActivityManager.RunningAppProcessInfo appProcessInfo : appProcessInfos) {if (appProcessInfo.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND) {if (appProcessInfo.processName.equals(this.getApplicationInfo().processName)) {Log.d(TAG, "EntryActivity isRunningForeGround");return true;}}}Log.d(TAG, "EntryActivity isRunningBackGround");return false;}}FloatingActionService.java ---- 悬浮窗所依附的Servicepackage com.example.qxb_810.floatbuttondemo.service;import android.app.Service;import android.content.Intent;import android.graphics.PixelFormat;import android.os.IBinder;import android.support.annotation.Nullable;import android.util.DisplayMetrics;import android.view.Display;import android.view.Gravity;import android.view.WindowManager;import android.widget.LinearLayout;import android.widget.Toast;import com.example.qxb_810.floatbuttondemo.application.MyApplication;import com.example.qxb_810.floatbuttondemo.button.FloatingActionButton;/*** create 2018/12/1 13:34* desc 悬浮按钮Service*/public class FloatingActionService extends Service {private WindowManager mWindowManager;private FloatingActionButton mButton;private int mScreenWidth;private int mScreenHeight;@Overridepublic void onCreate() {super.onCreate();this.initView();this.initEvent();}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null;}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();this.mWindowManager.removeViewImmediate(this.mButton);}/*** 添加按钮*/private void initView() {// 通过WindowManager来添加悬浮窗this.mWindowManager = (WindowManager) this.getApplicationContext().getSystemService(WINDOW_SERVICE);Display display = this.mWindowManager.getDefaultDisplay();DisplayMetrics metrics = new DisplayMetrics();display.getMetrics(metrics);this.mScreenWidth = metrics.widthPixels;this.mScreenHeight = metrics.heightPixels;youtParams params = ((MyApplication) this.getApplication()).getmFloatingLayoutParams();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {mFloatingLayoutParams.type = youtParams.TYPE_APPLICATION_OVERLAY;} else {mFloatingLayoutParams.type = youtParams.TYPE_TOAST;}params.format = PixelFormat.RGBA_8888;params.flags = youtParams.FLAG_NOT_TOUCH_MODAL | youtParams.FLAG_NOT_FOCUSABLE; params.gravity = Gravity.LEFT | Gravity.TOP; // 左上为坐标点// 设置View⼤⼩params.height = 50;params.width = 50;// 设置View坐标位置params.x = 0;params.y = mScreenHeight / 2;this.mButton = FloatingActionButton.getInstance(this);this.mWindowManager.addView(mButton, params);}/*** 初始化事件*/private void initEvent() {this.mButton.setOnClickListener(v -> {// 项⽬中是在这⾥进⾏添加名单弹窗和移除名单弹窗的操作,但名单弹窗的初始化不在这⾥Toast.makeText(this, "点击了Button", Toast.LENGTH_SHORT).show();});}}FloatingActionButton – 弹窗按钮package com.example.qxb_810.floatbuttondemo.button;import android.content.Context;import android.graphics.Canvas;import android.support.annotation.Nullable;import android.util.AttributeSet;import youtInflater;import android.view.MotionEvent;import android.view.View;import android.view.WindowManager;import android.widget.FrameLayout;import android.widget.LinearLayout;import com.example.qxb_810.floatbuttondemo.R;import com.example.qxb_810.floatbuttondemo.application.MyApplication;import static android.content.Context.WINDOW_SERVICE;/*** create 2018/12/1 13:35* desc ⾃定义悬浮按钮 -- 这⾥随便写的⼀个布局⽂件*/public class FloatingActionButton extends FrameLayout {private Context mContext;private float mStartPointX;private float mStartPointY;private WindowManager mWindowManager;private youtParams mFloatingLayoutParams;private boolean isIntercept = false;private int mStatusHeight;public static FloatingActionButton getInstance(Context context) {FloatingActionButton button = new FloatingActionButton(context);return button;}public FloatingActionButton(Context context) {this(context, null);}public FloatingActionButton(Context context, @Nullable AttributeSet attrs) {this(context, attrs, -1);}public FloatingActionButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);mContext = context;initView();}@Overrideprotected void onLayout(boolean changed, int left, int top, int right, int bottom) {super.onLayout(changed, left, top, right, bottom);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);}/*** 初始化View*/private void initView(){// 随便添加⼀个简单的View布局作为悬浮窗View view = LayoutInflater.from(mContext).inflate(yout_floating_button, null, false);youtParams params = new youtParams(youtParams.WRAP_CONTENT,youtParams.WRAP_CONTENT); this.addView(view, params);this.mWindowManager = (WindowManager) getContext().getApplicationContext().getSystemService(WINDOW_SERVICE);this.mFloatingLayoutParams = ((MyApplication) getContext().getApplicationContext()).getmFloatingLayoutParams();this.mStatusHeight = getStatusHeight(mContext);}@Overridepublic boolean onTouchEvent(MotionEvent event) {//获取相对屏幕的坐标,即以屏幕左上⾓为原点float rawX = event.getRawX();float rawY = event.getRawY() - mStatusHeight; //statusHeight是系统状态栏的⾼度switch (event.getAction()){case MotionEvent.ACTION_DOWN:this.mStartPointX = event.getX();this.mStartPointY = event.getY();isIntercept = false;break;case MotionEvent.ACTION_MOVE:mFloatingLayoutParams.x = (int)(rawX - mStartPointX);mFloatingLayoutParams.y = (int)(rawY - mStartPointY);this.mWindowManager.updateViewLayout(this, mFloatingLayoutParams);isIntercept = true;break;case MotionEvent.ACTION_UP:mFloatingLayoutParams.x = 0; // 这⾥的策略是默认松⼿吸附到左侧如果需要吸附到右侧则改为mFloatingLayoutParams.x = mScreenWidth; mScreenWidth 是屏幕宽度,不想吸附则注释这⼀句即可 this.mWindowManager.updateViewLayout(this, mFloatingLayoutParams);break;}return isIntercept ? isIntercept : super.onTouchEvent(event);}/*** 状态栏的⾼度*/public static int getStatusHeight(Context context) {int statusHeight = -1;try {Class clazz = Class.forName("com.android.internal.R$dimen"); //使⽤反射获取实例Object object = clazz.newInstance();int height = Integer.parseInt(clazz.getField("status_bar_height").get(object).toString());statusHeight = context.getResources().getDimensionPixelSize(height);} catch (Exception e) {e.printStackTrace();}return statusHeight;}}布局⽂件<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:background="@color/colorPrimary"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="12312313131313"android:textSize="20sp" /></LinearLayout>以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。
android 小米 自由窗口 实现原理

android 小米自由窗口实现原理一、引言Android系统中的小米自由窗口技术,是一种新型的显示和计算技术,具有高效率、低功耗等优点。
本篇文章将详细介绍自由窗口的实现原理,从硬件支持到软件设计,深入探讨自由窗口的技术特点和应用场景。
二、硬件支持小米自由窗口技术的实现,离不开其内置的显示芯片。
通过硬件级支持,显示芯片能够实现高效的多窗口处理,从而为自由窗口的实现提供了基础。
在硬件层面,显示芯片能够将多个窗口无缝拼接,实现高效的多任务处理。
三、软件设计自由窗口的实现主要依赖于Android系统中的WindowManager和SurfaceFlinger等API。
通过这些API,开发者可以创建和管理多个窗口,并在不同窗口之间进行切换。
自由窗口的核心思想是将应用程序的界面拆分成多个小窗口,这些窗口可以在屏幕上同时显示,从而实现高效的多任务处理。
每个窗口可以独立绘制,互不干扰,大大提高了显示效率。
四、技术特点1.高效率:自由窗口技术通过并行处理多个窗口,实现了高效的显示和计算。
多个窗口可以同时绘制,大大提高了显示效率。
2.低功耗:由于自由窗口技术可以独立绘制窗口,互不干扰,因此可以减少不必要的画面刷新,降低功耗。
3.可定制性强:开发者可以根据自己的需求,定制窗口的大小、位置、透明度等属性,以满足不同的应用场景。
五、应用场景1.多任务处理:自由窗口技术适用于需要同时处理多个任务的应用场景,如多任务办公、游戏等。
2.多媒体播放:自由窗口技术可以同时播放多个音视频文件,实现高效的多媒体播放。
3.视频会议:自由窗口技术适用于需要同时展示会议资料和视频会议界面的场景,提高会议效率。
六、总结小米自由窗口技术的实现原理主要依赖于硬件的支持和软件的优化设计。
通过将应用程序的界面拆分成多个小窗口,并在屏幕上同时显示,实现了高效的多任务处理。
自由窗口技术具有高效率、低功耗、可定制性强等优点,适用于多任务处理、多媒体播放和视频会议等多种应用场景。
Android利用WindowManager生成悬浮按钮及悬浮菜单

Android利⽤WindowManager⽣成悬浮按钮及悬浮菜单简介本⽂模仿实现的是360⼿机卫⼠基础效果,同时后续会补充⼀些WindowManager的原理知识。
整体思路360⼿机卫⼠的内存球其实就是⼀个没有画⾯的应⽤程序,整个应⽤程序的主体是⼀个Service。
我们的程序开始以后,启动⼀个service,同时关闭activity即可:public class MainActivity extends Activity {private static final String TAG = MainActivity.class.getSimpleName();@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);startService(new Intent(this, FloatWindowService.class));finish();}}import android.os.IBinder;import android.util.Log;import java.util.Timer;import java.util.TimerTask;public class FloatWindowService extends Service {private static final String TAG = FloatWindowService.class.getSimpleName();public FloatWindowService() {}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "on start command");FloatWindowManager.instance(getApplicationContext()).createFloatWindow();return super.onStartCommand(intent, flags, startId);}@Overridepublic IBinder onBind(Intent intent) {// TODO: Return the communication channel to the service.throw new UnsupportedOperationException("Not yet implemented");}}我们要注意的是,传统的Service默认是运⾏在UI线程中的,这点与封装了⼀个Thread和Handler的intentService不同,所以我们可以直接在Service中更改UI相关的内容。
android Activity实现从底部弹出或滑出选择菜单或窗口

博客分类:
•android Activity
android Activity实现从底部弹出菜单或窗口android Activity滑出选择菜单或窗口androidActivity
本例使用activity实现弹出滑动窗口或菜单,主要是使用了一些设置activity的样式来实现弹出窗口和滑动效果,实现如下:
第一步:设计要弹出窗口的xml布局:
Xml代码
第二步:创建SelectPicPopupWindow类继承Activity类并实现OnClickListener接口(可以不用在这里实现这个借口,根据自己需要和方便实现),其他代码实现跟编写常规Activity 一样就OK,如下:
Java代码
第三步:编写MainActivity类,这里很简单就是点击启动刚才要实现窗口的MainActivity 即可:
Java代码
第四步:这里要注意下AndroidManifest.xml对SelectPicPopupWindow的配置跟常规的不一样为该activity改添加android:theme属性,如下:
Xml代码
第五步:这一步是实现本实例最重要的一部就是设置android:theme属性样式以实现本例所需要的效果,如下:
Xml代码
第六步:在贴出弹出和销毁时的动画效果代码:
push_bottom_in.xml
Xml代码
push_buttom_out.xml
Xml代码
注意:这两个xml需要放在res/anim的anim文件夹下第七步;运行效果如图:。
Android悬浮窗的简单实现

Android悬浮窗的简单实现⽬录概述原理Android的界⾯绘制,都是通过 WindowManager 的服务来实现的。
WindowManager 实现了 ViewManager 接⼝,可以通过获取 WINDOW_SERVICE 系统服务得到。
⽽ViewManager 接⼝有 addView ⽅法,我们就是通过这个⽅法将悬浮窗控件加⼊到屏幕中去。
为了让悬浮窗与Activity脱离,使其在应⽤处于后台时悬浮窗仍然可以正常运⾏,使⽤Service来启动悬浮窗并做为其背后逻辑⽀撑。
权限在 API Level >= 23 的时候,需要在AndroidManefest.xml⽂件中声明权限 SYSTEM_ALERT_WINDOW 才能在其他应⽤上绘制控件。
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />除了这个权限外,我们还需要在系统设置⾥⾯对本应⽤进⾏设置悬浮窗权限。
该权限在应⽤中需要启动 Settings.ACTION_MANAGE_OVERLAY_PERMISSION 来让⽤户⼿动设置权限。
if (!Settings.canDrawOverlays(this)) {showError("当前⽆权限,请授权");startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 0);} else {startService(new Intent(MainActivity.this, FloatingService.class));}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (requestCode == 0) {if (!Settings.canDrawOverlays(this)) {showError("授权失败");} else {showMsg("授权成功");startService(new Intent(MainActivity.this, FloatingService.class));}}}LayoutParamWindowManager 的 addView ⽅法有两个参数,⼀个是需要加⼊的控件对象,另⼀个参数是 youtParam 对象。
Android中可自由移动悬浮窗口的实现xsmilesBlog

Android中可自由移动悬浮窗口的实现xsmilesBlog Android中可自由移动悬浮窗口的实现2011年7月27日android, 技术相关7 评论第二届 Google 暑期大学生博客分享大赛 – 2011 Android 成长篇本文为参加Google暑期大学生博客分享大赛特别撰写。
—————————————————————-大家对悬浮窗概念不会陌生,相信每台电脑桌面的右上角都会有这么一个东西,它总是出现在所有页面的顶端(Top Show)。
但在Android平台中如何实现这样的效果呢?先来看一看效果图。
看见在Google搜索框上面的那个Icon图片了嘛。
下面我就来详细介绍一下在Android平台下悬浮窗口的实现,并让它能够随手指的触摸而移动。
一、实现原理及移动思路调用WindowManager,并设置youtParams的相关属性,通过WindowManager的addView方法创建View,这样产生出来的View根据youtParams属性不同,效果也就不同了。
比如创建系统顶级窗口,实现悬浮窗口效果!然后通过覆写悬浮View中onTouchEvent方法来改变youtParams中x和y的值来实现自由移动悬浮窗口。
二、示例代码先来看一看悬浮View的代码,这里用一个ImageView作为演示01public class MyFloatView extends ImageView {02 private float mTouchStartX;03 private float mTouchStartY;04 private float x;05 private float y;0607 private WindowManager wm=(WindowManager)getContext().getApplicationContext().getSystemService("window");08 //此wmParams变量为获取的全局变量,用以保存悬浮窗口的属性09 private youtParams wmParams =((MyApplication)getContext().getApplicationContext()).getMywmParams();1011 public MyFloatView(Context context) {12 super(context);13 // TODO Auto-generated constructor stub14 }1516 @Override17 public boolean onTouchEvent(MotionEvent event) {18 //获取相对屏幕的坐标,即以屏幕左上角为原点19 x = event.getRawX();20 y = event.getRawY()-25; //25是系统状态栏的高度21 Log.i("currP", "currX"+x+"====currY"+y);22 switch(event.getAction()) {23 case MotionEvent.ACTION_DOWN: //捕获手指触摸按下动作24 //获取相对View的坐标,即以此View左上角为原点25 mTouchStartX = event.getX();26 mTouchStartY = event.getY();27 Log.i("startP","startX"+mTouchStartX+"====startY"+mTouchStartY);28 break;2930 case MotionEvent.ACTION_MOVE: //捕获手指触摸移动动作31 updateViewPosition();32 break;3334 case MotionEvent.ACTION_UP: //捕获手指触摸离开动作35 updateViewPosition();36 mTouchStartX=mTouchStartY=0;37 break;38 }39 return true;40 }4142 private void updateViewPosition(){43 //更新浮动窗口位置参数44 wmParams.x=(int)( x-mTouchStartX);45 wmParams.y=(int) (y-mTouchStartY);46 wm.updateViewLayout(this, wmParams); //刷新显示47 }4849}上面的wmParams变量(即youtParams)的存储采用了extends Application的方式来创建全局变量,示例代码如下:01public class MyApplication extends Application {0203 /**04 * 创建全局变量05 * 全局变量一般都比较倾向于创建一个单独的数据类文件,并使用static静态变量06 *07 * 这里使用了在Application中添加数据的方法实现全局变量08 * 注意在AndroidManifest.xml中的Application节点添加android:name=".MyApplication"属性09 *10 */11 private youtParams wmParams=new youtParams(); 1213 public youtParams getMywmParams(){14 return wmParams;15 }16}再来看一看Activity中的代码:01public class MyFloatViewActivity extends Activity {02 /** Called when the activity is first created. */0304 private WindowManager wm=null;05 private youtParams wmParams=null;0607 private MyFloatView myFV=null;080910 @Override11 public void onCreate(Bundle savedInstanceState) {12 super.onCreate(savedInstanceState);13 setContentView(yout.main);14 //创建悬浮窗口15 createView();1617 }18192021 private void createView(){22 myFV=new MyFloatView(getApplicationContext());23 myFV.setImageResource(R.drawable.icon); //这里简单的用自带的Icom来做演示24 //获取WindowManager25 wm=(WindowManager)getApplicationContext().getSystemService("window");26 //设置LayoutParams(全局变量)相关参数27 wmParams = ((MyApplication)getApplication()).getMywmParams();2829 /**30 *以下都是youtParams的相关属性31 * 具体用途可参考SDK文档32 */33 wmParams.type=LayoutParams.TYPE_PHONE; //设置window type34 wmParams.format=PixelFormat.RGBA_8888; //设置图片格式,效果为背景透明3536 //设置Window flag37 wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL38 | LayoutParams.FLAG_NOT_FOCUSABLE;39 /*40 * 下面的flags属性的效果形同“锁定”。
Android实现控件悬浮效果实例代码

Android实现控件悬浮效果实例代码随着移动互联⽹的快速发展,它已经和我们的⽣活息息相关了,在公交地铁⾥⾯都能看到很多⼈的⼈低头看着⾃⼰的⼿机屏幕,从此“低头族”⼀词就产⽣了,作为⼀名移动⾏业的开发⼈员,我⾃⼰也是⼀名“低头族”,上下班时间在公交地铁上看看新闻来打发下时间,有时候也会看看那些受欢迎的App的⼀些界⾯效果,为什么⼈家的app那么受欢迎?跟⽤户体验跟UI设计也有直接的关系,最近在美团和⼤众点评的App看到如下效果,我感觉⽤户好,很⼈性化,所以⾃⼰也尝试着实现了下,接下来就讲解下实现思路!如上图(2)我们看到了,当⽴即抢购布局向上滑动到导航栏布局的时候,⽴即抢购布局就贴在导航栏布局下⾯,下⾯的其他的布局还是可以滑动,当我们向下滑动的时候,⽴即抢购的布局⼜随着往下滑动了,看似有点复杂,但是⼀说思路可能你就顿时恍然⼤悟了。
当我们向上滑动过程中,我们判断⽴即抢购的布局是否滑到导航栏布局下⾯,如果⽴即抢购的上⾯顶到了导航栏,我们新建⼀个⽴即抢购的悬浮框来显⽰在导航栏下⾯,这样⼦就实现了⽴即抢购贴在导航栏下⾯的效果啦,⽽当我们向下滑动的时候,当⽴即抢购布局的下⾯刚好到了刚刚新建的⽴即抢购悬浮框的下⾯的时候,我们就移除⽴即抢购悬浮框,可能说的有点拗⼝,既然知道了思路,接下来我们就来实现效果。
新建⼀个Android项⽬,取名MeiTuanDemo,先看⽴即抢购(buy_layout.xml)的布局,这⾥为了⽅便我直接从美团上⾯截去了图⽚<?xml version="1.0" encoding="UTF-8"?><LinearLayout xmlns:android="/apk/res/android"android:orientation="horizontal"android:layout_width="fill_parent"android:layout_height="wrap_content" ><ImageViewandroid:id="@+id/buy_layout"android:layout_width="fill_parent"android:layout_height="wrap_content"android:background="@drawable/buy" /></LinearLayout>⽴即抢购的布局实现了,接下来实现主界⾯的布局,上⾯是导航栏布局,为了⽅便还是直接从美团截取的图⽚,然后下⾯的ViewPager布局,⽴即抢购布局,其他布局放在ScrollView⾥⾯,界⾯还是很简单的<LinearLayout xmlns:android="/apk/res/android"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:id="@+id/imageView1"android:scaleType="centerCrop"android:layout_width="match_parent"android:layout_height="45dip"android:src="@drawable/navigation_bar" /><com.example.meituandemo.MyScrollViewandroid:id="@+id/scrollView"android:layout_width="fill_parent"android:layout_height="fill_parent" ><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical" ><ImageViewandroid:id="@+id/iamge"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/pic"android:scaleType="centerCrop" /><includeandroid:id="@+id/buy"layout="@layout/buy_layout" /><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/one"android:scaleType="centerCrop" /><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/one"android:scaleType="centerCrop" /><ImageViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/one"android:scaleType="centerCrop" /></LinearLayout></com.example.meituandemo.MyScrollView></LinearLayout>你会发现上⾯的主界⾯布局中并不是ScrollView,⽽是⾃定义的⼀个MyScrollView,接下来就看看MyScrollView类中的代码package com.example.meituandemo;import android.content.Context;import android.os.Handler;import android.util.AttributeSet;import android.view.MotionEvent;import android.widget.ScrollView;/*** 博客地址:/xiaanming** @author xiaanming**/public class MyScrollView extends ScrollView {private OnScrollListener onScrollListener;/*** 主要是⽤在⽤户⼿指离开MyScrollView,MyScrollView还在继续滑动,我们⽤来保存Y的距离,然后做⽐较*/private int lastScrollY;public MyScrollView(Context context) {this(context, null);public MyScrollView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public MyScrollView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}/*** 设置滚动接⼝* @param onScrollListener*/public void setOnScrollListener(OnScrollListener onScrollListener) {this.onScrollListener = onScrollListener;}/*** ⽤于⽤户⼿指离开MyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll⽅法中 */private Handler handler = new Handler() {public void handleMessage(android.os.Message msg) {int scrollY = MyScrollView.this.getScrollY();//此时的距离和记录下的距离不相等,在隔5毫秒给handler发送消息if(lastScrollY != scrollY){lastScrollY = scrollY;handler.sendMessageDelayed(handler.obtainMessage(), 5);}if(onScrollListener != null){onScrollListener.onScroll(scrollY);}};};/*** 重写onTouchEvent,当⽤户的⼿在MyScrollView上⾯的时候,* 直接将MyScrollView滑动的Y⽅向距离回调给onScroll⽅法中,当⽤户抬起⼿的时候,* MyScrollView可能还在滑动,所以当⽤户抬起⼿我们隔5毫秒给handler发送消息,在handler处理 * MyScrollView滑动的距离*/@Overridepublic boolean onTouchEvent(MotionEvent ev) {if(onScrollListener != null){onScrollListener.onScroll(lastScrollY = this.getScrollY());}switch(ev.getAction()){case MotionEvent.ACTION_UP:handler.sendMessageDelayed(handler.obtainMessage(), 5);break;}return super.onTouchEvent(ev);}/**** 滚动的回调接⼝** @author xiaanming**/public interface OnScrollListener{/*** 回调⽅法,返回MyScrollView滑动的Y⽅向距离* @param scrollY* 、*/public void onScroll(int scrollY);}}⼀看代码你也许明⽩了,就是对ScrollView的滚动Y值进⾏监听,我们知道ScrollView并没有实现滚动监听,所以我们必须⾃⾏实现对ScrollView的监听,我们很⾃然的想到在onTouchEvent()⽅法中实现对滚动Y轴进⾏监听,可是你会发现,我们在滑动ScrollView的时候,当我们⼿指离开ScrollView。
Android创建悬浮窗的完整步骤

Android创建悬浮窗的完整步骤在Android中想要创建悬浮窗分为三步1.申请权限2.使⽤服务启动悬浮窗3.设置悬浮窗参数并添加进WindowManager下⾯话不多说了,来⼀起看看详细的实现过程申请权限⾸先需要申请悬浮窗权限,在清单⽂件中 manifest 下添加<!-- 低版本悬浮窗所需权限 --><uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>在Activity中动态申请权限public class MainActivity extends Activity {/** 悬浮窗权限标识码 */public static final int CODE_WINDOW = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 申请悬浮窗权限if (Build.VERSION.SDK_INT >= 23) {if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "请打开此应⽤悬浮窗权限-Shendi", Toast.LENGTH_SHORT).show();startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), CODE_WINDOW); }}// 关闭当前activity,这样只显⽰悬浮窗finish();}// 权限申请成功后的回调@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {switch (requestCode) {// 不给权限就退出case Permission.CODE_WINDOW:if (resultCode != Activity.RESULT_OK) System.exit(0);break;default:Toast.makeText(this, "未知权限回调: " + requestCode, Toast.LENGTH_SHORT).show();}}}使⽤服务启动悬浮窗对于悬浮窗的操作主要使⽤ WindowManager创建⼀个服务,并在清单⽂件中注册public class TestService extends Service {@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {return super.onStartCommand(intent, flags, startId);}@Overridepublic IBinder onBind(Intent intent) {return null;}}在清单⽂件的Application中注册服务<service android:name=".TestService" />在Activity中启动服务Intent intent = new Intent(this, TestService.class);startService(intent);接下来需要创建悬浮窗的界⾯,这⾥⽅便演⽰直接使⽤代码创建也可以使⽤inflate函数将xml⽂件变view对象View.inflate(context, yout.main_activity, null);在服务的onStartCommand函数中内容如下@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Button btn = new Button(this);btn.setText("hello,world");return super.onStartCommand(intent, flags, startId);}设置悬浮窗参数并添加进WindowManager这⾥直接上代码,看注释@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Button btn = new Button(this);btn.setText("hello,world");// 获取WindowManagerWindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE); // 创建布局参数youtParams params = new youtParams(); /** 设置参数 */params.type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?youtParams.TYPE_APPLICATION_OVERLAY :youtParams.TYPE_PHONE;params.format = PixelFormat.RGBA_8888;// 设置窗⼝的⾏为准则params.flags = youtParams.FLAG_NOT_FOCUSABLE;//设置透明度params.alpha = 1.0f;//设置内部视图对齐⽅式,这边位置为左边靠上params.gravity = Gravity.LEFT | Gravity.TOP;//窗⼝的左上⾓坐标params.x = 0;params.y = 0;//设置窗⼝的宽⾼,这⾥为⾃动params.width = youtParams.WRAP_CONTENT;params.height = youtParams.WRAP_CONTENT;// 添加进WindowManagerwm.addView(btn, params);return super.onStartCommand(intent, flags, startId);}完整代码如下TestActivitypackage shendi.app.game.robot;import android.app.Activity;import android.content.Intent;import .Uri;import android.os.Build;import android.os.Bundle;import android.provider.Settings;import android.widget.Toast;public class TestActivity extends Activity {/** 悬浮窗权限标识码 */public static final int CODE_WINDOW = 0;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);// 申请悬浮窗权限if (Build.VERSION.SDK_INT >= 23) {if (!Settings.canDrawOverlays(this)) {Toast.makeText(this, "请打开此应⽤悬浮窗权限-Shendi", Toast.LENGTH_SHORT).show();startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), CODE_WINDOW); }}Intent intent = new Intent(this, TestService.class);startService(intent);// 关闭当前activity,这样只显⽰悬浮窗finish();}// 权限申请成功后的回调@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {switch (requestCode) {// 不给权限就退出case Permission.CODE_WINDOW:if (resultCode != Activity.RESULT_OK) System.exit(0);break;default:Toast.makeText(this, "未知权限回调: " + requestCode, Toast.LENGTH_SHORT).show();}}}TestServicepackage shendi.app.game.robot;import android.app.Service;import android.content.Intent;import android.graphics.PixelFormat;import android.os.Build;import android.os.IBinder;import android.view.Gravity;import android.view.WindowManager;import android.widget.Button;public class TestService extends Service {@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Button btn = new Button(this);btn.setText("hello,world");// 获取WindowManagerWindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);// 创建布局参数youtParams params = new youtParams();/** 设置参数 */params.type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ?youtParams.TYPE_APPLICATION_OVERLAY :youtParams.TYPE_PHONE;params.format = PixelFormat.RGBA_8888;// 设置窗⼝的⾏为准则params.flags = youtParams.FLAG_NOT_FOCUSABLE;//设置透明度params.alpha = 1.0f;//设置内部视图对齐⽅式,这边位置为左边靠上params.gravity = Gravity.LEFT | Gravity.TOP;//窗⼝的左上⾓坐标params.x = 0;params.y = 0;//设置窗⼝的宽⾼,这⾥为⾃动params.width = youtParams.WRAP_CONTENT;params.height = youtParams.WRAP_CONTENT;// 添加进WindowManagerwm.addView(btn, params);return super.onStartCommand(intent, flags, startId);}@Overridepublic IBinder onBind(Intent intent) {return null;}}运⾏ app,可以在屏幕左上⾓看到 hello,world的按钮悬浮拖动效果给悬浮组件添加触碰事件可以实现拖动效果,按钮组件不适⽤这⾥给出简单的实现代码⽚段private int upX, upY;// 视图移动处理view.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getActionMasked()) {case MotionEvent.ACTION_DOWN:upX = (int) event.getRawX();upY = (int) event.getRawY();break;case MotionEvent.ACTION_MOVE:// 与上⼀次位置相差不到5则不移动if (event.getRawX() - upX > 5 || event.getRawY() - upY > 5) {params.x = (int) event.getRawX();params.y = (int) event.getRawY();wm.updateViewLayout(view, params);}break;case MotionEvent.ACTION_UP:// 相差不到5则代表点击if (event.getRawX() - upX < 5 && event.getRawY() - upY < 5) {// TODO}break;}return false;}});移除悬浮窗可以在 onDestry 函数中进⾏移除@Overridepublic void onDestroy() {wm.removeView(view);super.onDestroy();}总结到此这篇关于Android创建悬浮窗的⽂章就介绍到这了,更多相关Android悬浮窗内容请搜索以前的⽂章或继续浏览下⾯的相关⽂章希望⼤家以后多多⽀持!。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
大家对悬浮窗概念不会陌生,相信每台电脑桌面的右上角都会有这么一个东西,它总是出现在所有页面的顶端(Top Show)。
但在Android 平台中如何实现这样的效果呢?先来看一看效果图。
看见在Google搜索框上面的那个Icon图片了嘛。
下面我就来详细介绍一下在Android平台下悬浮窗口的实现,并让它能够随手指的触摸而移动。
一、实现原理及移动思路调用WindowManager,并设置youtParams的相关属性,通过WindowManager的addView方法创建View,这样产生出来的View根据youtParams属性不同,效果也就不同了。
比如创建系统顶级窗口,实现悬浮窗口效果!然后通过覆写悬浮View中onTouchEvent方法来改变youtParams中x和y的值来实现自由移动悬浮窗口。
二、示例代码先来看一看悬浮View的代码,这里用一个ImageView作为演示[java]view plaincopyprint?1.public class MyFloatView extends ImageView {2.private float mTouchStartX;3.private float mTouchStartY;4.private float x;5.private float y;6.7.private WindowManager wm=(WindowManager)getContext().getApplicationContext().getSystemService("window");8.//此wmParams变量为获取的全局变量,用以保存悬浮窗口的属性9.private youtParams wmParams = ((MyApplication)getContext().getApplicationContext()).getMywmParams();10.11.public MyFloatView(Context context) {12.super(context);13.// TODO Auto-generated constructor stub14.}16.@Override17.public boolean onTouchEvent(MotionEvent event) {18.//获取相对屏幕的坐标,即以屏幕左上角为原点19.x = event.getRawX();20.y = event.getRawY()-25; //25是系统状态栏的高度21.Log.i("currP", "currX"+x+"====currY"+y);22.switch (event.getAction()) {23.case MotionEvent.ACTION_DOWN: //捕获手指触摸按下动作24.//获取相对View的坐标,即以此View左上角为原点25.mTouchStartX = event.getX();26.mTouchStartY = event.getY();27.Log.i("startP", "startX"+mTouchStartX+"====startY"+mTouchStartY);28.break;29.30.case MotionEvent.ACTION_MOVE: //捕获手指触摸移动动作31.updateViewPosition();32.break;33.34.case MotionEvent.ACTION_UP: //捕获手指触摸离开动作35.updateViewPosition();36.mTouchStartX=mTouchStartY=0;37.break;38.}39.return true;40.}41.42.private void updateViewPosition(){43.//更新浮动窗口位置参数44.wmParams.x=(int)( x-mTouchStartX);45.wmParams.y=(int) (y-mTouchStartY);46.wm.updateViewLayout(this, wmParams); //刷新显示47.}48.49.}上面的wmParams变量(即youtParams)的存储采用了extends Application的方式来创建全局变量,示例代码如下:[java]view plaincopyprint?1.public class MyApplication extends Application {2.3./**4.* 创建全局变量5.* 全局变量一般都比较倾向于创建一个单独的数据类文件,并使用static静态变量7.* 这里使用了在Application中添加数据的方法实现全局变量8.* 注意在AndroidManifest.xml中的Application节点添加android:name=".MyApplication"属性9.*10.*/11.private youtParams wmParams=new youtParams();12.13.public youtParams getMywmParams(){14.return wmParams;15.}16.}再来看一看Activity中的代码:[java]view plaincopyprint?1.public class MyFloatViewActivity extends Activity {2./** Called when the activity is first created. */3.4.private WindowManager wm=null;5.private youtParams wmParams=null;6.7.private MyFloatView myFV=null;8.9.@Override10.public void onCreate(Bundle savedInstanceState) {11.super.onCreate(savedInstanceState);12.setContentView(yout.main);13.//创建悬浮窗口14.createView();15.16.}17.18.private void createView(){19.myFV=new MyFloatView(getApplicationContext());20.myFV.setImageResource(R.drawable.icon); //这里简单的用自带的Icom来做演示21.//获取WindowManager22.wm=(WindowManager)getApplicationContext().getSystemService("window");23.//设置LayoutParams(全局变量)相关参数24.wmParams = ((MyApplication)getApplication()).getMywmParams();25.26./**27.*以下都是youtParams的相关属性28.* 具体用途可参考SDK文档29.*/30.wmParams.type=LayoutParams.TYPE_PHONE; //设置window type31.wmParams.format=PixelFormat.RGBA_8888; //设置图片格式,效果为背景透明32.33.//设置Window flag34.wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL35.| LayoutParams.FLAG_NOT_FOCUSABLE;36./*37.* 下面的flags属性的效果形同“锁定”。
38.* 悬浮窗不可触摸,不接受任何事件,同时不影响后面的事件响应。
39.wmParams.flags=LayoutParams.FLAG_NOT_TOUCH_MODAL40.| LayoutParams.FLAG_NOT_FOCUSABLE41.| LayoutParams.FLAG_NOT_TOUCHABLE;42.*/43.44.wmParams.gravity=Gravity.LEFT|Gravity.TOP; //调整悬浮窗口至左上角,便于调整坐标45.//以屏幕左上角为原点,设置x、y初始值46.wmParams.x=0;47.wmParams.y=0;48.49.//设置悬浮窗口长宽数据50.wmParams.width=40;51.wmParams.height=40;52.53.//显示myFloatView图像54.wm.addView(myFV, wmParams);55.56.}57.58.@Override59.public void onDestroy(){60.super.onDestroy();61.//在程序退出(Activity销毁)时销毁悬浮窗口62.wm.removeView(myFV);63.}64.}最后,别忘了在AndroidManifest.xml中添加权限:[html]view plaincopyprint?1.<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW">2.</uses-permission>这样一个可以置顶显示、悬浮、且可自由移动的窗口就完工了。
运行一下,然后按Home键返回桌面试试看(不能点击返回键,演示程序这里设置了销毁窗体)三、一些说明WindowManager的方法很简单,基本用到的就三个addView,removeView,updateViewLayout。
而youtParams的属性就多了,非常丰富,这个也是关键所在。
这里例举两个window type:[java]view plaincopyprint?1./**2.* Window type: phone. These are non-application windows providing3.* user interaction with the phone (in particular incoming calls).4.* These windows are normally placed above all applications, but behind5.* the status bar.6.*/7.public static final int TYPE_PHONE = FIRST_SYSTEM_WINDOW+2;8.9./**10.* Window type: system window, such as low power alert. These windows11.* are always on top of application windows.12.*/13.public static final int TYPE_SYSTEM_ALERT = FIRST_SYSTEM_WINDOW+3;可以看出TYPE_SYSTEM_ALERT的显示层次比TYPE_PHONE还要高,有兴趣的可以试一试显示效果哦!另外关键的window flag:[java]view plaincopyprint?1./** Window flag: this window won't ever get focus. */2.public static final int FLAG_NOT_FOCUSABLE = 0x00000008;3.4./** Window flag: this window can never receive touch events. */5.public static final int FLAG_NOT_TOUCHABLE = 0x00000010;6.7./** Window flag: Even when this window is focusable (its8.* {@link #FLAG_NOT_FOCUSABLE is not set), allow any pointer events9.* outside of the window to be sent to the windows behind it. Otherwise10.* it will consume all pointer events itself, regardless of whether they11.* are inside of the window. */12.public static final int FLAG_NOT_TOUCH_MODAL = 0x00000020;最后,关于Android平台下的悬浮窗口,有人说很不友好,有人很困惑哪里会用到。