常に前面に表示されるビュー

もしビューを他のアプリ起動中でも前面に表示したい場合はWindowManagerクラスを使います。

このクラスを使うとAndroid端末で画面表示に関わっているレイヤーを操作することができ、ビューの優先度を高めていつでもビューを表示することが可能になります。

手順は次の通りです。

  1. 常時表示するビューのレイアウト
  2. ビューを常に表示するためにサービス(Service)クラスを作る
  3. マニュフェストに権限を追加する。
  4. アクティビティ側からそのサービスを呼び出す。

常時表示するビューのレイアウト

例として画面上に最優先で表示したいビューとして次のレイアウトを作りました。

always_show_view.xml
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" >

    <Button
        android:id="@+id/close_button" 
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:text="Click!" 
        android:textSize="25sp" />

</LinearLayout>

画面中央にボタンが1つあるだけのシンプルなレイアウトです。

ビューを常時表示するサービスクラスを作る

ここではアプリが閉じられたとしてもビューを表示し続けたいのでServiceクラスからWindowManagerで表示したいビューを操作します。

例として次のようなサービスを作ってみます。

AlwaysViewService.java
/*プレイヤーを画面上に浮き上がらせて表示するためのサービス*/
public class AlawaysViewService > extends Service 
{
    View player_view;
        //画面に全面表示させるビュー
    WindowManager wm;
    
    @Override
    public void onCreate()
    {
        super.onCreate();
    }
    
    @Override
    public void onStart(Intent intent, int startId)
    {
        super.onStart(intent, startId);
        LayoutInflater inflater = LayoutInflater.from(this);
        
        //画面に常に表示するビューのレイアウトの設定
        WindowManager.LayoutParams params 
        = new WindowManager.LayoutParams(
            WindowManager.LayoutParams.MATCH_PARENT,
            WindowManager.LayoutParams.WRAP_CONTENT,
            0, 80,
            WindowManager.LayoutParams.TYPE_SYSTEM_ALERT,
            WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
            PixelFormat.TRANSLUCENT);
        wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
        player_view = inflater.inflate(R.layout.always_show_view, null);
            //レイヤーに重ねたいビュー
        
        final Button closeButton 
            = (Button) player_view.findViewById(R.id.closeButton);
        closeButton.setOnClickListener(new View.OnClickListener() 
        {
            @Override
            public void onClick(View v) 
            {
                onDestroy();
            }
        });
        
        wm.addView(player_view, params);
            //レイヤーにビューを重ねる。
    }
    
    @Override
    public void onDestroy()
    {
        super.onDestroy();
        
        wm.removeView(player_view);
            //ビューをレイヤーから削除する
    }
    
    @Override
    public IBinder onBind(Intent intent) 
    {
        return null;
    }

}

WindowManager.LayoutParamsの5番目の引数にはウインドウの種類を、6番目の引数にはウインドウがフォーカスが受け取れるかなどのフラグを設定します。

ウインドウのタイプについてはリファレンスでのWindowManager.LayoutParams#typeのページ、フラグについてはWindowManager.LayoutParams#flagsのページに詳しい説明が書いてあります。

マニフェストに権限を追加する

WindowManagerでレイヤーを操作するには権限が必要です。

また、サービスクラスも使っているのでまとめて次のようにAndroidManifest.xmlに権限を追加します。

        </activity>
        <service android:name=".AlwaysViewService" />
            <!-- サービスクラスを追加 -->
    </application>
    
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
        <!-- 追加 -->
    
</manifest>

アクティビティからサービスを呼び出す。

最後にアクティビティ側からサービスを次のように呼び出します。

MainActivity.java
public class MainActivity extends FragmentActivity 
{
    
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        startService(new Intent(this, AlwaysViewService.class));
    }

これで画面上にビューが表示されます。

アプリが閉じられたとしてもビューは次のように常に画面上に表示されます。

上の画像ではアプリ一覧の中にボタンが表示されていますがボタンが全体のフォーカスを奪ってしまうことはないように設定してあります。

なのでボタンとボタン外の部分の両方ともクリックできるようになっています。

ただ全面表示させるビューが全体のフォーカスを奪ってしまうと端末が操作不可能になることがあるので取扱いには注意が必要です。

関連項目
プライバシーポリシー