How to add items dynamically in a ListView that is inside a Fragment?

1

I'm developing a layout in an Android app that will be used in Tablets, basically the main layout has a Toolbar DrawerLayout , a FrameLayout and a Fragment , as below:

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

    <include
        android:id="@+id/toolbar"
        layout="@layout/default_toolbar" />

    <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"
        android:layout_below="@id/toolbar">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:baselineAligned="false"
            android:orientation="horizontal">

            <FrameLayout
                android:id="@+id/content_frame"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="0.8" />

            <fragment
                android:id="@+id/history_frag"
                class="br.com.exemplo.HistoryFragment"
                android:layout_width="0dp"
                android:layout_height="match_parent"
                android:layout_weight="0.2"
                tools:layout="@layout/history_fragment" />

        </LinearLayout>

        <ListView
            android:id="@+id/left_drawer"
            android:layout_width="240dp"
            android:layout_height="match_parent"
            android:layout_gravity="start"
            android:background="@android:color/background_light"
            android:choiceMode="singleChoice"
            android:divider="@android:color/transparent"
            android:dividerHeight="1dp" />

    </android.support.v4.widget.DrawerLayout>

</RelativeLayout>

The content_frame is responsible for accommodating the fragments according to the option selected and the history_frag is a fixed , in> has the 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">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:layout_marginTop="16dp"
        android:text="@string/lbl_history"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/textView1"
        android:layout_marginBottom="16dp">

        <ListView
            android:id="@android:id/list"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:choiceMode="singleChoice" />

    </ScrollView>

    <Button
        android:id="@+id/btnClear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/scrollView"
        android:text="@string/lbl_clear" />

</RelativeLayout>

I would like to know how to dynamically add new items in the ListView that stays within history_frag , through the current fragment that is in content_frame . I tried to do this:

// Fragment qualquer que está no content_frame, todos os fragments que serão chamados 
// possuem um Button chamado btnRandom.
public class ExemploFragment extends Fragment {

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

        Button btnRandom = (Button) v.findViewById(R.id.btnRandom);

        btnRandom.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // aqui é adicionado um novo item ao history_frag
                HistoryFragment historyFrag = (HistoryFragment) getActivity().
                        getSupportFragmentManager().findFragmentById(R.id.history_frag);
                if (historyFrag != null) {
                    historyFrag.addHistory("Um item qualquer");
                }
            }
        });

        return v;
    }

}

The HistoryFrame class looks like this:

public class HistoryFragment extends ListFragment {

    private ArrayAdapter<String> mArrayAdapter;
    private List<String> mList;

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

        mList = new ArrayList<String>();
        mList.add("a");
        mList.add("b");
        mList.add("c");
        mArrayAdapter = new ArrayAdapter<String>(getActivity(), android.R.layout.simple_list_item_1, mList);
        setListAdapter(mArrayAdapter);
    }

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

        Button btnClear = (Button) v.findViewById(R.id.btnClear);
        btnClear.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mArrayAdapter.clear();
                mArrayAdapter.notifyDataSetChanged();
            }
        });

        return v;
    }

    public void addHistory(String history) {
        if (mArrayAdapter != null) {
            mArrayAdapter.add(history);
            mArrayAdapter.notifyDataSetChanged();
        }
    }

}

In this way, only the first item is added to the ListView , I tried to debug the code and the items are passed to the HistoryFragment correctly, they just are not updated. I also tried calling notifyDataSetChanged(); inside runOnUiThread , but it did not work. Does anyone have any idea where I might be going wrong?

    
asked by anonymous 15.03.2015 / 23:09

1 answer

2

The problem is that you have put ListView inside ScrollView , which is unnecessary because ListView already manages the items that are displayed in the space that is given to it to "render".

I understand that you want to force TextView and Button to appear and ListView occupy the rest of the available space. Giving a suggestion would be:

<?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:orientation="vertical">

    <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="16dp"
        android:layout_marginTop="16dp"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:weight="1"
        android:choiceMode="singleChoice" />

    <Button
        android:id="@+id/btnClear"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/lbl_clear" />
</LinearLayout>

The trick here is to use layout_height="0dp" and layout_weight="1" , which forces you to ListView occupy all available space after calculating the size of the other children of the same parent.

    
16.03.2015 / 00:25