Java 如何使ActionBar在“中移动”;无障碍服务“;
我是“无障碍服务”这一主题的新手。我能够滚动按钮点击,并能够关闭手机和其他许多东西, 但是我想让我的布局(action_bar.xml)可以移动 所以 有人能告诉我如何使活动杆可移动吗 这是我的 action_bar.xml::Java 如何使ActionBar在“中移动”;无障碍服务“;,java,android,xml,accessibilityservice,Java,Android,Xml,Accessibilityservice,我是“无障碍服务”这一主题的新手。我能够滚动按钮点击,并能够关闭手机和其他许多东西, 但是我想让我的布局(action_bar.xml)可以移动 所以 有人能告诉我如何使活动杆可移动吗 这是我的 action_bar.xml:: 覆盖按照与活动或片段上的常规视图相同的规则工作。没有像android:movable=“true”这样的神奇属性可以使覆盖层可移动。你应该自己做。 下面是我的可移动视图的示例: action\u bar.xml(这里我用自定义拖拽式布局替换LinearLayout) A
覆盖按照与
活动
或片段
上的常规视图
相同的规则工作。没有像android:movable=“true”这样的神奇属性可以使覆盖层可移动。你应该自己做。
下面是我的可移动视图的示例:
action\u bar.xml(这里我用自定义拖拽式布局替换LinearLayout
)
ActionBarService.Java
@Override
protected void onServiceConnected() {
// Create an overlay and display the action bar
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT, // Overlay must be full screen otherwise my trick will not work
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // Allow another windows to receive touch events
PixelFormat.TRANSLUCENT);
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
}
它似乎起作用了,如果没有,请告诉我。由@fishbone给出的答案基本上是正确的,除了可访问性服务中的覆盖不一样的一小部分。当然,做出这样的假设可以简化事情,但最终是错误的。可访问性服务有一些非常重要的考虑因素,在大多数情况下,它们的行为与活动完全相同,但可访问性服务启动覆盖的方式非常重要,并且与大多数视图的行为方式不同,特别是在它们如何截取触摸事件方面。你必须非常小心触摸事件。最终,您希望视图是可触摸的,但不是占据整个窗口。为此,您可以使用以下两种类型:
类型\可访问性\覆盖
或
类型\应用程序\覆盖
这两种行为相似,但并非如此。如果您在实际视图中无法接收触摸事件,后者可能会对您有所帮助
核心问题是,WindowManager可用的布局参数只允许您完全拦截触摸事件,或者根本不拦截触摸事件。你不能让它为你的观点的这一部分这样做,而不是为其他人。试图将事件通过您的窗口传递到您不拥有的窗口的逻辑。。。不要去那里
因此,您必须做的是,没有一个完整的布局视图。您必须将视图添加为可触摸视图,但您的视图只能占据屏幕上它实际上必须覆盖的部分。这显然应该尽可能少(因为触摸事件将无法进入此视图)。然后,您必须执行一个自定义的按住触摸侦听器,并执行触摸和拖动逻辑来手动移动视图
您可能仅将触摸/拖动视图用于替换。如中所示,有一个按钮可以启用“拖动模式”来替换它。只有当整个布局添加到窗口时,删除布局,只添加较小的非布局版本,这只是您的工具栏视图
不幸的是,这里没有简单的答案。这不是可访问性API想要做的事情。我也有义务提醒你,谷歌正在考虑的对无障碍服务的新期望几乎肯定会导致类似的无障碍服务在谷歌Play商店中被删除/不允许。非常感谢你的工作。但我仍然面临一个问题,即如果覆盖是全屏的,那么另一个窗口将不接收触摸事件。。请检查此项并尝试解决此问题此答案很好,但忽略了基本问题,即这是在一个可访问性服务中发生的,该服务有特殊考虑。@SanjuBaghla:抱歉,我错过了这一时刻@CHRISM是对的,这将很难实现。由于重叠超出了可访问性服务
主题,我认为,您应该发布另一个问题或搜索现有的解决方案。
@Override
protected void onServiceConnected() {
// Create an overlay and display the action bar
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
lp.type = WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
lp.format = PixelFormat.TRANSLUCENT;
lp.flags |= WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
lp.width = WindowManager.LayoutParams.WRAP_CONTENT;
lp.height = WindowManager.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.TOP;
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
}
<?xml version="1.0" encoding="utf-8"?>
<your.package.name.DraggableLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/power"
android:layout_weight="1"
android:text="Power"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/volume_up"
android:text="Volume"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:layout_weight="1"
android:id="@+id/scroll"
android:text="Scroll"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<Button
android:id="@+id/swipe"
android:text="Swipe"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</your.package.name.DraggableLayout>
public class DraggableLayout extends LinearLayout implements View.OnDragListener {
GestureDetector mLongClickDetector;
Point mPickPoint;
public DraggableLayout(Context context) {
this(context, null, 0);
}
public DraggableLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public DraggableLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// When user performs a long press, we begin dragging
mLongClickDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
public void onLongPress(MotionEvent e) {
mPickPoint = new Point((int) e.getX(), (int) e.getY());
View.DragShadowBuilder shadowBuilder = new View.DragShadowBuilder(DraggableLayout.this) {
@Override
public void onProvideShadowMetrics(Point outShadowSize, Point outShadowTouchPoint) {
outShadowSize.set(getWidth(), getHeight());
outShadowTouchPoint.set(mPickPoint.x, mPickPoint.y);
}
};
startDrag(null, shadowBuilder, null, 0);
}
});
}
@Override
protected void onAttachedToWindow() {
// We should register this class as OnDragListener to parent view to catch DROP events from it
((ViewGroup) getParent()).setOnDragListener(this);
super.onAttachedToWindow();
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
//This is also an important point: we must intercept touch events before the child elements (Buttons and so on)
return mLongClickDetector.onTouchEvent(ev);
}
@Override
public boolean onDragEvent(DragEvent event) {
if (event.getAction() == DragEvent.ACTION_DROP) {
// And when user performs drop we change position of view
setX(event.getX() - mPickPoint.x);
setY(event.getY() - mPickPoint.y);
return true;
}
return false;
}
@Override
public boolean onDrag(View v, DragEvent event) {
return onDragEvent(event);
}
}
@Override
protected void onServiceConnected() {
// Create an overlay and display the action bar
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
mLayout = new FrameLayout(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.MATCH_PARENT, // Overlay must be full screen otherwise my trick will not work
WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, // Allow another windows to receive touch events
PixelFormat.TRANSLUCENT);
LayoutInflater inflater = LayoutInflater.from(this);
inflater.inflate(R.layout.action_bar, mLayout);
wm.addView(mLayout, lp);
}