LoginSignup
0
0

More than 1 year has passed since last update.

Android Jetpack の Navigationを使ってみた

Posted at

Androidで画面をたくさんある場合、その画面の数分layout.xmlとFragmentを作成することになるが、どのFragmentからどのFramgmentへ、何の条件のときに遷移するかを制御するのがコードでベタベタになってしまいます。

Android Jetpack の Navigationを使うとその辺がスッキリします。

参考URL

本家Android developers
[Android] 10分で作る、Navigationによる画面遷移
Navigation Componentの使い方(概要〜画面遷移〜データの受け渡し編)

簡単に手順だけ説明しますので詳細はgitHubに上がっているソースを見てください。
gitHub

build.gladle

build.gradleに依存関係を追加します

dependencies {
    ・・・
    def nav_version = "2.5.2"
    implementation "androidx.navigation:navigation-fragment:$nav_version"
    implementation "androidx.navigation:navigation-ui:$nav_version"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
    implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
    implementation "androidx.navigation:navigation-compose:$nav_version"
    ・・・
}

resの下にnavigationフォルダ、xmlを作る

resの下に「navigation」という名前でフォルダを作ります。
Screenshot_20221121_220857.png
フォルダを作ったら、「navigation」を右クリック、→「新規」→「Navigation Resource File」を選択します。これは「res」を右クリックしても出てきません。
Screenshot_20221121_221036.png
こんな画面が出てきます。ファイル名にxmlのファイル名を入れます。(何でもいい)とりあえず、「navigation_graph.xml」と入れます。
Screenshot_20221121_221358.png
とりあえず、navigation_graph.xmlをダブルクリックして開いてみましょう。こんな画面が表示されるはずです。
Screenshot_20221121_224244.png
今はまだ空っぽでなにもありません。

Fragmentを作成、MainActivityとつながるようにする

取り敢えず、Fratmentを3つ作り、MainActivityからつながるようにします。ここはAcdroidStudioの雛形に沿って作ります。

class layout xml
FragmentMain.kt fragment_main.xml
Fragment01.kt fragment_01.xml
Fragment02.kt fragment_01.xml

FragmentMainはMainActivityから呼ばれる最初のFragmentです。そのあとは
FragmentMain、Fragment01.kt、Fragment02.ktの3つのFragmentを3各点回しで画面遷移できるようにします。

まず、MainActivityから

MainActivityは単純に、activity_main.xmlのレイアウトを呼んであげます。

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater).apply {
            setContentView(this.root)
        }
    }
}

次に、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">

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/fragmentContainerView"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:navGraph="@navigation/navigation_graph"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

activity_main.xmlのミソは、この3行です。

android:name="androidx.navigation.fragment.NavHostFragment"
app:navGraph="@navigation/navigation_graph"
app:defaultNavHost="true"

FragmentのNavigationを編集する

Navigationのフローの編集に入ります。開いたnavigation_graph.xmlの上の+のボタンをクリックするとFragmantの一覧が出てきます。
Screenshot_20221122_211242.png
FragmentMain、Fragment01、Fragment02を適当な位置に配置します。こんな感じです。
Screenshot_20221122_211815.png
お互いのFragmentを線で結んでやります。お互い3つのFragmentが行き来できるようにすると、このようなフローになります。
Screenshot_20221122_212035.png
それぞれのFragmentから2本づつ、合計6本の線がでているのがわかるでしょうか。
Screenshot_20221122_212324.png
上から順に
Mian → 01
Main → 02
01 → 02
01 → Main
02 → 01
02 → Main
の6本です。

FragmentMain

FragmentMainはFragment01とFragment02に遷移するフローがありますので、これをボタンのイベントにくくりつけてやります。
FragmentMain.kt

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = FragmentMainBinding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.button01.setOnClickListener {
            // Fragment01へ
            Navigation.findNavController(binding.root).navigate(R.id.action_fragmentMain_to_fragment01) 
        }
        binding.button02.setOnClickListener {
            // Fragment02へ
            Navigation.findNavController(binding.root).navigate(R.id.action_fragmentMain_to_fragment02) 
        }
    }

ここで注目してほしいのはFragmentMainの中で直接遷移先のFragmentを指定しているわけではないということです。
Mian → 01 の場合、
R.id.action_fragmentMain_to_fragment01
が遷移先を示しています。このR.id.XXXXはNavigationフローの編集のウィンドウのConponetTreeに出ているactionの名前と一致します。つまり、フローでつながっている1本の線を指しているわけです。R.id.action_XXXX_to_YYYYのXXXとYYYYがモロ、Fragmentの名前なのでアレですが、ここは名前を変えることができるので、意味のあるイベント名とかにもできます。例えばXXX_BUTTON_PUSHとか、LOGINとか。

