Android – 下部ナビゲーションで新しい画面に遷移する
■「←」を消す
・コード修正
これは「MainActivity.kt」で画面生成時の処理を修正します
【修正前】
package com.example.myapplication import ... class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navView: BottomNavigationView = findViewById(R.id.nav_view) val navController = findNavController(R.id.nav_host_fragment) // Passing each menu ID as a set of Ids because each // menu should be considered as top level destinations. val appBarConfiguration = AppBarConfiguration(setOf( R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications)) setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) } }
onCreate()の中で、15-17行目のAppBarConfiguration()メソッドに、新しく追加した「R.id.navigation_newitem」を登録する(下図の赤線)だけで、「←」ボタンを消すことができます
【修正後】
package com.example.myapplication import ... class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val navView: BottomNavigationView = findViewById(R.id.nav_view) val navController = findNavController(R.id.nav_host_fragment) // Passing each menu ID as a set of Ids because each // menu should be considered as top level destinations. val appBarConfiguration = AppBarConfiguration(setOf( R.id.navigation_home, R.id.navigation_dashboard, R.id.navigation_notifications, R.id.navigation_newitem)) setupActionBarWithNavController(navController, appBarConfiguration) navView.setupWithNavController(navController) } }
・画面を確認する
戻るボタン(「←」)消えましたねー!
■画面に表示する文字列の修正
フラグメントを作る際に、「フラグメント (ViewModel 付き)」を選択したので、クラスファイルも以下の2つが用意されています
- フラグメント:NewItemFragment.kt
- ViewModel:NewItemViewModel.kt
・NewItemFragment.kt
まずは、自動作成されたフラグメントのクラスファイルを見てみましょう
package com.example.myapplication.ui.newitem import ... class NewItemFragment : Fragment() { companion object { fun newInstance() = NewItemFragment() } private lateinit var viewModel: NewItemViewModel override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { return inflater.inflate(R.layout.fragment_newitem, container, false) } override fun onActivityCreated(savedInstanceState: Bundle?) { super.onActivityCreated(savedInstanceState) viewModel = ViewModelProviders.of(this).get(NewItemViewModel::class.java) // TODO: Use the ViewModel } }
5行目:フラグメントを継承したサブクラスとしてのNewItemFragmentのクラス宣言ですね
7~9行目:インスタンスの生成をしていますが、他のフラグメントのクラスファイルでは、記載されていない処理になります
11行目:もう一つのクラスファイルであるViewModelのオブジェクトを取得するため、NewItemViewModel型の変数宣言です
13~19行目:これはViewが生成された際に呼び出されるメソッドで、画面が表示される前に呼び出される処理を記載するメソッドですが、推奨としては、レイアウトのinflateだけを行うのがよいそうです!
※ちなみに
先に記載したクラス宣言の5行目で以下のように記載することで、上記のonCreateView()メソッドのinflateは不要だそうです!
つまり、onCreateView()メソッドでinflateしかしないのなら、onCreateView()メソッドそのものが不要ということ!!!
21~25行目:で、onCreateView()メソッドの代わりに初期化処理をするのが、このonActivityCreated()メソッドなんだそうです!
でも「バージョン 1.3.0-alpha02」ではonActivityCreated()メソッドは非推奨になったとあり、onViewCreated()メソッドを使うそうだ!
lateinitで宣言されたViewModelの変数もここで初期化していますね
そして、TODOのコメントがある通り、ここで画面のtextを更新する処理を設定します
単純に書けばいいのではなく、ViewModelが存在しているので、ViewModel内でtextに設定する文字列を宣言して、その変数をフラグメントで使用するというのが、正しい使い方になります
※ちなみに
HomeFragment.ktはこんな感じ
package com.example.myapplication.ui.home import ... class HomeFragment : Fragment() { private lateinit var homeViewModel: HomeViewModel override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { homeViewModel = ViewModelProviders.of(this).get(HomeViewModel::class.java) val root = inflater.inflate(R.layout.fragment_home, container, false) val textView: TextView = root.findViewById(R.id.text_home) homeViewModel.text.observe(viewLifecycleOwner, Observer { textView.text = it }) return root } }
HomeのonCreateView()メソッドでやってる処理をNewItemでは、onViewCreated()メソッドでやればいいだけです
・NewItemViewModel.kt
それでもViewModelの方も見てみましょう
package com.example.myapplication.ui.newitem import androidx.lifecycle.ViewModel class NewItemViewModel : ViewModel() { // TODO: Implement the ViewModel }
実にシンプルw
とりあえず、TODOに欲しいものを書けばいい感じです!
※ちなみに
HomeViewModel.ktはこんな感じなので、これは合わせ込みにいけばよいかと思いますね
package com.example.myapplication.ui.home import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class HomeViewModel : ViewModel() { private val _text = MutableLiveData().apply { value = "This is home Fragment" } val text: LiveData = _text }
・クラスファイルのソース修正
下部ナビゲーションは画面をフラグメントで作成しているので、フラグメントのクラスファイルを先に説明したのですが、実際にはViewModelありきのフラグメントなので、修正は以下の順で行います
- ViewModel:NewItemViewModel.kt
- フラグメント:NewItemFragment.kt
1. ViewModel:NewItemViewModel.kt の修正
今回はtextだけなので、深く考えずに、homeをベースに同じように修正します
homeからこの部分を持ってきて、textにセットする文字列を変えるだけですね!
【修正後】
package com.example.myapplication.ui.newitem import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class NewItemViewModel : ViewModel() { // TODO: Implement the ViewModel private val _text = MutableLiveData().apply { value = "This is newitem Fragment" } val text: LiveData = _text }
2. フラグメント:NewItemFragment.kt の修正
何度も言うように、今回はtextの書き換えだけですので、homeのソースを真似ますw
homeで行っていたrootは、onViewCreated()メソッドでは、引数のviewで入ってくるので、それ以外はそのままで大丈夫ですね
【修正後】
不要なものは取っ払って、実現に必要なソースのみを記載します
package com.example.myapplication.ui.newitem import ... class NewItemFragment : Fragment(R.layout.fragment_newitem) { private lateinit var viewModel: NewItemViewModel override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) viewModel = ViewModelProviders.of(this).get(NewItemViewModel::class.java) val textView: TextView = view.findViewById(R.id.text_newitem) viewModel.text.observe(viewLifecycleOwner, Observer { // Update the UI textView.text = it }) } }
・画面を確認する
無事に文字列が変更されることが確認できました!
■最後に
無事に下部ナビゲーションの修正が完了しました!
Windows10で動画が撮れるようになったので、かなり便利っす!w
次は、今回修正した下部ナビゲーションをベースに以下のような修正をしてみたいですねー
- フラグメントにボタンを設置する
- ボタン押下で文字列を変更する
ではでは