可移动悬浮窗关于随着手势移动的坐标区分与需要注意的事项1加手机「可移动悬浮窗关于随着手势移动的坐标区分与需要注意的事项」

   日期:2025-01-12     作者:o93v3       评论:0    移动:http://w.yusign.com/mobile/news/12017.html
核心提示:想要做一个简单的像悬浮球那样的能在手机桌面上随意拖动的效果,首先你需要知道1:往手机桌面上添加一个自定义view(
想要做一个简单的像悬浮球那样的能在手机桌面上随意拖动的效果,首先你需要知道
1:往手机桌面上添加一个自定义view(悬浮球)使用的是WindowManager.addView(View view, WindowManager.LayoutParams params); ---->WindowManager.LayoutParams是用于指定view在桌面中的位置,以及view在桌面中的一些属性
2:如果想出现悬浮球效果,在清单文件中必须声明 <uses-permission android :name= "android.permission.SYSTEM_ALERT_WINDOW" /> 权限
3:如果想随意移动你的自定义View必须在View中重写onTouchEvent)方法来记录坐标的变化(注意,每个View中都有onTouchEvent方法,注意区别onTouchEvent方法,最后使用windowManager.updateViewLayout(View view, WIndowManager.LayoutParams params);更新自定义view(悬浮球)的位置

现在我们开始实现自定义view(悬浮球
1:先定义一个悬浮球的布局文件small_floatball,由于这次讲述的重点不在这里,所以不详细说明,直接上代码
<? xml version= "1.0" encoding= "utf-8" ?>
<FrameLayout xmlns: android = "http://schemas.android.com/apk/res/android"
android :layout_width= "50dp"
android :layout_height= "50dp"
android :id= "@+id/small_window_layout"
android :background= "@android:color/transparent"
android :orientation= "vertical" >

<ImageView
android :layout_width= "35dp"
android :layout_height= "35dp"
android :id= "@+id/img_bg"
android :background= "@drawable/icon_bg"
android :layout_gravity= "center"
/>
<ImageView
android :layout_width= "wrap_content"
android :layout_height= "wrap_content"
android :id= "@+id/img_ball"
android :background= "@drawable/icon_ball"
android :layout_gravity= "center" />
</FrameLayout>

效果图(注意xml文件中的Framelayout和ImageView的大小








2:现在我们开始自定义view
public class FloatBall extends LinearLayout {


private float mDownX;
private float mDownY;

private float mOnMoveX;
private float mOnMoveY;

private float mInViewX;
private float mInViewY;

private WindowManager.LayoutParams mParams;
private WindowManager mWindowManager;

public FloatBall(Context context) {
super(context);
LayoutInflater.from(context).inflate(R.layout.small_floatball, this);

View view = findViewById(R.id.small_window_layout);

mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

mParams = new WindowManager.LayoutParams();
mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
mParams.format = PixelFormat.RGBA_8888;
mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
mParams.gravity = Gravity.LEFT | Gravity.TOP;
mParams.height = view.getLayoutParams().height;
mParams.width = view.getLayoutParams().width;
mParams.x = mWindowManager.getDefaultDisplay().getWidth();
mParams.y = mWindowManager.getDefaultDisplay().getHeight() / 2;

mWindowManager.addView(this, mParams);
}



@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
//当按手指按下时的事件
case MotionEvent.ACTION_DOWN:
mDownX = event.getRawX();
mDownY = event.getRawY() - getStatusBarHeight();
mOnMoveX = event.getRawX();
mOnMoveY = event.getRawY() - getStatusBarHeight();
mInViewX = event.getX();
mInViewY = event.getY();
break;
//当手指移动时的事件
case MotionEvent.ACTION_MOVE:
mOnMoveX = event.getRawX();
mOnMoveY = event.getRawY() - getStatusBarHeight();
upDateFloatBallLocation();
break;
//当手指拿起时的事件
case MotionEvent.ACTION_UP:
// 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。
if (mOnMoveX == mDownX && mOnMoveY == mDownY) {

}
break;

}
return true;
}

private void upDateFloatBallLocation() {
mParams.x = (int)(mOnMoveX - mInViewX);
mParams.y = (int)(mOnMoveY - mInViewY);
mWindowManager.updateViewLayout(this, mParams);
}

//这个方法是获得状态栏的高度,可以不用深究
private int getStatusBarHeight() {
int statusBarHeight = 0;
if (statusBarHeight == 0) {
try {
Class<?> c = Class.forName("com.android.internal.R$dimen");
Object o = c.newInstance();
Field field = c.getField("status_bar_height");
int x = (Integer) field.get(o);
statusBarHeight = getResources().getDimensionPixelSize(x);
} catch (Exception e) {
e.printStackTrace();
}
}
return statusBarHeight;
}
}


接下来我们来说刚才没有解释的三个方法和mParams参数的含义

1:构造函数中的mParams的主要的参数含义

//初始化mParams
mParams = new WindowManager.LayoutParams();

mParams.type = WindowManager.LayoutParams.TYPE_PHONE;
mParams.format = PixelFormat.RGBA_8888;
mParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;

//这个gravity属性是指定view的对齐方式,之前我们在位置坐标中所得左上角就是在这里定义的
mParams.gravity = Gravity.LEFT | Gravity.TOP;
//这个是设置view在桌面中的大小
mParams.height = view.getLayoutParams().height;
mParams.width = view.getLayoutParams().width;
//这个非常非常容易搞错!这个是定义控件在桌面中的位置,这个位置是以view的左上角为原点的,而不是以这个view的中心作为原点!搞清楚这个你就可以理解之后的onTouchEvent中的一些不理解的地方
mParams.x = mWindowManager.getDefaultDisplay().getWidth();//让这个悬浮按钮的初始x坐标是最左边
mParams.y = mWindowManager.getDefaultDisplay().getHeight() / 2; //让这个悬浮按钮的初始y坐标是中间

2:onTouchEvent()
还记得之前的那几个坐标参数的含义吗

private float mDownX;
private float mDownY;

private float mOnMoveX;
private float mOnMoveY;

private float mInViewX;
private float mInViewY;




public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
//当按手指按下时的事件
case MotionEvent.ACTION_DOWN:
mDownX = event.getRawX();
mDownY = event.getRawY() - getStatusBarHeight();
mOnMoveX = event.getRawX();
mOnMoveY = event.getRawY() - getStatusBarHeight();
mInViewX = event.getX();
mInViewY = event.getY();
break;
//当手指移动时的事件
case MotionEvent.ACTION_MOVE:
mOnMoveX = event.getRawX();
mOnMoveY = event.getRawY() - getStatusBarHeight();
upDateFloatBallLocation();
break;
//当手指拿起时的事件
case MotionEvent.ACTION_UP:
// 如果手指离开屏幕时,xDownInScreen和xInScreen相等,且yDownInScreen和yInScreen相等,则视为触发了单击事件。
if (mOnMoveX == mDownX && mOnMoveY == mDownY) {

}
break;

}
return true;
}

