ViewPager в DialogFragment - IllegalStateException: Фрагмент не имеет вида

Чего я хочу достичь

  • От FragmentActivity показывает диалоговое окно при нажатии кнопки действия на панели действий.
  • DialogFragment - Диалог без заголовка
  • TabHost - вкладки в верхней части диалога
  • ViewPager with FragmentPagerAdapter - Swipable, содержимое которого связано с вкладками
  • 2-3 кнопки диалога (разные подклассы диалога, разные кнопки) - не должны находиться в одном из Fragment ViewPager, то есть те же кнопки должны оставаться в нижней части диалога независимо от того, какой Fragment показывает ViewPager.


Эта проблема

IllegalStateException: Fragment does not have a view


Что я пробовал/сделал до сих пор

  • Использование пакета android.support.v4 для необходимых классов
  • Вызов getChildFragmentManager() вместо getSupportedFragmentManager()
  • Реализовано то, что пост № 10 предложил по этой ссылке https://code.google.com/p/android/issues/detail?id=42601. Я ViewPager код непосредственно в два моих класса Fragment, которые, как предполагается, должен отображать DialogFragment, плюс класс DialogFragment.
  • В своем пользовательском DialogFragment я сначала попытался переопределить onCreateView, затем onCreateDialog а затем оба одновременно. Все, что я должен бежать, но с неожиданными результатами.
    • Только onCreateView: не AlertDialog.Builder связаться с AlertDialog.Builder для создания необходимых кнопок, кроме того, что результаты диалога были отличными.
    • Только onCreateDialog: сообщение об ошибке показано выше. Я все еще думаю, что этот метод настолько близок, насколько я достиг того, чего я хочу достичь.
    • И onCreateView и onCreateDialog: onCreateDialog раскладку диалога в onCreateView и добавили кнопки диалога в AlertDialog.Builder в onCreateDialog. AlertDialog.Builder диалоговое окно, но добавленные кнопки из AlertDialog.Builder были не видны. Кроме того, клавиатура не отображается при нажатии на поле EditText.


Исходный код

Большинство из них приходят из учебника, чтобы реализовать использование TabHost в Android 2.2 + ViewPager и фрагменты. Код ActivityFragment вместо этого находится в DialogFragment. Однако я заменил его ViewPager на измененный из исходного кода из этого ответа qaru.site/info/36692/.... Это должно было быть в состоянии wrap_content по высоте.

Неисправный код в моем проекте, я полагаю, находится в DialogFragment onCreateDialog.

@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
    AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(), AlertDialog.THEME_HOLO_DARK);
    LayoutInflater inflater = getActivity().getLayoutInflater();
    view = inflater.inflate(R.layout.dialog_test, null);
    addActionButtons(builder, view);    
    builder.setView(view);

    mViewPager = (WrapContentHeightViewPager) view.findViewById(R.id.viewpager);

    initialiseTabHost();

    List<Fragment> fragments = getFragments();

    pageAdapter = new DialogPageAdapter(getChildFragmentManager(), fragments);
    mViewPager.setAdapter(pageAdapter);
    mViewPager.setOnPageChangeListener(this);

    Dialog dialog = builder.create();
    dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
    dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
    dialog.show();

    return dialog;
}


Стек трассировки журнала LogCat

FATAL EXCEPTION: main
java.lang.IllegalStateException: Fragment does not have a view
    at android.support.v4.app.Fragment$1.findViewById(Fragment.java:1425)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:901)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088)
    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1444)
    at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:461)
    at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:1011)
    at android.support.v4.view.ViewPager.populate(ViewPager.java:880)
    at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1374)
    at my.app.package.name.WrapContentHeightViewPager.onMeasure(WrapContentHeightViewPager.java:31)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5059)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1396)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5059)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:15481)
    at android.widget.RelativeLayout.measureChildHorizontal(RelativeLayout.java:617)
    at android.widget.RelativeLayout.onMeasure(RelativeLayout.java:399)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5059)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5059)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5059)
    at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1396)
    at android.widget.LinearLayout.measureVertical(LinearLayout.java:681)
    at android.widget.LinearLayout.onMeasure(LinearLayout.java:574)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5059)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5059)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5059)
    at android.widget.FrameLayout.onMeasure(FrameLayout.java:310)
    at com.android.internal.policy.impl.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2377)
    at android.view.View.measure(View.java:15481)
    at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:1982)
    at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1200)
    at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1398)
    at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1118)
    at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:4525)
    at android.view.Choreographer$CallbackRecord.run(Choreographer.java:725)
    at android.view.Choreographer.doCallbacks(Choreographer.java:555)
    at android.view.Choreographer.doFrame(Choreographer.java:525)
    at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:711)
    at android.os.Handler.handleCallback(Handler.java:615)
    at android.os.Handler.dispatchMessage(Handler.java:92)
    at android.os.Looper.loop(Looper.java:137)
    at android.app.ActivityThread.main(ActivityThread.java:4946)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.jav


