Ящик навигации + Viewpager + setVisibility = InflateException / NullPointer

Я разрабатываю приложение для Android, и я столкнулся с некоторыми проблемами.

В моей MainActivity меня есть следующие компоненты:

  • Навигационный ящик (инициализирует и загружает многие фрагменты)
  • ViewPager (только для ArticleFragment который отображает подробный вид статьи)

Нормальный, ViewPager связан с определенным действием, но я действительно хочу использовать как навигационный ящик, так и ViewPager. Единственный способ – реализовать оба элемента в одной активности.

DrawerLayout состоит из самого ящика навигации и области содержимого. В моей области содержимого у меня есть FrameLayout и ViewPager . Проблема в том, что ViewPager всегда отображается.

Поэтому моя идея состояла в том, чтобы играть с свойством android:visibility чтобы поочередно показывать / скрывать FrameLayout и ViewPager. Если вы посмотрите на мой activity_main.xml вы можете заметить, что android:visibility установлена ​​на invisible на ViewPager .

/layout/activity_main.xml

  <!-- The main content view --> <RelativeLayout android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:id="@+id/container" android:paddingTop="?android:attr/actionBarSize" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- ViewPager --> <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" /> </RelativeLayout> <!-- The navigation drawer --> <fragment android:id="@+id/navigation_drawer" android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent" android:layout_gravity="start" android:name="NavigationDrawerFragment" /> </android.support.v4.widget.DrawerLayout> 

А потом:

MainActivity.java

 public class MainActivity extends ActionBarActivity implements NavigationDrawerFragment.NavigationDrawerCallbacks { private NavigationDrawerFragment mNavigationDrawerFragment; private FrameLayout mContainer; private ViewPager mPager; private PagerAdapter mPagerAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Set up the navigation drawer mContainer = (FrameLayout) findViewById(R.id.container); mNavigationDrawerFragment = (NavigationDrawerFragment) getSupportFragmentManager().findFragmentById(R.id.navigation_drawer); mNavigationDrawerFragment.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout)); // Set up the viewpager mPager = (ViewPager) findViewById(R.id.pager); mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager()); mPager.setAdapter(mPagerAdapter); mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { invalidateOptionsMenu(); } }); } //-------------------------------// // NAVIGATION DRAWER // //-------------------------------// /** * Update the main content by replacing fragments */ @Override public void onNavigationDrawerItemSelected(int position) { Fragment fragment = null; Boolean viewPagerArticles = false; switch (position) { case 0: fragment = new HomeFragment(); break; case 1: fragment = new FooFragment(); break; case 2: viewPagerArticles = true; // Hide navigation drawer container and show the viewpager mContainer.setVisibility(FrameLayout.GONE); mPager.setVisibility(ViewPager.VISIBLE); // NullPointerException with new this line. Why? // Fragment already instanciate in ScreenSlidePagerAdapter -> getItem() -> ArticleFragment.create()? //fragment = new ArticleFragment(); break; default: break; } // Show the view pager and hide navigation drawer container // ================= // THE BUG IS HERE // ================= if (!viewPagerArticles) { mContainer.setVisibility(FrameLayout.VISIBLE); mPager.setVisibility(ViewPager.GONE); } if (fragment != null) { FragmentManager fragmentManager = getSupportFragmentManager(); fragmentManager.beginTransaction() .replace(R.id.container, fragment) .commit(); } } ... //-------------------------------// // VIEWPAGER // //-------------------------------// private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter { public ScreenSlidePagerAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int position) { return DayFragment.create(position); } @Override public int getCount() { ... } } ... } 

NavigationDrawerFragment.java

http://pastebin.com/LwKZnNiB

Просмотр содержимого ViewPager

На моем HomeFragment меня есть кнопка с onClickListener:

 mButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { ((MainActivity)getActivity()).onNavigationDrawerItemSelected(2); } }); 

