Android仿优酷视频的悬浮窗播放效果

之前接了需求要让视频播放时可以像优酷视频那样在悬浮窗里播放,并且悬浮窗和主播放页面之间要实现无缝切换,项目中使用的是自封装的ijkplayer
这个要求就代表不能在悬浮窗中新建视频控件,所以需要在悬浮窗中复用主页面的视频控件,以达到无缝衔接的效果。

主页面对应的视频控件的父view

<FrameLayout
      android:id="@+id/vw_live"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:layout_centerInParent="true"/>

用FrameLayout作为添加视频控件的ParentView,通过addview方法将新建的播放器控件添加到父控件内部

vw_live = new IjkVideoView(this);
video_frame = findViewById(R.id.vw_live);
video_frame.addView(vw_live);

主播放界面的启动模式

播放主界面的activity的启动模式不能为默认,因为我们要保证播放主界面在显示悬浮窗的时候退到后台,但是整个的应用不能退到后台,所以activity的启动模式改为singleInstance

android:launchMode="singleInstance"

退到后台我们通过moveTaskToBack(true)方法;

moveTaskToBack(true);

可以让播放界面退到后台而整个应用不会退回后台

权限请求

要使用悬浮窗需要申请权限

<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
if (!Settings.canDrawOverlays(this)) {
      Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
      startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 2);
    } 

悬浮窗

 @SuppressLint("ClickableViewAccessibility")
  public void showFloatingWindowView(IjkVideoView view) {
    // 悬浮窗显示视图
    LayoutInflater layoutInflater = LayoutInflater.from(activity);
    mShowView = layoutInflater.inflate(R.layout.video_floating_window_layout, null);;
    // 获取系统窗口管理服务
    mWindowManager = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
    // 悬浮窗口参数设置及返回
    mFloatParams = getParams();
    //floatingWindow内部控件实例
    init(view);
    // 设置窗口触摸移动事件
    mShowView.setOnTouchListener(new FloatViewMoveListener());

    // 悬浮窗生成
    mWindowManager.addView(mShowView, mFloatParams);
  }
  private void init(IjkVideoView viewGroup){
    videoLayout = mShowView.findViewById(R.id.floating_video);
    videoLayout.removeAllViews();
    if (viewGroup != null){
      ijkVideoView = viewGroup;
      videoLayout.addView(ijkVideoView,new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT
          ,ViewGroup.LayoutParams.MATCH_PARENT));
    }

    mBtnCloseFloatingWindow = mShowView.findViewById(R.id.close_floating_view);
    mBtnCloseFloatingWindow.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {

      }
    });
    mBtnBackFloatingWindow = (ImageView)mShowView.findViewById(R.id.back_floating_view);
    mBtnBackFloatingWindow.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {

      }
    });
  }

  private WindowManager.LayoutParams getParams() {
    WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams();
    //设置悬浮窗口类型
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      layoutParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
    } else {
      layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;
    }
    //设置悬浮窗口属性
    layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
        | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
        | WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR
        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
    //设置悬浮窗口透明
    layoutParams.format = PixelFormat.TRANSLUCENT;
    //设置悬浮窗口长宽数据
    layoutParams.width = 500;
    layoutParams.height = 340;
    //设置悬浮窗显示位置
    layoutParams.gravity = Gravity.START | Gravity.TOP;
    layoutParams.x = 100;
    layoutParams.y = 100;
    return layoutParams;
  }

悬浮窗的xml,可通过自定义获得自己想要的效果

<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/floating_video_layout"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
  <FrameLayout
    android:id="@+id/floating_video"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

  <ImageView
    android:id="@+id/close_floating_view"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:layout_gravity="end"
    android:padding="10dp"
    android:src="@android:drawable/ic_menu_close_clear_cancel" />

  <ImageView
    android:id="@+id/back_floating_view"
    android:layout_width="50dp"
    android:layout_height="50dp"
    android:padding="10dp"
    android:src="@android:drawable/ic_menu_revert" />
</FrameLayout>

悬浮窗的滑动,我们可以通过自定义点击监听实现

