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);
}
}
}
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?.