Can';t在Android上的自定义视图上启用辅助功能

Can';t在Android上的自定义视图上启用辅助功能,android,accessibility,Android,Accessibility,我正在尝试在名为MyCompass的自定义视图上启用可访问性功能。指南针有两个值,风速和方向,我希望当用户触摸指南针时,如果启用了对讲和触摸探索功能,可以大声读出它们。正如您在下面的代码中所看到的,为了调试的目的,我放置了两个日志语句。我确实从这两方面得到了如下输出 D/MyCompass: accessibility event sent D/MyCompass: populate with 0.36666667, 267.0 仅仅实现一个可访问性事件,并不能让Android大声读出它。辅助

我正在尝试在名为MyCompass的自定义视图上启用可访问性功能。指南针有两个值,风速和方向,我希望当用户触摸指南针时,如果启用了对讲和触摸探索功能,可以大声读出它们。正如您在下面的代码中所看到的,为了调试的目的,我放置了两个日志语句。我确实从这两方面得到了如下输出

D/MyCompass: accessibility event sent D/MyCompass: populate with 0.36666667, 267.0
仅仅实现一个可访问性事件,并不能让Android大声读出它。辅助功能事件监视用户如何在辅助功能模式下与其设备交互。如果您希望以这种方式读取某些内容,则必须实现

您的问题可能会发生,因为您的自定义视图在默认情况下不可聚焦,这是对讲的一个要求。您可以通过将属性
android:focusable
设置为true来解决此问题,如下所示:

<com.example.android.sunshine.app.MyCompass
android:layout_gravity="center_horizontal"
android:id="@+id/detail_wind_direction_compass"
android:layout_marginTop="4dp"
android:focusable="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />


这里有更多关于它的信息,我终于找到了答案。要使对讲读取dispatchPopulateAccessibilityEvent()中动态添加的文本,我需要发送AccessibilityEvent.TYPE\u VIEW\u聚焦事件,而不是AccessibilityEvent.TYPE\u VIEW\u text\u CHANGED事件

package com.example.android.sunshine.app;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.ShapeDrawable;
import android.graphics.drawable.shapes.OvalShape;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;

public class MyCompass extends View {
    private static final String LOG_TAG = MyCompass.class.getSimpleName();
    private static final int COMPASS_WIDTH = 400;
    private static final int COMPASS_HEIGHT = 400;
    private static final int MAX_HAND_LENGTH = 200;
    private static final int HAND_WIDTH = 10;
    private static final int COMPASS_RADIUS = MAX_HAND_LENGTH / 2;
    private static final float HAND_MAX_M_PER_SEC = 10;
    private static final float WIND_SPEED_GREEN = 4;
    private static final float WIND_SPEED_YELLOW = 6;
    private static final float WIND_SPEED_RED = 8;
    private static final int GREEN = 0xff00ff00;
    private static final int BLUE = 0xff0000ff;
    private static final int YELLOW = 0xffffff00;
    private static final int RED = 0xffff0000;
    private static final Paint BLUE_PAINT = new Paint();
    private static final Paint GREEN_PAINT = new Paint();
    private static final Paint YELLOW_PAINT = new Paint();
    private static final Paint RED_PAINT = new Paint();

    private ShapeDrawable mGreenCircle;
    private ShapeDrawable mYellowCircle;
    private ShapeDrawable mRedCircle;
    private float mDirection = 0;
    private float mSpeed = 0;
    private int centerX = COMPASS_WIDTH / 2;
    private int centerY = COMPASS_HEIGHT / 2;


    // for code
    public MyCompass(Context context) {
        super(context);
    }

