Makes end of list footers have zero height.

This commit is contained in:
Vavassor 2017-07-01 23:23:42 -04:00
parent 5d621cecda
commit afa21f5a5c
5 changed files with 47 additions and 51 deletions

View File

@ -21,6 +21,7 @@ import android.support.v7.widget.RecyclerView;
import android.view.View; import android.view.View;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import android.widget.TextView; import android.widget.TextView;
import android.support.v7.widget.RecyclerView.LayoutParams;
import com.keylesspalace.tusky.R; import com.keylesspalace.tusky.R;
@ -51,18 +52,27 @@ public class FooterViewHolder extends RecyclerView.ViewHolder {
public void setState(State state) { public void setState(State state) {
switch (state) { switch (state) {
case LOADING: { case LOADING: {
RecyclerView.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
container.setLayoutParams(layoutParams);
container.setVisibility(View.VISIBLE); container.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.VISIBLE); progressBar.setVisibility(View.VISIBLE);
endMessage.setVisibility(View.GONE); endMessage.setVisibility(View.GONE);
break; break;
} }
case END: { case END: {
RecyclerView.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT);
container.setLayoutParams(layoutParams);
container.setVisibility(View.GONE); container.setVisibility(View.GONE);
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
endMessage.setVisibility(View.GONE); endMessage.setVisibility(View.GONE);
break; break;
} }
case EMPTY: { case EMPTY: {
RecyclerView.LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT);
container.setLayoutParams(layoutParams);
container.setVisibility(View.VISIBLE); container.setVisibility(View.VISIBLE);
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
endMessage.setVisibility(View.VISIBLE); endMessage.setVisibility(View.VISIBLE);

View File

@ -175,7 +175,11 @@ public class TimelineAdapter extends RecyclerView.Adapter implements AdapterItem
} }
public void setFooterState(FooterViewHolder.State newFooterState) { public void setFooterState(FooterViewHolder.State newFooterState) {
FooterViewHolder.State oldValue = footerState;
footerState = newFooterState; footerState = newFooterState;
if (footerState != oldValue) {
notifyItemChanged(statuses.size());
}
} }
public void setMediaPreviewEnabled(boolean enabled) { public void setMediaPreviewEnabled(boolean enabled) {

View File

@ -407,7 +407,15 @@ public class AccountListFragment extends BaseFragment implements AccountActionLi
} }
if (fromId != null || adapter.getItemCount() <= 1) { if (fromId != null || adapter.getItemCount() <= 1) {
setFooterState(FooterViewHolder.State.LOADING); /* When this is called by the EndlessScrollListener it cannot refresh the footer state
* using adapter.notifyItemChanged. So its necessary to postpone doing so until a
* convenient time for the UI thread using a Runnable. */
recyclerView.post(new Runnable() {
@Override
public void run() {
adapter.setFooterState(FooterViewHolder.State.LOADING);
}
});
} }
Callback<List<Account>> cb = new Callback<List<Account>>() { Callback<List<Account>> cb = new Callback<List<Account>>() {
@ -468,9 +476,9 @@ public class AccountListFragment extends BaseFragment implements AccountActionLi
} }
fulfillAnyQueuedFetches(fetchEnd); fulfillAnyQueuedFetches(fetchEnd);
if (accounts.size() == 0 && adapter.getItemCount() == 1) { if (accounts.size() == 0 && adapter.getItemCount() == 1) {
setFooterState(FooterViewHolder.State.EMPTY); adapter.setFooterState(FooterViewHolder.State.EMPTY);
} else { } else {
setFooterState(FooterViewHolder.State.END); adapter.setFooterState(FooterViewHolder.State.END);
} }
} }
@ -479,20 +487,6 @@ public class AccountListFragment extends BaseFragment implements AccountActionLi
fulfillAnyQueuedFetches(fetchEnd); fulfillAnyQueuedFetches(fetchEnd);
} }
/* This needs to be called from the endless scroll listener, which does not allow notifying the
* adapter during the callback. So, this is the workaround. */
private void setFooterState(FooterViewHolder.State state) {
// Set the adapter to set its state when it's bound, if the current Footer is offscreen.
adapter.setFooterState(state);
// Check if it's onscreen, and update it directly if it is.
RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) {
FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setState(state);
}
}
private void onRefresh() { private void onRefresh() {
fetchAccounts(null, adapter.getTopId(), FetchEnd.TOP); fetchAccounts(null, adapter.getTopId(), FetchEnd.TOP);
} }

View File

