0

enter image description here

I am going on with Show List of Items in GridView and If I scroll the GridView the whole screen Have to Scroll not only the GridView for this purpose I used custom GridView classExpandableHeightGridView.It shown the GridView in full screen when Scroll happened.What problem I am facing is I have grabbed the list of values from WebService API call and also I have done some pagination work around in this scrolling process,that's initially It show only first Ten Items in the GridView.If we scroll down the Grid it will call the WebService API call for another Ten values If response contains more Values.It is showing all List of Items in ExpandableHeightGridView that the WebService API call is calling even we don't scroll the GridView. If I use default GridView Instead of ExpandableHeightGridView It will work properly for 10,10 pagination but scrolling is enable only for GridView not the Whole Screen.I need both task(full screen Scroll,Pagination for 10,10,..etc) to perform.

Below is my Code ExpandableHeightGridView.java

 public class ExpandableHeightGridView extends GridView {

        boolean expanded = true;

        public ExpandableHeightGridView(Context context){
            super(context);
        }

        public ExpandableHeightGridView(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        public ExpandableHeightGridView(Context context, AttributeSet attrs,
                                        int defStyle) {
            super(context, attrs, defStyle);
        }

        public boolean isExpanded() {
            return expanded;
        }

        public void setExpanded(boolean expanded) {
            this.expanded = expanded;
        }

        @Override
        public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            // HACK! TAKE THAT ANDROID!
            if (isExpanded()) {
                // Calculate entire height by providing a very large height hint.
                // View.MEASURED_SIZE_MASK represents the largest height possible.
                int expandSpec = MeasureSpec.makeMeasureSpec(MEASURED_SIZE_MASK,
                        MeasureSpec.AT_MOST);
                super.onMeasure(widthMeasureSpec, expandSpec);

                ViewGroup.LayoutParams params = getLayoutParams();
                params.height = getMeasuredHeight();
            } else {
                super.onMeasure(widthMeasureSpec, heightMeasureSpec);
            }
        }
    }

Activity class

    private void loadFeed(boolean keepListViewShown) {       

            final FeedRequest<ItemsFeed, ?> request = ItemFeedRequest(0, getLastPostDate());
            feedState.lastRequestPageAndSortParams = request.getPageAndSortParams();
            getFeedListView().setAdapter(createAdapter(new ArrayList<String>()));
        }




    private FeedRequest<ItemsFeed, ?> ItemFeedRequest(int page, Date lastPostDate) {
            return VisitedItemFeedRequest.builder(this.user.getId())
                    .pageAndOrdering(PageAndSortParams.builder()
                            .limit(10).dateOffset(lastPostDate).page(page).build())
                    .build();
        }

    private ListAdapter createAdapter(List<String> items) {
        PagedAsyncDataLoader<ItemsFeed> pagedDataProvider = new PagedAsyncDataLoader<ItemsFeed>() {
            @Override
            @SuppressWarnings("unchecked")
            public void loadPage(int page, RequestListener<ItemsFeed> requestListener) {

                final FeedRequest request =
                        ItemFeedRequest(page, getLastPostDate());
                feedState.lastRequestPageAndSortParams = request.getPageAndSortParams();

                //use cache only for the first page of data
                long cacheExpirationDelay = page == 0 ? Constants.CacheExpirationDuration.ONE_SECOND :
                        Constants.CacheExpirationDuration.ALWAYS_EXPIRED;

                getRequestController().execute(request, cacheExpirationDelay, requestListener);
            }
        };
        endlessFeedAdapter = new FeedAdapter(createListAdapter(items), pagedDataProvider);

        mergeAdapter = new MergeAdapter();
        mergeAdapter.addAdapter(endlessFeedAdapter);

        return mergeAdapter;
    }

    }
    private final class FeedAdapter extends EndlessFeedAdapter<String,ItemsFeed> {
        int count = 0;
        public FeedAdapter(ArrayAdapter<String> wrapped, PagedAsyncDataLoader<ItemsFeed>
                pagedDataProvider) {
            super(wrapped, pagedDataProvider);
        }

        @Override
        protected List<String> collectItems(ItemsFeed FEED) {
            return FEED.getData();
        }

        @Override
        protected boolean shouldLoadNextPage(ItemsFeed feed) {
            if (feed.getPaging() == null || feed.getPaging().getNext() == null
                    || feed.getPaging().getNext().isEmpty())
                return false;
            return true;

        }

        @Override
        protected void onRequestStarted() {         
                super.onRequestStarted();
                hideErrorLoading();       

        }
        protected void showErrorLoading(String errorMessage) {
            getErrorPanelController().showActionButton(android.R.drawable.ic_menu_rotate,
                    endlessAdapterLoadErrorClickListener)
                    .errorWithDefaultIcon(errorMessage).show();
        }

        private final View.OnClickListener endlessAdapterLoadErrorClickListener = new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                hideErrorLoading();
                if (endlessFeedAdapter.getCurrentPage() <= 1) {
                    reloadData();
                } else {
                    endlessFeedAdapter.restartAppending();
                }
            }
        };
        protected void hideErrorLoading() {
            getErrorPanelController().hide();
        }

        private void reloadData() {
            feedState.clear();
            loadFeed(false);
        }
        @Override
        public void onRequestFailure(Exception spiceException) {
            super.onRequestFailure(spiceException);
            showErrorLoading(getString(R.string.failed_to_load_feed));
        }

        @Override
        public void onRequestSuccess(ItemsFeed feed, boolean cached) {
            super.onRequestSuccess(feed, cached);
            feedState.updatePaging(feed.getPaging());
            if (cached) {
                //ASOC-221 - handle cached result and display message to user that "offline" results were shown
                showErrorLoading(getString(R.string.offline_data_displayed));
            }
        }

        @Override
        protected void onItemsAdded(List<String> items) {
            super.onItemsAdded(items);
            feedState.appendItems(items);
        }

        @Override
        protected void onNoMoreData() {
            if (feedState.getItems() != null && feedState.getItems().size() > 0) {
                //show "No more data" only if current list do not contain any items
                //otherwise it is more like "Feed is empty" or "No data" message
                mergeAdapter.setActive(noMoreDataView, true);
            }
        }
    }

 protected ArrayAdapter<String> createListAdapter(List<String> feed) {

        return (new VisitedItemListAdapter(this, feed));//Adapter class to show List Items in Grid
    }

