簡體   English   中英

如何在“輔助功能服務”中制作ActionBar Movable

[英]How to make ActionBar Movable in “Accessibility Services”

我是主題“無障礙服務”的新手。我能夠滾動按鈕點擊,並能夠關閉手機和更多的東西,但我想讓我的布局(action_bar.xml)可移動所以,任何人都可以告訴我請如何使action_bar可移動

這是我的

action_bar.xml ::

<LinearLayout 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="@string/power"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
<Button
    android:id="@+id/volume_up"
    android:text="@string/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="@string/scroll"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>
<Button
    android:id="@+id/swipe"
    android:text="@string/swipe"
    android:layout_weight="1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"/>

和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();
    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);  
}

@fishbone的答案大多是正確的,除了可訪問性服務中的覆蓋不一樣的小部分。 當然,做出這個假設可以簡化事情,但最終卻是錯誤的。 可訪問性服務有一些非常重要的注意事項,並且在大多數情況下,它們的行為與活動完全相同,但Accessibility Services啟動疊加的方式非常重要,與大多數視圖的行為方式不同,尤其是它們攔截觸摸事件的方式。 你必須非常小心觸摸事件。 最終你希望視圖可以觸摸,但不是,占據整個窗口。 您可以使用的兩種類型是:

TYPE_ACCESSIBILITY_OVERLAY

要么

TYPE_APPLICATION_OVERLAY

這兩個表現相似,但不是。 如果您在實際視圖中遇到觸摸事件,后者可能會對您有所幫助。

核心問題是,WindowManager可用的布局參數只允許您完全攔截觸摸事件或根本不執行此操作。 對於這部分視圖,您不能這樣做,而不能為其他人這樣做。 嘗試將事件從窗口傳遞到您不擁有的窗口的邏輯...只是不去那里。

因此,您需要做的是沒有完整的布局視圖。 您必須將視圖添加為Touchable,但是您的視圖僅占用屏幕上實際必須覆蓋的部分。 這應該盡可能地盡可能小(因為觸摸事件將無法與這種觀點相提並論)。 然后,您必須執行自定義保持觸摸偵聽器,並執行觸摸和拖動邏輯以手動移動視圖。

您可以僅使用觸摸/拖動視圖進行更換。 如同,有一個按鈕,使“拖動模式”可以替換它。 並且只有在將整個布局添加到窗口時,刪除布局,然后添加只是工具欄視圖的較小的非布局版本。

不幸的是,這里沒有簡單的答案。 這不是Accessibility API要執行的操作。 我也有義務提醒您,谷歌正在考慮的對無障礙服務的新期望幾乎肯定會導致無障礙服務在Google Play商店中刪除/不允許這樣做。

疊加層的工作方式與ActivityFragment的常用View相同。 沒有魔法屬性如android:movable="true"可以使疊加層移動。 你應該自己做。 這是我的可移動View示例:

action_bar.xml (這里我用自定義DraggableLayout替換LinearLayout

<?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>

DraggableLayout.class

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);
    }
}

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);  
}

它似乎工作,如果不是那樣,請告訴我。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM