Java – how to get (or simulate) the viewpager in dialogfragment?
When I use alertdialog. Builder, I receive an IllegalStateException that says "the fragment has no view", which puzzles me (and the stack is useless)
I can pop up a pop-up window using viewpager, which can perform the actions I want, but it doesn't have the buttons I want. I really like the appearance of the default alertdialog, so I'd better use it if possible (for consistency reasons). If not, I can make a custom dialog that looks exactly the same
So how do I make viewpager work in alertdialog / dialogfragment (or similar)?
Edit: just to clarify, it doesn't have to be alertdialog, but I want to choose the option of setting title, (permanent) message and button
Edit2: therefore, when f is returned in fragmentfirst newinstance(), a "fragment has no view" error occurs. This should return the fragment to the getitem() method in the adapter, which should return the fragment associated with the correct location. I hope this can help anyone find out what the problem is
Edit3: after messing up some things, I now get this error: fragment is not found. Fragment default {47febfa#1 id = 0x7f0c00b7 Android: switcher: 2131493047 ID 0x7f0c00b7 (COM. Example. Tim. Timapp: ID / pager) view: 0}, basically telling me something to try to find pager view in the wrong fragment? Not sure how to solve this problem. Note that fragmentdefault is exactly the same as fragmentfirst except for its name and some IDs
Edit4: (March 11, 2016) a question: when using the newinstance method (such as the operation I did inside the fragment), should the returned fragment have a view? When I call if (f.getview() = = null), it returns true, which makes me wonder if F should even have a view. If so, why not? The layout of each newinstance method I see on the Internet is exactly the same as my layout, so it looks as if I haven't lost anything. In addition, for some reason, oncreateview in fragments (fragmentfirst, fragmentsecond, etc.) will never arrive. I have a log. D after oncreateview, which has never been displayed in logcat. Do you have any ideas?
Code: call dialogfragment
TestActivityFragment newFragment = new TestActivityFragment();
newFragment.show(getChildFragmentManager(), "dialog");
TestActivityFragment:
package com.example.fragments.MainFragments.Test;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v13.app.FragmentStatePagerAdapter;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.example.tim.timapp.R;
public class TestActivityFragment extends DialogFragment {
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
LayoutInflater inflater = getActivity().getLayoutInflater();
final View view = inflater.inflate(R.layout.test_dialog, null);
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setView(view)
.setPositiveButton("POS", null)
.setNegativeButton("NEG", null)
.setTitle("TEST_TITLE")
.setMessage("TEST_MESSAGE");
ViewPager mPager = (ViewPager) view.findViewById(R.id.pager);
FragmentStatePagerAdapter mPagerAdapter = new TestAdapter(getChildFragmentManager());
mPager.setAdapter(mPagerAdapter);
return builder.create();
}
private class TestAdapter extends FragmentStatePagerAdapter {
public TestAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch(position) {
case 0: return FragmentFirst.newInstance("FragmentFirst, Instance 1");
case 1: return FragmentSecond.newInstance("SecondFragment, Instance 1");
case 2: return FragmentThird.newInstance("ThirdFragment, Instance 1");
case 3: return FragmentThird.newInstance("ThirdFragment, Instance 2");
default: return FragmentDefault.newInstance("DefaultFragment");
}
}
@Override
public int getCount() {
return 5;
}
}
}
One of the fragments
package com.example.fragments.MainFragments.Test;
import android.app.Fragment;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import com.example.tim.timapp.R;
public class FragmentFirst extends Fragment{
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.frag_first, container, false);
TextView tv = (TextView) v.findViewById(R.id.tvFragFirst);
tv.setText(getArguments().getString("msg"));
return v;
}
public static FragmentFirst newInstance(String text) {
FragmentFirst f = new FragmentFirst();
Bundle b = new Bundle();
b.putString("msg", text);
f.setArguments(b);
return f;
}
}
XML
test_ dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
(I have also made viewpager as the parent layout, and there is nothing in it and nothing has changed.)
frag_ first.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/tvFragFirst"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:text="TextView"
android:textAppearance="?android:textAppearanceMedium"/>
</RelativeLayout>
Logging
03-09 15:30:55.910 23343-23343/? I/art: Not late-enabling -Xcheck:jni (already on)
03-09 15:30:55.940 23343-23349/? E/art: Failed sending reply to debugger: Broken pipe
03-09 15:30:55.940 23343-23349/? I/art: Debugger is no longer active
03-09 15:30:55.950 23343-23343/? W/System: ClassLoader referenced unkNown path: /data/app/com.example.tim.timapp-2/lib/x86_64
03-09 15:30:56.060 23343-23356/? D/OpenGLRenderer: Use EGL_SWAP_BEHAVIOR_PRESERVED: true
03-09 15:30:56.150 23343-23356/? I/OpenGLRenderer: Initialized EGL, version 1.4
03-09 15:30:56.210 23343-23356/? W/EGL_emulation: eglSurfaceAttrib not implemented
03-09 15:30:56.210 23343-23356/? W/OpenGLRenderer: Failed to set EGL_SWAP_BEHAVIOR on surface 0x7f5f5597db40, error=EGL_SUCCESS
03-09 15:30:58.870 23343-23343/com.example.tim.timapp D/GSF - getChildCount: 0
03-09 15:30:58.910 23343-23343/com.example.tim.timapp D/AndroidRuntime: Shutting down VM
03-09 15:30:58.910 23343-23343/com.example.tim.timapp E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.tim.timapp, PID: 23343
java.lang.IllegalStateException: Fragment does not have a view
at android.app.Fragment$1.onFindViewById(Fragment.java:2181)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:963)
at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1148)
at android.app.BackStackRecord.run(BackStackRecord.java:793)
at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1535)
at android.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:562)
at android.support.v13.app.FragmentStatePagerAdapter.finishUpdate(FragmentStatePagerAdapter.java:168)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1177)
at android.support.v4.view.ViewPager.populate(ViewPager.java:1025)
at android.support.v4.view.ViewPager.onMeasure(ViewPager.java:1545)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureHorizontal(LinearLayout.java:1112)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:632)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.LinearLayout.measureChildBeforeLayout(LinearLayout.java:1465)
at android.widget.LinearLayout.measureVertical(LinearLayout.java:748)
at android.widget.LinearLayout.onMeasure(LinearLayout.java:630)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at android.view.View.measure(View.java:18788)
at android.view.ViewGroup.measureChildWithMargins(ViewGroup.java:5951)
at android.widget.FrameLayout.onMeasure(FrameLayout.java:194)
at com.android.internal.policy.PhoneWindow$DecorView.onMeasure(PhoneWindow.java:2643)
at android.view.View.measure(View.java:18788)
at android.view.ViewRootImpl.performMeasure(ViewRootImpl.java:2100)
at android.view.ViewRootImpl.measureHierarchy(ViewRootImpl.java:1191)
at android.view.ViewRootImpl.performTraversals(ViewRootImpl.java:1452)
at android.view.ViewRootImpl.doTraversal(ViewRootImpl.java:1107)
at android.view.ViewRootImpl$TraversalRunnable.run(ViewRootImpl.java:6013)
at android.view.Choreographer$CallbackRecord.run(Choreographer.java:858)
at android.view.Choreographer.doCallbacks(Choreographer.java:670)
at android.view.Choreographer.doFrame(Choreographer.java:606)
at android.view.Choreographer$FrameDisplayEventReceiver.run(Choreographer.java:844)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:5417)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
03-09 15:35:59.030 23343-23343/? I/Process: Sending signal. PID: 23343 SIG: 9
PS. if I forget to add a piece of code, please let me know so that I can add it
resolvent:
So I finally managed to get what I wanted. However, some things have changed
In addition to replacing return builder. Create(); In addition, the oncreatedialog() method remains unchanged. Use return builder. Show(); And some appearance changes
The correct (cough) name is testadapter now pageradapter, not fragmentstatepageradapter. It may not be beautiful, but it works
private class TestAdapter extends PagerAdapter {
private int mCurrentPosition = -1;
@Override
public int getCount() {
return pageAmount;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
LayoutInflater inflater = getActivity().getLayoutInflater();
int layoutThingy;
switch(position) {
case 0:
layoutThingy = R.layout.fragment_generalsettingsinputdialog1;
break;
case 1:
layoutThingy = R.layout.fragment_generalsettingsinputdialog2;
break;
case 2:
layoutThingy = R.layout.fragment_generalsettingsinputdialog3;
break;
default:
layoutThingy = R.layout.fragment_viewpagererror;
}
View view = inflater.inflate(layoutThingy, null);
container.addView(view);
view.requestFocus();
return view;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
((ViewPager) container).removeView((View) object);
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == ((View) object);
}
@Override
public void setPrimaryItem(ViewGroup container, int position, Object object) {
super.setPrimaryItem(container, position, object);
if (position != mCurrentPosition) {
View view = (View) object;
CustomPager pager = (CustomPager) container;
if (view != null) {
mCurrentPosition = position;
pager.measureCurrentView(view);
}
}
}
}
Fragments (the fragments mentioned as one of the fragments in the original post have disappeared. They are no longer needed
test_ The dialog.xml file has also been changed. Now it contains a custom viewpager (and some page indicators, but this is not part of what bothers me)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true">
<com.example.tim.timapp.CustomStuff.CustomPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:overScrollMode="never"/>
<com.viewpagerindicator.CirclePageIndicator
android:id="@+id/circlePageIndicator"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:fillColor="@color/colorPrimary"
app:strokeColor="@color/lightGrey"/>
</LinearLayout>
To continue, the custompager is as follows:
package com.example.tim.timapp.CustomStuff;
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
public class CustomPager extends ViewPager {
private View mCurrentView;
public CustomPager(Context context) {
super(context);
}
public CustomPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mCurrentView == null) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
return;
}
int height = 0;
mCurrentView.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = mCurrentView.getMeasuredHeight();
if (h > height) height = h;
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void measureCurrentView(View currentView) {
mCurrentView = currentView;
requestLayout();
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
It may look daunting, but it doesn't do much after adjusting the viewpager to the size of the current display page. It doesn't look beautiful in all types of animation, and it's slow, but it can be done every time
Finally, frag_ First. XML. These can be any layout XML you want, as long as it fits alertdialog. XML
Just to (prove) that it's working. This is a picture. If you need more information, please feel free to ask. I've been struggling for a long time, so I'm glad to help you