1.最近做项目有一个弹出框的需求,要求是一个跟随手指滑动的view,点击就弹出一个View,再点击就收缩起来。在网上找资料,发现没有现成的,于是只有自己找思路,自己动手了。
2.思路:使用WindowManager的addView方法添加一个View,设置onTouch事件(onTouch事件会有很多坑),View中设置OnClick事件,监听并再View旁边再动态添加一个我姑且叫它springview。再点击的时候如果这个springView存在就移除,这样就实现了点击时的弹出跟收缩springView的目的,另外你还可以为这个springview弹出时设置动画,当然这个动画也会有很多坑。如果大家在使用中发现有很多坑可以给我留言,或者发邮件(hierophantzw@gmail.com),这些坑我就不在这里说了。下面我做了一个demo,封装了一下,大家拿到之后基本上就是可以直接用了,只需要传递一个activity的对象即可,这个对象是获取WindowManager的必要条件。
3.首先上效果图
4.部分关键代码贴出:
//封装的一个类的构造函数,需要一个activity对象
public FloatingViewController(Activity contextActivity)
{
this.contextActivity = contextActivity;
wManager = contextActivity.getWindowManager();
wmParams = new WindowManager.LayoutParams();
wmParams.format = PixelFormat.RGBA_8888;
wmParams.flags = LayoutParams.FLAG_NOT_FOCUSABLE;
wmParams.gravity = Gravity.LEFT | Gravity.TOP;
}
//View的手指跟随
View.setOnTouchListener()
(new View.OnTouchListener(){
@Override
public boolean onTouch(View v, MotionEvent event)
{
switch (event.getAction())
{
case MotionEvent.ACTION_DOWN:
xInView = event.getX();
yInView = event.getY();
xDownInScreen = event.getRawX();
yDownInScreen = event.getRawY() - getStatusBarHeight();
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
Log.e("test", xInScreen + "down" + yInScreen);
break;
case MotionEvent.ACTION_MOVE:
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
if (xInScreen == xDownInScreen && yInScreen == yDownInScreen)
{
}
else
{
removeBigWindow();
// hideView();
}
updateViewPosition();
break;
case MotionEvent.ACTION_UP:
xInScreen = event.getRawX();
yInScreen = event.getRawY() - getStatusBarHeight();
if (xInScreen == xDownInScreen && yInScreen == yDownInScreen)
{
Log.e("test", xInScreen + "up" + yInScreen);
// openBigWindow();
// showView();
return false;
}
else
{
Toast.makeText(contextActivity, "no click event", 1000).show();
return true;
}
// break;
}
return false;
}
});
View.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
circleButton.getLocationOnScreen(loacation);
Log.d("test", "location-x:" + loacation[0] + "--Y:" + loacation[1]);
int viewRight = screenWidth - (wmParams.x + wmParams.width / 2);
int viewLeft = wmParams.x;
//根据屏幕宽度来决定弹出窗口在左边还是右边显示的问题
if (viewLeft > viewLength)
{
openLeftBigWindow();//左边边弹出窗口
}
else
{
if (viewRight > viewLength)
{
openRightBigWindow();//右边弹出窗口
}
else
{
xInScreen = screenWidth;
xInView = 60;//宽度可以自己设置
yInView = 60;
wmParams.x = (int) xInScreen;
wmParams.y = (int) yInScreen;
updateViewPosition();
}
}
}
});
wmParams.width = wmParams.height = (int) (60 * screenScale);
//记录每一次View移动的位置,下一次启动的时候确保View在上一次移动的那个位置
locationPreferences = contextActivity.getPreferences(android.content.Context.MODE_PRIVATE);
xInScreen = locationPreferences.getFloat("x", new SizeUtils(contextActivity).sysWidth);
yInScreen = locationPreferences.getFloat("y", new SizeUtils(contextActivity).sysHeight / 2);
xInView = 60;
yInView = 60;
wmParams.x = (int) xInScreen;
wmParams.y = (int) yInScreen;
//这里在屏幕上显示了一个按钮
wManager.addView(View, wmParams);
updateViewPosition();
}
//贴出一个关键函数,展示弹出窗口如何显示的代码
protected void openLeftBigWindow()
{
if (wmcParams == null && childView == null)
{
wManager = contextActivity.getWindowManager();
wmcParams = new WindowManager.LayoutParams();
wmcParams.format = PixelFormat.RGBA_8888;
wmcParams.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
wmcParams.gravity = Gravity.LEFT | Gravity.TOP;
wmcParams.x = (int) (loacation[0] - viewLength);
wmcParams.y = (int) (wmParams.y);
wmcParams.width = WindowManager.LayoutParams.WRAP_CONTENT;
wmcParams.height = WindowManager.LayoutParams.WRAP_CONTENT;
childView = new SpringView(contextActivity, screenScale, screenWidth, wManager, wmcParams, Orientaion.LEFT,
this);
containerLayout = new LinearLayout(contextActivity);
containerLayout.addView(childView);
wManager.addView(containerLayout, wmcParams);
}
else
{
removeBigWindow();
}
}