62.懸浮所有頁面之上、可拖拽的互動按鈕FloatDragView
阿新 • • 發佈:2019-01-10
一個專案在開發的過程中,網路請求一般使用的是測試地址,開發完成可能還有模擬環境地址,然後是正式地址。那麼在開發和測試的過程中,就需要動態切換請求地址。這就需要一個類似Spinner的下拉框來完成這個功能,一開始我是寫在Main頁面,就一個簡單的Spinner,但是限制是如果跳轉到更深層次的頁面,就切換不了連結地址了。這就需要使用WindowManager建立一個view,使之懸浮於所有activity之上,隨時隨地切換地址。效果如下:
1.建立一個FloatDragViewManager來管理WindowManager新增刪除view
public class FloatDragViewManager implements FloatDragView.OnClickListener, FloatDragView.OnScrollListener {
private WindowManager mWindowManager;
private WindowManager.LayoutParams mFdvParams;
private Context mContext;
public void showFloatDragView() {
mContext = BaseApplication.getInstance();
mWindowManager = (WindowManager) mContext.getSystemService(WINDOW_SERVICE);
mFloatDragView = new FloatDragView(mContext);//是一個自定義的可拖拽的view,下面會寫
mFloatDragView.setOnClickListener(this);
mFloatDragView.setOnScrollListener(this);
mFloatDragView.setText(mUrlArr[0]);
mFdvParams = new WindowManager.LayoutParams();
mFdvParams.type = WindowManager.LayoutParams.TYPE_PHONE;//級別在activity之上
mFdvParams.format = PixelFormat.TRANSPARENT;//背景透明
mFdvParams.gravity = Gravity.LEFT | Gravity.TOP;//位置
mFdvParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mFdvParams.width = WindowManager.LayoutParams.WRAP_CONTENT;//寬高
mFdvParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowManager.addView(mFloatDragView, mFdvParams);
}
}
別忘了要有許可權
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
並在設定中也要找到該應用,開啟懸浮窗許可權。
我在Main頁中顯示懸浮窗:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mManager = new FloatDragViewManager();
mManager.showFloatDragView();
}
這時就應該可以看見了。
2.點選懸浮窗顯示一個RecyclerView,提供點選事件改變連結地址:
private RecyclerView mSpinnerRv;
private WindowManager.LayoutParams mRvParams;
private String[] mUrlArr = new String[]{"測試", "正式", "模擬"};
private boolean mIsSpinnerShow;//列表是否顯示的狀態
@Override
public void onClick() {
if (mSpinnerRv == null) {
mSpinnerRv = new RecyclerView(mContext);
mSpinnerRv.setBackgroundResource(R.drawable.corner_cyan_bg);
mSpinnerRv.setLayoutManager(new LinearLayoutManager(mContext));
mSpinnerRv.addOnItemTouchListener(new OnItemClickListener() {
@Override
public void onSimpleItemClick(BaseQuickAdapter adapter, View view, int position) {
mFloatDragView.setText(mUrlArr[position]);
Constant.BASE_URL = Constant.URL_ARR[position];
Toast.makeText(mContext, Constant.BASE_URL, Toast.LENGTH_SHORT).show();
mWindowManager.removeView(mSpinnerRv);//移除列表
mIsSpinnerShow = false;
}
});
mSpinnerRv.setAdapter(new DataAdapter());
}
if (mIsSpinnerShow) {//移除列表
mWindowManager.removeView(mSpinnerRv);
} else {//新增列表
mRvParams = new WindowManager.LayoutParams();
mRvParams.type = WindowManager.LayoutParams.TYPE_PHONE;
mRvParams.gravity = Gravity.LEFT | Gravity.TOP;
mRvParams.format = PixelFormat.TRANSPARENT;
mRvParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mRvParams.x = mFdvParams.x;//列表位置在FloatDragView之下
mRvParams.y = mFdvParams.y + mFloatDragView.getHeight();
mRvParams.width = mFloatDragView.getWidth();
mRvParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
mWindowManager.addView(mSpinnerRv, mRvParams);
}
mIsSpinnerShow = !mIsSpinnerShow;
}
這時就已經可以實現點選切換地址了,但是不能拖動的話會擋住其他view
3.FloatDragView實現拖拽:
private float mTouchX;
private float mTouchY;
private float mStartX;
private float mStartY;
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getRawX();
float y = event.getRawY() - getStatusBarHeight(getContext());
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchX = event.getX();
mTouchY = event.getY();
mStartX = x;
mStartY = y;
break;
case MotionEvent.ACTION_MOVE:
if (mOnScrollListener != null) {
mOnScrollListener.onScroll((int) (x - mTouchX), (int) (y - mTouchY));
}
break;
case MotionEvent.ACTION_UP:
mTouchX = mTouchY = 0;
if (Math.abs(x - mStartX) < 5 && Math.abs(y - mStartY) < 5) {// 用於區別是滑動了還是點選了
if (mOnClickListener != null) {
mOnClickListener.onClick();
}
}
break;
}
return true;
}
/**
* 滑動監聽,供外部呼叫
*/
public void setOnScrollListener(OnScrollListener onScrollListener) {
mOnScrollListener = onScrollListener;
}
public interface OnScrollListener {
void onScroll(int x, int y);
}
在manager中:
/**
* 滑動監聽,動態改變按鈕和列表的位置
*/
@Override
public void onScroll(int x, int y) {
mFdvParams.x = x;
mFdvParams.y = y;
mWindowManager.updateViewLayout(mFloatDragView, mFdvParams);//更新位置
if (mIsSpinnerShow) {//如果列表顯示的話
mRvParams.x = mFdvParams.x;
mRvParams.y = mFdvParams.y + mFloatDragView.getHeight();
mWindowManager.updateViewLayout(mSpinnerRv, mRvParams);
}
}
4.最後在FloatDragViewManager中新增消除view的方法:
public void removeFloatDragView() {
mWindowManager.removeView(mFloatDragView);
if (mSpinnerRv != null && mIsSpinnerShow) {
mWindowManager.removeView(mSpinnerRv);
}
}
在Main中呼叫:
@Override
protected void onDestroy() {
super.onDestroy();
mManager.removeFloatDragView();
}