说“ok glass”会显示一个命令列表,根据用户的头部动作自动滚动。
GDK中是否有内置的UI元素来实现这一点?或者我是否必须编写自己的使用传感器的代码?
答案 0 :(得分:2)
我尝试重新实现部分内容。它并不像谷歌那样闪亮,但这些可以作为一个起点:
https://github.com/pscholl/glass_snippets/blob/master/lib/src/main/java/de/tud/ess/HeadListView.java https://github.com/pscholl/glass_snippets/blob/master/lib/src/main/java/de/tud/ess/HeadScrollView.java
答案 1 :(得分:1)
我在https://developers.google.com/glass/develop/gdk/dev-guides浏览了GDK的开发人员指南,在https://developers.google.com/glass/develop/gdk/reference/index浏览了参考资料,从2013年12月发布的XE 12开始,GDK中肯定没有这样的内置UI元素。
所以现在的答案是肯定的,你必须使用传感器来实现它。
答案 2 :(得分:1)
目前没有使用传感器滚动列表的原生GDK UI元素(事实上,根据this issue,似乎不鼓励使用ListView
。)
但是,我能够在my app中合理地完成以下工作。我的列表固定为4个元素(这有助于确定滚动发生了多少),因此您可以相应地调整它(请参阅注释)。
import com.google.android.glass.media.Sounds;
import com.google.android.glass.touchpad.Gesture;
import com.google.android.glass.touchpad.GestureDetector;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.view.MotionEvent;
import android.widget.ListView;
/**
* Implements sensor-based scrolling of a ListView
*/
public class SensorListController implements SensorEventListener, GestureDetector.BaseListener {
static final String TAG = "SensorListController";
Context mContext;
ListView mList;
SensorManager mSensorManager;
private float[] mRotationMatrix = new float[16];
private float[] mOrientation = new float[9];
private float[] history = new float[2];
private float mHeading;
private float mPitch;
boolean mActive = true;
GestureDetector mGestureDetector;
public SensorListController(Context context, ListView list) {
this.mContext = context;
this.mList = list;
history[0] = 10;
history[1] = 10;
mGestureDetector = new GestureDetector(mContext);
mGestureDetector.setBaseListener(this);
}
/**
* Receive pass-through of event from View
*/
public boolean onMotionEvent(MotionEvent event) {
return mGestureDetector.onMotionEvent(event);
}
@Override
public boolean onGesture(Gesture gesture) {
switch (gesture) {
case TWO_LONG_PRESS:
// Toggle on and off accelerometer control of the list by long press
playSuccessSound();
toggleActive();
return true;
case TWO_TAP:
// Go to top of the list
playSuccessSound();
scrollToTop();
return true;
}
return false;
}
/**
* Should be called from the onResume() of Activity
*/
public void onResume() {
mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR),
SensorManager.SENSOR_DELAY_UI);
}
/**
* Should be called from the onPause() of Activity
*/
public void onPause() {
mSensorManager.unregisterListener(this);
}
/**
* Toggles whether the controller modifies the view
*/
public void toggleActive() {
mActive = !mActive;
}
@Override
public void onSensorChanged(SensorEvent event) {
if (mList == null || !mActive) {
return;
}
if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) {
SensorManager.getRotationMatrixFromVector(mRotationMatrix, event.values);
SensorManager.remapCoordinateSystem(mRotationMatrix, SensorManager.AXIS_X,
SensorManager.AXIS_Z, mRotationMatrix);
SensorManager.getOrientation(mRotationMatrix, mOrientation);
mHeading = (float) Math.toDegrees(mOrientation[0]);
mPitch = (float) Math.toDegrees(mOrientation[1]);
float xDelta = history[0] - mHeading; // Currently unused
float yDelta = history[1] - mPitch;
history[0] = mHeading;
history[1] = mPitch;
float Y_DELTA_THRESHOLD = 0.13f;
// Log.d(TAG, "Y Delta = " + yDelta);
int scrollHeight = mList.getHeight()
/ 19; // 4 items per page, scroll almost 1/5 an item
// Log.d(TAG, "ScrollHeight = " + scrollHeight);
if (yDelta > Y_DELTA_THRESHOLD) {
// Log.d(TAG, "Detected change in pitch up...");
mList.smoothScrollBy(-scrollHeight, 0);
} else if (yDelta < -Y_DELTA_THRESHOLD) {
// Log.d(TAG, "Detected change in pitch down...");
mList.smoothScrollBy(scrollHeight, 0);
}
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
private void scrollToTop() {
mList.smoothScrollToPosition(0);
}
private void playSuccessSound() {
// Play sound to acknowledge action
AudioManager audio = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
audio.playSoundEffect(Sounds.SUCCESS);
}
}
我在ListActivity
中使用了上述内容。我在onCreate()
初始化它,这是初始化它的方法:
private void initListController() {
mListView = getListView();
mListView.setChoiceMode(ListView.CHOICE_MODE_NONE);
mListView.setSelector(android.R.color.transparent);
mListView.setClickable(true);
mListController = new SensorListController(this, mListView);
}
这也会使选择指标从视图中删除,使其变得透明。
上述控制器还使用两个手指按下来暂停/恢复滚动,并用两个手指点击滚动到列表顶部(并用声音确认这两个动作)。请注意,要使这些手势生效,您需要覆盖活动中的onGenericMotionEvent()
并传递事件,例如:
@Override
public boolean onGenericMotionEvent(MotionEvent event) {
// We need to pass events through to the list controller
if (mListController != null) {
return mListController.onMotionEvent(event);
}
return false;
}