Kanade Labo

かなで研究所

Android Studio カメラアプリ作成その6(カメラ表示1)

こんにちは かなで です。

「カメラアプリを作る」ということに関して、いろんなサイトを調べたのですが、どのサイトもアプリ作成経験がある大前提の記載であり、そのまま読んでも全くわかりませんでした。

初心者中の初心者が、基礎を調べずカメラアプリを作ろうということ自体間違ってるのでしょう。

とは言え、そうなると意地でも作ってやろうという気持ちになります。

トライ&エラーを繰り返し、少しずつ変化していくエラー。

やっとのことで、「エミュレータ上でPCのカメラ映像を表示する。」というところまで漕ぎつけたので、記事にしたいと思います。

知ってる人からしてみたら、「そんなの当たり前じゃん」ということだったり、「それで今はたまたまうまく表示されたんだろうけど、完全に間違ってるし」というものだらけだと思いますので、そういう前提でお読みいただければと思います。

逆に、プログラミング経験なしのAndroid開発初心者1日目の人が、いきなり「カメラアプリのサンプルを作りたい」という場合は役に立つような記事にしたいと思いますので、よろしくお願いします。

前置きが長くなりましたが始めます。

結果的に基礎になったのは以下の公式サイトでした。

https://developer.android.com/training/camerax/preview?hl=ja

開いたときに選択されている、「プレビュー」の項目になります。

まずはこちら

import androidx.camera.camera2.Camera2Config
import androidx.camera.core.CameraXConfig

public class MyCameraXApplication : Application(),  CameraXConfig.Provider {
  override fun getCameraXConfig(): CameraXConfig {
    return Camera2Config.defaultConfig()
  }
}

CameraX が初期化されるタイミングを細かく制御するには、Application クラスに CameraXConfig.Provider インターフェースを実装します。ほとんどのアプリにこのレベルの管理は必要ありません。

ほとんどのアプリにこのレベルの管理は必要ありません。と書いてますが、プレビューするまでであれば、こちらの記載は必要ありませんでした。

実は後で少し戻ってくるのですが、今は次に進めます。

<FrameLayout
    android:id="@+id/container">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
</FrameLayout>

次は「PreviewViewをレイアウトに追加する」というやつです。

ここで全く知らない人からしたら、これをどこに書くのかわからないんです!

「app/res/layout/activity_main.html」こちらをダブルクリックで開きます。

このような画面が開くはずです。

一応横向きを標準で使おうと思ったので、向きを変えることにしました。

この「カメラ回転させますよ~」というアイコンをクリックして「Portrait」というものから「Landscape」に変更します。

こんな感じになりました。

次に、これは表示イメージ(デザインモード)ですが、こちらもコードで書かれているので、コードを表示します。

右上で「Design」となっているのがデザインモードなので、これを「Code」に変更します。

これがCodeに変更した後の画面です。

ここで注意すべきなのが、「赤文字」がないということです。

赤文字があると、アプリの実行まで行くことができません。

ここで赤枠の説明ですが、「<TextView」から始まり、「/>」で終わっています。

この部分が、「テキストを表示するもの」で、それに関する設定が入っています。

「android:text="Hello World!"」と書いてあるのを見るとわかる通り、ハローワールドを表示するテキストビューです。

先ほどの「<FrameLayout~」はこの後の赤矢印の部分に入れてみます。

<FrameLayout
    android:id="@+id/container">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
</FrameLayout>

「FrameLayout」と「androidx.camera.view.PreviewView」が赤くなっていますね。

つまりこのままでは実行できないことを示します。これを解決するために一旦赤字を右クリックします。

そして、「コンテキストアクションの表示」をクリックします。

「必須属性 android:layout_height を挿入する」をはじめ、複数の記述が表示されていますね。

今回のFrameLayoutだと、「必須属性」と書いている、「android:layout_height」と「android:layout:witdh」がないことで、赤字(問題)となっているようです。

試しに一番上を押してみます。

    <FrameLayout
        android:id="@+id/container" android:layout_height="">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
    </FrameLayout>

