1

There's very little literature on this topic, and google's documents don't account for the possibility of customization (listviewanimation) of the fragment's list using ListFragment extension. Therefore, I'm going to ask this question, and then answer it as best as possible, because I also want 50 reputation points so I can finally thank great explainers on this website through comments.

For the purpose of this comment, I will have components from the listviewanimation lib laced in:

https://github.com/nhaarman/ListViewAnimations

Answer:

We will need to set up 4 components to have a proper fragment with a listview component

  • The Activity Creating the fragment through the activity's fragment manager.
  • The Fragment class which will be pretty basic fragment stuff, it will have the listview, and it will link that listview with an arrayadapter.
  • The Adapter class which for our purposes will only handle strings.
  • WITHIN THE ADAPTER CLASS the final fourth component will be a viewholder class which will allow the rows within the list to be created faster, since each row's individual components will be wrapped up in a class that will allow for quicker object instantiation.

Ok so, first will be the code for the activity, this code can be called by a button click or some other event. When the event happens, the fragment manager will be created, and that fragment manager will create a transaction which is a fancy way of saying, the manager will communicate between the activity and the newly formed fragment to get everything set up properly.

Here's the code that should be placed in your activity where the event occurs:

FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
GenericFragment fragment = new GenericFragment();
fragmentTransaction.add(R.id.pager, fragment); 
//Replace R.id.pager with the view that you want your fragment to go in.
fragmentTransaction.commit();

That's it! Not so bad, is it? Now let's move on to the GenericFragment class, which you can create a different name of course. I won't be posting all the code for this, but I'll step through everything you need for a fragment class that has a listview:

  • Have your Fragment class extend Fragment
  • Have an empty constructor for this class (google requires it... -__- )

Create a newInstance method which will handle the passing of data from the activity to the fragment when a 'new instance' of the fragment is created from the activity:

I'll help you with this one:

public static GenericFragment newInstance(String StuffYouWantGetsPassedFromActivityToFragment) {
    GenericFragment GenericFragment = new GenericFragment();

    Bundle args = new Bundle();
    GenericFragment.setArguments(args);

    return GenericFragment;
}

Again not so bad, right? We're still not done, we still need to override onCreateView and onCreate, then we'll be done with this simple step!

Ok for onCreateView:

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

    addGoalButton = (Button) view.findViewById(R.id.btn_newRow); //Created for testing purposes
    lv = (ListView) view.findViewById(R.id.GenericListView);

    addGoalButton.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) { //Created for testing purposes
            genericAdapter.add("Goal");
            genericAdapter.notifyDataSetChanged();
        }

    });

    lv.setAdapter(genericAdapter);
    return view;
}

That above code may seem like a monstrosity, and you're right! The high level overview is that you're getting the layout file that you want the fragment to look like. From that layout file, you're getting the listview and creating a variable to hold it in. Then you're calling that listView's 'setAdapter' method to add the next step, the adapter class. For testing purposes, I added that button, so that you can mentally extend this tutorial l8er. (delete all button code if you'd like just a list)

Ok, one last step in the fragment class: Overriding OnCreate!

The OnCreate method is where you want to instantiate all your private variables like the genericAdapter variable or anything that you'd like to use over the multiple parts of the Fragment class.

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    ArrayList<String> exampleItemList = new ArrayList<String>();
    exampleItemList.add("item1");
    exampleItemList.add("item2");
    exampleItemList.add("item3");
    exampleItemList.add("item4");
    exampleItemList.add("item5");
    exampleItemList.add("item6");
    exampleItemList.add("item7");
    exampleItemList.add("item8");
    exampleItemList.add("item9");
    exampleItemList.add("item10");
    exampleItemList.add("item11");
    exampleItemList.add("item12");
    genericAdapter = new genericAdapter(getActivity(), 0, exampleItemList);

    setHasOptionsMenu(true); // Allows the fragment to change the menu buttons
}

I added the example items to an arrayList to make this tutorial a bit more transparent about where data is coming from, and where it's going.

That's it! You're Fragment is done! It's almost over, I promise.

Let's knock these last two steps out together, creating a GenericAdapter class that extends ArrayAdapter and has a private inner ViewHolder class to wrap all the layout components in:

 public class GenericAdapter extends ArrayAdapter<String>

