ListFragment does not accept my layout
Asked Answered
B

10

11

According to this link: ListFragment android developers

I want to set my custom layout for list, but it makes exceptions.

Here is the code:

public class ListFragmentActivity extends FragmentActivity {

@Override
public void onCreate(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    FragmentManager fm = getSupportFragmentManager();
    if(fm.findFragmentById(android.R.id.content) == null)
    {
        myListFragments list = new myListFragments();
        fm.beginTransaction().add(android.R.id.content, list).commit();
    }
}

public static class myListFragments extends ListFragment
{
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        return inflater.inflate(R.layout.topoffers, container, false);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onActivityCreated(savedInstanceState);
        List<OfferModel> offers = Global.getInstance().getOffers();
        List<OfferModel> topOffers = new ArrayList<OfferModel>(4);
        for (int i = 0; i < 4; i++) {
            if (offers.get(i).getOfferImage() == null)
                offers.get(i).setOfferImage(
                        downloadFile(offers.get(i).getOfferImageUrl()));
            topOffers.add(offers.get(i));
        }
        LazyAdapter adapter = new LazyAdapter(getActivity());
        adapter.setData(topOffers);
        setListAdapter(adapter);
        setListShown(true);
    }

    public Bitmap downloadFile(String fileUrl) {
        URL myFileUrl = null;
        try {
            myFileUrl = new URL(fileUrl);
        } catch (MalformedURLException e) {
            e.printStackTrace();
            return null;
        }
        try {
            HttpURLConnection conn = (HttpURLConnection) myFileUrl
                    .openConnection();
            conn.setDoInput(true);
            conn.connect();
            InputStream is = conn.getInputStream();
            return BitmapFactory.decodeStream(is);
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}}

and my custom layout is R.layout.topoffers

Logcat:

 05-15 21:43:56.975: W/dalvikvm(218): threadid=3: thread exiting with uncaught exception (group=0x4001b188) 
 05-15 21:43:56.975: E/AndroidRuntime(218): Uncaught handler: thread main exiting due to uncaught exception
 05-15 21:43:56.995: E/AndroidRuntime(218): java.lang.RuntimeException: Unable to start activity ComponentInfo{org.anddev.android.ikiwi/org.anddev.android.ikiwi.ListFragmentActivity}:
    java.lang.IllegalStateException: Can't be used with a custom content view 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2496) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.app.ActivityThread.access$2200(ActivityThread.java:119) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.os.Handler.dispatchMessage(Handler.java:99) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.os.Looper.loop(Looper.java:123) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.app.ActivityThread.main(ActivityThread.java:4363) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at java.lang.reflect.Method.invokeNative(Native Method) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at java.lang.reflect.Method.invoke(Method.java:521) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at dalvik.system.NativeStart.main(Native Method) 
 05-15 21:43:56.995: E/AndroidRuntime(218): Caused by: java.lang.IllegalStateException:
    Can't be used with a custom content view 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.support.v4.app.ListFragment.setListShown(ListFragment.java:282)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.support.v4.app.ListFragment.setListShown(ListFragment.java:258)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at org.anddev.android.ikiwi.ListFragmentActivity$myListFragments.onActivityCreated(ListFragmentActivity.java:57)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:891)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1080)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:622)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1416)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.support.v4.app.FragmentActivity.onStart(FragmentActivity.java:505)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1129)
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.app.Activity.performStart(Activity.java:3723) 
 05-15 21:43:56.995: E/AndroidRuntime(218):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2468)
 05-15 21:43:56.995: E/AndroidRuntime(218):     ... 11 more 
 05-15 21:43:57.025: I/dalvikvm(218): threadid=7: reacting to signal 3 
 05-15 21:43:57.025: E/dalvikvm(218): Unable to open stack trace file '/data/anr/traces.txt': Permission denied
Blowfish answered 15/5, 2012 at 20:44 Comment(4)
This needs to be more specific than 'it makes exceptions'Dasilva
right but i can not determine what is makes exceptionBlowfish
Post your logcat showing the errorsTarboosh
Which is line 57 in ListFragmentActivity?Tarboosh
T
5

This sounds like an issue that's been reported to Google already.

Google Issue

If this is indeed your issue, there's a couple of suggestions at the bottom of that page for fixing it (well, more making it work than fixing it).

