- 前言
- 1 增加权限申请
- 2 使用layout定义view,代替paint
- 2.1 显示大小问题
- 2.2 更新view函数
- 2.2.1 LayoutInflater布局服务
- 2.3 差异
- 3 尝试使用windowmanager自定义函数更新view
- 3.1 参考文章
- 4 拖动悬浮球
- 4.1 参考文章
- 4.2 分析功能
- 4.3 实现
当前实现了直接通过paint绘制一个圆显示在最上层。
尝试新增内容:
1 增加权限申请,因为如果未打开权限,点击绘制圆按钮,app会异常退出。
2 尝试通过layout.xml文件绘制悬浮窗,并设置悬浮球的view的范围为圆,而非长方形
3 新增view的移动和点击双事件区分
4 移动时view重新显示
在activity创建中直接申请
代码来源:Android 可任意位置移动的悬浮窗
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//申请悬浮权限
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
if (!Settings.canDrawOverlays(getApplicationContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivityForResult(intent, 0);
} else {
// mIntent = new Intent(MainActivity.this, FloatWindowService.class);
// bindService(mIntent, serviceConnection, Context.BIND_AUTO_CREATE);//直接启动服务方式启动
Toast.makeText(getApplicationContext(), "open permission", Toast.LENGTH_SHORT).show();
}
}
}
定义一个layout文件,设置float_window_small.xml
id为small_window_layout
float_window_small.xml
布局效果
参考代码:Android 可任意位置移动的悬浮窗
仿照以下代码
LayoutInflater inflater = LayoutInflater.from(getApplication()); mFloatLayout = (LinearLayout) inflater.inflate(R.layout.float_window, null, false); View view = mFloatLayout.findViewById(R.id.playMonitor);//自定义悬浮窗布局 view.setOnTouchListener(this);//设置移动监听,此处view是自定义充满布局的控件 mWindowManager.addView(mFloatLayout, wp);
1 获取应用的布局服务
2 使用inflate()函数初始化定义布局mFloatLayout,注意参数为layout信息
3 查找到对应view的id
4 监听到移动
5 添加view?存疑,在监听中使用到了updateViewLayout,这里又用了addview
layout和view关系:我理解的是一个activity对应一个window,window中可以包含多个view,而view的内容就包含布局layout,布局可分为5种,布局中又包含多个控件。
参考:android layout与view机制
activity–window–view–layout–textview/button
需要注意两点。
view/layout的长宽定义在layoutparam中,即代码中看到的viewparams,类型为WindowManager.LayoutParams。
在set_viewparams中有定义,view的长宽为100,view的起始点(左上角)在(200,200)位置。
//窗口长宽,注意与view一致
viewparams.width = 100;
viewparams.height = 100;
//子控件,居左居上
viewparams.gravity = Gravity.LEFT | Gravity.TOP;
//起始位置 // 相对于创建的窗口位置
viewparams.x = 200;
viewparams.y = 200;
在strings.xml文件中定义了textview的显示内容
demo_v3_addmove 11111111
所以,呈现的效果是
我们尝试将显示内容增多
demo_v3_addmove 111111111111
效果一致。
尝试将viewparams参数的长宽变大
viewparams.width=200;
viewparams.height=200;
这时候发现显示变了,第一行显示9个1,第二行
updateViewLayout和addview
2.2.1 LayoutInflater布局服务参考文章:LayoutInflater(布局服务)
获取LayoutInflater:
LayoutInflater inflater1 = LayoutInflater.from(this); LayoutInflater inflater2 = getLayoutInflater(); LayoutInflater inflater3 = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);2.3 差异
使用layout创建悬浮球。
执行修改颜色函数时,显示的颜色就改变了,不需要wm移除后添加。
存疑:是否自定义view也可以实现。不适用,再找其他方法
设定颜色时会调用updateTextColors(),更新text颜色。
public void setTextColor(int color) {
mTextColor = ColorStateList.valueOf(color);
updateTextColors();
}
测试发现,第一次显示layout时,点击layout,颜色无法改变,应该是未识别到点击事件?
原因:我把创建点击layout监听放在了closebutton里了,移动到openbutton就可以。
待办:如何实现在layout上画图,然后填充颜色自定义。
3 尝试使用windowmanager自定义函数更新view之前已有的一项功能时点击view时,颜色变为绿色,使用的方法时先移除view,再重新添加。
打算使用下WindowManager.updateViewLayout(),看看是否有效。
在click监听中新增
public class touchfloatballview_youkaiListener implements View.OnClickListener {
@Override
public void onClick(View arg0) {
if (mWindowManager != null) {
Toast.makeText(getApplicationContext(), "change ball color", Toast.LENGTH_SHORT).show();
// ball.paint.setColor(Color.GREEN);//设置颜色为红
// ball.cx = 50;
ball.cy = 50;
// ball.();
// mWindowManager.updateViewLayout(ball, viewparams);
if (ball_status == false) {
record_on();
} else if (ball_status == true) {
record_off();
} else
Log.d("", "error value");
//方法1.先移除再添加
remove_view();
add_view();
//方法2.直接使用WindowManager.updateViewLayout
mWindowManager.updateViewLayout(ball,viewparams);
if (ball.getVisibility() == View.VISIBLE) {
Toast.makeText(getApplicationContext(), "view display", Toast.LENGTH_SHORT).show();
}
}
//(ball,viewparams);
}
}
测试失败。
3.1 参考文章view 的绘制和刷新
Android屏幕刷新机制
4 拖动悬浮球 4.1 参考文章Android 可任意位置移动的悬浮窗
关于View的setOnTouchListener和setOnClickListener冲突
用户手势检测-GestureDetector使用详解
Android MotionEvent详解
4.2 分析功能view监听触摸事件,其中主要是三种:按下ACTION_DOWN,移动ACTION_MOVE,弹起ACTION_UP。
与此同时还有一点是view的坐标,若改变则需要重新绘制view,进行刷新。
刷新条件:
1 监听到up事件
2 监听到移动,同步刷新
参考文章:可拖拽悬浮窗、对话框悬浮窗的简单实现
这里需要注意的一点,参考文章使用的是touch监听,而我之前写过一个click监听,主要是监听悬浮框的点击,来实现录制和停止。
4.3 实现
public class touchfloatballview_youkaiListener implements View.OnClickListener {
@Override
public void onClick(View arg0) {
if (mWindowManager != null) {
if (ball_status == false) {
record_on();
} else if (ball_status == true) {
record_off();
} else
Log.d("", "error value");
remove_view();
add_view();
}
}
}
// 代码来源:https://www.cnblogs.com/tianzhijiexian/p/3994546.html
private class FloatingListener implements View.OnTouchListener {
@Override
public boolean onTouch(View arg0, MotionEvent event) {
int action = event.getAction();
switch(action){
case MotionEvent.ACTION_DOWN:
isMove = false;
mTouchStartX = (int)event.getRawX();
mTouchStartY = (int)event.getRawY();
mStartX = (int)event.getX();
mStartY = (int)event.getY();
break;
case MotionEvent.ACTION_MOVE:
mTouchCurrentX = (int) event.getRawX();
mTouchCurrentY = (int) event.getRawY();
viewparams_layout.x += mTouchCurrentX - mTouchStartX;
viewparams_layout.y += mTouchCurrentY - mTouchStartY;
mWindowManager.updateViewLayout(mlayout, viewparams_layout);
mTouchStartX = mTouchCurrentX;
mTouchStartY = mTouchCurrentY;
break;
case MotionEvent.ACTION_UP:
mStopX = (int)event.getX();
mStopY = (int)event.getY();
//System.out.println("|X| = "+ Math.abs(mStartX - mStopX));
//System.out.println("|Y| = "+ Math.abs(mStartY - mStopY));
if(Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1){
isMove = true;
}
break;
}
return mGestureDetector.onTouchEvent(event); //此处必须返回false,否则OnClickListener获取不到监听
}
}
在打开layout view的button监听中创建上述两个监听,分别是click监听录制和播放,touch监听移动
public class openlayoutviewListener implements OnClickListener {
@Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
// display status in textview "button on"
text = (TextView) findViewById(R.id.textView);
text.setText("layoutview on");
Toast.makeText(getApplicationContext(), "layoutview on", Toast.LENGTH_SHORT).show();
if(status_layoutview == false){
mWindowManager.addView(mlayout, viewparams_layout);
status_layoutview = true;
}
// listen for floatingtextview touch
mlayout.setOnClickListener(new touchlayoutview_youkaiListener());
mlayout.setOnTouchListener(new FloatingListener());
}
}