このように表示されました。

じゃあ次の必須属性も同じように追加してみよう と「コンテキストアクションを表示」を押しても無反応です。

ここで、再度先ほどの画像に戻りますが、

追加した奴に、何やらマーク?がついてます。

イメージとしては「android:layout_heightという項目は追加したけど、その値は空っぽ「""でくくられてる中身がない」だよ。という事だと思います。

適当に「100」と入れてみると、単位が表示されました。

後で答え?が出てきますが、ここではpxで入れてみます。

なんだか黄色い背景になってしまいました。

これにカーソルを合わせます。

Avoid using "px" as units; use "dp" instead
「px」を単位として使用することは避けてください。代わりに「dp」を使用してください
Convert to "dp"...  、 その他のアクション

だそうです。ここで「Convert to "dp"」を押すと…

What is the sceen density the current px value works with?
現在のpx値が機能するシーン密度はどれくらいですか?

そんなこと聞かれてもわかりません。適当にそのまま「OK」を押します。

無事黄色網掛けはなくなりました。

改めて、「コンテキストアクションの表示」を押すと

なんか減りましたね。続けて「必須属性 android:layout_width を挿入する」をクリック

    <FrameLayout
        android:id="@+id/container" android:layout_height="100dp" android:layout_width="100dp">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
    </FrameLayout>

そして、同様に「100dp」と入れてみると、「FrameLayout」の文字の赤色じゃなくなりました。

一つ解決です。

横一列に並んでたので、改行してみました。特に問題はありませんでした。

ちょっと補足説明ですが、

ウィンドウ左下にある「問題」をクリックすると、今開いているファイルの問題点を指摘する一覧が表示されます。

「activity_main.xml」には3件の問題があって
・This view is not constrained. It only has designtime positions, so it will jump to (0,0) at runtime unless you add the constraints(18行目)
・Class referenced in the layout file, androidx.camera.view.PreviewView, was not found in the project or the libraries(22行目)
・Cannot resolve class androidx.camera.view.PreviewView(22行目)
という風に読むことができます。

はい!突然ですが、ここで一旦「FrameLayout」の記載を全部削除してみます。

「問題はありません」と表示されました。

問題がある行数を見てもわかりますが、追加記述に問題があるということですね。

この画面(問題ビューと呼ぼう)は、トライ&エラーの際にずっと使っていたものになりますので、ちょくちょく出てきますので、毎回の説明は省略します。

それでは、先ほどのFrameLayoutを使わず、別の方法を試したいと思います。

デザインモードに戻して…

「Palette」から「Layouts」をクリックして

「FrameLayout」を画面イメージにドラッグ&ドロップします。

左下に「FrameLayout」というものが追加されたのと、画面イメージには上半分くらいの大きさの選択枠が表示されました。

この状態で、Codeモードに戻ります。

    <FrameLayout
        android:layout_width="729dp"
        android:layout_height="194dp"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp">

    </FrameLayout>

どうでしょう?さっきとちょっと違うのですが、似たような「FrameLayout」が表示されました。

問題ビューには、この1つのみが表示されています。

今度はこれを右クリックします。

「クイックフィックスの表示」をクリックします。

今度はこんな選択肢(一つだけなので分かりにくいですが、選択肢です)が表示されました。

Suppress: Add tools:ignore="MissingConstraints" attribute
抑制:tools:ignore = "MissingConstraints"属性を追加します