Tarboosh answered 16/5, 2012 at 4:29 Comment(7)
thank you mr barak but in this suggestion he wrote in the short term I can only see overriding setEmptyText(String)::void and manually handling an empty view.. ..... how can i override setEmptyText function?Blowfish
I believe you just delete the textview from your layout and in your onActivityCreated put setEmptyText("Your emptyText message"). All the examples I've found show that being used before you create/set the adapter.Tarboosh
i did what you said to me but unfortunately it does not work, it still causes exception.Blowfish
it working correctly with its default layout, but i still can not apply my layout forlistBlowfish
i found what causes the problem but i can not solve it, the problem was in setListShown(boolean), when i delete it,it working correctly but i need it cuz i am implementing AsyncTaskLoader in loading data so need to make the list hidden while loading data as sson as the progress bar can appearBlowfish
okay thank you mr barak, i made fragment in my layout and give it my list fragment class .... many thanks for helpBlowfish
In my case, I just need to use ((TextView)getListView().getEmptyView()).setText(getString(R.string.empty_message)); instead of setEmptyText(getString(R.string.empty_message)). Credit for the Google issue link above.Privily
Y
23

Create the layout file list_content.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
    <LinearLayout android:id="@+id/progressContainer"
            android:orientation="vertical"
            android:layout_width="match_parent" 
            android:layout_height="match_parent"
            android:visibility="gone"
            android:gravity="center">
        
        <ProgressBar style="?android:attr/progressBarStyleLarge"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content" />
        <TextView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textAppearance="?android:attr/textAppearanceSmall"
                android:text=""
                android:paddingTop="4dip"
                android:singleLine="true" />
            
    </LinearLayout>
        
    <FrameLayout android:id="@+id/listContainer"
            android:layout_width="match_parent" 
            android:layout_height="match_parent">
            
        <ListView android:id="@android:id/list"
                android:layout_width="match_parent" 
                android:layout_height="match_parent"
                android:drawSelectorOnTop="false" />
        <TextView android:id="@+id/internalEmpty"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:textAppearance="?android:attr/textAppearanceLarge" />
    </FrameLayout>
        
</FrameLayout>

Put this inside your ListFragment class:

public ListView mList;
boolean mListShown;
View mProgressContainer;
View mListContainer;

public void setListShown(boolean shown, boolean animate){
    if (mListShown == shown) {
        return;
    }
    mListShown = shown;
    if (shown) {
        if (animate) {
            mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
                    getActivity(), android.R.anim.fade_out));
            mListContainer.startAnimation(AnimationUtils.loadAnimation(
                    getActivity(), android.R.anim.fade_in));
        }
        mProgressContainer.setVisibility(View.GONE);
        mListContainer.setVisibility(View.VISIBLE);
    } else {
        if (animate) {
            mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
                    getActivity(), android.R.anim.fade_in));
            mListContainer.startAnimation(AnimationUtils.loadAnimation(
                    getActivity(), android.R.anim.fade_out));
        }
        mProgressContainer.setVisibility(View.VISIBLE);
        mListContainer.setVisibility(View.INVISIBLE);
    }
}
public void setListShown(boolean shown){
    setListShown(shown, true);
}
public void setListShownNoAnimation(boolean shown) {
    setListShown(shown, false);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    int INTERNAL_EMPTY_ID = 0x00ff0001;
    View root = inflater.inflate(R.layout.list_content, container, false);
    (root.findViewById(R.id.internalEmpty)).setId(INTERNAL_EMPTY_ID);
    mList = (ListView) root.findViewById(android.R.id.list);
    mListContainer =  root.findViewById(R.id.listContainer);
    mProgressContainer = root.findViewById(R.id.progressContainer);
    mListShown = true;
    return root;
}

Now you can use normally:

setListShown(boolean shown);
setListShown(boolean shown, boolean animate);
setListShownNoAnimation(boolean shown);

Source:

http://source-android.frandroid.com/frameworks/base/core/java/android/app/ListFragment.java

http://source-android.frandroid.com/frameworks/base/core/res/res/layout/list_content.xml

Yorker answered 19/9, 2012 at 23:6 Comment(0)
Y
14

This might be easier: Create your layout as you would normally but don't add the list/empty/loading stuff. Then in your listfragment's onCreateView:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = super.onCreateView(inflater, container, savedInstanceState);
    ViewGroup parent = (ViewGroup) inflater.inflate(R.layout.mylayout, container, false);
    parent.addView(v, 0);
    return parent;
}

