emeraldhieu
emeraldhieu

Reputation: 9439

How to add footer ProgressBar after the last item of GridView

This is my code. It loads more data when being out of data. I want to add a footer ProgressBar to GridView when it loads more data. How to do? I've seen many questions on StackOverflow but there is no answer for it.

public class MainActivity extends Activity {
    private static final String TAG = "MainActivity";
    private final List<Integer> commonImageList = new ArrayList<Integer>();
    private int index = 0;
    private boolean isLoading = false;
    private static final int NUM = 18;
    private ImageAdapter adapter;

    @Override
    public void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final Task task = new Task(mThumbIds, index);
        task.setOnPostExecuteListener(new OnPostExecuteListener<List<Integer>>() {
            @Override
            public void onPostExecute(final List<Integer> result) {
                System.out.println("RESULT: " + result);
                if(result.isEmpty()) {
                    return;
                }

                // Store it.
                commonImageList.addAll(result);

                // Prepare gridView.
                final GridView gridview = (GridView) findViewById(R.id.gridview);
                adapter = new ImageAdapter(MainActivity.this, commonImageList);
                gridview.setAdapter(adapter);

                gridview.setOnScrollListener(new OnScrollListener() {
                    @Override
                    public void onScrollStateChanged(final AbsListView view, final int scrollState) {

                    }

                    @Override
                    public void onScroll(final AbsListView view, final int firstVisibleItem,
                            final int visibleItemCount, final int totalItemCount) {
                        System.out.println("firstVisibleItem: " + firstVisibleItem);
                        System.out.println("visibleItemCount: " + visibleItemCount);
                        System.out.println("totalItemCount: " + totalItemCount);

                        final boolean loadMore = (firstVisibleItem + visibleItemCount >= totalItemCount);
                        System.out.println("loadMore: " + loadMore);
                        System.out.println("isLoading: " + isLoading);

                        if(loadMore && !isLoading) {
                            // TODO Show footer here.


                            ShowLog.showLogInfo(TAG, "============= LOAD MORE =============");
                            // Get more images.
                            index = index + NUM;
                            final Task task = new Task(mThumbIds, index);
                            task.setOnPreExecuteListener(new OnPreExecuteListener() {
                                @Override
                                public void onPreExecute() {
                                    isLoading = true;
                                }
                            });
                            task.setOnPostExecuteListener(new OnPostExecuteListener<List<Integer>>() {
                                @Override
                                public void onPostExecute(final List<Integer> result) {
                                    System.out.println("RESULT222: " + result);

                                    if(result.isEmpty()) {
                                        return;
                                    }
                                    System.out.println("HIEU THONG MINH");

                                    // Update common list.
                                    commonImageList.addAll(result);

                                    // Update adapter.
                                    adapter.notifyDataSetChanged();

                                    isLoading = false;
                                }
                            });
                            task.execute();
                        }
                    }
                });
            }
        });
        task.execute();

    }

    private class Task extends AbstractWorkerTask<Void, Void, List<Integer>> {
        private final Integer []thumbs;
        private final int index;

        public Task(final Integer []thumbs, final int index) {
            this.thumbs = thumbs;
            this.index = index;
        }

        @Override
        protected List<Integer> doInBackground(final Void... params) {
            final List<Integer> list = new ArrayList<Integer>();
            for(int i = index; i < index + NUM && i < thumbs.length; ++i) {
                list.add(thumbs[i]);
            }
            return list;
        }
    }

    public static class ImageAdapter extends BaseAdapter {
        private final Context context;              
        private final List<Integer> imageList;

        public ImageAdapter(final Context c, final List<Integer> imageList) {
            context = c;
            this.imageList = imageList;
        }

        @Override
        public int getCount() {
            return imageList.size();
        }

        @Override
        public Object getItem(final int position) {
            return null;
        }

        @Override
        public long getItemId(final int position) {
            return 0;
        }

        // create a new ImageView for each item referenced by the Adapter
        @Override
        public View getView(final int position, final View convertView, final ViewGroup parent) {
            ImageView imageView;
            if (convertView == null) {  // if it's not recycled, initialize some attributes
                imageView = new ImageView(context);
                imageView.setLayoutParams(new GridView.LayoutParams(150, 150));
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                imageView.setPadding(8, 8, 8, 8);

            } else {
                imageView = (ImageView) convertView;
            }

            imageView.setImageResource(imageList.get(position));
            return imageView;
        }
    }

    // references to our images
    private static final Integer[] mThumbIds = {
            R.drawable.sample_2, R.drawable.sample_3,
            R.drawable.sample_4, R.drawable.sample_5,
            R.drawable.sample_6, R.drawable.sample_7,
            R.drawable.sample_0, R.drawable.sample_1,
            R.drawable.sample_2, R.drawable.sample_3,
            R.drawable.sample_4, R.drawable.sample_5,
            R.drawable.sample_6, R.drawable.sample_7,
            R.drawable.sample_0, R.drawable.sample_1,
            R.drawable.sample_2, R.drawable.sample_3,
            R.drawable.sample_4, R.drawable.sample_5,
            R.drawable.sample_6, R.drawable.sample_7,
            R.drawable.sample_0, R.drawable.sample_1,
            R.drawable.sample_2, R.drawable.sample_3,
            R.drawable.sample_4, R.drawable.sample_5,
            R.drawable.sample_6, R.drawable.sample_7,
            R.drawable.sample_0, R.drawable.sample_1,
            R.drawable.sample_2, R.drawable.sample_3,
            R.drawable.sample_4, R.drawable.sample_5,
    };
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/gridview"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:columnWidth="150dp"
    android:numColumns="3"
    android:verticalSpacing="10dp"
    android:horizontalSpacing="10dp"
    android:stretchMode="columnWidth"
    android:gravity="center"
