ユーザ用ツール

サイト用ツール


サイドバー

プログレス合同会社

広告

android:studio:application:feature-depart:route-module

04.経路一覧編集画面の作成

経路一覧を編集する画面を:feature:depart:routeモジュールに作成します。

共通UIモジュールの作成と同様に、トップディレクトリで:feature:depart:routeを作成し、javaディレクトリ名の変更、および、サンプルテストクラスの削除を行います。

FeatureConfigurePluginの適用

:feature:depart:routeモジュールのbuild.gradle.ktsにビルドプラグインを適用します。

plugins {
  alias(libs.plugins.android.library)
  alias(libs.plugins.kotlin.android)
  id("build.logic.feature.configure")
}

android {
  namespace = "jp.co.progress_llc.portal.feature.depart.route"
  compileSdk {
    version = release(36)
  }

  defaultConfig {
    minSdk = 28

    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles("consumer-rules.pro")
  }

  buildTypes {
    release {
      isMinifyEnabled = false
      proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
    }
  }
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
  }
  kotlinOptions {
    jvmTarget = "11"
  }
}

dependencies {

  implementation(libs.androidx.core.ktx)
  implementation(libs.androidx.appcompat)
  implementation(libs.material)
  testImplementation(libs.junit)
  androidTestImplementation(libs.androidx.junit)
  androidTestImplementation(libs.androidx.espresso.core)
  implementation(project(":core:ui"))
}

2行目~3行目、9行目~15行目、17行目~32行目、37行目~39行目
ビルドプラグインで定義しているので削除します。
3行目
/build-logic/build.gradle.ktsで定義したビルドプラグインのidを指定します。
16行目、40行目~42行目
テストを行うときまで削除します。
43行目
共通UIモジュールを使用します。

適用後、『Sync Now』で内容をプロジェクトに反映させます。

表示画面の作成

:feature:depart:routeモジュールにpresentationディレクトリ(パッケージ)を追加し、直下にDepartRouteScreen.ktを作成します。
※暫定的にViewModelのない画面として作成します。

package jp.co.progress_llc.portal.feature.depart.route.presentation

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import jp.co.progress_llc.portal.core.ui.components.AppTitleBox
import jp.co.progress_llc.portal.core.ui.theme.AppTheme
import jp.co.progress_llc.portal.core.ui.components.CustomOutlinedTextField

private object FieldName {
  const val ROUTE     = "経路名"
  const val DEPARTURE = "発駅"
  const val VIA       = "経由駅"
  const val ARRIVAL   = "着駅"
}