Now you can use setListShown...

Yahrzeit answered 22/5, 2013 at 8:58 Comment(6)
Just tried, it works. Best solution here! Much more simple than the other one as you keep all the methods from the SDK working.Introduce
Not only can you use setListShow(), but you get all the stock behavior and look within the confines of your own greater layout. You may want to put a container within the parent and add the super view to it instead of to the parent itself.Dichromaticism
This works, but as you can see here, it causes your hierarchy to have two android:id/list.Citadel
+1 billion. I needed this solution for a different problem. I needed my own extra Views above and below the ListView used in ListFragment. I wanted to keep their ListView because I wanted to keep the progress bar/empty TextView functionality, but I needed some other Views in the fragment as well, not just a ListView. This method allowed me to drop their whole layout into my own. Took some playing around, but I was able to drop it into an empty FrameLayout in the middle of my LinearLayout. For whatever reason I couldn't directly add the view like you did without my layout looking wrong.Crossley
Also the Android doc's (scroll to onCreateView()) suggest something similar, where you <include> the list_content layout (the resource ID for their default layout -can be found in the Android SDK's /res folder) in your XML. But that would only work with API 11+ while this approach should be backward compatible with the Support-V4 library's ListFragment back to API 4. Kudos man, I wouldn't have thought of doing this.Crossley
" but don't add the list/empty/loading stuff. " - I need to show a specific string text in @+id/empty TextView. Is there a solution for that?Opec
P
8

Just replace the original ListView with your CustomListView Layout within the onCreateView method. Worked for me.

    @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View layout = super.onCreateView(inflater, container,
            savedInstanceState);
    ListView lv = (ListView) layout.findViewById(android.R.id.list);
    ViewGroup parent = (ViewGroup) lv.getParent();

    // Remove ListView and add CustomView  in its place
    int lvIndex = parent.indexOfChild(lv);
    parent.removeViewAt(lvIndex);
    LinearLayout mLinearLayout = (LinearLayout) inflater.inflate(
            R.layout.custom_list, container, false);
    parent.addView(mLinearLayout, lvIndex, lv.getLayoutParams());
    return layout;
}
Pembrook answered 8/4, 2013 at 13:42 Comment(1)
Kudos for removing the unnecessary list view from the hierarchy.Citadel
T
5

This sounds like an issue that's been reported to Google already.

Google Issue

If this is indeed your issue, there's a couple of suggestions at the bottom of that page for fixing it (well, more making it work than fixing it).

Tarboosh answered 16/5, 2012 at 4:29 Comment(7)
thank you mr barak but in this suggestion he wrote in the short term I can only see overriding setEmptyText(String)::void and manually handling an empty view.. ..... how can i override setEmptyText function?Blowfish
I believe you just delete the textview from your layout and in your onActivityCreated put setEmptyText("Your emptyText message"). All the examples I've found show that being used before you create/set the adapter.Tarboosh
i did what you said to me but unfortunately it does not work, it still causes exception.Blowfish
it working correctly with its default layout, but i still can not apply my layout forlistBlowfish
i found what causes the problem but i can not solve it, the problem was in setListShown(boolean), when i delete it,it working correctly but i need it cuz i am implementing AsyncTaskLoader in loading data so need to make the list hidden while loading data as sson as the progress bar can appearBlowfish
okay thank you mr barak, i made fragment in my layout and give it my list fragment class .... many thanks for helpBlowfish
In my case, I just need to use ((TextView)getListView().getEmptyView()).setText(getString(R.string.empty_message)); instead of setEmptyText(getString(R.string.empty_message)). Credit for the Google issue link above.Privily
L
2

