Android
 Computer >> コンピューター >  >> システム >> Android

Androidの可視性リスナー(Visibility Listener)の使い方と導入すべき理由

AndroidのUIはViewを組み合わせて構築されており、通常のアプリケーションには複数のViewが存在します。ユーザーが現在どのViewを見ているのかを把握するには、可視性リスナー(Visibility Listeners)を実装する必要があります。

この記事では、Viewの表示状態を検知するためのさまざまな手法について詳しく解説します。

Viewを画面に表示させる方法

リスナーを正しく機能させるには、まず対象のViewがレイアウト階層内に存在していることを確認する必要があります。これには2つの方法があります。

  1. XMLファイルで定義されたレイアウトに、あらかじめViewが組み込まれている
  2. 動的にViewを作成し、addViewメソッドを使って追加する
public void addView (View child, ViewGroup.LayoutParams params)

childは追加したいView、LayoutParamsはレイアウトパラメータ(幅や高さなど)を表します。

Viewの可視性ステータスはInteger型で、以下の3つの値のいずれかを取ります。

  1. VISIBLE(0):ユーザーに対してViewが表示されている状態
  2. INVISIBLE(4):ユーザーには見えないものの、レイアウト上のスペースは占有している状態
  3. GONE(8):Viewが非表示であり、レイアウト上のスペースも一切占有しない状態

Viewがレイアウト階層に組み込まれた後は、可視性が変化したタイミングを検知するためのネイティブな仕組みがいくつか用意されています。

onVisibilityChanged

protected void onVisibilityChanged (View changedView, int visibility)

このメソッドは、そのView自身または祖先ビュー(親ビュー)の可視性が変化した際に呼び出されます。変化後の可視性ステータスは、visibility引数から取得できます。

onWindowVisibilityChanged

protected void onWindowVisibilityChanged (int visibility)

このメソッドは、Viewが属するウィンドウ自体の可視性が変化した際に呼び出されます。ただし、このメソッドが呼ばれても、そのウィンドウが実際にユーザーから見えているとは限りません。別のウィンドウに隠れている可能性があるためです。

可視性リスナーの実践例

これら2つのリスナーの動作を確認するために、シンプルなプロジェクトを作成してみましょう。LinearLayoutの中にTextViewとボタンを配置し、ボタンをクリックするとカスタムビューがレイアウトに追加される構成です。

Androidの可視性リスナー(Visibility Listener)の使い方と導入すべき理由

カスタムビューのコードは以下の通りです。

package com.tomerpacific.viewvisibility;

import android.content.Context;
import android.graphics.Color;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import static android.view.Gravity.CENTER;

public class MyCustomView extends LinearLayout {

    private final String TAG = MyCustomView.class.getSimpleName();

    public MyCustomView(Context context) {
        super(context);
        this.setBackgroundColor(Color.GREEN);
        this.setGravity(CENTER);
        TextView myTextView = new TextView(context);
        myTextView.setText("My Custom View");
        addView(myTextView);
    }

    @Override
    public void onVisibilityChanged(View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);

        Log.d(TAG, "View " + changedView + " changed visibility to " + visibility);
    }

    @Override
    public void onWindowVisibilityChanged(int visibility) {
        super.onWindowVisibilityChanged(visibility);

        Log.d(TAG, "Window visibility changed to " + visibility);
    }

}

続いて、MainActivityのコードです。

package com.tomerpacific.viewvisibility;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

public class MainActivity extends AppCompatActivity {

    private Button addCustomViewBtn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        addCustomViewBtn = (Button) findViewById(R.id.addCustomViewBtn);

        addCustomViewBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                LinearLayout mainLayout = (LinearLayout) findViewById(R.id.mainLayout);
                MyCustomView myCustomView = new MyCustomView(getApplicationContext());
                myCustomView.setLayoutParams(new LinearLayout.LayoutParams(
                    LinearLayout.LayoutParams.MATCH_PARENT, 
                    LinearLayout.LayoutParams.WRAP_CONTENT));

                mainLayout.addView(myCustomView);
            }
        });
    }
}

ここではボタンにOnClickListenerをアタッチしています。

アプリを実行してボタンを押すと、次のような挙動になります。

https://giphy.com/gifs/8JZA6Djt7DmYpEXj2h/html5

サンプルプロジェクトはこちらから入手できます。

ViewTreeObserverを活用する

ViewTreeObserverは、ビューツリーにおけるさまざまな可視性の変化を通知する多数のリスナーを持つネイティブオブジェクトです。特に注目すべきリスナーとして、以下の3つが挙げられます。

  • OnGlobalLayoutListener
  • OnWindowAttachListener
  • OnWindowFocusChangeListener

ViewTreeObserverをアタッチするには、以下のように記述します。

LinearLayout linearLayout = (LinearLayout) findViewById(R.id.YOUR_VIEW_ID);

ViewTreeObserver viewTreeObserver = linearLayout.getViewTreeObserver(); 
viewTreeObserver.addOnGlobalLayoutListener (new ViewTreeObserver.OnGlobalLayoutListener() { 
    
    @Override 
    public void onGlobalLayout() {
        linearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this); 
        //TODO Add Logic
    } 
});

removeOnGlobalLayoutListenerを使用するにはAPI 15超(16以上)が必要です。

コード中の linearLayout.getViewTreeObserver().removeOnGlobalLayoutListener(this) の行によって、リスナーが一度だけ呼び出されることが保証されます。継続的に変更を監視したい場合は、この行を削除してください。

ご意見やご提案があれば、お気軽にお寄せください。

  1. Safariでプライベートブラウジングを使う理由と設定方法を徹底解説

    macOSの標準ブラウザであるSafariは、近年のWebブラウザと同様に高度に進化しており、高いセキュリティ性を備え、複数のタブも快適に同時処理できます。さらに、Safariには「プライベートブラウジング」モードが搭載されており、閲覧履歴を残さずにこっそりとWebを利用することが可能です。 MacのSafariでプライベートブラウジングを活用する理由は数多くあります。この記事では、プライベートブラウジングとは何か、Macでどのように使えば安全で機密性の高いブラウジング体験を実現できるのかを詳しく解説します。 サイバー犯罪が増加している現代において、プライベートブラウジングは個人情報を守り、悪

  2. 個人用リマインダーアプリの使い方と活用すべき理由

    「えっ、まさか!完全に忘れてた!」 この言葉、私が一日に何度も口にするフレーズです。物忘れが多いからですが、脳や健康に問題があるわけではなく、現代社会があまりにもスピーディーに動いていることが原因だと気づきました。やることは山ほどあり、会うべき人もたくさんいて、Netflixで観たい作品も次々と追加される――こんな環境では、何かを忘れてしまうのも無理はありません。 後回しにしても問題ないこともあれば、絶対に忘れてはいけない重要なこともあります。その代表格が「薬の服用時間」です。ほかにも、在宅勤務中のオンライン会議などは見逃せません。薬や通院予定の管理には、Systweakの「Medicine