KDP(電子出版)のメモ 急急如律令

Amazon Kindleダイレクト・パブリッシングでの電子出版や電子書籍の作成販売について、文章やイラストの作成や編集方法について書いています。

アンドロイドアプリで横長画面(ランドスケープ)で表示が崩れる

あなた:

androidスマホで横長の画面だと表示が崩れる

<?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"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/toolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#303F9F"
        android:title="@string/app_name"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navigationIconTint="@android:color/white"
        app:titleCentered="true"
        app:titleTextColor="@android:color/white" />

    <TextView
        android:id="@+id/banner_ad_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:autoLink="web"
        android:background="#FFF8E1"
        android:gravity="center"
        android:padding="8dp"
        android:text="@string/banner_text"
        android:textColor="#4E342E"
        android:textSize="14sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/toolbar" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/openSettingsButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="@string/open_settings_button_text"
        app:layout_constraintEnd_toStartOf="@+id/guideline2"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toBottomOf="@id/banner_ad_text" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/figureButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="16dp"
        android:text="@string/load_illustrations"
        app:layout_constraintEnd_toStartOf="@+id/guideline2"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toBottomOf="@id/openSettingsButton" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button_load_body"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="@string/load_body"
        app:layout_constraintEnd_toStartOf="@+id/guideline2"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toBottomOf="@id/figureButton" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/coverButton"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="@string/load_cover"
        app:layout_constraintEnd_toStartOf="@+id/guideline2"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toBottomOf="@id/button_load_body" />

    <ScrollView
        android:id="@+id/log_scrollview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="8dp"
        android:background="#EEEEEE"
        android:padding="8dp"
        app:layout_constraintBottom_toTopOf="@id/action_buttons_layout"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/coverButton">

        <TextView
            android:id="@+id/text_log"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/log_placeholder"
            android:textColor="#000000"
            android:textIsSelectable="true"
            android:textSize="14sp"
            android:typeface="monospace" />
    </ScrollView>

    <LinearLayout
        android:id="@+id/action_buttons_layout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="end"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/button_cancel"
            style="@style/Widget.MaterialComponents.Button.OutlinedButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/cancel" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/button_convert"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/start_conversion" />
    </LinearLayout>

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="80dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_begin="336dp" />

</androidx.constraintlayout.widget.ConstraintLayout>

ChatGPT:

横長画面(ランドスケープ)で表示が崩れる原因はいくつか考えられますが、主なポイントとして以下が挙げられます:

app:layout_constraintGuide_begin="80dp"
app:layout_constraintGuide_begin="336dp"
  • 横幅が狭いデバイスでは、336dp が画面外になる可能性があります。
  • 固定dpではなく、パーセンテージで指定したほうが柔軟に対応できます。

横幅が狭いデバイスでは、336dp が画面外になる可能性があります。

固定dpではなく、パーセンテージで指定したほうが柔軟に対応できます。

app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="@+id/guideline"
  • 画面が狭くなると、2本のガイドライン間に要素が収まりきらない。

画面が狭くなると、2本のガイドライン間に要素が収まりきらない。

たとえば:

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.2" />

<androidx.constraintlayout.widget.Guideline
    android:id="@+id/guideline2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.8" />

これで画面サイズに対して20%と80%の位置にガイドラインが設置され、横長でも縦長でもバランスが取れます。

あるいは、ガイドラインを使わず app:layout_constraintStart_toStartOf="parent" と End_toEndOf="parent" で中央寄せし、layout_marginStart / layout_marginEnd を指定して幅を抑える方法もあります。

res/layout-land/ ディレクトリを作成して、横画面専用のXMLを用意するのも一つの手です。UI要素の配置を最適化しやすくなります。

必要なら修正済みXMLも用意しますので、やってみたい方向を教えてください!

あなた:

layout-landのサンプルが見たい

ChatGPT:

了解です!layout-land 用のサンプルを用意しますね。ここでは以下のような変更を加えた例を紹介します:

  • ランドスケープ(横画面)で表示崩れしないように、
  • ボタンを横並びにしてスペースを有効活用
  • Guideline は使わず、画面幅に応じて調整されるように変更

ランドスケープ(横画面)で表示崩れしないように、

ボタンを横並びにしてスペースを有効活用

Guideline は使わず、画面幅に応じて調整されるように変更

<?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"
    android:id="@+id/main_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">

    <com.google.android.material.appbar.MaterialToolbar
        android:id="@+id/toolbar"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#303F9F"
        android:title="@string/app_name"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:titleCentered="true"
        app:titleTextColor="@android:color/white" />

    <TextView
        android:id="@+id/banner_ad_text"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:background="#FFF8E1"
        android:gravity="center"
        android:padding="8dp"
        android:text="@string/banner_text"
        android:textColor="#4E342E"
        android:textSize="14sp"
        app:layout_constraintTop_toBottomOf="@id/toolbar"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />

    <!-- ボタン群を横に並べる -->
    <LinearLayout
        android:id="@+id/buttons_row"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        android:gravity="center"
        android:layout_marginTop="16dp"
        app:layout_constraintTop_toBottomOf="@id/banner_ad_text"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/openSettingsButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/open_settings_button_text" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/figureButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="@string/load_illustrations" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/button_load_body"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="@string/load_body" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/coverButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="8dp"
            android:text="@string/load_cover" />
    </LinearLayout>

    <ScrollView
        android:id="@+id/log_scrollview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="16dp"
        android:layout_marginBottom="8dp"
        android:background="#EEEEEE"
        android:padding="8dp"
        app:layout_constraintTop_toBottomOf="@id/buttons_row"
        app:layout_constraintBottom_toTopOf="@id/action_buttons_layout"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <TextView
            android:id="@+id/text_log"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/log_placeholder"
            android:textColor="#000000"
            android:textIsSelectable="true"
            android:textSize="14sp"
            android:typeface="monospace" />
    </ScrollView>

    <LinearLayout
        android:id="@+id/action_buttons_layout"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:gravity="end"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent">

        <com.google.android.material.button.MaterialButton
            android:id="@+id/button_cancel"
            style="@style/Widget.MaterialComponents.Button.OutlinedButton"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/cancel" />

        <com.google.android.material.button.MaterialButton
            android:id="@+id/button_convert"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="@string/start_conversion" />
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>
  • layout ディレクトリにある通常レイアウトと違い、layout-land は横画面のときだけ自動的に適用されます。
  • ConstraintLayout のままでも、LinearLayout とうまく組み合わせれば柔軟に対応可能です。

layout ディレクトリにある通常レイアウトと違い、layout-land は横画面のときだけ自動的に適用されます。

ConstraintLayout のままでも、LinearLayout とうまく組み合わせれば柔軟に対応可能です。

必要に応じて、tablet 用や sw600dp などでデバイスサイズごとに調整も可能です。 別の画面構成パターンを見たい場合も気軽に聞いてください!