Today I had the same issue. Looking the solution in Google, I found a post in a japanese blog. (http://blog.nkzn.net/entry/2012/06/14/160706).

For use setListShown(boolean) you must do first in your layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <FrameLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >
    </ListView>
    </FrameLayout>

    <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_centerInParent="true"
    android:gravity="center"
    android:visibility="gone" >

    <ProgressBar
        android:id="@android:id/progress"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    </LinearLayout>
</RelativeLayout>

Now in your ListFragment:

public class SampleListFragment extends ListFragment {

  /** ID for progressbar parent */
  private static final int INTERNAL_PROGRESS_CONTAINER_ID = 0x00ff0002;
  /** ID for listview parent */
  private static final int INTERNAL_LIST_CONTAINER_ID = 0x00ff0003;

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.custom_list_layout, container, false);

    // get you progressBar and his parent
    ProgressBar pBar = (ProgressBar) view.findViewById(android.R.id.progress);
    LinearLayout pframe = (LinearLayout) pBar.getParent();
    pframe.setId(INTERNAL_PROGRESS_CONTAINER_ID);

    ListView listView = (ListView) view.findViewById(android.R.id.list);
    listView.setItemsCanFocus(false);
    FrameLayout lFrame = (FrameLayout) listView.getParent();
    lFrame.setId(INTERNAL_LIST_CONTAINER_ID);    

    return view;
  } 
}

with this 2 ids numbers seted in his parents setListShown(boolean) will work without problems.

Leventhal answered 8/5, 2013 at 23:8 Comment(1)
I read the ListFragment and this is the only way.. Thank you =)Neuropath
T
1

Another solution that worked for me as well is just to put this line

<include layout="@android:layout/list_content" />

instead of your list view.

You are able to build your own content on top of it or surround it with some other views. For example, here is how my layout looks like:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="@dimen/default_view_padding"
        android:gravity="center"
        android:weightSum="4">

    <ImageButton
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:id="@+id/btnCounterBack"
            android:src="?attr/ic_previous"
            android:background="?android:attr/selectableItemBackground"
            android:contentDescription="@null"/>

    <TextView
            android:id="@+id/tvCounterLevel"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:text="@string/counter_categories"
            android:layout_gravity="center"
            android:paddingTop="@dimen/default_view_padding"
            android:paddingBottom="@dimen/default_view_padding"
            android:layout_alignParentTop="true"
            android:layout_alignParentLeft="true"
            android:layout_alignParentStart="true"
            android:gravity="center"/>

</RelativeLayout>

<LinearLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:gravity="center_vertical"
        android:background="?attr/dropShadowBackground"
        android:orientation="vertical" >

    <include layout="@android:layout/list_content" />

</LinearLayout>

Toilet answered 5/8, 2014 at 20:0 Comment(0)
B
0

I just needed to change my empty text TextView properties and did this

@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
    // Swap the new cursor in. (The framework will take care of closing the
    // old cursor once we return)
    mAdapter.swapCursor(cursor);
    if (cursor.getCount() == 0) {
        setEmptyText(getString(R.string.no_users));
        TextView tvEmpty = (TextView) getListView().getEmptyView();
        tvEmpty.setTextColor(getResources().getColor(R.color.blue));
    }
    // The list should now be shown.
    if (isResumed()) {
        setListShown(true);
    } else {
        setListShownNoAnimation(true);
    }
}

Do not forget that if you try initializing tvEmpty before you call setEmptyText("Empty"), you'll run into a NullPointerException

Backsaw answered 29/4, 2013 at 4:53 Comment(0)
R
0

This code worked for me:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View root = super.onCreateView(inflater, container, savedInstanceState);

    ((TextView)root.findViewById(0x00ff0001)).setText("some text");

    ListView list = (ListView) root.findViewById(android.R.id.list);
    list.setEmptyView(root.findViewById(0x00ff0001));

    return root;
}
Richmal answered 19/10, 2013 at 5:26 Comment(0)
H
0

A little bit late, but did not see this answer.

Inside Fragment:

    @Override
    public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
            final Bundle savedInstanceState) {
        final View view = inflater.inflate(R.layout.fragment_list_activity,
                container, false);  

        ListFragmentHelper.adaptView(view);

        return view;
    }

but bear in mind that in fragment_list_activity.xml you need to set the IDs android:id="@id/loading", android:id="@id/content" and android:id="@id/empty" for your views!

Hamil answered 6/12, 2017 at 16:24 Comment(0)
A
-2

Try to remove setListShown(true);?

I had same problem, some time ago. It's seams that you cant use it if you have custom layout in ListFragment.

Allotrope answered 13/7, 2012 at 13:22 Comment(1)
But I want to use setListSHown so I can Control whether the list is being displayed. I'd like to make it not displayed when waiting for the initial data to show in it. During this time an indeterminant progress indicator will be shown instead. The prgress indicator would be nice.Ye

© 2022 - 2024 — McMap. All rights reserved.