日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > Android >内容正文

Android

Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮...

發布時間:2024/1/17 Android 67 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮... 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Android6.0 源碼修改之 仿IOS添加全屏可拖拽浮窗返回按鈕
前言
之前寫過屏蔽系統導航欄功能的文章,具體可看Android6.0 源碼修改之屏蔽導航欄虛擬按鍵(Home和RecentAPP)/動態顯示和隱藏NavigationBar

在某些特殊定制的版本中要求完全去掉導航欄,那么當用戶點進一些系統自帶的應用界面如設置、聯系人等,就沒法退出了,雖然可以在actionBar中添加back按鈕,但總不能每一個app都去添加吧。所以靈機一動我們就給系統添加一個全屏可拖拽的浮窗按鈕,點擊的時候處理返回鍵的邏輯。它大概長這樣(審美可能丑了點,你們可以自由發揮)

在這里插入圖片描述
圖1 最終效果圖

思路分析
通過分析之前的NavigationBar代碼,發現系統是通過WindowManager添加View的方式來實現,此處我們也可以模擬這種方法來添加
添加懸浮窗以后監聽觸摸事件,跟隨手指移動重新修改view的layoutParam
松手后獲取當前X坐標,小于屏幕width的一半則平移歸位至屏幕左邊
添加系統的返回按鍵功能
一、添加懸浮窗
private void showFloatingWindow() {

DisplayMetrics outMetrics = new DisplayMetrics(); mWindowManager.getDefaultDisplay().getMetrics(outMetrics); screenWidth = outMetrics.widthPixels; screenHeight = outMetrics.heightPixels;layoutParams = new WindowManager.LayoutParams(); layoutParams.type = WindowManager.LayoutParams.TYPE_PHONE; layoutParams.format = PixelFormat.RGBA_8888; layoutParams.gravity = Gravity.LEFT | Gravity.TOP; layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; layoutParams.width = 100; layoutParams.height = 100; layoutParams.x = 200; layoutParams.y = 200;button = new ImageButton(mContext); button.setBackground(mContext.getResources().getDrawable(R.drawable.fab_background));//系統通訊錄里的藍色圓形圖標 button.setImageResource(R.drawable.ic_sysbar_back);//系統本身的back圖標 mWindowManager.addView(button, layoutParams); isShowFloatingView = true;

}
代碼很簡單,就是通過windowManager添加一個ImageButton,寬高都是100的,位置在屏幕左上角為原點的200,200。需要注意的是因為我們是在源碼里添加,而且是M的版本,所以type為WindowManager.LayoutParams.TYPE_PHONE。如果是在普通的app里注意事項可參考這篇

二、添加觸摸事件監聽
button.setOnTouchListener(new FloatingOnTouchListener());

private class FloatingOnTouchListener implements View.OnTouchListener {

private int lastX; private int lastY;@Override public boolean onTouch(View view, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:isDrag = false;lastX = (int) event.getRawX();lastY = (int) event.getRawY();break;case MotionEvent.ACTION_MOVE:isDrag = true;int nowX = (int) event.getRawX();int nowY = (int) event.getRawY();int movedX = nowX - lastX;int movedY = nowY - lastY;lastX = nowX;lastY = nowY;layoutParams.x = layoutParams.x + movedX;layoutParams.y = layoutParams.y + movedY;//獲取當前手指移動的x和y,通過updateViewLayout方法將改變后的x和y設置給buttonmWindowManager.updateViewLayout(view, layoutParams);break;case MotionEvent.ACTION_UP:if (isDrag) {log("lastX=" + lastX + " screenWidth=" + screenWidth);//手指抬起時,判斷是需要滑動到屏幕左邊還是屏幕右邊if (lastX >= screenWidth / 2) {setAnimation(view, lastX, screenWidth);} else {setAnimation(view, -lastX, 0);}}break;}//返回true則消費事件,返回false則傳遞事件,此處特殊處理是為了和點擊事件區分return isDrag || view.onTouchEvent(event); }

三、添加抬起滑動歸位動畫
private void setAnimation(final View view, int fromX, int toX) {

final ValueAnimator animator = ValueAnimator.ofInt(fromX, toX);if (Math.abs(fromX) < screenWidth / 4 || fromX > screenWidth * 3 / 4)animator.setDuration(300);elseanimator.setDuration(600);animator.setInterpolator(new LinearInterpolator());animator.addListener(new Animator.AnimatorListener() {@Overridepublic void onAnimationStart(Animator animation) {}@Overridepublic void onAnimationEnd(Animator animation) {log("onAnimationEnd=");savePreValue(layoutParams.x, layoutParams.y);}@Overridepublic void onAnimationCancel(Animator animation) {}@Overridepublic void onAnimationRepeat(Animator animation) {}});animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {int current = (int) animator.getAnimatedValue();log("current=" + current);layoutParams.x = Math.abs(current);mWindowManager.updateViewLayout(view, layoutParams);}});animator.start(); }

}
同樣是通過改變button的x和y值來達到滑動效果,只不過我只需要x平移,y為0,需要斜著滑的你們可自由發揮,為了使滑動看上去平滑,給動畫添加了一個線性插值器,設置滑動時間,監聽返回插值進度,這樣動態設置給button。為了保存button的最終位置,添加了一個動畫完成監聽,并將x和y寫入到SharedPreferences中保存。