これはよくわかってませんが、押しておきます(笑

    <FrameLayout
        android:layout_width="729dp"
        android:layout_height="194dp"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp"
        tools:ignore="MissingConstraints">

    </FrameLayout>

すると、こんなものが追加され、

先ほどの赤い問題もなくなりました。

ここで新たに、黄色の注意メッセージも表示されました。
This FrameLayout view is unnecessary (no children, no background, no id, no style)

同じように「クイックフィックスの表示」をすると、今度は2択でした。

なんとなく上を推奨するんだろうと押してみると、FrameLayoutが丸ごと消えちゃいましたので、下の方を選んでみます。

    <FrameLayout
        android:layout_width="729dp"
        android:layout_height="194dp"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp"
        tools:ignore="MissingConstraints,UselessLeaf">

    </FrameLayout>

よくわからない謎の文言が追加されましたが、問題ビューには何も表示されなくなりました。

このような感じで「コンテキストアクションの表示」と「クイックフィックスの表示」を行いながら進めていきます。

本記事ではもう少しだけ進めます。

次に、この矢印部分に、最初に入れていたこれを追加します。

    <androidx.camera.view.PreviewView
        android:id="@+id/previewView" />
    <FrameLayout
        android:layout_width="729dp"
        android:layout_height="194dp"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp"
        tools:ignore="MissingConstraints,UselessLeaf">
        <androidx.camera.view.PreviewView
            android:id="@+id/previewView" />
    </FrameLayout>

こんな感じですね。

そして、いま追加した「@+id/previewView」のところを 「@+id/viewFinder」 に変更します。

ここは別に変更しなくてもいいんだと思いますが、、「previewView」と「PreviewView」が違うものを指してるっぽいとか、実際ずっと混乱し続けて、いまだに混乱してますが、違うものなら違うってわかるようにした方が混乱しにくいかなということで、名前を変更しておきます。

ここはただの名前のタグ(変数)のようなので、該当箇所全部変えればOKのようです。

ちなみにviewFinderは別のサイトから受け売りです。

赤枠をviewFinderに変更しました。青枠のPreviewViewは変更しちゃいけないやつです。

次に「androidx.camera.view.PreviewView」の赤字を解決します。

Class referenced in the layout file, androidx.camera.view.PreviewView, was not found in the project or the libraries
Cannot resolve class androidx.camera.view.PreviewView

問題は2つ、先に下の方を解決するのが正解でした(結果論)

クイックフィックスを行うと

Add depondency on androidx.camera-view (alpha)

ちょっと翻訳しても意味わかりませんが、これをクリックしますと

右下で何やらごにょごにょ動いて、ファイルのダウンロードか再配置か走ってるようですが、何が増えたのかはわかりませんでした。

そして、それが終わると、問題ビューが4つに増えました。

'layout_height' 属性を定義する必要があります
'layout_width' 属性を定義する必要があります
要素 androidx.camera.view.PreviewView に必要な属性 android:layout_height がありません
要素 androidx.camera.view.PreviewView に必要な属性 android:layout_width がありません

一見増えてダメかなと思いますが、よく見ると、最初にFrameLayoutの時に経験したものと同じっぽいですね。

した二つのクイックフィックスを行うと、こうなりました。↓

で、数字は、FrameLayoutと同じ729dpと194dpを入れます(これ間違いですが、一緒に経験してください(笑

改行してちょっと見やすくして…

これで問題ビューもゼロになってます。

ちょっと戻りますが、先ほど赤ではなく黄色の文章で「 UselessLeaf 」なんてものを追加しましたが、今削除してみると、黄色表示にはなりませんでした。

きっとFrameLayoutという中身がなかった故の警告で、今はandroidx.camera.view.PreviewViewという中身を入れたので、黄色にはならなくなったようです。

かなり長くなってしまいましたが、これで「activity_main.xml」の弄りは終了となります。(今のところは!

デザインモードに戻してみると…

このように表示されました。先にネタバレをしておくと…黒い部分がプレビューが表示される範囲になります(笑

最後に「activity_main.xml」を張り付けておきます。

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Hello World!"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <FrameLayout
        android:layout_width="729dp"
        android:layout_height="194dp"
        tools:layout_editor_absoluteX="1dp"
        tools:layout_editor_absoluteY="1dp"
        tools:ignore="MissingConstraints">
        <androidx.camera.view.PreviewView
            android:id="@+id/viewFinder"
            android:layout_width="729dp"
            android:layout_height="194dp"/>
    </FrameLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

最後までお読みいただきありがとうございました。
気になることがあったら、コメント頂けると嬉しいです。
自主学習も兼ねて記事にするかもしれません。

-AndroidStudio