在这里我只想解释一下为什么要剪掉状态栏的高度,因为悬浮窗是不能移动到状态栏之上的,但是我们的getRawY的参考坐标原点是屏幕左上角,也是状态栏的左上角,因为移动不过去我们就把坐标原点改为ActionBar的左上角,所以剪掉了状态栏的高度


2:upDateFloatBallLocation()

private void upDateFloatBallLocation() {
mParams.x = (int)(mOnMoveX - mInViewX);
mParams.y = (int)(mOnMoveY - mInViewY);
//更新悬浮球位置函数
mWindowManager.updateViewLayout(this, mParams);
}

这里我解释下
mParams.x = (int)(mOnMoveX - mInViewX);
mParams.y = (int)(mOnMoveY - mInViewY);
这里回想刚才1中说明的那个问题,mParams.x和mParams.y是自定义view的位置,但是这个位置是以这个view的左上角的点作为原点的,如果mInViewX和mInViewY就是(0, 0),也就是view的左上角,那么mParams.x = mOnMoveX; mParams.y=mOnMoveY;
但是如果不是(0, 0)那么你想想是不是应该是
mParams.x = (int)(mOnMoveX - mInViewX);
mParams.y = (int)(mOnMoveY - mInViewY);
如果想不通,那就画图试试,注意getX, getRawX, getY和getRawY的区别



这里提醒下,mParams必须是WindowManager.LayoutParams而不是view的LayoutParams

     本文地址:http://w.yusign.com/news/12017.html    述古往 http://w.yusign.com/static/ , 查看更多
 
特别提示:本信息由相关用户自行提供,真实性未证实,仅供参考。请谨慎采用,风险自负。

举报收藏 0打赏 0评论 0
 
更多>同类资讯
0相关评论

相关文章
最新文章
推荐文章
推荐图文
资讯
点击排行
{