Help us understand the problem. What is going on with this article?

[Android]Screen に Viewが表示されたか判定する

はじめに

View が Screen に表示されたか判定する処理を作成します。例えば Player が Screen に表示されたら動画の再生を開始したい、TextView が表示されたらテキストカラーを変えたい、といった処理に使えるサンプルを作成してみたいと思います。

Feb-18-2020 00-47-23.gif

TL;DR

表示されたか判定する方法はシンプルです、 Screen の Rectと View の Rect を取得して、 Screen の Rectに View のRect が含まれているか判定するだけです。

1. Screen の範囲(Rect)を取得する

MainActivity.kt
private fun getScreenRect() : Rect {
    val displayMetrics = DisplayMetrics()
    windowManager.defaultDisplay.getMetrics(displayMetrics)
    return Rect(0, 0, displayMetrics.widthPixels,displayMetrics.heightPixels)
}

2. View の範囲(Rect)を取得する

MainActivity.kt
private fun View.getViewRect() : Rect {
    val array = IntArray(2)
    this.getLocationOnScreen(array)
    return Rect(this.width, this.height, array[0], array[1])
}

3. Screen に View に表示されているか判定する

MainActivity.kt
  scroll_view.viewTreeObserver.addOnScrollChangedListener {
    val screenRect = getScreenRect()

    val oneRect = one.getViewRect()
    if (screenRect.contains(oneRect)) {
      // 含まれているときの処理
    }
    else {
      // 含まれていないときの処理
    }

レイアウトの準備する

判定処理を記述するためにスクロールしなければスクリーンに表示できないようなレイアウトを作成します。ScrollView の中に TextView が3つ含まれているレイアウトを準備しておきましょう。

Feb-17-2020 21-54-33.gif

activity_main.xml
<ScrollView android:id="@+id/scroll_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <LinearLayout
        android:id="@+id/linear_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">
        <TextView
            android:id="@+id/one"
            android:layout_width="match_parent"
            android:layout_height="200dp"
            android:textAlignment="center"
            android:textSize="80sp"
            android:text="One" /></LinearLayout>
</ScrollView>

Screen の範囲(Rect)を取得する

Screen の位置(サイズ)は windowsManager.defaultDisplay.getMetrics()に取得できます。このgetMetricsで取得した幅と高さを利用して、Screen の範囲を示す Rect オブジェクトを作成しましょう。(ここで取得できるサイズは Pixel になります)

Screen no.png

MainActivity.kt
private fun getScreenRect() : Rect {
    val displayMetrics = DisplayMetrics()
    windowManager.defaultDisplay.getMetrics(displayMetrics)
    return Rect(0, 0, displayMetrics.widthPixels,displayMetrics.heightPixels)
}

View の範囲(Rect)を取得する

View の左上の座標をView.getLocationInWindowで取得できます。また View の高さと幅は View.widthView.heightで取得できます。これらの値を組み合わせて View が表示されている範囲を示す Rectオブジェクトを作成しましょう。(ここも取得できるサイズは Pixel になります)

Viewno.png

MainActivity.kt
private fun View.getViewRect() : Rect {
    val array = IntArray(2)
    this.getLocationOnScreen(array)
    return Rect(this.width, this.height, array[0], array[1])
}

Screen に View に表示されているか判定する

あとは ScrollView のスクロール位置が更新された時、Screen に View が表示されているか判定する処理を記述すれば完成となります。判定処理を記述する箇所は ScrollViewviewTreeObserveraddOnScrollChangedListenerになります。そこに Screen の範囲(Rect)に View の範囲(Rect)が含まれるか判定する処理を記述していきます。(含まれるか判定するには Rect の contains が便利です、含まているかそうでないかを Boolean で返すメソッドになります。)

Feb-18-2020 00-47-23.gif

MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val oneTextView = one
    val twoTextView = two
    val threeTextView = three

    scroll_view.viewTreeObserver.addOnScrollChangedListener {
        val screenRect = getScreenRect()

        val oneRect = one.getViewRect()
        val oneColor = if (screenRect.contains(oneRect)) {
            Color.RED
        } else {
            Color.WHITE
        }
        oneTextView.setBackgroundColor(oneColor)

        val twoRect = twoTextView.getViewRect()
        val twoColor = if (screenRect.contains(twoRect)) {
            Color.RED
        } else {
            Color.WHITE
        }
        twoTextView.setBackgroundColor(twoColor)

        val threeRect = threeTextView.getViewRect()
        val threeColor = if (screenRect.contains(threeRect)) {
            Color.RED
        } else {
            Color.WHITE
        }
        threeTextView.setBackgroundColor(threeColor)
    }
}

参考文献

kaleidot725
組み込みエンジニア➔ Androidエンジニア プログラミングを続けたいがために Web 系へ
https://medium.com/kaleidot725
yumemi
みんなが知ってるあのサービス、実はゆめみが作ってます。スマホアプリ/Webサービスの企画・UX/UI設計、開発運用。Swift, Kotlin, PHP, Vue.js, React.js, Node.js, AWS等エンジニア・クリエイターの会社です。東京(三軒茶屋)/京都(四条烏丸)/札幌/大阪/福岡に展開中!Twitterで情報配信中https://twitter.com/yumemiinc
http://www.yumemi.co.jp
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした