[解決済み] 新しいNavigation Drawer ActivityテンプレートでonNavigationItemSelectedを使用してフラグメントを切り替える(Android Studio 1.4以降)。
質問
IntelliJがAndroid StudioのNavigation DrawerテンプレートのActivityを変更し、Activityクラスのコード行数が少なくなりました。新しいActivityクラスは、次のようになります。
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camara) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
ここで最も注目すべき変化のひとつは、メソッドです。
onNavigationItemSelected(MenuItem item)
旧Navigation Drawerテンプレートの定義は、このメソッドでした。
onNavigationItemSelected(int position, long itemId)
この古いテンプレートを変更するには、内側の
PlaceHolderFragment
クラスを作成し、独自のフラグメントとレイアウトを作成し、このようにします。
Fragment fragment = null;
switch (position) {
case 0:
fragment = new FragmentA();
break;
case 1:
fragment = new FragmentB();
break;
default:
break;
}
if (fragment != null) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.frame_container, fragment).commit();
}
しかし、これは新しいテンプレートでは動作しません(少なくとも、私の少ない知識では)。私は試してみました。
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
Snackbar snackbar = Snackbar.make(findViewById(android.R.id.content), item.getTitle() + " clicked", Snackbar.LENGTH_SHORT);
Fragment fragment = null;
switch (id) {
case R.id.nav_home:
fragment = HomeFragment.getFragInstance();
break;
case R.id.nav_news:
fragment = NewsFragment.getFragInstance();
break;
default:
break;
}
if (fragment != null) {
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.addToBackStack(null);
transaction.replace(R.id.drawer_layout, fragment);
transaction.commit();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
return true;
}
が、レイアウトは
home
のレイアウトも表示されます。
news
レイアウトになります。
行のため、このような現象が起きていると思われます。
transaction.replace(R.id.drawer_layout, fragment);
フラグメントは
FrameLayout
と、旧来のNavigation Drawerのレイアウトはこのようなものでした。
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Framelayout to display Fragments -->
<FrameLayout
android:id="@+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<!-- Listview to display slider menu -->
<ListView
android:id="@+id/list_sliderMenu"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="@color/white"
android:dividerHeight="1dp"
android:listSelector="@drawable/list_selector"
android:background="@color/list_background"/>
でも、新しいのはこんな感じです。
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
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:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/app_bar_base"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_base"
app:menu="@menu/activity_base_drawer" />
</android.support.v4.widget.DrawerLayout>
長い話になりますが、新しいテンプレートを修正して、フラグメントを切り替えられるようにするにはどうしたらよいでしょうか。
解決方法は?
というわけで、@L.L.さんの回答をもとに、この問題を解決することができました。
まず、FrameLayout を
content_main.xml
ファイルを作成します。
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="@+id/content_frame"/>
あなたの
MainActivity
(という名前のメソッドを定義してください(または、ナビゲーションドロワーを持つアクティビティをどのような名前にしたとしてもかまいません)。
displayView
public void displayView(int viewId) {
Fragment fragment = null;
String title = getString(R.string.app_name);
switch (viewId) {
case R.id.nav_news:
fragment = new NewsFragment();
title = "News";
break;
case R.id.nav_events:
fragment = new EventsFragment();
title = "Events";
break;
}
if (fragment != null) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.content_frame, fragment);
ft.commit();
}
// set the toolbar title
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(title);
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
}
NewsFragment、EventsFragment、GalleryFragmentの3つのカスタムFragmentを切り替えて使用しています。
メニューに
activity_main_drawer
内容をこのように変更しました。
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single">
<item android:id="@+id/nav_news"
android:icon="@android:drawable/ic_menu_news"
android:title="News" />
<item android:id="@+id/nav_events"
android:icon="@android:drawable/ic_menu_events"
android:title="Events" />
<item android:id="@+id/nav_gallery"
android:icon="@android:drawable/ic_menu_gallery"
android:title="Gallery" />
</group>
</menu>
Activityクラスに戻ると
onNavigationItemSelected
メソッド
はこうしてください。
@Override
public boolean onNavigationItemSelected(MenuItem item) {
displayView(item.getItemId());
return true;
}
最後に、onCreateメソッドの最後のステートメントです。
@Override
protected void onCreate(Bundle savedInstanceState) {
....
....
displayView(R.id.nav_news);
}
これは、ユーザーが最初に目にする表示をNewsにしたいからです。
バックプレスイベントを処理します。
現状では、いずれかのフラグメントから戻るボタンを押すとアプリが終了してしまいます。私は、ユーザーが戻るボタンを押したときに、アプリをニュースフラグメント(私のホームフラグメント)に戻したいと思っています。そこで、次のようにしました。
ブーリアン変数を宣言。
private boolean viewIsAtHome;
で、その後に
displayView()
メソッドでこうしました。
public void displayView(int viewId){
Fragment fragment = null;
String title = getString(R.string.app_name);
switch (viewId) {
case R.id.nav_news:
fragment = new NewsFragment();
title = getString(R.string.news_title);
viewIsAtHome = true;
break;
case R.id.nav_events:
fragment = new EventsFragment();
title = getString(R.string.events_title);
viewIsAtHome = false;
break;
case R.id.nav_gallery:
fragment = new GalleryFragment();
title = getString(R.string.gallery_title);
viewIsAtHome = false;
break;
最後に、古い
onBackPressed
メソッドを作成し、次のように新しいメソッドを作成します。
外側
その
onCreate()
メソッドを使用します。
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
if (!viewIsAtHome) { //if the current view is not the News fragment
displayView(R.id.nav_news); //display the News fragment
} else {
moveTaskToBack(true); //If view is in News fragment, exit application
}
}
私の場合、動作します。
関連
-
[解決済み】AndroidのSSL接続でトラストアンカーが見つからない
-
[解決済み】コンテンツには、id属性が「android.R.id.list」であるListViewが必要です。
-
[解決済み] ユーザーが拒否する可能性のあるパーミッションが必要なコール
-
[解決済み】apkインストール時のINSTALL_FAILED_NO_MATCHING_ABIS
-
[解決済み】onCreateOptionsMenu(Menu メニュー)とは何ですか?)
-
[解決済み】プロガードを有効にすると、タスク ':app:crashlyticsStoreDeobsDebug' の依存関係を判断できない。
-
[解決済み】'dependencies' を '(groovy.lang.Closure)' に適用できない。)
-
[解決済み] com.android.supportのライブラリは全て全く同じバージョン表記である必要があります。
-
[解決済み] APKのインストール中にDELETE_FAILED_INTERNAL_ERRORエラーが発生する。
-
[解決済み] フラグメント使用時のAndroid Navigation Drawerの画像とUpキャレットの切り替えについて
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】このアクティビティでは、Theme.AppCompatテーマ(またはその子孫)を使用する必要があります。
-
[解決済み】コンテンツには、id属性が「android.R.id.list」であるListViewが必要です。
-
[解決済み】apkファイルのインストール中に「パッケージが破損しているようです」というエラーが発生する。
-
[解決済み】ビューのルートとしてNULLを渡さないようにする(膨張したレイアウトのルート要素でレイアウトパラメータを解決する必要がある)。
-
[解決済み】アクティビティにない場所でのgetLayoutInflater()の呼び出し
-
[解決済み】googleコンソールエラー`OR-IEH-01`について
-
[解決済み】android.content.res.Resources$NotFoundExceptionの取得:androidにリソースが存在する場合でも例外が発生する。
-
[解決済み] Androidでイメージビューの背景を透明に設定する
-
[解決済み] AndroidでBluetoothが有効かどうかのチェックに失敗する(REQUEST_ENABLE_BTを変数に解決できない)。
-
[解決済み] Android Fragment onAttach() 非推奨