web-dev-qa-db-ja.com

新しいナビゲーション引き出しアクティビティテンプレートでonNavigationItemSelectedを使用してフラグメントを切り替える(Android Studio 1.4以降)

IntelliJは、Activityクラスのコード行を減らして、Android St​​udioのNavigation Drawerテンプレート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;
}
}

ここで最も注目すべき変更点の1つはメソッドです。

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で置き換えられ、古いナビゲーションドロワーレイアウトは次のようになります。

<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>

簡単に言えば、新しいテンプレートを変更してフラグメントを切り替えるにはどうすればよいですか?

40

だから、@ 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);

}

3つのカスタムフラグメントを切り替えています。 NewsFragment、EventsFragment、GalleryFragment。

メニューで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メソッドを削除し、次のような新しいメソッドを作成しますoutside the 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
    }
}

私のために働く。

81

DrawerLayoutは変更しないでください。「content_main.xml」にフレームを追加するだけです。

以下の手順に従ってください:

  1. 「layout」フォルダーにある「content_main.xml」ファイルを開きます。

  2. 以下のコードを使用してください。

    <?xml version="1.0" encoding="utf-8"?> 
    <RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
        xmlns:tools="http://schemas.Android.com/tools"
        xmlns:app="http://schemas.Android.com/apk/res-auto" Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/app_bar_main"
        tools:context=".MainActivity">    
        <FrameLayout
            Android:layout_width="match_parent"
            Android:layout_height="match_parent" Android:id="@+id/mainFrame">
        </FrameLayout>   
    </RelativeLayout>
    
  3. onNavigationItemSelectedメソッドに移動します。

    public boolean onNavigationItemSelected(MenuItem item) {
      int id = item.getItemId();
      Fragment fragment;
    
    if (id == R.id.nav_camara) {
        fragment = new YourFragment();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.mainFrame, fragment);
        ft.commit();
    }
    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;
    }
    
12
L.L.

別の方法は次のとおりです。

public boolean onNavigationItemSelected(MenuItem item) {
    // Handle navigation view item clicks here.
    Fragment fragment;
    int id = item.getItemId();

    if (id == R.id.nav_camera) {
        // Handle the camera action
        fragment = new BlankFragment();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.container_new, fragment);
        ft.commit();
    } else if (id == R.id.nav_gallery) {
        fragment = new HorizontalView();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.container_new,fragment);
        ft.commit();
    } else if (id == R.id.nav_slideshow) {
        fragment = new FragmentVerticleView();
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        ft.replace(R.id.container_new,fragment);
        ft.commit();

    } 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;
}

そして、すべてのフラグメントをアクティビティに実装する必要があります。私の場合は

MainActivity.Java

    public class MainActivity extends AppCompatActivity
    implements BlankFragment.OnFragmentInteractionListener, HorizontalView.OnFragmentInteractionListener,FragmentVerticleView.OnFragmentInteractionListener,OnNavigationItemSelectedListener
     { 
    //coding stuff
    }

フラグメントJavaファイルでスローされる例外を処理するには

    "must implement OnFragmentInteractionListener"

以下のメソッドを追加するだけです

      public void    onFragmentInteraction(Uri uri){
    //We can keep this empty
}

そして、あなたはそこに行きます!準備完了

このチュートリアルに感謝します

4
Gaurav Karia

私が助けることができるかどうかはわかりませんが、NavigationDrawerActivityのレイアウトテンプレートを変更する場合は、<Path\to\Program_Files>\Android\Android Studio\plugins\Android\lib\templates\activities\NavigationDrawerActivity\root\res\layoutで見つけることができます。

次のようなレイアウトにするのが最善だと思います-

<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
<Android.support.v4.widget.DrawerLayout
    xmlns:Android="http://schemas.Android.com/apk/res/Android"
    xmlns:tools="http://schemas.Android.com/tools"
    Android:id="@+id/drawer_layout"
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    tools:context="${relativePackage}.${activityClass}">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <FrameLayout
        Android:id="@+id/container"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent" />

    <!-- Android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         If you're not building against API 17 or higher, use
         Android:layout_gravity="left" instead. -->
    <!-- The drawer is given a fixed width in dp and extends the full height of
         the container. -->
    <NavigationView Android:id="@+id/navigation_drawer"
        Android:layout_width="@dimen/navigation_drawer_width"
        Android:layout_height="match_parent"
        Android:layout_gravity="<#if buildApi gte 17>start<#else>left</#if>" />

</Android.support.v4.widget.DrawerLayout>

これは、以前にR.id.containerFragmentsを置き換えていた方法で機能します。

0
jaibatrik

Android St​​udio 1.4によって自動作成されたテンプレートも使用しましたが、あなたと同じ問題に遭遇しました。

まず、activity_main.xmlを変更しました

<?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">

<!--Main-->
<LinearLayout
    Android:layout_width="match_parent"
    Android:layout_height="match_parent"
    Android:orientation="vertical">
    <!-- The ActionBar -->
    <include
        layout="@layout/toolbar"
        Android:layout_width="match_parent"
        Android:layout_height="wrap_content" />
    <FrameLayout
        Android:id="@+id/content"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent">
    </FrameLayout>
</LinearLayout>

<!--Drawer-->
<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"
    app:menu="@menu/drawer" /></Android.support.v4.widget.DrawerLayout>

2つの部分を含むDrawerLayout

  1. メイン画面(LinearLayout
  2. 引き出し(NavigationView

メイン画面にはActionBarが含まれ、FrameLayout(R.id.content)はフラグメントに置き換えられます。引き出しには、ヘッダーとメニューが含まれています。

そのため、onNavigationItemSelectedをオーバーライドし、R.id.contentをフラグメントに置き換えます。

MainActivityコードは次のとおりです。

    @Override
public boolean onNavigationItemSelected(MenuItem item) {
    Fragment fragment;
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    // Handle navigation view item clicks here.
    int id = item.getItemId();

    if (id == R.id.nav_A) {
        fragment = new AFragment();
        ft.replace(R.id.content, fragment).commit();        
    } else if (id == R.id.nav_B){
        fragment = new BFragment();
        ft.replace(R.id.content, fragment).commit();
    } else if (id == R.id.nav_settings) {
        Intent intent = new Intent(MainActivity.this, SettingsActivity.class);
        startActivity(intent);
    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    drawer.closeDrawer(GravityCompat.START);
    return true;
}

メインページもフラグメントです。メインページをセットアップするより良い方法があるかどうかはわかりませんが、onCreateメソッドでメインページをセットアップします。

//MainPageFragment
    FragmentTransaction ft = getFragmentManager().beginTransaction();
    ft.replace(R.id.content, new MainPageFragment()).commit();

PS。こちらがtoolbar.xml、ActionBarです

<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.CoordinatorLayout
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" Android:fitsSystemWindows="true"
tools:context="jean.yang.MainActivity">
<Android.support.design.widget.AppBarLayout Android:layout_height="wrap_content"
    Android:layout_width="match_parent" Android:theme="@style/AppTheme.AppBarOverlay">
    <Android.support.v7.widget.Toolbar Android:id="@+id/toolbar"
        Android:layout_width="match_parent" Android:layout_height="?attr/actionBarSize"
        Android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay" />
</Android.support.design.widget.AppBarLayout>
</Android.support.design.widget.CoordinatorLayout>
0
Jean Y.C. Yang