Главная » Разработка для Android » Создание компаса и автогоризонта

0

В главе 4 вы разработали простой элемент CompassView, чтобы поэкспе- риментировать с созданием  собственных  графических элементов.  В этом примере1  вы расширите  возможности CompassView,  сначала  научив  его показывать  параметры  pitch и roll, а затем и положение  устройства  в про- странстве.

1. Откройте проект Compass, созданный  при изучении  главы 4. Нужно внести некоторые изменения в элемент CompassView, а также в Актив- ность Compass, в которой он размещен. Чтобы обеспечить максималь- ную независимость логики от представления, элемент CompassView

1     Все фрагменты  кода в этом примере  — часть проекта  Artificial Horizon  из главы 14, их можно загрузить с сайта Wrox.com.

не будет взаимодействовать с датчиками  напрямую.  Вместо этого он будет обновляться из Активности. Начните  с добавления  в класс CompassView полей и геттеров/сеттеров для параметров pitch и roll.

float pitch = 0;

float roll = 0;

public float getPitch() {

return pitch;

}

public void setPitch(float pitch) {

this.pitch = pitch;

}

public float getRoll() {

return roll;

}

public void setRoll(float roll) {

this.roll = roll;

}

2. Обновите метод onDraw, нарисовав с его помощью две окружности, ко- торые будут использоваться для отображения значений  pitch и roll.

@Override

protected void onDraw(Canvas canvas) { [ … Ранее написанный код … ]

2.1.Создайте  новую окружность,  закрашенную  наполовину,  которая

вращается в соответствии с боковым наклоном (roll).

RectF rollOval = new RectF((mMeasuredWidth/3)-mMeasuredWidth/7, (mMeasuredHeight/2)-mMeasuredWidth/7, (mMeasuredWidth/3)+mMeasuredWidth/7, (mMeasuredHeight/2)+mMeasuredWidth/7

); markerPaint.setStyle(Paint.Style.STROKE); canvas.drawOval(rollOval, markerPaint); markerPaint.setStyle(Paint.Style.FILL); canvas.save();

canvas.rotate(roll, mMeasuredWidth/3, mMeasuredHeight/2);

canvas.drawArc(rollOval, 0, 180, false, markerPaint);

canvas.restore();

2.2.Создайте еще одну окружность, которая в состоянии покоя закра- шена наполовину и, в зависимости от изменений параметра pitch, может быть как пустой, так и полностью закрашенной:

RectF pitchOval = new RectF((2*mMeasuredWidth/3)-mMeasuredWidth/7, (mMeasuredHeight/2)-mMeasuredWidth/7, (2*mMeasuredWidth/3)+mMeasuredWidth/7, (mMeasuredHeight/2)+mMeasuredWidth/7

);

markerPaint.setStyle(Paint.Style.STROKE); canvas.drawOval(pitchOval, markerPaint); markerPaint.setStyle(Paint.Style.FILL);

canvas.drawArc(pitchOval, 0-pitch/2, 180+(pitch), false, markerPaint);

markerPaint.setStyle(Paint.Style.STROKE);

}

3. На этом процесс внесения  изменений в класс CompassView  можно считать завершенным. Если теперь запустить приложение, оно должно выглядеть, как на рис. 14.4.

Рис. 14.4.

4. Теперь  перейдите  к Активности Compass. Для  отслеживания поло- жения  устройства  в пространстве  с помощью датчика  магнитного поля  и акселерометра используйте объект  SensorManager. Спер- ва добавьте поля для хранения последних зафиксированных по- казаний  этих датчиков,  а также ссылки  на объекты  CompassView и SensorManager.

float[] aValues = new float[3]; float[] mValues = new float[3]; CompassView compassView; SensorManager sensorManager;

5. Создайте  новый метод updateOrientation, который использует  акту- альный азимут, а также значения pitch и roll для обновления элемента CompassView.

private void updateOrientation(float[] values) {

if (compassView!= null) { compassView.setBearing(values[0]); compassView.setPitch(values[1]); compassView.setRoll(-values[2]); compassView.invalidate();

}

}

6. Обновите  метод onCreate, чтобы получить  ссылки на объекты Com- passView и SensorManager, инициализировав азимут и значения pitch и roll.

@Override

public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);

compassView = (CompassView)this.findViewById(R.id.compassView);

sensorManager = (SensorManager)getSystemService(Context.SENSOR_ SERVICE);

updateOrientation(new float[] {0, 0, 0});

}

7. Создайте новый метод calculateOrientation для вычисления положе- ния устройства в пространстве, используя поля, хранящие последние записанные  показания акселерометра и датчика магнитного поля.

private float[] calculateOrientation() {

float[] values = new float[3];

float[] R = new float[9];

SensorManager.getRotationMatrix(R, null, aValues, mValues); SensorManager.getOrientation(R, values);

// Преобразуйте радианы в градусы.

values[0] = (float) Math.toDegrees(values[0]); values[1] = (float) Math.toDegrees(values[1]); values[2] = (float) Math.toDegrees(values[2]);

return values;

}

8. Реализуйте интерфейс SensorEventListener в виде поля. Внутри  об- работчика onSensorChanged нужно проверить тип датчика и обновить поля, хранящие последние показания акселерометра или датчика маг- нитного поля, прежде чем вызвать метод updateOrientation с помощью calculateOrientation.

private final SensorEventListener sensorEventListener = new

SensorEventListener() {

public void onSensorChanged(SensorEvent event) {

if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER)

aValues = event.values;

if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)

mValues = event.values;

updateOrientation(calculateOrientation());

}

public void onAccuracyChanged(Sensor sensor, int accuracy) {}

};

9. Теперь переопределите обработчики onResume и onStop, чтобы реги- стрировать и отменять регистрацию SensorEventListener, когда Актив- ность становится видимой или скрывается.

@Override

protected void onResume()

{

super.onResume();

Sensor accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ ACCELEROMETER);

Sensor magField = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_

FIELD);

sensorManager.registerListener(sensorEventListener, accelerometer, SensorManager.SENSOR_DELAY_FASTEST);

sensorManager.registerListener(sensorEventListener, magField, SensorManager.SENSOR_DELAY_FASTEST);

}

@Override

protected void onStop()

{

sensorManager.unregisterListener(sensorEventListener);

super.onStop();

}

Запустив приложение, вы должны увидеть три индикатора, которые динамически обновляются при изменении положения устройства в пространстве.

10. Автогоризонт  более полезен  в вертикальном положении. Для этого необходимо изменить систему отсчета автогоризонта, обновив метод calculateOrientation, в котором должна  преобразовываться система координат.

private float[] calculateOrientation() {

float[] values = new float[3]; float[] R = new float[9]; float[] outR = new float[9];

SensorManager.getRotationMatrix(R, null, aValues, mValues); SensorManager.remapCoordinateSystem(R,

SensorManager.AXIS_X,

SensorManager.AXIS_Z, outR);

SensorManager.getOrientation(outR, values);

// Преобразуйте радианы в градусы.

values[0] = (float) Math.toDegrees(values[0]); values[1] = (float) Math.toDegrees(values[1]); values[2] = (float) Math.toDegrees(values[2]);

return values;

}

Источник: Майер P. Android 2 : программирование приложений для планшетных компьютеров и смартфонов : [пер. с англ. ] / Рето Майер. — М. : Эксмо, 2011. — 672 с. — (Мировой компьютерный бестселлер).

По теме:

  • Комментарии