四、添加點擊返回功能
通過打印日志分析,系統導航欄的返回按鍵,發現其原理是通過KeyButtonView的觸摸事件發送一個KeyEvent事件給系統來實現返回功能

源碼位置frameworksbasepackagesSystemUIsrccomandroidsystemuistatusbarpolicyKeyButtonView.java

public boolean onTouchEvent(MotionEvent ev) {

final int action = ev.getAction(); int x, y; if (action == MotionEvent.ACTION_DOWN) {mGestureAborted = false; } if (mGestureAborted) {return false; }switch (action) {case MotionEvent.ACTION_DOWN://按下的時間mDownTime = SystemClock.uptimeMillis();setPressed(true);if (mCode != 0) {//按下事件sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);} else {// Provide the same haptic feedback that the system offers for virtual keys.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);}removeCallbacks(mCheckLongPress);postDelayed(mCheckLongPress, ViewConfiguration.getLongPressTimeout());break;case MotionEvent.ACTION_MOVE:x = (int)ev.getX();y = (int)ev.getY();setPressed(x >= -mTouchSlop&& x < getWidth() + mTouchSlop&& y >= -mTouchSlop&& y < getHeight() + mTouchSlop);break;case MotionEvent.ACTION_CANCEL:setPressed(false);if (mCode != 0) {sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);}removeCallbacks(mCheckLongPress);break;case MotionEvent.ACTION_UP:final boolean doIt = isPressed();setPressed(false);if (mCode != 0) {if (doIt) {//抬起事件sendEvent(KeyEvent.ACTION_UP, 0);sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);playSoundEffect(SoundEffectConstants.CLICK);} else {sendEvent(KeyEvent.ACTION_UP, KeyEvent.FLAG_CANCELED);}} else {// no key code, just a regular ImageViewif (doIt) {performClick();}}removeCallbacks(mCheckLongPress);break; }return true;

}

//以下為我們給button添加的點擊事件
private void sendEvent(int action, int flags, long when) {

int mCode = 4; Log.e(TAG, "mCode="+mCode + " flags="+flags); final int repeatCount = (flags & KeyEvent.FLAG_LONG_PRESS) != 0 ? 1 : 0; final KeyEvent ev = new KeyEvent(when - 100, when, action, mCode, repeatCount,0, KeyCharacterMap.VIRTUAL_KEYBOARD, 0,flags | KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,InputDevice.SOURCE_KEYBOARD); InputManager.getInstance().injectInputEvent(ev,InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);

}

button.setOnClickListener(new View.OnClickListener() {

@Overridepublic void onClick(View v) {Log.e(TAG,"click dragButton ...");final long mDownTime = SystemClock.uptimeMillis();//onBackPressed();sendEvent(KeyEvent.ACTION_DOWN, 0, mDownTime);new Handler().postDelayed(new Runnable() {@Overridepublic void run() {sendEvent(KeyEvent.ACTION_UP, 0, SystemClock.uptimeMillis());}}, 300);} });

需要注意的地方,系統返回鍵對應的code為4,所以mCode=4,KeyButtonView的觸摸事件包含按下和抬起,所以我們只需模擬發送按下和抬起事件,可以看到抬起事件加了300ms的延時發送,這是關鍵不然系統不會處理。
原文地址https://www.cnblogs.com/cczheng-666/p/10741082.html

總結

以上是生活随笔為你收集整理的Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮...的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。