Reputation: 1096
I want to create PullToRefresh list fragment with pager. I'm using ActionBarSherlock, and this implementation of the list. I had no problems without fragment, but I need to support two-pane layout.
layout files
activity
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin" >
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SubcatNavActivity" />
</LinearLayout>
fragment
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/subcat_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
Activity is pretty simple
public class SubcatNavActivity extends SherlockFragmentActivity
{
private SubcatNavPager mPager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.activity_subcat_nav);
mPager = new SubcatNavPager(this);
mPager.initialisePaging();
setProgressBarIndeterminateVisibility(true);
}
}
I have created pager class to also use it later in main activity for two-pane mode.
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentPagerAdapter;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.ViewPager;
import com.actionbarsherlock.app.ActionBar;
import com.actionbarsherlock.app.ActionBar.Tab;
import com.actionbarsherlock.app.SherlockFragmentActivity;
public class SubcatNavPager implements ActionBar.TabListener
{
public SectionsPagerAdapter mSectionsPagerAdapter;
public ViewPager mViewPager;
private SherlockFragmentActivity mFragmentActivity;
public SubcatNavPager(SherlockFragmentActivity fa) {
mFragmentActivity = fa;
}
public void initialisePaging() {
mFragmentActivity.setTitle(mFragmentActivity.getResources().getString(SiteContent.curr_cat.nameID));
try {
List<Fragment> fragments = new Vector<Fragment>();
mSectionsPagerAdapter = new SectionsPagerAdapter(mFragmentActivity.getSupportFragmentManager(), fragments);
for (int i = 0; i < SiteContent.curr_cat.content.size(); ++i) {
Fragment tmp = SiteContent.curr_cat.fragment.newInstance();
if (!(tmp instanceof ContentDownloader)) {
throw new IllegalStateException(
"Fragment must implement content downloader interface.");
}
Bundle args = new Bundle();
args.putInt(SubcatListFragment.SUBCAT_IDX, i);
tmp.setArguments(args);
fragments.add((Fragment)tmp);
}
mViewPager = (ViewPager)mFragmentActivity.findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
final ActionBar actionBar = mFragmentActivity.getSupportActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
mViewPager
.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
actionBar.setSelectedNavigationItem(position);
}
});
for (int i = 0; i < mSectionsPagerAdapter.getCount(); i++) {
actionBar.addTab(actionBar.newTab()
.setText(mSectionsPagerAdapter.getPageTitle(i)).setTabListener(this));
}
actionBar.setDisplayHomeAsUpEnabled(true);
}
catch (Exception e) {}
}
@Override
public void onTabSelected(Tab tab, FragmentTransaction fragmentTransaction) {
int pos = tab.getPosition();
SiteContent.setCurrSubCat(pos);
mViewPager.setCurrentItem(pos);
((ContentDownloader)mSectionsPagerAdapter.getItem(pos)).downloadContent(false);
}
@Override
public void onTabUnselected(Tab tab, FragmentTransaction ft) {}
@Override
public void onTabReselected(Tab tab, FragmentTransaction ft) {}
public class SectionsPagerAdapter extends FragmentPagerAdapter
{
private List<Fragment> fragments;
public SectionsPagerAdapter(FragmentManager fm, List<Fragment> fList) {
super(fm);
fragments = fList;
}
@Override
public Fragment getItem(int position) {
Fragment tmp = fragments.get(position);
return tmp;
}
@Override
public int getCount() { return fragments.size(); }
@Override
public CharSequence getPageTitle(int position) {
return mFragmentActivity.getResources().getString(SiteContent.curr_cat.content.get(position).nameID);
}
}
}
And finally, the fragment itself
import com.actionbarsherlock.app.SherlockListFragment;
import com.handmark.pulltorefresh.library.PullToRefreshBase;
import com.handmark.pulltorefresh.library.PullToRefreshBase.Mode;
import com.handmark.pulltorefresh.library.PullToRefreshListView;
public class SubcatListFragment extends SherlockListFragment implements ContentDownloader
{
public static final String SUBCAT_IDX = "subcat_idx";
protected ArrayAdapter<SiteItem> adapter;
protected DownloadSubcatTask loadTask;
protected SiteSubcat subcat;
private PullToRefreshListView mPullToRefreshListView;
private boolean loadRequested;
public SubcatListFragment() {
adapter = null;
loadRequested = false;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
subcat = SiteContent.curr_cat.content.get(args.getInt(SUBCAT_IDX));
adapter = new ArrayAdapter<SiteItem>(getActivity(), android.R.layout.simple_list_item_1, subcat.items);
this.setListAdapter(adapter);
if (loadRequested == true)
downloadContent(false);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.fragment_subcat_nav, container, false);
ListView lv = (ListView) layout.findViewById(R.id.subcat_list);
ViewGroup parent = (ViewGroup) lv.getParent();
int lvIndex = parent.indexOfChild(lv);
parent.removeViewAt(lvIndex);
mPullToRefreshListView = new PullToRefreshListView(layout.getContext());
mPullToRefreshListView.setMode(Mode.BOTH);
mPullToRefreshListView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>()
{
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
downloadContent(true);
}
});
parent.addView(mPullToRefreshListView, lvIndex, lv.getLayoutParams());
return layout;
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
Intent subcatIntent = new Intent(getActivity(), NewsActivity.class);
SiteContent.setCurrItem((int)id);
startActivity(subcatIntent);
}
@Override
public void downloadContent(boolean bRefresh) {
// on first call to onTabSelected this fragment is not created, yet
if (subcat == null)
loadRequested = true;
else
{
loadRequested = false;
if (loadTask == null && (adapter.isEmpty() == true || bRefresh == true))
(loadTask = new DownloadSubcatTask()).execute(subcat.getUrl());
}
}
protected void showProgress(boolean bShow) {
getActivity().setProgressBarIndeterminateVisibility(bShow);
}
private class DownloadSubcatTask extends DownloadTask {
public DownloadSubcatTask() {}
@Override
protected void onPreExecute() {
super.onPreExecute();
showProgress(true);
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
adapter.clear();
loadTask = null;
try {
SiteContent.curr_cat.parser.newInstance().parse(result, adapter);
}
catch (Exception e) {}
mPullToRefreshListView.onRefreshComplete();
adapter.notifyDataSetChanged();
showProgress(false);
}
}
}
As you can see, everything consists of stuff from examples. But the problem is that list is not shown when I start the app. I can see the tabs, the loading indicator is gone (and I know adapter has data) but list area is clear white. And I can't pull the list to refresh it. But if i try to swap pages, suddenly data appears in previous page (actually not previous, but the one before). It seems it has something to do with adapter loading first two fragments, but I can figure out what's wrong.
How to make lists appears when they are loaded? And more general question, is this the right architecture to go on?
EDIT:
if I remove all pull-to-refresh code like this
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View layout = inflater.inflate(R.layout.fragment_subcat_nav, container, false);
return layout;
}
and set default list id in the fragment layout android:id="@android:id/list"
list view is displayed as it should. can't figure out why pull-to-refresh causes problems.
Upvotes: 0
Views: 3280
Reputation: 1096
this is how i fixed the problem (list fragment need to return a list view)
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.fragment_subcat_nav, container, false);
ListView lv = (ListView) layout.findViewById(android.R.id.list);
mPullToRefreshListView = new PullToRefreshListView(getActivity());
mPullToRefreshListView.setLayoutParams(lv.getLayoutParams());
mPullToRefreshListView.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener<ListView>()
{
@Override
public void onRefresh(PullToRefreshBase<ListView> refreshView) {
downloadContent(true);
}
});
return mPullToRefreshListView;
}
Upvotes: 2