I'm trying to create the following scenario:
User clicks a Button
> this shows a DialogFragment
The DialogFragment
contains a ViewPager
, which has 2 tabs - one shows a colour picker fragment and the other a symbol picker fragment
Each picker fragment contains an adapter which transforms an array of colours/symbols into a nice grid.
However, it's currently showing up blank - the DialogFragment
appears, with the other parts of the fragment, but no adapter view.
Here's what I have:
The initial activity is called EditActivity
. It has a Button
, which, when clicked, calls this function to reveal the DialogFragmentPickers
:
public void showPickers() {
if(mDialogFragmentPickers == null) return;
mDialogFragmentPickers.setColourSet(mColourSet);
mDialogFragmentPickers.show(mFragmentManager, "Pickers");
}
DialogFragmentPickers
is initialised in the onCreate
method of EditActivity
like this:
mDialogFragmentPickers = new DialogFragmentPickers();
The ColourSet
being passed in is basically just an array of the colours that are to be shown in the picker. DialogFragmentPickers
should then pass it on through to the FragmentColourPicker
when it's initialised.
The DialogFragmentPickers
class looks like this (I've only shown the parts pertaining to the ColourPicker
, but the SymbolPicker
works in the same way):
public class DialogFragmentPickers extends DialogFragment {
private PickersPagerAdapter mPagerAdapter;
private ViewPager mViewPager;
private ColourSet mColourSet;
private FragmentColourPicker mColourPicker;
@Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
// Inflate layout
View view = inflater.inflate(R.layout.dialog_fragment_pickers, container, false);
mPagerAdapter = new PickersPagerAdapter(getChildFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = view.findViewById(R.id.pager);
mViewPager.setAdapter(mPagerAdapter);
return view;
}
public void setColourSet(ColourSet colourSet) {
mColourSet = colourSet;
if(mColourPicker == null) getColourPickerFragment();
else mColourPicker.setColourSet(mColourSet);
}
private void getColourPickerFragment() {
if (mPagerAdapter == null) return;
mColourPicker = (FragmentColourPicker) mPagerAdapter.getItem(0);
if(mColourSet != null) mColourPicker.setColourSet(mColourSet);
}
public class PickersPagerAdapter extends FragmentPagerAdapter
{
PickersPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return new FragmentColourPicker();
case 1:
return new FragmentSymbolPicker();
default:
return null;
}
}
@Override
public int getCount() {
return 2;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
return getResources().getString(R.string.colours);
case 1:
return getResources().getString(R.string.symbols);
}
return null;
}
}
The layout file for this contains:
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Current + adjacent page titles...-->
<android.support.v4.view.PagerTitleStrip
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:background="#33b5e5"
android:paddingBottom="4dp"
android:paddingTop="4dp"
android:textColor="#fff" />
</android.support.v4.view.ViewPager>
The first Fragment used in this pager is FragmentColourPicker
. It is defined like this:
public class FragmentColourPicker extends Fragment {
GridView mColourGrid;
Context mContext;
ColourSet mColourSet;
ChartColourAdapter mColourAdapter;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_colour_picker, container, false);
mColourGrid = view.findViewById(R.id.gridview_colourPicker);
initialiseWithColourSet(); // Returns without doing anything if colourSet is not set up yet
return view;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mContext = getActivity();
}
@Override
public void onDestroy(){ super.onDestroy();}
public void setColourSet(ColourSet thisColourSet) {
mColourSet = thisColourSet;
initialiseWithColourSet(); // Returns without doing anything if the colourGrid is not set up yet
}
public void initialiseWithColourSet() {
// Make sure that the colourSet and the colourGrid have both been initialised
if(mColourSet == null) return;
if(mColourGrid == null) return;
// Now set up ChartColourAdapter to display colours in grid
// Initialise currently highlighted colour to default
// Set on click listener for each colour
mColourAdapter = new ChartColourAdapter(mContext,
R.layout.adapter_pattern_colour_cell_layout,
mColourSet.getColours());
mColourGrid.setAdapter(mColourAdapter);
}
}
and the layout file for FragmentColourPicker
(fragment_colour_picker.xml):
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/colour_picker_fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/fui_transparent"
android:orientation="vertical">
<GridView
android:id="@+id/gridview_colourPicker"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorBg"
android:paddingBottom="@dimen/activity_standard_margin"
android:columnWidth="@dimen/grid_cell_column_width"
android:gravity="center"
android:horizontalSpacing="10dp"
android:numColumns="auto_fit"
android:padding="@dimen/activity_small_margin"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" />
<TextView
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text="@string/prompt_swipe_for_symbols"
android:padding="@dimen/activity_small_margin"
android:background="@color/colorBg"
/>
</LinearLayout>
When I run all of this, the DialogFragment
appears when the button is clicked, and shows the FragmentColourPicker
. I can swipe to the FragmentSymbolPicker
and back. However, the only thing shown in the ColourPicker is the TextView
which prompts the user to swipe across to see the symbols. The GridView
with the actual colours in it doesn't show at all.
From the debugger, I think the issue is that initialiseWithColourSet
only ever seems to have either colourSet
OR colourGrid
set - never both. This makes it return without attempting to set up the colour adapter.
If initialiseWithColourSet
is called from onCreateView
, then colourGrid is set, but colourSet is not (since it hasn't been passed in yet). That's reasonable enough. However, when colourSet is passed in later (from the DialogFragment), colourGrid has gone back to being null, so again the function returns without doing anything.
I clearly have something in the wrong order, or am re-initialising the colourGrid / ColourPicker without realising it.
It looks like an order issue to me. To ensure you're getting your data to the Fragment
at the right time, I would pass the data that the fragments need into the Adapter
via the constructor. I would keep a reference of them there and then instantiate the fragments using a static newInstance(... requiredData)
method. Then, you can be sure that when they are "created" by the adapter, they'll have the required information.
Something like this:
...
Object myRequiredData;
static FragmentColourPicker newInstance(... requiredData) {
FragmentColourPicker f = new FragmentColourPicker();
f.setRequiredData(requiredData);
return f;
}
public void setRequiredData(Object reqData){
this.myRequiredData = reqData;
}
...
public class PickersPagerAdapter extends FragmentPagerAdapter {
Object reqData0;
Object reqData1;
PickersPagerAdapter(FragmentManager fm, Object reqData0, Object reqData1) {
super(fm);
this.reqData0 = reqData0;
this.reqData1 = reqData1;
}
@Override
public Fragment getItem(int position) {
switch(position) {
case 0:
return FragmentColourPicker.newInstance(reqData0);
case 1:
return FragmentSymbolPicker.newInstance(reqData1);
default:
return null;
}
}
...
}