@ -275,7 +275,15 @@ public class NotificationsFragment extends SFragment implements
} }
if (fromId != null || adapter.getItemCount() <= 1) { if (fromId != null || adapter.getItemCount() <= 1) {
setFooterState(FooterViewHolder.State.LOADING); /* When this is called by the EndlessScrollListener it cannot refresh the footer state
* using adapter.notifyItemChanged. So its necessary to postpone doing so until a
* convenient time for the UI thread using a Runnable. */
recyclerView.post(new Runnable() {
@Override
public void run() {
adapter.setFooterState(FooterViewHolder.State.LOADING);
}
});
} }
Call<List<Notification>> call = mastodonApi.notifications(fromId, uptoId, null); Call<List<Notification>> call = mastodonApi.notifications(fromId, uptoId, null);
@ -342,9 +350,9 @@ public class NotificationsFragment extends SFragment implements
} }
fulfillAnyQueuedFetches(fetchEnd); fulfillAnyQueuedFetches(fetchEnd);
if (notifications.size() == 0 && adapter.getItemCount() == 1) { if (notifications.size() == 0 && adapter.getItemCount() == 1) {
setFooterState(FooterViewHolder.State.EMPTY); adapter.setFooterState(FooterViewHolder.State.EMPTY);
} else { } else {
setFooterState(FooterViewHolder.State.END); adapter.setFooterState(FooterViewHolder.State.END);
} }
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
@ -355,20 +363,6 @@ public class NotificationsFragment extends SFragment implements
fulfillAnyQueuedFetches(fetchEnd); fulfillAnyQueuedFetches(fetchEnd);
} }
/* This needs to be called from the endless scroll listener, which does not allow notifying the
* adapter during the callback. So, this is the workaround. */
private void setFooterState(FooterViewHolder.State state) {
// Set the adapter to set its state when it's bound, if the current Footer is offscreen.
adapter.setFooterState(state);
// Check if it's onscreen, and update it directly if it is.
RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) {
FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setState(state);
}
}
private void fulfillAnyQueuedFetches(FetchEnd fetchEnd) { private void fulfillAnyQueuedFetches(FetchEnd fetchEnd) {
switch (fetchEnd) { switch (fetchEnd) {
case BOTTOM: { case BOTTOM: {

View File

@ -360,7 +360,15 @@ public class TimelineFragment extends SFragment implements
} }
if (fromId != null || adapter.getItemCount() <= 1) { if (fromId != null || adapter.getItemCount() <= 1) {
setFooterState(FooterViewHolder.State.LOADING); /* When this is called by the EndlessScrollListener it cannot refresh the footer state
* using adapter.notifyItemChanged. So its necessary to postpone doing so until a
* convenient time for the UI thread using a Runnable. */
recyclerView.post(new Runnable() {
@Override
public void run() {
adapter.setFooterState(FooterViewHolder.State.LOADING);
}
});
} }
Callback<List<Status>> callback = new Callback<List<Status>>() { Callback<List<Status>> callback = new Callback<List<Status>>() {
@ -423,9 +431,9 @@ public class TimelineFragment extends SFragment implements
} }
fulfillAnyQueuedFetches(fetchEnd); fulfillAnyQueuedFetches(fetchEnd);
if (statuses.size() == 0 && adapter.getItemCount() == 1) { if (statuses.size() == 0 && adapter.getItemCount() == 1) {
setFooterState(FooterViewHolder.State.EMPTY); adapter.setFooterState(FooterViewHolder.State.EMPTY);
} else { } else {
setFooterState(FooterViewHolder.State.END); adapter.setFooterState(FooterViewHolder.State.END);
} }
swipeRefreshLayout.setRefreshing(false); swipeRefreshLayout.setRefreshing(false);
} }
@ -436,20 +444,6 @@ public class TimelineFragment extends SFragment implements
fulfillAnyQueuedFetches(fetchEnd); fulfillAnyQueuedFetches(fetchEnd);
} }
/* This needs to be called from the endless scroll listener, which does not allow notifying the
* adapter during the callback. So, this is the workaround. */
private void setFooterState(FooterViewHolder.State state) {
// Set the adapter to set its state when it's bound, if the current Footer is offscreen.
adapter.setFooterState(state);
// Check if it's onscreen, and update it directly if it is.
RecyclerView.ViewHolder viewHolder =
recyclerView.findViewHolderForAdapterPosition(adapter.getItemCount() - 1);
if (viewHolder != null) {
FooterViewHolder holder = (FooterViewHolder) viewHolder;
holder.setState(state);
}
}
private void fulfillAnyQueuedFetches(FetchEnd fetchEnd) { private void fulfillAnyQueuedFetches(FetchEnd fetchEnd) {
switch (fetchEnd) { switch (fetchEnd) {
case BOTTOM: { case BOTTOM: {