android实现可自由移动、监听点击事件的悬浮窗

发布时间:2019-08-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了android实现可自由移动、监听点击事件的悬浮窗脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

最近因为项目需要,自己实现了个可以自由移动,并且长按可以跳出一个控制播放的,大的悬浮窗。

好,开始吧。首先我们先聊权限,悬浮窗需要在manifest中声明一个权限:

 <uses-PErmission andROId:name="android.permission.SysTEM_ALERT_WINDOW" />

然后呢,嗯,我们来讲讲关于悬浮窗实现的原理。

在Andriod中,所有的界面元素都要通过windowmanger来实现,像ActivITy、Fragment等等这些也是在其上实现。因此,我们的悬浮窗自然要通过这个实现。

这个项目中,我们自定义了两个悬浮窗view。我们以其中一个比较简单为例

我们自定义一个管理可以统一管理悬浮窗的类MyWindowManager,负责创建,删除悬浮窗

 /**  * Created by shiwe on 2017/3/7.  * 悬浮窗管理  * 创建,移除  * 单例模式  */  public class MyWindowManager {   PRivate FloatNormalView normalView;  private FloatControlView controlView;   private static MyWindowManager instance;   private MyWindowManager() {  }   public static MyWindowManager getInstance() {   if (instance == null)    instance = new MyWindowManager();   return instance;  }    /**   * 创建小型悬浮窗   */  public void createNormalView(Context context) {   if (normalView == null)    normalView = new FloatNormalView(context);  }   /**   * 移除悬浮窗   *   * @param context   */  public void removeNormalView(Context context) {   if (normalView != null) {    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);    windowManager.removeView(normalView);    normalView = null;   }  }   /**   * 创建小型悬浮窗   */  public void createControlView(Context context) {   if (controlView == null)    controlView = new FloatControlView(context);  }   /**   * 移除悬浮窗   *   * @param context   */  public void removeControlView(Context context) {   if (controlView != null) {    WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);    windowManager.removeView(controlView);    controlView = null;   }  } }

然后看看我们自定义的一个view,其继承自LinearLayout,我们在initLayoutParams初始化这个控件的位置等其他参数;在initEvent方法中定义随手指移动的监听事件以及长按的监听事件。

 public class FloatNormalView extends LinearLayout {   private Context context = null;  private View view = null;  private ImageView ivShowControlView = null;  private WindowManager.LayoutParams lp = new WindowManager.LayoutParams();  private static WindowManager windowManager;   private float mTouchStartX;  private float mTouchStartY;  private float x;  private float y;  private boolean initViewPlace = false;  private MyWindowManager myWindowManager;  private boolean isControlViewShowing = false;   public FloatNormalView(Context context) {   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();  }    /**   * 初始化参数   */  private void initLayoutParams() {   //屏幕高   int screenWidth = windowManager.getDefaultDisplay().getWidth();   int screenHeight = 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);  }   /**   * 设置悬浮窗监听事件   */  private void initEvent() {   ivShowControlView.setOnLongClickListener(new OnLongClickListener() {    @override    public boolean onLongClick(View view) {     if (!isControlViewShowing) {      myWindowManager.createControlView(context);      isControlViewShowing = true;     } else {      myWindowManager.removeControlView(context);      isControlViewShowing = false;     }     return true;    }   });   view.setOnTouchListener(new OnTouchListener() {    @Override    public boolean onTouch(View v, MotionEvent event) {     switch (event.getAction()) {      case MotionEvent.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;      case MotionEvent.ACTION_MOVE:       // 获取相对屏幕的坐标,以屏幕左上角为原点       x = event.getRawX();       y = event.getRawY();       updateViewPosition();       break;       case MotionEvent.ACTION_UP:       break;     }     return true;    }   });  }   /**   * 更新浮动窗口位置   */  private void updateViewPosition() {   lp.x = (int) (x - mTouchStartX);   lp.y = (int) (y - mTouchStartY);   windowManager.updateViewLayout(this, lp);  }

最后,只需要在Activity中调用MywindowManager中调用createxxx方法就可以。

 public class MainActivity extends AppCompatActivity {   MyWindowManager myWindowManager;   @Override  protected void onCreate(@Nullable Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   setContentView(R.layout.activity_main);   myWindowManager = MyWindowManager.getInstance();   myWindowManager.createNormalView(this.getApplicationContext());  } }

最后,附上demo项目的下载地址: android实现悬浮窗

android教程
脚本网站
android studio

脚本宝典总结

以上是脚本宝典为你收集整理的android实现可自由移动、监听点击事件的悬浮窗全部内容,希望文章能够帮你解决android实现可自由移动、监听点击事件的悬浮窗所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。