Когда я загружаю MainActivity, у меня есть эти ошибки: InflateException и NullPointerException

 AndroidRuntime﹕ FATAL EXCEPTION: main java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.android/com.example.android.ui.MainActivity}: android.view.InflateException: Binary XML file line #34: Error inflating class fragment at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261) at android.app.ActivityThread.access$600(ActivityThread.java:141) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:137) at android.app.ActivityThread.main(ActivityThread.java:5103) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:525) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) at dalvik.system.NativeStart.main(Native Method) Caused by: android.view.InflateException: Binary XML file line #34: Error inflating class fragment at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713) at android.view.LayoutInflater.rInflate(LayoutInflater.java:755) at android.view.LayoutInflater.inflate(LayoutInflater.java:492) at android.view.LayoutInflater.inflate(LayoutInflater.java:397) at android.view.LayoutInflater.inflate(LayoutInflater.java:353) at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:267) at android.app.Activity.setContentView(Activity.java:1895) at android.support.v7.app.ActionBarActivity.superSetContentView(ActionBarActivity.java:216) at android.support.v7.app.ActionBarActivityDelegateICS.setContentView(ActionBarActivityDelegateICS.java:111) at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:76) at com.example.android.ui.MainActivity.onCreate(MainActivity.java:42) at android.app.Activity.performCreate(Activity.java:5133) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)            at android.app.ActivityThread.access$600(ActivityThread.java:141)            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)            at android.os.Handler.dispatchMessage(Handler.java:99)            at android.os.Looper.loop(Looper.java:137)            at android.app.ActivityThread.main(ActivityThread.java:5103)            at java.lang.reflect.Method.invokeNative(Native Method)            at java.lang.reflect.Method.invoke(Method.java:525)            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)            at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at com.example.android.ui.MainActivity.onNavigationDrawerItemSelected(MainActivity.java:117) at com.example.android.ui.NavigationDrawerFragment.selectItem(NavigationDrawerFragment.java:202) at com.example.android.ui.NavigationDrawerFragment.onCreate(NavigationDrawerFragment.java:80) at android.support.v4.app.Fragment.performCreate(Fragment.java:1477) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:893) at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1082) at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1184) at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:291) at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685)            at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)            at android.view.LayoutInflater.inflate(LayoutInflater.java:492)            at android.view.LayoutInflater.inflate(LayoutInflater.java:397)            at android.view.LayoutInflater.inflate(LayoutInflater.java:353)            at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:267)            at android.app.Activity.setContentView(Activity.java:1895)            at android.support.v7.app.ActionBarActivity.superSetContentView(ActionBarActivity.java:216)            at android.support.v7.app.ActionBarActivityDelegateICS.setContentView(ActionBarActivityDelegateICS.java:111)            at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:76)            at com.example.android.ui.MainActivity.onCreate(MainActivity.java:42)            at android.app.Activity.performCreate(Activity.java:5133)            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)            at android.app.ActivityThread.access$600(ActivityThread.java:141)            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)            at android.os.Handler.dispatchMessage(Handler.java:99)            at android.os.Looper.loop(Looper.java:137)            at android.app.ActivityThread.main(ActivityThread.java:5103)            at java.lang.reflect.Method.invokeNative(Native Method)            at java.lang.reflect.Method.invoke(Method.java:525)            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)            at dalvik.system.NativeStart.main(Native Method) 

Все нормально (без ошибок, активность загружена) без:

  // ================= // THE BUG IS HERE // ================= if (!viewPagerArticles) { mContainer.setVisibility(FrameLayout.VISIBLE); mPager.setVisibility(ViewPager.GONE); } 

… но это не соответствует моим ожиданиям, потому что фрагменты навигационного ящика всегда скрываются (это нормально из-за mContainer.setVisibility(FrameLayout.GONE); . Я просто хочу инвертировать видимость mContainer / mPager.

Надеюсь, я был достаточно ясен …!

Есть идеи?

Вы получаете это NullPointerException потому что вы создали фрагмент NavigationDrawerFragment . Точнее, в onCreate() вы вызываете selectItem() который распространяется через Activity (зарегистрированный как слушатель) на onNavigationDrawerItemSelected() вызов onNavigationDrawerItemSelected() . Проблема заключается в том, что фрагмент будет setContentView() в точке, когда setContentView()onCreate() ), что означает, что вы должны ввести onNavigationDrawerItemSelected() вызов onNavigationDrawerItemSelected() перед строк:

 mContainer = (FrameLayout) findViewById(R.id.container); mPager = (ViewPager) findViewById(R.id.pager); 

onNavigationDrawerItemSelected() эти ссылки в onNavigationDrawerItemSelected() .

Чтобы решить эту проблему, вы можете просто заменить текущий <fragment /> на макете Activity базовым контейнером (например, заполнителем, например, FrameLayout ), и добавить onCreate() NavigationDrawerFragment вручную в onCreate() после строк выше (где вы привязываете представления) , Может быть другое лучшее решение (или я мог бы сделать другие предложения), но не совсем понятно, как вы хотите справиться с видимостью. Возможно, вы можете расширить это.

Изменить 2 :

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Set up the navigation drawer mContainer = (FrameLayout) findViewById(R.id.container); // Set up the viewpager mPager = (ViewPager) findViewById(R.id.pager); mPagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager()); mPager.setAdapter(mPagerAdapter); mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { invalidateOptionsMenu(); } }); if (savedInstanceState == null) { NavigationDrawerFragment ndf = new NavigationDrawerFragment(); ndf.setUp(R.id.navigation_drawer, (DrawerLayout) findViewById(R.id.drawer_layout)); getSupportFragmentManager().beginTransaction().add(R.id.nav_drawer, ndf).commit(); } } 

Изменить 1:

 //... <!-- ViewPager --> <android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" /> </RelativeLayout> <!-- The navigation drawer --> <FrameLayout android:id="@+id/nav_drawer" android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent" android:layout_gravity="start" /> </android.support.v4.widget.DrawerLayout> 

И в onCreate() в конце:

 //... mPager.setAdapter(mPagerAdapter); mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() { @Override public void onPageSelected(int position) { invalidateOptionsMenu(); } }); getSupportFragmentManager().beginTransaction().add(R.id.nav_drawer, new NavigationDrawerFragment()).commit(); 

Если вы получаете исключение из кода выше, он находится в том же onNavigationDrawerItemSelected() ?

Intereting Posts