EndlessFeedAdapter.java

public abstract class EndlessFeedAdapter<TYPE, RESPONSE> extends EndlessAdapter
        implements RequestListener<RESPONSE> {
    private PagedAsyncDataLoader<RESPONSE> pagedAsyncDataLoader;
    private int currentPage = 1;

    private boolean shouldLoadMore = true;

    private volatile boolean requestInProgress = false;

    public EndlessFeedAdapter(ArrayAdapter<TYPE> wrapped, PagedAsyncDataLoader<RESPONSE>
            pagedAsyncDataLoader) {
        super(wrapped);
        super.setRunInBackground(false);
        this.pagedAsyncDataLoader = pagedAsyncDataLoader;
    }

    @Override
    protected boolean cacheInBackground()  {
        if (shouldLoadMore) {
            if (requestInProgress) {
                return true;
            }
            onRequestStarted();
            pagedAsyncDataLoader.loadPage(currentPage, this);
            return true;
        }
        return false;
    }

    protected void onRequestStarted() {
        requestInProgress = true;
    }

    @Override
    public void onRequestFailure(Exception spiceException) {
        requestInProgress = false;
        stopAppending();
    }

    @Override
    public void onRequestSuccess(RESPONSE response, boolean cached) {
        //ASOC-221 - it is handled in overriding classes
        requestInProgress = false;
        ++currentPage;
        List<TYPE> items = collectItems(response);
        if (items == null || items.isEmpty()) {
            stopAppending();
            onNoMoreData();
            return;
        }
        @SuppressWarnings("unchecked") final ArrayAdapter<TYPE> wrappedAdapter =
                ((ArrayAdapter<TYPE>)getWrappedAdapter());
        List<TYPE> newItems = new ArrayList<>(10);
        for (TYPE item : items) {
            if (wrappedAdapter.getPosition(item) == -1) {
                newItems.add(item);
            }
        }

        if (!newItems.isEmpty()) {
            onItemsAdded(newItems);
            wrappedAdapter.addAll(newItems);
        }
        if (!shouldLoadNextPage(response)) {
            stopAppending();
            onNoMoreData();
        }

        onDataReady();
    }

    /**
     * Called when adapter has been detected that feed doesn't have more data to load
     * it happened inside {@link #onRequestSuccess(Object, boolean)}} if response do not contain any data
     * or if call to {@link #shouldLoadNextPage(Object)} returned false
     */
    protected void onNoMoreData() {}

    /**
     * Called when new items have been added to wrapped adapter
     * @param items items
     */
    protected void onItemsAdded(List<TYPE> items) {}

    @Override
    protected void appendCachedData() {
    }

    /**
     *
     * @param response    server response
     * @return items returned in response to server request
     */
    protected abstract List<TYPE> collectItems(RESPONSE response);

    @Override
    public void stopAppending() {
        this.shouldLoadMore = false;
        super.stopAppending();
    }

    @Override
    protected View getPendingView(ViewGroup parent) {
        return LayoutInflater.from(parent.getContext()).inflate(R.layout.pending_row, null);
    }

    @Override
    public void setRunInBackground(boolean runInBackground) {
        throw new UnsupportedOperationException("EndlessFeedAdapter works only " +
                "in runInBackground = false mode");
    }

    /**
     *
     * @param response    server response
     * @return <tt>true</tt> if current response should result in loading of new data page,
     * <tt>false</tt> otherwise
     */
    protected abstract boolean shouldLoadNextPage(RESPONSE response);

    /**
     * Make sure that this endless ListView will start loading new data
     */
    @Override
    public void restartAppending() {
        shouldLoadMore = true;
        onDataReady();
        super.restartAppending();
        cacheInBackground();
    }


    public int getCurrentPage() {
        return currentPage;
    }
}

