2014-02-05 2 views
6

말하기 "ok glass"라고 말하면 사용자의 머리 동작에 따라 자동으로 스크롤되는 명령 목록이 나타납니다.머리 움직임으로 스크롤하는 내장 ScrollView

이것을 구현하는 GDK에 기본 제공 UI 요소가 있습니까? 아니면 센서를 사용하는 자체 코드를 작성해야합니까?

답변

1

사실 (센서를 사용하여 목록을 스크롤에 대한 기본 GDK UI 요소가 현재 없습니다 : 그것은 구글의 하나처럼 반짝 아니지만, 그 시작점이 될 수 있습니다 , 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); 
} 

이 또한 투명하여보기에서 선택 표시를 제거는.

위의 컨트롤러는 두 손가락을 사용하여 스크롤을 일시 중지/다시 시작하고 두 손가락을 사용하여 목록의 맨 위로 스크롤하여 소리와 함께 두 동작을 모두 인식합니다.

이 솔루션에 대한 전체 소스 코드를 on Github 볼 수 있고, APK가 here을 다운로드 할 수 있습니다
@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; 
} 

: 이러한 제스처가 작동하려면, 당신은 당신의 활동에 onGenericMotionEvent()을 무시하고 같은 이벤트를 통과 할 필요가 있습니다 .