    // for XML file
    public MyCompass(Context context, AttributeSet attrs) {
        super(context, attrs);

        BLUE_PAINT.setColor(BLUE);
        BLUE_PAINT.setStyle(Paint.Style.STROKE);
        BLUE_PAINT.setStrokeWidth(HAND_WIDTH);
        GREEN_PAINT.setColor(GREEN);
        YELLOW_PAINT.setColor(YELLOW);
        RED_PAINT.setColor(RED);

        mGreenCircle = new ShapeDrawable(new OvalShape());
        mYellowCircle = new ShapeDrawable(new OvalShape());
        mRedCircle = new ShapeDrawable(new OvalShape());
        drawCircle(mGreenCircle, Math.round(MAX_HAND_LENGTH / HAND_MAX_M_PER_SEC * WIND_SPEED_GREEN), GREEN);
        drawCircle(mYellowCircle, Math.round(MAX_HAND_LENGTH / HAND_MAX_M_PER_SEC * WIND_SPEED_YELLOW), YELLOW);
        drawCircle(mRedCircle, Math.round(MAX_HAND_LENGTH / HAND_MAX_M_PER_SEC * WIND_SPEED_RED), RED);

    }

    private void drawCircle(ShapeDrawable drawable, int radius, int color) {
        drawable.getPaint().setColor(color);
        drawable.setBounds(centerX - radius, centerY - radius, centerX + radius, centerY + radius);
    }

    // for inflation
    public MyCompass(Context context, AttributeSet attrs, int defaultStyle) {
        super(context, attrs, defaultStyle);
    }

    // speed is in km/h
    public void setDirectionAndSpeed(float direction, float speed) {
        mDirection = direction;
        mSpeed = speed * 1000 / 3600; // convert km/h to m/s
        MyCompass compass = (MyCompass) findViewById(R.id.detail_wind_direction_compass);
        //compass.setContentDescription(compass.getContentDescription() + " is " + mSpeed + " m/s at " + mDirection);


        Context context = getContext();
        AccessibilityManager accessibilityManager =
            (AccessibilityManager) context.getSystemService(
                Context.ACCESSIBILITY_SERVICE);
        if (accessibilityManager.isEnabled()) {
            sendAccessibilityEvent(
                AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED);
            Log.d(LOG_TAG, "accessibility event sent");
        }

        invalidate();
    }

    @Override
    protected void onMeasure(int wMeasureSpec, int hMeasureSpec) {
        int wSpecMode = MeasureSpec.getMode(wMeasureSpec);
        int wSpecSize = MeasureSpec.getSize(wMeasureSpec);
        int myWidth = wSpecSize;

        int hSpecMode = MeasureSpec.getMode(hMeasureSpec);
        int hSpecSize = MeasureSpec.getSize(hMeasureSpec);
        int myHeight = hSpecSize;

        if (wSpecMode == MeasureSpec.EXACTLY) {
            myWidth = wSpecSize;
        } else if (wSpecMode == MeasureSpec.AT_MOST || wSpecMode == MeasureSpec.UNSPECIFIED) {
            // Wrap Content
            myWidth = COMPASS_WIDTH;
        }

        if (hSpecMode == MeasureSpec.EXACTLY) {
            myHeight = hSpecSize;
        } else if (hSpecMode == MeasureSpec.AT_MOST || hSpecMode == MeasureSpec.UNSPECIFIED) {
            // Wrap Content
            myHeight = COMPASS_HEIGHT;
        }
        setMeasuredDimension(myWidth, myHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        mRedCircle.draw(canvas);
        mYellowCircle.draw(canvas);
        mGreenCircle.draw(canvas);
        int handLength = (int) (mSpeed / HAND_MAX_M_PER_SEC * MAX_HAND_LENGTH);
        canvas.drawLine(
                centerX,
                centerY,
                (float) (centerX + handLength * Math.sin(mDirection / 180 * Math.PI)),
                (float) (centerY - handLength * Math.cos(mDirection / 180 * Math.PI)),
                BLUE_PAINT
        );

    }

    @Override
    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent ev) {
        super.dispatchPopulateAccessibilityEvent(ev);
        if (ev.getEventType() == AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED) {
            Log.d(LOG_TAG, "populate with " + mSpeed + ", " + mDirection);
            ev.getText().add(String.valueOf(mSpeed) + " m/s from " + String.valueOf(mDirection));
        }

        return true;
    }

}
<com.example.android.sunshine.app.MyCompass
android:layout_gravity="center_horizontal"
android:id="@+id/detail_wind_direction_compass"
android:layout_marginTop="4dp"
android:focusable="true"
android:layout_height="wrap_content"
android:layout_width="wrap_content" />