PagedAsyncDataLoader.java

public interface PagedAsyncDataLoader<RESULT> {
    /**
     * Loads page of data asynchronously passing result in provided request listener
     * @param page page number (first page is represented by 0)
     * @param requestListener    request listener
     */
    void loadPage(int page,RequestListener<RESULT> requestListener);
}

VisitedItemFeedRequest.java

public class VisitedItemFeedRequest extends FeedRequest<ItemsFeed,ItemApi> {

    protected String userId;


    protected VisitedItemFeedRequest(Builder builder) {
        super(builder);
        this.userId = builder.userId;

    }

    @Override
    public ItemsFeed execute(ItemApi itemApi) throws Exception {
        PageAndSortParams pageAndSortParams = getPageAndSortParams();

        ItemsFeed itemFeed =  itemApi.userItemFeed(userId,1,
                1,pageAndSortParams.getPage(),10,    
               pageAndSortParams.getLimit(),true);

        return itemFeed;
    }
    public static Builder builder(String capsuleId){
        return new Builder(capsuleId);
    }


    public static class Builder extends FeedRequest.Builder<VisitedItemFeedRequest> {

        private String userId;


        public Builder(String capsuleId) {
            this.userId = capsuleId;
        }

        @Override
        public VisitedItemFeedRequest build(){
            return new VisitedItemFeedRequest(this);
        }
    }


}
Jamal
  • 976
  • 2
  • 14
  • 39

1 Answers1

2

You should use a GridView like https://stackoverflow.com/a/24617051/754439 and add the ImageView as a header. Nesting an AdapterView under a ScrollView is discouraged: How can I put a ListView into a ScrollView without it collapsing?.

Community
  • 1
  • 1
nekojsi
  • 1,423
  • 2
  • 13
  • 28
  • @ nekojsi Thanks for your reply I will check and let you know – Jamal Dec 04 '14 at 10:25
  • I added `HeaderGridView` insted of `ExpandableHeightGridView` and also added this class in my xml layout file.I need some clarification about how to add `ImageView` as a `Header` – Jamal Dec 04 '14 at 11:50
  • You would probably use one of the `HeaderGridView#addHeaderView` methods. – nekojsi Dec 04 '14 at 13:27
  • Have to call `addHeaderView` method from My `Activity` before calling `setAdapter` method right? – Jamal Dec 04 '14 at 13:33
  • I am getting this Exception `Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first`. – Jamal Dec 04 '14 at 14:10
  • When inflating the header view, you should specify the GridView as the parent, but not attach it (pass boolean `false`). Later, after initializing it (e.g. set the actual image to show), use `addHeaderView`. – nekojsi Dec 04 '14 at 14:57
  • What I tried is 1.after initialization of `HeaderGridView` with variable name `feedListView` I have set this `feedListView.addHeaderView(feedListView, null, false);` 2.Before calling `setAdapter` I have called `feedListView.addHeaderView(header);` after this I have called the `setAdapter` method.the `header` is a variable of my `ImageView` but still it is showing the `Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first` – Jamal Dec 05 '14 at 06:28
  • Could you clarify the `feedListView.addHeaderView(feedListView, null, false);` statement? You should probably not use that. Additionally, we need the way you are creating `header`, because the exception is probably raised about it. – nekojsi Dec 05 '14 at 11:45
  • I got it initially I tried with `ImageView` from same xml layout but later I realized to use separate `layout` for ImageView(Which act as a header in our code) and `inflate` that layout file into our Activity. now it is working good as what we needed – Jamal Dec 05 '14 at 12:13
  • nekojsi, The list's last row items are not showing by fully.it is showing partially as per this screen shot http://i.stack.imgur.com/o8Llq.png – Jamal Jan 14 '15 at 07:22