android - example - ViewPager en DialogFragment-IllegalStateException: Fragment no tiene una vista
fragmentpageradapter example (4)
Lo que quiero lograr
- Desde
FragmentActivity
muestra un cuadro de diálogo al hacer clic en un botón de acción en la barra de acciones -
DialogFragment
: un diálogo sin título -
TabHost
: pestañas en la parte superior del cuadro de diálogo -
ViewPager
conFragmentPagerAdapter
- Swipable, cuyo contenido está conectado a las pestañas - 2-3 Botones de diálogo (diferentes subclases del cuadro de diálogo, botones diferentes): no se supone que estén en uno de los
ViewPager
deViewPager
, lo que significa que los mismos botones deben permanecer en la parte inferior delViewPager
de diálogo, independientemente de lo queViewPager
Fragment
theViewPager
.
El problema
IllegalStateException: Fragment does not have a view
Lo que he intentado / hecho hasta ahora
- Usar el paquete
android.support.v4
para las clases necesarias - Llamar a
getChildFragmentManager()
lugar degetSupportedFragmentManager()
- Implementé lo que se sugiere en la publicación n.º 10 de este enlace https://code.google.com/p/android/issues/detail?id=42601 . Copio / pego el código directamente en mis dos clases de
Fragment
, que se supone que se muestra enDialogFragment
, más la claseDialogFragment
. - En mi
DialogFragment
personalizado, primero intenté reemplazaronCreateView
, luegoonCreateDialog
y luego ambos al mismo tiempo. Todo lo cual pude ejecutar pero con resultados inesperados.- Solo
onCreateView
: no se puede llegar aAlertDialog.Builder
para crear los botones necesarios, salvo que los resultados delAlertDialog.Builder
de diálogo fueron excelentes. - Solo
onCreateDialog
: el mensaje de error que se muestra arriba. Todavía me imagino que este método será lo más cercano a lo que quiero lograr. - Tanto
onCreateView
comoonCreateDialog
:onCreateDialog
el diseño delonCreateView
diálogo enonCreateView
y agregaron los botones de diálogo aAlertDialog.Builder
enonCreateDialog
. Esto mostraba el diálogo, pero los botones agregados deAlertDialog.Builder
no eranAlertDialog.Builder
. Además, el teclado no apareció al hacer clic en un campoEditText
.
- Solo
Código fuente
La mayoría viene de Tutorial para implementar el uso de TabHost en Android 2.2 + ViewPager y Fragments . El código del ActivityFragment
está en cambio en un DialogFragment
. Sin embargo, reemplacé su ViewPager con uno modificado del código fuente de esta respuesta https://stackoverflow.com/a/18167273/2375978 . Esto fue para ser wrap_content
en altura.
El código defectuoso en mi proyecto está en el método onCreateDialog
, creo.
@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;
}
Stack trace LogCat log
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
También...
- Sin éxito, he podido probar la otra posible solución mencionada en https://code.google.com/p/android/issues/detail?id=42601 , mencionada en la publicación # 2 y # 13, porque no he entendido cómo y dónde puedo usarlo en mi código (supongo que estoy en el mismo bote que la persona que escribió el número 18).
Creo que me encontré con este mismo problema y aprendí algunas cosas mirando la fuente de DialogFragment .
Parece que aunque anular onCreateDialog (...) es una forma válida de crear un cuadro de diálogo personalizado, dará como resultado que DialogFragment tenga una vista nula, tal como indica el mensaje de error. En la mayoría de los casos, esto está bien: el DialogFragment no necesita una Vista para mostrar un Diálogo, pero si desea anidar más fragmentos (como lo hace), esto no funcionará.
Teniendo en cuenta que desea interactuar con AlertDialog.Builder, realmente no hay una solución perfecta que yo pueda ver, pero tiene algunas opciones:
- Cree los botones en su cuadro de diálogo como parte de la Vista (sin usar AlertDialog.Builder). Para ello, anula onCreateView en lugar de onCreateDialog. Debería poder obtener la funcionalidad que menciona al colocar los botones en su propio fragmento. Hacemos algo similar en mi concierto, y prefiero este método.
- Implemente su propio tipo que hereda de Fragment y que refleja el DialogFragment en todos los sentidos, excepto en permitir lo que necesita. Esto no debería ser demasiado aterrador ya que DialogFragment es solo ~ 400 y está muy comentada. Podría ser divertido.
- Use un PagerAdapter regular en lugar de un FragmentPagerAdapter. De esta forma, no importará que su DialogFragment no tenga una Vista.
Gracias a @Tommy Visic por escribir una descripción realmente buena, funcionó.
Publicando el código que funcionó para mí.
He eliminado el código de construcción Dialog
del método onCreateDialog
eliminado de hecho el método onCreateDialog
y la vista de diálogo que he estado implementando en la vista personalizada del cuadro de Dialog''s
he incluido como una View
en el método onCreateView
y todas las cosas comenzaron a funcionar.
@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;
}
Uno de los problemas enfrentados con esta implementación es:
Cuando una Activity
tiene una Toolbar/ActionBar
entonces también se muestra en el DialogFragment
para evitar que lo que se debe hacer es: Implementar el método onViewCreated
de Fragment
y agregar el código siguiente
Dialog dialog = getDialog();
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
float dimAmount = 0.6f;
dialog.getWindow().setDimAmount(dimAmount);
Esto eliminará la Toolbar
de Toolbar
del DialogFragment
y la Activity
se mostrará tal como está.
Aclamaciones
Gracias @Tommy
Saludos Zeus
Si implementa onCreateDialog
para usar AlertDialog
, se topará con IllegalStateException: Fragment does not have a view
al acceder a getChildFragmentManager
o algo equivalente.
Para resolver este problema, implemente tanto onCreateDialog
como onCreateView
, donde onCreateView
devuelve la vista inflada en 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")
// Error
// 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?
}
}
Utilizar el
onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
en lugar de onCreateDialog (Bundle savedInstanceState). No cree un diálogo de alerta, use el inflador proporcionado por el método y cree su vista. Esto funciona para mi.
¡Atentamente!