LayoutInflater layoutInflater;

//Used to get the correct LayoutInflater to inflate each row item
public GenericAdapter(Context context, int resource, List<String> objects) {
    super(context, 0, objects);
    layoutInflater = layoutInflater.from(context);
}


/**
 * @param position The position in the list to get the data for that row item.
 * @param convertView The view for the row item that will be shown in the list.
 * @param parent Having this object allows you to use the LayoutInflater for the parent.
 * @return
 */
@Override
public View getView(int position, View convertView, ViewGroup parent) {

    final GenericViewHolder GenericViewHolder;
    final String item = getItem(position);

    if(convertView == null){
        LinearLayout rootView = (LinearLayout) layoutInflater.inflate(R.layout.item_row, parent, false);
        genericViewHolder = genericViewHolder.create(rootView);
        rootView.setTag(genericViewHolder);
    }
    else{
        genericViewHolder = (genericViewHolder) convertView.getTag();
    }

    genericViewHolder.textView.setText(item);

    return genericViewHolder.rootView;
}

/**
 * ViewHolder's allow for a single object to maintain a Goal row item, so that the row item
 * doesn't have to create each individual component (textview layout etc.) each time the
 * row object is created/recreated. Allows for fast scrolling with little latency.
 */
private static class GenericViewHolder {
    public final LinearLayout rootView;
    public final GripView gripView;
    public final TextView textView;


    private GoalViewHolder(LinearLayout rootView, GripView gripView, TextView textView) {
        this.rootView = rootView;
        this.gripView = gripView;
        this.textView = textView;
    }

    public static GoalViewHolder create(LinearLayout rootView){
        TextView textView = (TextView)rootView.findViewById(R.id.list_row_draganddrop_textview);
        GripView gripView = (GripView)rootView.findViewById(R.id.list_row_draganddrop_touchview);
        return new GenericViewHolder(rootView, gripView, textView);
    }
}

}

That was again, a monstrosity, let's look at the high level overview, we created an adapter class, and a viewholder class for the adapter class to use. In the adapter's constructor we got a layoutinflater to help with inflating each row's item. Then, we created the getView method which get's called thousands of times in your app, because it handles making the each row appear when it's viewable by the user. The getView method sees if the view to be converted into a row is null or not. If it is, it will create a new data entry (a viewholder), but if it's not null, then that viewholder has already been created, so we get whatever was inside the viewholder already, so that we don't have to create a new row item.

phew! I don't expect you to understand any of that, but congrats if you do.

Ok so that's it. You should be set, and when your activity's event get's called, the fragment will show up in whatever view is containing the fragment. I'll post my xml files in my answer so that I can get those delicious upvotes (or not, I may be completely incorrect, but this worked for me!)

enjoy life, don't give up!