@Composable
fun DepartRouteScreen() {
  var routeName        by remember { mutableStateOf(FieldName.ROUTE) }
  var departureStation by remember { mutableStateOf(FieldName.DEPARTURE) }
  var viaStation       by remember { mutableStateOf(FieldName.VIA) }
  var arrivalStation   by remember { mutableStateOf(FieldName.ARRIVAL) }

  Scaffold(
    topBar = { AppTitleBox() }
  ) { innerPadding ->
    Column(
      modifier = Modifier
        .padding(innerPadding)
        .fillMaxSize()
        .background(MaterialTheme.colorScheme.background)
        .padding(8.dp),
      verticalArrangement = Arrangement.spacedBy(2.dp)
    ) {
      Text(
        text = "経路一覧編集",
        style = MaterialTheme.typography.titleLarge,
      )
      // 新規登録行
      Card(
        modifier = Modifier
          .fillMaxWidth()
          .border(
            width = 1.dp,
            color = MaterialTheme.colorScheme.outline,
            shape = MaterialTheme.shapes.small
          )
        .padding(horizontal = 8.dp),
        colors = CardDefaults.cardColors(
          containerColor = MaterialTheme.colorScheme.background
        )
      ) {
        Row(
          modifier = Modifier
            .fillMaxWidth()
            .padding(top = 10.dp)
        ) {
          CustomOutlinedTextField(
            value = routeName,
            onValueChange = { value: String -> routeName = value },
            label = {
              Text(
                text  = FieldName.ROUTE,
                style = MaterialTheme.typography.bodySmall
              )
            },
            modifier = Modifier.fillMaxWidth(),
            textStyle = MaterialTheme.typography.bodySmall.copy(
              color = MaterialTheme.colorScheme.primary
            ),
            contentPadding = PaddingValues(start = 8.dp, end = 8.dp, top = 2.dp),
            shape = RoundedCornerShape(6.dp),
            singleLine = true,
            height = 32.dp
          )
        }
        Row(
          modifier = Modifier
            .fillMaxWidth()
            .padding(top = 8.dp, bottom = 4.dp)
        ) {
          CustomOutlinedTextField(
            value = departureStation,
            onValueChange = { value: String -> departureStation = value },
            label = {
              Text(
                text  = FieldName.DEPARTURE,
                style = MaterialTheme.typography.bodySmall
              )
            },
            modifier = Modifier.weight(1f),
            textStyle = MaterialTheme.typography.bodySmall.copy(
              color = MaterialTheme.colorScheme.primary,
              textDecoration = TextDecoration.Underline
            ),
            readOnly = true,
            contentPadding = PaddingValues(start = 8.dp, end = 8.dp, top = 2.dp),
            shape = RoundedCornerShape(6.dp),
            singleLine = true,
            height = 32.dp
          )
          Spacer(modifier = Modifier.width(6.dp))
          CustomOutlinedTextField(
            value = viaStation,
            onValueChange = { value: String -> viaStation = value },
            label = {
              Text(
                text  = FieldName.VIA,
                style = MaterialTheme.typography.bodySmall
              )
            },
            modifier = Modifier.weight(1f),
            textStyle = MaterialTheme.typography.bodySmall.copy(
              color = MaterialTheme.colorScheme.primary,
              textDecoration = TextDecoration.Underline
            ),
            readOnly = true,
            contentPadding = PaddingValues(start = 8.dp, end = 8.dp, top = 2.dp),
            shape = RoundedCornerShape(6.dp),
            singleLine = true,
            height = 32.dp
          )
          Spacer(modifier = Modifier.width(6.dp))
          CustomOutlinedTextField(
            value = arrivalStation,
            onValueChange = { value: String -> arrivalStation = value },
            label = {
              Text(
                text  = FieldName.ARRIVAL,
                style = MaterialTheme.typography.bodySmall
              )
            },
            modifier = Modifier.weight(1f),
            textStyle = MaterialTheme.typography.bodySmall.copy(
              color = MaterialTheme.colorScheme.primary,
              textDecoration = TextDecoration.Underline
            ),
            readOnly = true,
            contentPadding = PaddingValues(start = 8.dp, end = 8.dp, top = 2.dp),
            shape = RoundedCornerShape(6.dp),
            singleLine = true,
            height = 32.dp
          )
        }
        // ボタン行
        Row(
          modifier = Modifier
            .fillMaxWidth()
            .padding(top = 4.dp, bottom = 10.dp),
          horizontalArrangement = Arrangement.spacedBy(8.dp, Alignment.CenterHorizontally)
        ) {
          Button(
            onClick = { },
            modifier = Modifier
              .height(28.dp)
              .width(80.dp),
            contentPadding = PaddingValues(horizontal = 8.dp)
          ) {
            Text("登録", style = MaterialTheme.typography.bodySmall)
          }
          OutlinedButton(
            onClick = {
              routeName        = FieldName.ROUTE
              departureStation = FieldName.DEPARTURE
              viaStation       = FieldName.VIA
              arrivalStation   = FieldName.ARRIVAL
            },
            modifier = Modifier
              .height(28.dp)
              .width(80.dp),
            contentPadding = PaddingValues(horizontal = 8.dp, vertical = 4.dp),
            colors = ButtonDefaults.outlinedButtonColors(
              containerColor = MaterialTheme.colorScheme.secondaryContainer,
              contentColor = MaterialTheme.colorScheme.onSecondaryContainer
            )
          ) {
            Text("クリア", style = MaterialTheme.typography.bodySmall)
          }
        }
      }
    }
  }
}

@Preview(showBackground = true)
@Composable
fun DepartRouteScreenPreview() {
  AppTheme {
    DepartRouteScreen()
  }
}

18行目~23行目
画面内で使用する定数をまとめて定義しています。
25行目
Jetpack Compose関数であることを宣言します。
27行目~30行目
各入力データの初期値をmutableStateで設定しています。
47行目~188行目
経路の新規登録ブロックを定義しています。
61行目~84行目
新規登録ブロックの1行目で経路名を入力します。
85行目~152行目
新規登録ブロックの2行目で発駅、経由駅、着駅を入力します。
153行目~187行目
新規登録ブロックの3行目で登録ボタンとクリアボタンを用意します。
161行目
登録ボタンをクリックしても何もしないようにしています。
170行目~175行目
クリアボタンで既定値に戻るようにしています。
193行目~199行目
Android Studioで画面のプレビューを表示するための関数を定義しています。
なくても構いません。

android/studio/application/feature-depart/route-module.txt · 最終更新: by プログレス合同会社