自定义View:悬浮球与加速球
先来看一张动态图
昨天跟着视频学了如何自定义View并做成仿360悬浮球与加速球的样式
可以看出来,做成的效果有:
- 点击按钮后退出Activity,呈现一个圆形的悬浮球,可以随意拖动并会自动依靠到屏幕一侧,且拖动时会变成一张图片
- 当点击悬浮球时,悬浮球隐藏,底部出现一个加速球,双击加速球时,呈现水量逐渐增高且波动幅度较小的效果,单击时波浪上下波动且幅度渐小
- 点击屏幕不包含底部加速球的部位,加速球会隐藏,悬浮球重新出现
要做出这么一个效果,需要两个自定义View与一个自定义ViewGroup
首先,需要先设计悬浮球View——FloatBall
简单起见,为FloatBall指定一个默认宽度和高度——150像素
然后在onDraw(Canvas canvas)方法中,判断FloatBall是否正在被拖动isDrag,如果是,则绘制一张默认图片bitmap,否则则根据绘图函数绘制圆形与居中文本
因为FloatBall是不存在于Activity中而在屏幕单独显示的,所以需要用WindowManager来添加View并显示
新建一个类,命名为ViewManager,用来总的管理View的显示与删除
私有化构造函数并采用单例模式
ViewManager包含有显示与隐藏悬浮球与加速球的函数
//显示浮动小球public void showFloatBall() {if (floatBallParams == null) {floatBallParams = new LayoutParams();floatBallParams.width = floatBall.width;floatBallParams.height = floatBall.height - getStatusHeight();floatBallParams.gravity = Gravity.TOP | Gravity.LEFT;floatBallParams.type = LayoutParams.TYPE_TOAST;floatBallParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL;floatBallParams.format = PixelFormat.RGBA_8888;}windowManager.addView(floatBall, floatBallParams);}//显示底部菜单private void showFloatMenu() {if (floatMenuParams == null) {floatMenuParams = new LayoutParams();floatMenuParams.width = getScreenWidth();floatMenuParams.height = getScreenHeight() - getStatusHeight();floatMenuParams.gravity = Gravity.BOTTOM;floatMenuParams.type = LayoutParams.TYPE_TOAST;floatMenuParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL;floatMenuParams.format = PixelFormat.RGBA_8888;}windowManager.addView(floatMenu, floatMenuParams);}//隐藏底部菜单public void hideFloatMenu() {if (floatMenu != null) {windowManager.removeView(floatMenu);}}将悬浮球置于Service中开启,这样悬浮球就不那么容易被系统去除了
在onCreate()方法中调用showFloatBall()
此时,只要为MainActivity添加一个按钮,并设定当点击按钮后开启Service,此时即可看到屏幕显示了一个悬浮球
public void startService(View view) {Intent intent = new Intent(this, StartFloatBallService.class);startService(intent);finish();}不过此时悬浮球还不支持拖动与点击,还需要为其添加OnTouchListener与OnClickListener
View.OnTouchListener touchListener = new View.OnTouchListener() {float startX;float startY;float tempX;float tempY;@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:startX = event.getRawX();startY = event.getRawY();tempX = event.getRawX();tempY = event.getRawY();break;case MotionEvent.ACTION_MOVE:float x = event.getRawX() - startX;float y = event.getRawY() - startY;//计算偏移量,刷新视图floatBallParams.x += x;floatBallParams.y += y;floatBall.setDragState(true);windowManager.updateViewLayout(floatBall, floatBallParams);startX = event.getRawX();startY = event.getRawY();break;case MotionEvent.ACTION_UP://判断松手时View的横坐标是靠近屏幕哪一侧,将View移动到依靠屏幕float endX = event.getRawX();float endY = event.getRawY();if (endX < getScreenWidth() / 2) {endX = 0;} else {endX = getScreenWidth() - floatBall.width;}floatBallParams.x = (int) endX;floatBall.setDragState(false);windowManager.updateViewLayout(floatBall, floatBallParams);//如果初始落点与松手落点的坐标差值超过6个像素,则拦截该点击事件//否则继续传递,将事件交给OnClickListener函数处理if (Math.abs(endX - tempX) > 6 && Math.abs(endY - tempY) > 6) {return true;}break;}return false;}};OnClickListener clickListener = new OnClickListener() {@Overridepublic void onClick(View v) {windowManager.removeView(floatBall);showFloatMenu();floatMenu.startAnimation();}};floatBall.setOnTouchListener(touchListener);floatBall.setOnClickListener(clickListener);加速球ProgressBall的设计较为复杂,需要用到贝塞尔曲线来呈现波浪效果,且单击双击的效果也需要分开呈现
同样是让ProgressBall继承于View
进度值的意义在于限制水面最终上升到的高度,即根据目标进度值与最大进度值的比例来决定水面高度
波浪总的起伏次数Count用于在单击加速球时,水面上下波动的次数
总结
以上是生活随笔为你收集整理的自定义View:悬浮球与加速球的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 程序员需要了解的十个高级SQL概念
- 下一篇: 分页的limit_分页场景(limit,