转载请注明出处 http://blog.csdn.net/qq_31715429/article/details/77895842
本文出自:猴菇先生的博客
一个项目在开发的过程中,网络请求一般使用的是测试地址,开发完成可能还有仿真环境地址,然后是正式地址。那么在开发和测试的过程中,就需要动态切换请求地址。这就需要一个类似Spinner的下拉框来完成这个功能,一开始我是写在Main页面,就一个简单的Spinner,但是限制是如果跳转到更深层次的页面,就切换不了链接地址了。这就需要使用WindowManager创建一个view,使之悬浮于所有activity之上,随时随地切换地址。效果如下:
有没有萌化你的少女心啊,哈哈。。
代码已上传至 https://github.com/MonkeyMushroom/FloatDragView
图片来自iconfont,仅供学习交流使用,不得用于商业用途。
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();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mFdvParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
mFdvParams.type = WindowManager.LayoutParams.TYPE_PHONE;
}
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();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mRvParams.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
} else {
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();
}