Также...

  • Я безуспешно смог попробовать другое возможное решение, упомянутое в https://code.google.com/p/android/issues/detail?id=42601, упомянутое в постах № 2 и № 13, потому что я не понял как и где я могу использовать это в своем коде (я думаю, что я в той же лодке, что и человек, который написал № 18).

Ответ 1

Думаю, я просто столкнулся с этой проблемой и узнал несколько вещей, посмотрев на источник DialogFragment.

Похоже, что переопределение onCreateDialog (...) является допустимым способом создания настраиваемого диалогового окна, это приведет к тому, что DialogFragment будет иметь нулевой вид, как указано в сообщении об ошибке. В большинстве случаев это нормально - для диалогового окна DialogFragment нет необходимости в представлении, но если вы хотите еще больше разложить фрагменты (как и вы), это не будет летать.

Учитывая, что вы хотите взаимодействовать с AlertDialog.Builder, действительно нет идеального решения, которое я вижу, но у вас есть несколько вариантов:

  • Создайте кнопки в диалоговом окне как часть представления (не используя AlertDialog.Builder). Вы делаете это, переопределяя onCreateView вместо onCreateDialog. Вы должны иметь возможность получить упомянутую функциональность, поместив кнопки в свой собственный фрагмент. Мы делаем что-то подобное на моем концерте, и я очень предпочитаю этот метод.
  • Реализуйте свой собственный тип, который наследует от Fragment и который зеркально отображает DialogFragment, за исключением того, что вам нужно. Это не должно быть слишком страшно, поскольку DialogFragment составляет всего ~ 400 и сильно комментируется. Может быть весело.
  • Используйте обычный PagerAdapter вместо FragmentPagerAdapter. Таким образом, не будет иметь значения, что ваш DialogFragment не имеет представления.

Ответ 2

Используйте

onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)

вместо onCreateDialog (Bundle savedInstanceState). Не создавайте диалоговое окно оповещений, используйте надуватель, предоставляемый методом, и создавайте свое представление. Это работает для меня.

С уважением!

Ответ 3

Благодаря @Tommy Visic для написания действительно хорошего описания он работал.

Проводка кода, который работал у меня.

Я удалил строительный код Dialog из метода onCreateDialog методом удаления exact onCreateDialog и диалогового представления, которое я использовал в пользовательском представлении Dialog's, которое я включил в качестве View в метод onCreateView, и все вещи начали работать.

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.login_sigup_screen, null, false);
    bind = ButterKnife.bind(this, view);
    initViewPager();
    return view;
}

Столкнувшись с еще одной проблемой с этой реализацией:

Когда a Activity имеет Toolbar/ActionBar, то он также отображается в DialogFragment, чтобы избежать того, что должно быть сделано: Внесите onViewCreated метод Fragment и добавьте ниже код

Dialog dialog = getDialog();
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
float dimAmount = 0.6f;
dialog.getWindow().setDimAmount(dimAmount);

Это приведет к удалению Toolbar из DialogFragment и Activity будет отображаться как есть.

Приветствия

Спасибо @Tommy

Отношения Zeus

Ответ 4

Если вы реализуете onCreateDialog для использования AlertDialog, вы столкнетесь с IllegalStateException: Fragment does not have a view при доступе к getChildFragmentManager или чему-то эквивалентному.

Чтобы решить эту проблему, реализуйте как onCreateDialog и onCreateView, где onCreateView возвращает представление, накачанное в onCreateDialog.

class LocationPickerDialog : DialogFragment() {

    lateinit var customView: View

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        return customView
    }

    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        Log.d(TAG, "onCreateDialog")
        // StackOverflowError
        // customView = layoutInflater.inflate(R.layout.dialog_location_picker, null)
        customView = activity!!.layoutInflater.inflate(R.layout.dialog_location_picker, null)

        val builder = AlertDialog.Builder(context!!)
                .setView(customView)
                .setPositiveButton(android.R.string.ok) { _, _ ->
                    // do something
                }
                .setNegativeButton(android.R.string.cancel) { _, _ ->
                    // do something
                }
        val dialog = builder.create()

        return dialog
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        // if onCreateView doesn't return a view 
        // java.lang.IllegalStateException: Fragment does not have a view
        mapFragment = childFragmentManager.findFragmentByTag("map") as SupportMapFragment?
    }
}

https://code.luasoftware.com/tutorials/android/android-alertdialog-in-dialogfragment-fragment-does-not-have-a-view/