同じ要領で、Fragment01.kt

Fragment01.ktも同じ要領で、01 → 02、01 → Mainに遷移する処理を書いてやります

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = Fragment01Binding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.button02.setOnClickListener {
            // Fragment02へ
            findNavController().navigate(R.id.action_fragment01_to_fragment02)
        }
        binding.buttonMain.setOnClickListener {
            // FragmentMainへ
            findNavController().navigate(R.id.action_fragment01_to_fragmentMain)
        }
    }

同じ要領で、Fragment02.ktも

Fragment02.ktも同じ要領で、02 → 01、02 → Mainに遷移する処理を書いてやります

    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = Fragment02Binding.inflate(inflater, container, false)
        return binding.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.button01.setOnClickListener {
            // Fragment01へ
            findNavController().navigate(R.id.action_fragment02_to_fragment01)
        }
        binding.buttonMain.setOnClickListener {
            // FragmentMainへ
            findNavController().navigate(R.id.action_fragment02_to_fragmentMain)
        }
    }

これで3つのFragmentの3各点回しができるようになりました。\(^o^)/

actionに引数を定義してみる

ただ、これだけでは物足りません。各FragmentとFragmentを繋ぐ線のactionに引数を定義することができます。
フローのFragmentを選択するとその右のAttributeのビューに引数を追加できるビューが表示されます。
Screenshot_20221122_215743.png
試しにStringの引数を2つ定義してみました。
param1
param2
この引数の型ですが、String、Intぐらいであればうまく動くようですが、他の型だとうまく動かないという報告もあります。
Main → 01
に行くaction(FragmentとFragmentを繋ぐ線)がどうなっているか見てみます。
Screenshot_20221122_220210.png
「Argment Default Vale」に追加した引数、param1、param2が表示され、ここでデフォルト値が設定できます。デフォルト値は各action(FragmentとFragmentを繋ぐ線)毎に別々に設定できます。
同じように、Main → 02
に行くaction(FragmentとFragmentを繋ぐ線)は、
Screenshot_20221122_220508.png
同じように引数、param1、param2が表示され、デフォルト値が設定できるようになっています。

同じ要領で、Fragment01、Fragment02も引数を増やし、6本のaction全部に2個づつ引数を増やして、デフォルト値を設定してやります。

Fragmentの方は、引数をFragmentのEditTextから取ってきて設定してやる処理と、前のFragmentから引数が渡ってくるのでTextVoewに表示してやる処理を追加します。
FragmentMain.kt

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.message1.setText(param1)
        binding.message2.setText(param2)
        binding.button01.setOnClickListener {
            val action = FragmentMainDirections.actionFragmentMainToFragment01()
            action.param1 = binding.message1.text.toString()
            action.param2 = binding.message2.text.toString()
            // Fragment01へ
            Navigation.findNavController(binding.root).navigate(action)
        }
        binding.button02.setOnClickListener {
            // Fragment02へ
            val action = FragmentMainDirections.actionFragmentMainToFragment02()
            action.param1 = binding.message1.text.toString()
            action.param2 = binding.message2.text.toString()
            Navigation.findNavController(binding.root).navigate(action)
        }
    }

Fragment01.kt

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.message1.setText(param1)
        binding.message2.setText(param2)
        binding.button02.setOnClickListener {
            val action =Fragment01Directions.actionFragment01ToFragment02()
            action.param1 = binding.message1.text.toString()
            action.param2 = binding.message2.text.toString()
            // Fragment02へ
            findNavController().navigate(action)
        }
        binding.buttonMain.setOnClickListener {
            val action =Fragment01Directions.actionFragment01ToFragmentMain()
            action.param1 = binding.message1.text.toString()
            action.param2 = binding.message2.text.toString()
            // FragmentMainへ
            findNavController().navigate(action)
        }
    }

Fragment02.kt

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding.message1.setText(param1)
        binding.message2.setText(param2)
        binding.button01.setOnClickListener {
            val action = Fragment02Directions.actionFragment02ToFragment01()
            action.param1 = binding.message1.text.toString()
            action.param2 = binding.message2.text.toString()
            // Fragment01へ
            findNavController().navigate(action)
        }
        binding.buttonMain.setOnClickListener {
            val action = Fragment02Directions.actionFragment02ToFragmentMain()
            action.param1 = binding.message1.text.toString()
            action.param2 = binding.message2.text.toString()
            // FragmentMainへ
            findNavController().navigate(action)
        }
    }

以上、駆け足でAndroidのNavigationの説明しましたが、完成形はgitHubを見てください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0