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/