无法在Android上的自定义视图上启用辅助功能

时间:2016-06-09 00:14:53

标签: android accessibility

我尝试在名为MyCompass的自定义视图上启用辅助功能。指南针有两个值,风速和风向,如果启用了TalkBack和Explore By Touch,我希望当用户触摸指南针时大声读出它们。正如您在下面的代码中看到的,我将几个日志语句用于调试目的。我确实得到两者的输出如下。

 D/MyCompass: accessibility event sent
 D/MyCompass: populate with 0.36666667, 267.0

但是当我触摸MyCompass时,除了我在XML文件中的contentDescription中指定的内容之外,什么都不会被读出。 " @ string / compass"的值是"风速和风向",我的目标是在这些单词之后添加风速和风向的实际值。

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

这是代码。谢谢你的帮助。

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

}

3 个答案:

答案 0 :(得分:1)

您的问题很可能正在发生,因为您的自定义视图默认情况下无法关注,这是TalkBack的要求。您可以通过将属性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" />

以下是Android Documentation

中有关它的更多信息

答案 1 :(得分:1)

我终于找到了答案。为了使TalkBack在dispatchPopulateAccessibilityEvent()中读出动态添加的文本,我需要发送AccessibilityEvent.TYPE_VIEW_FOCUSED事件而不是AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED事件。

答案 2 :(得分:0)

简单地实施辅助功能事件,不会让Android大声读出。可访问性事件监视用户在辅助功能模式下如何与其设备进行交互。如果您希望以这种方式读出某些内容,则必须实现TextToSpeech