【Android】画面外からのスワイプを検知する【オーバーレイ】
オーバーレイを使ったアプリで、画面外からスワイプするとダイアログが表示されたりする機能ありますよね。
全く実装方法が分からなかったのですが、試行錯誤した結果一応それっぽいものができたので、記事にして残そうと思います。
・目標
スワイプを検知するためにタッチイベントを取得できるオーバーレイを表示し、タッチの始まった座標と、終了座標を比較して画面外からのスワイプならその旨をトーストで表示する。
・用意するクラス、レイアウト
・MainActivity.java
オーバーレイの表示、非表示を行う。
・MyService.java
オーバーレイの表示処理を行う。
・layout_main.xml
MainActivityのレイアウト。
・overlay.xml
タッチイベントを取得するオーバーレイ。
・layout_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/start" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="start" /> <Button android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="stop" /> </LinearLayout>
オーバーレイを表示、非表示するためのボタンを配置しただけの簡単なレイアウトです。
・MainActivity.java
public class MainActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.layout_main); Button start = (Button)findViewById(R.id.start); start.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v){ Intent intent = new Intent(MainActivity.this,MyService.class); MainActivity.this.startService(intent); } }); Button stop = (Button)findViewById(R.id.stop); stop.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v){ Intent intent = new Intent(MainActivity.this,MyService.class); MainActivity.this.stopService(intent); } }); } }
Startボタンをタッチすれば、オーバーレイを表示するサービスを実行し、Stopボタンをタッチで、サービスを停止します。
・overlay.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="fill_parent" > <RelativeLayout android:layout_width="5dp" android:layout_height="match_parent" android:background="#da0b00" > </RelativeLayout> </LinearLayout>
わかりやすいように、タッチを取得するオーバーレイの色は赤にしています。
・MyService.java
public class MyService extends Service{ private View v; private WindowManager wm; private float preX; @Override public int onStartCommand(Intent intent,int flags, int startId){ super.onStartCommand(intent, flags, startId); LayoutInflater inflater = LayoutInflater.from(this); wm = (WindowManager)getApplicationContext().getSystemService( Context.WINDOW_SERVICE); WindowManager.LayoutParams params = new WindowManager.LayoutParams( WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_ALERT, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_FULLSCREEN | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL, PixelFormat.TRANSLUCENT); params.gravity = Gravity.LEFT; v = inflater.inflate(R.layout.overlay, null); v.setOnTouchListener(new OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event) { if(event.getAction() == MotionEvent.ACTION_DOWN){ preX = event.getX(); } if(event.getAction() == MotionEvent.ACTION_UP){ if(preX < event.getX()){ Toast.makeText(MyService.this, "スワイプ", Toast.LENGTH_SHORT).show(); } } return false; } }); wm.addView(v, params); return START_STICKY; } @Override public void onDestroy(){ super.onDestroy(); wm.removeView(v); } @Override public IBinder onBind(Intent intent) { return null; } }
サービスが実行されると、オーバーレイのレイアウトを生成して表示します。
レイアウトにTouchListenerをセットし、タッチ座標を取得できるようにしています。
タッチが始まる座標と終わる座標を比較して画面外からのスワイプであれば、トーストで表示しています。
追記
service使うのでmanifestに記述するのをお忘れなく。