slackbot39243
  • 241
  • 3
  • 15
  • 2
    So, what's this, a tutorial? – Phantômaxx Nov 06 '14 at 16:02
  • Yea, pretty much. I couldn't find the proper resources to make a listview in a fragment, because google flooded that tutorial niche with some class called ListFragment, that doesn't easily allow for customization using libs like listviewanimation: https://github.com/nhaarman/ListViewAnimations Plus, I'm in a really boring class, so I figured I would document my approach. Plus, I really want those 50 rep points, so that I can comment on this post: http://stackoverflow.com/a/18319050/2977650 to thank them on a job well done – slackbot39243 Nov 06 '14 at 16:04
  • 1
    A ListView in a Fragment or in an Activity is my favourite way to provide ListViews, since years. And it's a very easy thing to do: just put a ListView in an xml layout an use that layout as the contententView for your Activity or Fragment. – Phantômaxx Nov 06 '14 at 16:08
  • That's what I had problems with. You say, "JUST do one sentence of instructions" when in reality there's so much more to do. I couldn't find a reliable source, so I made sure to be explicit with what's going on, and to be very specific as well, so there isn't an overwhelming amount of blunt info as in the case of google docs. Maybe it's just me though. I get distracted easily, and so google docs are a nightmare of boring text blocks – slackbot39243 Nov 06 '14 at 16:11
  • 1
    It's something so simple and intuitive. I don't provide the details, because it would require space, but it's really easy. – Phantômaxx Nov 06 '14 at 16:16
  • For you maybe, for someone not very quick on the uptake, like me, not so much. – slackbot39243 Nov 06 '14 at 16:18
  • 1
    http://www.vogella.com/tutorials/AndroidListView/article.html – Phantômaxx Nov 06 '14 at 16:22
  • 2
    How about just inflate a layout with a ListView as child? – StoneBird Nov 06 '14 at 16:25
  • From Vogella: http://puu.sh/cFDXz/d1330492a4.png From StackOverflow: http://puu.sh/cFE4b/8259d57d78.png Plus, no offense to vogella, but in the words of Sweet Brown, "Aint nobody got time fo dat" @StoneBird I guess I wanted to be more explicit so that people like me knew exactly where the listview object was to manipulate. No foul in doing it that way I suppose, but I haven't tried that. – slackbot39243 Nov 06 '14 at 16:33
  • 1
    @eduardowarded so are you ok with extending `Fragment` itself? I mean not `ListFragment` but the `Fragment` class. But you can't get around with overriding stuff though. – StoneBird Nov 06 '14 at 16:43
  • Yes? You're not giving me much to go on, so I'm gonna say, no I can't get around doing what you're describing. Look, I get what you're saying, I'm not skilled, so what? I'm trying to help out. What would you have me do? If you think what I showed was completely flawed then go ahead and explicitly show what needs to be done in an answer and I'll mark it as right. – slackbot39243 Nov 06 '14 at 17:05
  • 1
    Now, to simplify to the bones: a ListView is a "cousin" of the GridView (and a "minor brother" of the ExpandableListView). See here:http://developer.android.com/guide/topics/ui/declaring-layout.html#AdapterViews. – Phantômaxx Nov 06 '14 at 19:18

1 Answers1

0

The activity xml, most of it is irrelevant to you the reader, but the container view for the fragment is pager:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<!--Navigation Drawer Still Under Construction-->
<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         The drawer is given a fixed width in dp and extends the full height of
         the container. A solid background is used for contrast
         with the content view. -->

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#ffff"/>
</android.support.v4.widget.DrawerLayout>
<!--Navigation Drawer Still Under Construction-->


<!--Customizations on README at: https://github.com/astuetz/PagerSlidingTabStrip-->
<com.astuetz.PagerSlidingTabStrip
    android:id="@+id/tabs"
    android:layout_width="wrap_content"
    android:layout_height="48dip"
    app:pstsShouldExpand="true"
    app:pstsIndicatorHeight="5dip"
    app:pstsDividerPadding="0dip"
    app:pstsDividerColor="#ff6d00"
    app:pstsUnderlineColor="#ff5722"
    app:pstsIndicatorColor="#ff5722"/>

<!--To scale the viewpager vertically, android:layout_above="@+id/[viewname]" -->
<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/tabs"
    tools:context=".MainActivity" />

</RelativeLayout>

The xml layout for the fragment:

<?xml version="1.0" encoding="utf-8"?>



<Button
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="New Item"
    android:id="@+id/btn_newItem"
    android:layout_alignParentBottom="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true" />

<com.nhaarman.listviewanimations.itemmanipulation.DynamicListView
    android:id="@+id/GenericListView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_alignParentTop="true"
    android:layout_alignParentLeft="true"
    android:layout_alignParentStart="true"
    android:layout_above="@+id/btn_newGoal" />

The specific row item:

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

<com.nhaarman.listviewanimations.itemmanipulation.dragdrop.GripView
    android:id="@+id/list_row_draganddrop_touchview"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:color="@android:color/darker_gray"
    android:paddingBottom="4dp"
    android:paddingLeft="8dp"
    android:paddingRight="8dp"
    android:paddingTop="4dp" />

<TextView
    android:id="@+id/list_row_draganddrop_textview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fontFamily="sans-serif-light"
    android:gravity="center_vertical"
    android:minHeight="48dp"
    android:textColor="?android:attr/textColorSecondary"
    android:textSize="20sp"
    tools:ignore="UnusedAttribute" />
</LinearLayout>

The layout portion of the 2nd code snippet got cut off and SO wasn't agreeing with my ctrl K'ing, but the long and short of it, is that it doesn't matter, because the listview is there, so it doesn't matter whether you put it in a linear layout or a relative layout.

Good luck bro's happy coding

slackbot39243
  • 241
  • 3
  • 15