自定义View:悬浮球与加速球
先來(lái)看一張動(dòng)態(tài)圖
昨天跟著視頻學(xué)了如何自定義View并做成仿360懸浮球與加速球的樣式
可以看出來(lái),做成的效果有:
- 點(diǎn)擊按鈕后退出Activity,呈現(xiàn)一個(gè)圓形的懸浮球,可以隨意拖動(dòng)并會(huì)自動(dòng)依靠到屏幕一側(cè),且拖動(dòng)時(shí)會(huì)變成一張圖片
- 當(dāng)點(diǎn)擊懸浮球時(shí),懸浮球隱藏,底部出現(xiàn)一個(gè)加速球,雙擊加速球時(shí),呈現(xiàn)水量逐漸增高且波動(dòng)幅度較小的效果,單擊時(shí)波浪上下波動(dòng)且幅度漸小
- 點(diǎn)擊屏幕不包含底部加速球的部位,加速球會(huì)隱藏,懸浮球重新出現(xiàn)
要做出這么一個(gè)效果,需要兩個(gè)自定義View與一個(gè)自定義ViewGroup
首先,需要先設(shè)計(jì)懸浮球View——FloatBall
簡(jiǎn)單起見(jiàn),為FloatBall指定一個(gè)默認(rèn)寬度和高度——150像素
然后在onDraw(Canvas canvas)方法中,判斷FloatBall是否正在被拖動(dòng)isDrag,如果是,則繪制一張默認(rèn)圖片bitmap,否則則根據(jù)繪圖函數(shù)繪制圓形與居中文本
因?yàn)镕loatBall是不存在于Activity中而在屏幕單獨(dú)顯示的,所以需要用WindowManager來(lái)添加View并顯示
新建一個(gè)類,命名為ViewManager,用來(lái)總的管理View的顯示與刪除
私有化構(gòu)造函數(shù)并采用單例模式
ViewManager包含有顯示與隱藏懸浮球與加速球的函數(shù)
//顯示浮動(dòng)小球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中開(kāi)啟,這樣懸浮球就不那么容易被系統(tǒng)去除了
在onCreate()方法中調(diào)用showFloatBall()
此時(shí),只要為MainActivity添加一個(gè)按鈕,并設(shè)定當(dāng)點(diǎn)擊按鈕后開(kāi)啟Service,此時(shí)即可看到屏幕顯示了一個(gè)懸浮球
public void startService(View view) {Intent intent = new Intent(this, StartFloatBallService.class);startService(intent);finish();}不過(guò)此時(shí)懸浮球還不支持拖動(dòng)與點(diǎn)擊,還需要為其添加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;//計(jì)算偏移量,刷新視圖floatBallParams.x += x;floatBallParams.y += y;floatBall.setDragState(true);windowManager.updateViewLayout(floatBall, floatBallParams);startX = event.getRawX();startY = event.getRawY();break;case MotionEvent.ACTION_UP://判斷松手時(shí)View的橫坐標(biāo)是靠近屏幕哪一側(cè),將View移動(dòng)到依靠屏幕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);//如果初始落點(diǎn)與松手落點(diǎn)的坐標(biāo)差值超過(guò)6個(gè)像素,則攔截該點(diǎn)擊事件//否則繼續(xù)傳遞,將事件交給OnClickListener函數(shù)處理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的設(shè)計(jì)較為復(fù)雜,需要用到貝塞爾曲線來(lái)呈現(xiàn)波浪效果,且單擊雙擊的效果也需要分開(kāi)呈現(xiàn)
同樣是讓ProgressBall繼承于View
進(jìn)度值的意義在于限制水面最終上升到的高度,即根據(jù)目標(biāo)進(jìn)度值與最大進(jìn)度值的比例來(lái)決定水面高度
波浪總的起伏次數(shù)Count用于在單擊加速球時(shí),水面上下波動(dòng)的次數(shù)
總結(jié)
以上是生活随笔為你收集整理的自定义View:悬浮球与加速球的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 程序员需要了解的十个高级SQL概念
- 下一篇: SQLServer数据库设置项梳理