/**
   * 浮窗移动/点击监听
   */
  private class FloatViewMoveListener implements View.OnTouchListener {

    //开始触控的坐标,移动时的坐标(相对于屏幕左上角的坐标)
    private int mTouchStartX;
    private int mTouchStartY;
    //开始时的坐标和结束时的坐标(相对于自身控件的坐标)
    private int mStartX, mStartY;
    //判断悬浮窗口是否移动,这里做个标记,防止移动后松手触发了点击事件
    private boolean isMove;

    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
      int action = motionEvent.getAction();
      int x = (int) motionEvent.getX();
      int y = (int) motionEvent.getY();
      switch (action) {
        case MotionEvent.ACTION_DOWN:
          isMove = false;
          mTouchStartX = (int) motionEvent.getRawX();
          mTouchStartY = (int) motionEvent.getRawY();
          mStartX = x;
          mStartY = y;
          break;
        case MotionEvent.ACTION_MOVE:
          int mTouchCurrentX = (int) motionEvent.getRawX();
          int mTouchCurrentY = (int) motionEvent.getRawY();
          mFloatParams.x += mTouchCurrentX - mTouchStartX;
          mFloatParams.y += mTouchCurrentY - mTouchStartY;
          mWindowManager.updateViewLayout(mShowView, mFloatParams);
          mTouchStartX = mTouchCurrentX;
          mTouchStartY = mTouchCurrentY;
          float deltaX = x - mStartX;
          float deltaY = y - mStartY;
          if (Math.abs(deltaX) >= 5 || Math.abs(deltaY) >= 5) {
            isMove = true;
          }
          break;
        case MotionEvent.ACTION_UP:
          break;
        default:
          break;
      }
      //如果是移动事件不触发OnClick事件,防止移动的时候一放手形成点击事件
      return isMove;
    }
  }

悬浮窗的消失,在这里调用videoLayout.removeAllViews()是为了将复用的视频控件的父View清空,返回主播放activity的时候调用addview方法不会再报 child view has Parent,you have to call removeView()的错

public void dismiss() {
    if (mWindowManager != null && mShowView != null) {
      videoLayout.removeAllViews();
      if (mShowView.getParent() != null){
        mWindowManager.removeView(mShowView);
      }
    }
  }

启动悬浮窗

 public videoFloatingWindow(Context context){
    super(context);
    this.activity = context;
  }

对于悬浮窗的调用

用hasBind来记录是否调用了悬浮窗

 private void startFloatingWindow(){
    if (!Settings.canDrawOverlays(this)) {
      Toast.makeText(this, "当前无权限,请授权", Toast.LENGTH_SHORT);
      startActivityForResult(new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION, Uri.parse("package:" + getPackageName())), 2);
    } else {
      video_frame.removeView(vw_live);
      videoFloatingWindow.getInstance(this).showFloatingWindowView(vw_live);
      hasBind = true;
      moveTaskToBack(true);
    }
  }

注意

一.由于主界面activity使用了singleInstance启动模式,所以从悬浮窗返回主界面activity时,要添加flag

  Intent intent = new Intent(activity, activity.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        activity.startActivity(intent);

二.当主界面的activity退回后台,再重新进入主界面的时候,注意,不再调用onCreate方法,而是调用onNewIntent,所以重写onNewIntent方法,重新进入主界面,悬浮窗消失

 @Override
  protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    Log.d("RemoteView", "重新显示了");
    //不显示悬浮框
    if (hasBind){
      videoFloatingWindow.getInstance(this).dismiss();
      video_frame.removeAllViews();
      if (vw_live != null){
        video_frame.addView(vw_live);
      }
      hasBind = false;
    }
  }

总结