/>

Upvotes: 5

Views: 3973

Answers (2)

Balance
Balance

Reputation: 198

I have found a much less intrusive way to do this, by taking advantage of the dynamic layout changes when making an item visible / gone. For this purpose I used a relative layout, but might work with something else as well. This is the xml layout:

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

   <ProgressBar
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:id="@+id/loader_view"
    android:visibility="visible"
    android:layout_alignParentBottom="true"
    android:layout_alignParentStart="true"
    android:layout_centerHorizontal="true"
    android:padding="32dp" />

<GridView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/grid_view"
    android:layout_toStartOf="@id/loader_view"
    android:layout_alignParentRight="true"
    android:layout_alignParentEnd="false"
    android:layout_above="@+id/loader_view"
    android:numColumns="@integer/grid_view_column_count"
    android:scrollbarStyle="insideOverlay"
    android:scrollbars="none"
    android:listSelector="@null"
    android:smoothScrollbar="false"></GridView>

</RelativeLayout>

Some notes on this:

The progress bar is displayed below the gridview, but you have to define it before in the xml, because of the: android:layout_toStartOf="@id/loader_view" reference in the GridView.

You can increase the padding on the progressbar in order to make the loading area bigger, e.g. to match up with the row height of your grid.

The grid view's android:numColumns="@integer/grid_view_column_count" is a dynamic value from resources, feel free to change it. You can use just a number there, but it's nicer to externalise, as you can set the values depending on the screen width.

The following code goes to your Fragment's onCreateView:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.grid_and_loader_view, container, false);
    GridView gridView = (GridView) view.findViewById(R.id.grid_view);
    //store a class reference to the loader:
    _loader = (ProgressBar) view.findViewById(R.id.loader_view);
    //set up your grid adapter e.g.:
    //_adapter = new GridImageAdapter(this.getActivity());
    //gridView.setAdapter(_adapter);
    return view;
}

You can start / stop the loading from your fragment the following way:

public void startLoading() {
    if(_loader != null) {
        _loader.setVisibility(View.VISIBLE);
    }
}

public void stopLoading() {
    if(_loader != null) {
        _loader.setVisibility(View.GONE);
    }
}

I have found, that a better a solution is to control the loading behaviour from the adapter, so I passed the fragment as a reference in a form of a Loadable interface (optional) to the adapter, and call the above start/stopLoading functions from there.

Upvotes: 0

Trung Nguyen
Trung Nguyen

Reputation: 7532

Here the logic i did to add load more item in GridView
1. Create a fake item at the last of Adapter's input data

public class MediaGridAdapter extends BaseAdapter {

    private ArrayList<Media> list;
    private final Media special = new Media("-1", "", "", "", ""); 

    public MediaGridAdapter(Context context, int imageID, ArrayList<Media> array, int type) {

        list = array;

        if(list != null) {
            list.add(special);
        }
            }

public void appendDataList(ArrayList<Media> appendedList, boolean isEnd) { //called in postExecute to append new data

    //remove special element in original list
    list.remove(list.size() - 1);
    //append collection of media to list
    list.addAll(appendedList);
    //check to add special element
    if(!isEnd) {

        list.add(special);
    }
}   
}

2. In getView method : Check if it's the last position (is our fake item) return special layout( progress bar...) for this.

    if(position == (list.size() - 1)) {

        Context context = parent.getContext();
        item = (RelativeLayout) LayoutInflater.from(context).inflate(R.layout.item_special_more, null);
        item.setTag(MORE_BUTTON);
        return item;
    }

The last in onItemClick check tag to start getMoreAsyncTask

if (v.getTag().equals(MediaGridAdapter.MORE_BUTTON)) {    

                        GetMoreItems task = new GetMoreItems();
                        task.execute(url);
                        return;
                    }

Upvotes: 3

Related Questions