前言
当前实现了直接通过paint绘制一个圆显示在最上层。
尝试新增内容: 1 增加权限申请,因为如果未打开权限,点击绘制圆按钮,app会异常退出。 2 尝试通过layout.xml文件绘制悬浮窗,并设置悬浮球的view的范围为圆,而非长方形 3 新增view的移动和点击双事件区分 4 移动时view重新显示
1 增加权限申请
在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 {
Toast.makeText(getApplicationContext(), "open permission", Toast.LENGTH_SHORT).show();
}
}
}
2 使用layout定义view,代替paint
定义一个layout文件,设置float_window_small.xml id为small_window_layout
float_window_small.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/small_window_layout"
>
<TextView
android:id="@+id/percent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:text="@string/small_floatBall_text"
android:textColor="#FF0000"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
布局效果
参考代码: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);
mWindowManager.addView(mFloatLayout, wp);
1 获取应用的布局服务 2 使用inflate()函数初始化定义布局mFloatLayout,注意参数为layout信息 3 查找到对应view的id 4 监听到移动 5 添加view?存疑,在监听中使用到了updateViewLayout,这里又用了addview
2.1 显示大小问题
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)位置。
viewparams.width = 100;
viewparams.height = 100;
viewparams.gravity = Gravity.LEFT | Gravity.TOP;
viewparams.x = 200;
viewparams.y = 200;
在strings.xml文件中定义了textview的显示内容
<resources>
<string name="app_name">demo_v3_addmove</string>
<string name="small_floatBall_text">11111111</string>
</resources>
所以,呈现的效果是 我们尝试将显示内容增多
<resources>
<string name="app_name">demo_v3_addmove</string>
<string name="small_floatBall_text">111111111111</string>
</resources>
效果一致。
尝试将viewparams参数的长宽变大 viewparams.width=200; viewparams.height=200; 这时候发现显示变了,第一行显示9个1,第二行
2.2 更新view函数
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();
if (ball_status == false) {
record_on();
} else if (ball_status == true) {
record_off();
} else
Log.d("", "error value");
remove_view();
add_view();
mWindowManager.updateViewLayout(ball,viewparams);
if (ball.getVisibility() == View.VISIBLE) {
Toast.makeText(getApplicationContext(), "view display", Toast.LENGTH_SHORT).show();
}
}
}
}
测试失败。
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();
}
}
}
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();
if(Math.abs(mStartX - mStopX) >= 1 || Math.abs(mStartY - mStopY) >= 1){
isMove = true;
}
break;
}
return mGestureDetector.onTouchEvent(event);
}
}
在打开layout view的button监听中创建上述两个监听,分别是click监听录制和播放,touch监听移动
public class openlayoutviewListener implements OnClickListener {
@Override
public void onClick(View arg0) {
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;
}
mlayout.setOnClickListener(new touchlayoutview_youkaiListener());
mlayout.setOnTouchListener(new FloatingListener());
}
}
|