300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > Android 音乐播放器悬浮窗

Android 音乐播放器悬浮窗

时间:2024-06-29 23:53:24

相关推荐

Android 音乐播放器悬浮窗

之前的项目中写了个音乐播放器,这里记录下悬浮窗相关的东西。

废话不多说,先上个效果图

1、自定义悬浮框布局

根据效果图可以看到悬浮窗 布局由一张封面图,一个圆形进度条以及4个按钮组成。

布局内容就不写了,很简单。

悬浮窗控件 :FloatLayout继承自FrameLayout,引入布局文件。

初始化 windowManager

mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

DisplayMetrics dm = new DisplayMetrics();mWindowManager.getDefaultDisplay().getMetrics(dm);//获取屏幕的宽度,用于后边计算吸边操作screenWidth = dm.widthPixels;

然后通过 onInterceptTouchEvent 去处理按下、移动和抬起事件的分发拦截。这个是悬浮窗点击、移动的重点

刚开始打算是用onTouchEvent去处理触摸事件,经过验证发现并不能解决父布局和子View的点击冲突,于是试用了onInterceptTouchEvent 方法,发现这才是解决这里点击冲突正确的姿势。

public boolean onInterceptTouchEvent(MotionEvent ev) {//左上角为原点,获取相对屏幕的坐标x = (int) ev.getRawX();y = (int) ev.getRawY();//区分拖动和点击事件 ,判断是否需要拦截int action = ev.getAction();switch (action) {case MotionEvent.ACTION_DOWN://获取相对于父view的坐标点mTouchStartX = ev.getX();mTouchStartY = ev.getY();break;case MotionEvent.ACTION_MOVE://处理移动逻辑float moveStartX = ev.getX();float moveStartY = ev.getY();//移动的距离大于3,移动距位置if (Math.abs(mTouchStartX - moveStartX) > 3 && Math.abs(mTouchStartY - moveStartY) > 3) {mParams.x = (int) (x - mTouchStartX);mParams.y = (int) (y - mTouchStartY);mWindowManager.updateViewLayout(this, mParams);return super.onInterceptTouchEvent(ev);}break;case MotionEvent.ACTION_UP:float endX = ev.getRawX();//根据最终手指停留的地方,设置吸边效果if (endX > screenWidth / 2) {mParams.x = screenWidth - getWidth();} else {mParams.x = 0;}mWindowManager.updateViewLayout(this, mParams);float upX = ev.getX();float upY = ev.getY();if (Math.abs(upX - mTouchStartX) > 30 && Math.abs(upY - mTouchStartY) > 30){return true;}break;}return super.onInterceptTouchEvent(ev);}

接下来就是正常处理按钮的点击事件了。因为设计的是当 菜单按钮显示的时候,点击封面图是跳转其他页面,所以需要写一个计时器 把菜单布局收起来。并且在菜单布局收起来的时候,注意调用吸边操作

/*** 吸边操作*/private void adscrop() {if (isWindowLive){if (x > screenWidth / 2){mParams.x = screenWidth;}else{mParams.x = 0;}mWindowManager.updateViewLayout(this,mParams);}}

提供了一个悬浮窗的管理类,需要给悬浮窗定义一些公共方法

/*** 将小悬浮窗的参数传入,用于更新小悬浮窗的位置。* @param params*/public void setParams(WindowManager.LayoutParams params){this.mParams = params;}/*** 设置最大进度条* @param maxLength*/public void setMaxProgress(int maxLength){mFloatSeekbar.setMax(maxLength);}/*** 更新进度条* @param progress*/public void upDataProgress(int progress){mFloatSeekbar.setProgress(progress);}/***隐藏*/public void hide(){mView.setVisibility(GONE);}/*** 显示*/public void show(){mView.setVisibility(VISIBLE);}/*** 开始/暂停* @param isStart*/public void startOrStop(boolean isStart){if (isStart){isPlaying = true;mIvStart.setImageResource(R.mipmap.float_image_stop);}else{isPlaying = false;mIvStart.setImageResource(R.mipmap.float_image_start);}}

/*** 设置悬浮窗是否被销毁,如果被销毁,移除计时器* @param isLive*/public void windowState(boolean isLive){isWindowLive = isLive;if (isWindowLive){handler.removeCallbacks(runnable);}}

2、FloatWindowManager 管理类

/*** 创建悬浮窗* @param context*/public static void creatFloatWindow(Context context){mParams = new WindowManager.LayoutParams();mWindowManager = getWindowManager(context);mFloatLayout = new FloatLayout(context);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {mParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;} else {mParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT;}//设置图片格式,透明背景效果mParams.format = PixelFormat.RGBA_8888;//设置不可聚焦mParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;//设置位置左上方mParams.gravity = Gravity.START | Gravity.TOP;DisplayMetrics dm = new DisplayMetrics();//取得窗口属性mWindowManager.getDefaultDisplay().getMetrics(dm);//窗口的宽度int screenWidth = dm.widthPixels;//窗口高度int screenHeight = dm.heightPixels;//以屏幕左上角为原点,设置x、y初始值,相对于gravitymParams.x = screenWidth;mParams.y = screenHeight / 2 + screenWidth / 3;//设置悬浮窗口长宽数据mParams.width = WindowManager.LayoutParams.WRAP_CONTENT;mParams.height = WindowManager.LayoutParams.WRAP_CONTENT;mFloatLayout.setParams(mParams);mWindowManager.addView(mFloatLayout, mParams);}

/*** 移除悬浮窗*/public static void removeFloatWindowManager() {boolean isAttach = true;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {isAttach = mFloatLayout.isAttachedToWindow();}if (mHasShown && isAttach && mWindowManager != null)mWindowManager.removeView(mFloatLayout);mHasShown = false;mFloatLayout.windowState(false);}

/***返回已创建的WindowManager。* @param context* @return*/private static WindowManager getWindowManager(Context context) {if (mWindowManager == null){mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);}return mWindowManager;}因为设计的是音乐播放器,,所以播放功能应该放在service,悬浮窗的控制也放在service中,所以需要提供公共方法public static void hide() {if (mHasShown)mFloatLayout.hide();mHasShown = false;}public static void show() {if (!mHasShown)mFloatLayout.show();mHasShown = true;mFloatLayout.windowState(true);}public static void setMaxProgress(int length){if (mHasShown || mFloatLayout != null)mFloatLayout.setMaxProgress(length);}public static void updataProgress(int progress) {if (mHasShown || mFloatLayout != null)mFloatLayout.upDataProgress(progress);}public static void startMusic(boolean isStart){mFloatLayout.startOrStop(isStart);}

最近借鉴了一下朋友的设计 重新 封装了一个播放器,有兴趣的朋友可以探讨一下

XAudioPlayer: 音频播放器 ()

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。