到此这篇关于Android仿优酷视频的悬浮窗播放的文章就介绍到这了,更多相关android 优酷视频悬浮窗播放内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Android 8.0如何完美适配全局dialog悬浮窗弹出

    前言 最近项目targetSdkVersion升级到了26,出现很多问题趟了很多坑,其中就包括本篇的需要解决的问题:全局dialog 不显示. 出现场景 有时候我们需要在App中弹dialog,但是却不知道依附的是哪个Activity,这个时候通常会启动一个service来依附,显示一个全局的dialog. Android 6.0出现的悬浮窗权限 为什么从6.0说起? 在Android6.0之后,使用悬浮窗功能需要申请开启悬浮窗权限,在API23以下版本编译,悬浮窗权限关闭的,但是没有权限限制,

  • 详解android6.0版本下悬浮窗实现

    悬浮窗在安卓中实现起来还是比较容易的,这几天在网上温习了相关资料,运行在我安卓6.0手机上才发现,原来在6.0手机上不是行的. 第一反应肯定是权限相关问题,做了相关处理后,果然让悬浮窗原形毕露了.直接贴代码. public class MainActivity extends AppCompatActivity { private static final int ALERT_WINDOW_PERMISSION_CODE = 100; private Button start_float; @O

  • Android悬浮窗按钮实现点击并显示/隐藏多功能列表

    前言 最近在一个项目中,需要制作录屏的功能,原先是在应用中有录屏/控制的按钮,思考之下觉得这种效果并不好,因此就想制作一个可以悬浮的悬浮窗,这样不论手机在什么界面中都可以对录屏功能进行控制. 这里就来构建一个桌面的悬浮窗,使用了DataBinding的MVVM模式,这些方面就不再多提. FloatNormalView 这个是一个普通的悬浮窗,悬浮窗只有一个按钮,点击按钮显示更多的按钮. 首先是页面布局: <?xml version="1.0" encoding="utf

  • android 添加随意拖动的桌面悬浮窗口

    用过新版本android 360手机助手都人都对 360中只在桌面显示一个小小悬浮窗口羡慕不已吧? 其实实现这种功能,主要有两步: 1.判断当前显示的是为桌面.这个内容我在前面的帖子里面已经有过介绍,如果还没看过的赶快稳步看一下哦. 2.使用windowManager往最顶层添加一个View .这个知识点就是为本文主要讲解的内容哦.在本文的讲解中,我们还会讲到下面的知识点: a.如果获取到状态栏的高度 b.悬浮窗口的拖动 c.悬浮窗口的点击事件 有开始之前,我们先来看一下效果图:  接下来我们来

  • Android 获取判断是否有悬浮窗权限的方法

    现在很多应用都会用到悬浮窗,很多国产rom把悬浮窗权限加入控制了,你就需要判断是否有悬浮窗权限,然后做对应操作. Android 原生有自带权限管理的,只是被隐藏了.看android源码在android.app下就有个AppOpsManager类. 类说明如下: /** * API for interacting with "application operation" tracking. * * <p>This API is not generally intended

  • Android实现桌面悬浮窗、蒙板效果实例代码

    现在很多安全类的软件,比如360手机助手,百度手机助手等等,都有一个悬浮窗,可以飘浮在桌面上,方便用户使用一些常用的操作. 今天这篇文章,就是介绍如何实现桌面悬浮窗效果的. 首先,看一下效果图. 悬浮窗一共分为两个部分,一个是平常显示的小窗口,另外一个是点击小窗口显示出来的二级悬浮窗口. 首先,先看一下这个项目的目录结构. 最关键的就是红框内的四个类. 首先,FloatWindowService是一个后台的服务类,主要负责在后台不断的刷新桌面上的小悬浮窗口,否则会导致更换界面之后,悬浮窗口也会随

  • Android仿优酷视频的悬浮窗播放效果

    之前接了需求要让视频播放时可以像优酷视频那样在悬浮窗里播放,并且悬浮窗和主播放页面之间要实现无缝切换,项目中使用的是自封装的ijkplayer 这个要求就代表不能在悬浮窗中新建视频控件,所以需要在悬浮窗中复用主页面的视频控件,以达到无缝衔接的效果. 主页面对应的视频控件的父view <FrameLayout android:id="@+id/vw_live" android:layout_width="match_parent" android:layout_

  • Android仿腾讯视频实现悬浮窗效果

    前言 相信大家对Android悬浮窗应该是很熟悉了,比如说腾讯视频.爱奇艺等APP都有悬浮窗功能.在你打游戏的同时还可以看视频,充分利用屏幕空间.还有微信,360手机卫士等APP也有悬浮窗功能.那么Android悬浮窗是怎么实现的呢? 项目源码:Android仿腾讯视频悬浮窗的实现 其实并不难,核心代码就只有一行: windowManager.addView(view, layoutParams) 效果图 对view比较熟悉的同学们应该发现了,其实我们的悬浮窗就是一个view,我把只需要把vie

  • JavaScript使用DeviceOne开发实战(四)仿优酷视频应用

    大家没有进行开发之前首先需要考虑系统的差异性,比如说IOS手机有没有回退键,所以在开发时一定要考虑二级解密需要有回退键,否则ios的手机就会陷入到这个页面回不去. 安卓系统有回退键,针对这个情况需要要求用户在3秒钟之内连续按回退键两次才退出系统,以此防止用户误按回退键,具体代码实现如下: [mw_shl_code=javascript,true]page.on("back", function(){ if (canBack) { global.exit(); } else { nf.t

  • Android仿360桌面手机卫士悬浮窗效果

    大家好,今天给大家带来一个仿360手机卫士悬浮窗效果的教程,在开始之前请允许我先说几句不相干的话. 不知不觉我发现自己接触Android已有近三个年头了,期间各种的成长少不了各位高手的帮助,总是有很多高手喜欢把自己的经验写在网上,供大家来学习,我也是从中受惠了很多,在此我深表感谢.可是我发现我却从来没有将自己平时的一些心得拿出来与大家分享,共同学习,太没有奉献精神了.于是我痛定思痛,决定从今天开始写博客,希望可以指点在我后面的开发者,更快地进入Android开发者的行列当中. 好了,废话就说这么

  • Android仿优酷圆形菜单学习笔记分享

    先来看看效果: 首先来分析一下: 这个菜单可以分成三个菜单: 1.一级菜单(即最内圈那个菜单) 2.二级菜单(即中间圈那个菜单) 3.三级菜单(即最外圈那个菜单) 首先,可以将这三个菜单使用相对布局 一级菜单只有一个按钮(即home),可以控制二级和三级菜单 二级菜单有三个按钮(即menu),中间那个按钮可以控制三级菜单 三级菜单有七个按钮 那先把布局文件先写出来,采用三个相对布局(即每个菜单采用一个相对布局) <RelativeLayout xmlns:android="http://s

  • Android基于API的Tabs3实现仿优酷tabhost效果实例

    本文实例讲述了Android基于API的Tabs3实现仿优酷tabhost效果.分享给大家供大家参考,具体如下: 前两天老师就让自己写个视频播放器客户端,这个是他上课讲的一个小小demo,通过查看安卓API的tabs3,实现仿优酷视频客户端的tabhost效果.我的API路径是D:\android\sdk\samples\android-17\ApiDemos\src\com\example\android\apis\view下的Tabs3,下面是实现效果: 废话不多说了,直接上码: MainA

  • Android 使用Vitamio打造自己的万能播放器(5)——在线播放(播放优酷视频)

     前言 为了保证每周一篇的进度,又由于Vitamio新版本没有发布, 决定推迟本地播放的一些功能(截图.视频时间.尺寸等),跳过直接写在线播放部分的章节.从Vitamio的介绍可以看得出,其支持http.m3u8等多种网络协议,本章将编写播放优酷视频的例子. 系列 1.Android使用Vitamio打造自己的万能播放器(1)--准备 2.Android使用Vitamio打造自己的Android万能播放器(2)-- 手势控制亮度.音量.缩放 3.Android使用Vitamio打造自己的Andr

  • Android编程实现仿优酷旋转菜单效果(附demo源码)

    本文实例讲述了Android编程实现仿优酷旋转菜单效果.分享给大家供大家参考,具体如下: 首先,看下效果: 不好意思,不会制作动态图片,只好上传静态的了,如果谁会,请教教我吧. 首先,看下xml文件: <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" a

  • Android编程实现仿优酷圆盘旋转菜单效果的方法详解【附demo源码下载】

    本文实例讲述了Android编程实现仿优酷圆盘旋转菜单效果的方法.分享给大家供大家参考,具体如下: 目前,用户对安卓应用程序的UI设计要求越来越高,因此,掌握一些新颖的设计很有必要. 比如菜单,传统的菜单已经不能满足用户的需求. 其中优酷中圆盘旋转菜单的实现就比较优秀,这里我提供下我的思路及实现,仅供参考. 该菜单共分里外三层导航菜单.可以依次从外向里关闭三层菜单,也可以反向打开,并且伴有圆盘旋转的动画效果 首先,看下效果: 以下是具体的代码及解释: 1. 菜单布局文件: 大家看到主要有三个Ra

  • Android开发实现高仿优酷的客户端图片左右滑动切换功能实例【附源码下载】

    本文实例讲述了Android开发实现高仿优酷的客户端图片左右滑动切换功能.分享给大家供大家参考,具体如下: 本例是用ViewPager去做的实现,支持自动滑动和手动滑动,不仅优酷网,实际上有很多商城和门户网站都有类似的实现: 具体思路: 1. 工程中需要添加android-support-v4.jar,才能使用ViewPager控件. 2. 图片的自动切换: 可使用Timer或者ScheduledExecutorService,这个有多重方式可以实现. 同时要切换底部的dots(园点) 3.Ha

随机推荐