finish implementation of sticky header implementation. This feature was created according to the this implementation : https://stackoverflow.com/questions/32949971/how-can-i-make-sticky-headers-in-recyclerview-without-external-lib

Signed-off-by: alex <alex.plutta@googlemail.com>
Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
This commit is contained in:
alex 2019-08-17 20:30:09 +02:00 committed by Andy Scherzinger
parent 13e7aff0a5
commit 792a6b95a6
No known key found for this signature in database
GPG key ID: 6CADC7E3523C308B
4 changed files with 149 additions and 22 deletions

View file

@ -41,6 +41,7 @@ import com.owncloud.android.ui.activities.data.files.FilesRepository;
import com.owncloud.android.ui.activity.FileActivity;
import com.owncloud.android.ui.activity.FileDisplayActivity;
import com.owncloud.android.ui.adapter.ActivityListAdapter;
import com.owncloud.android.ui.adapter.StickyHeaderAdapter;
import com.owncloud.android.ui.interfaces.ActivityListInterface;
import com.owncloud.android.ui.preview.PreviewImageActivity;
import com.owncloud.android.ui.preview.PreviewImageFragment;
@ -174,7 +175,7 @@ public class ActivitiesActivity extends FileActivity implements ActivityListInte
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new ActivityListItemDecoration());
recyclerView.addItemDecoration(new ActivityListItemDecoration( adapter));
recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override

View file

@ -2,35 +2,54 @@ package com.owncloud.android.ui.activities;
import android.graphics.Canvas;
import android.graphics.Color;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.owncloud.android.ui.adapter.ActivityListAdapter;
import com.owncloud.android.R;
import com.owncloud.android.ui.adapter.StickyHeaderAdapter;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
public class ActivityListItemDecoration extends RecyclerView.ItemDecoration {
private final String TAG = this.getClass().getSimpleName();
private View currentHeader;
private final StickyHeaderAdapter adapter;
public ActivityListItemDecoration(StickyHeaderAdapter stickyHeaderAdapter) {
this.adapter = stickyHeaderAdapter;
}
@Override
public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
super.onDrawOver(c, parent, state);
View topChild = parent.getChildAt(0);
int topChildPosition = parent.getChildAdapterPosition(topChild);
if (topChildPosition == -1) {
if (topChild == null) {
return;
}
ActivityListAdapter adapter = (ActivityListAdapter) parent.getAdapter();
int topChildPosition = parent.getChildAdapterPosition(topChild);
Object topElement = adapter.getActivityAtByPosition(topChildPosition);
if (topElement instanceof ActivityListHeader) {
currentHeader = parent.getChildAt(0);
currentHeader.setBackgroundColor(Color.WHITE);
if (topChildPosition == RecyclerView.NO_POSITION) {
return;
}
View currentHeader = getHeaderViewForItem(topChildPosition, parent);
fixLayoutSize(parent, currentHeader);
int contactPoint = currentHeader.getBottom();
View childInContact = getChildInContact(parent, contactPoint);
if (childInContact == null) {
return;
}
if (adapter.isHeader(parent.getChildAdapterPosition(childInContact))) {
moveHeader(c, currentHeader, childInContact);
return;
}
drawHeader(c, currentHeader);
}
@ -40,4 +59,50 @@ public class ActivityListItemDecoration extends RecyclerView.ItemDecoration {
header.draw(c);
c.restore();
}
private void moveHeader(Canvas c, View currentHeader, View nextHeader) {
c.save();
c.translate(0, nextHeader.getTop() - currentHeader.getHeight());
currentHeader.draw(c);
c.restore();
}
private View getChildInContact(RecyclerView parent, int contactPoint) {
View childInContact = null;
for (int i = 0; i < parent.getChildCount(); i++) {
View currentChild = parent.getChildAt(i);
if (currentChild.getBottom() > contactPoint) {
if (currentChild.getTop() <= contactPoint) {
childInContact = currentChild;
break;
}
}
}
return childInContact;
}
private View getHeaderViewForItem(int itemPosition, RecyclerView parent) {
int headerPosition = adapter.getHeaderPositionForItem(itemPosition);
int layoutId = adapter.getHeaderLayout(itemPosition);
View header = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
header.setBackgroundColor(Color.WHITE);
adapter.bindHeaderData(header, headerPosition);
return header;
}
private void fixLayoutSize(ViewGroup parent, View view) {
// Specs for parent (RecyclerView)
int widthSpec = View.MeasureSpec.makeMeasureSpec(parent.getWidth(), View.MeasureSpec.EXACTLY);
int heightSpec = View.MeasureSpec.makeMeasureSpec(parent.getHeight(), View.MeasureSpec.UNSPECIFIED);
// Specs for children (headers)
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec, parent.getPaddingLeft() + parent.getPaddingRight(), view.getLayoutParams().width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec, parent.getPaddingTop() + parent.getPaddingBottom(), view.getLayoutParams().height);
view.measure(childWidthSpec, childHeightSpec);
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
}
}

View file

@ -80,12 +80,13 @@ import java.util.List;
import java.util.Locale;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
/**
* Adapter for the activity view
*/
public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> implements StickyHeaderAdapter {
static final int HEADER_TYPE = 100;
static final int ACTIVITY_TYPE = 101;
@ -142,7 +143,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
values.add(activity);
} else {
sTime = time;
values.add(new ActivityListHeader(sTime));
values.add(sTime);
values.add(activity);
}
}
@ -238,16 +239,11 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
} else {
ActivityViewHeaderHolder activityViewHeaderHolder = (ActivityViewHeaderHolder) holder;
ActivityListHeader header = (ActivityListHeader) values.get(position);
activityViewHeaderHolder.title.setText((String) header.getHeadline());
activityViewHeaderHolder.title.setText((String) values.get(position));
}
}
public Object getActivityAtByPosition(int pos) {
return values.get(pos);
}
private ImageView createThumbnailNew(PreviewObject previewObject) {
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(px, px);
params.setMargins(10, 10, 10, 10);
@ -435,6 +431,37 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
}
@Override
public int getHeaderPositionForItem(int itemPosition) {
int headerPosition = 0;
do {
if (this.isHeader(itemPosition)) {
headerPosition = itemPosition;
break;
}
itemPosition -= 1;
} while (itemPosition >= 0);
return headerPosition;
}
@Override
public int getHeaderLayout(int headerPosition) {
return R.layout.activity_list_item_header;
}
@Override
public void bindHeaderData(View header, int headerPosition) {
TextView textView = header.findViewById(R.id.title_header);
String headline = (String) values.get(headerPosition);
textView.setText(headline);
}
@Override
public boolean isHeader(int itemPosition) {
return this.getItemViewType(itemPosition) == HEADER_TYPE;
}
protected class ActivityViewHolder extends RecyclerView.ViewHolder {
private final ImageView activityIcon;
@ -453,7 +480,7 @@ public class ActivityListAdapter extends RecyclerView.Adapter<RecyclerView.ViewH
}
}
protected class ActivityViewHeaderHolder extends RecyclerView.ViewHolder {
public class ActivityViewHeaderHolder extends RecyclerView.ViewHolder {
private final TextView title;

View file

@ -0,0 +1,34 @@
package com.owncloud.android.ui.adapter;
import android.view.View;
public interface StickyHeaderAdapter {
/**
* This method gets called by {@link HeaderItemDecoration} to fetch the position of the header item in the adapter
* that is used for (represents) item at specified position.
* @param itemPosition int. Adapter's position of the item for which to do the search of the position of the header item.
* @return int. Position of the header item in the adapter.
*/
int getHeaderPositionForItem(int itemPosition);
/**
* This method gets called by {@link HeaderItemDecoration} to get layout resource id for the header item at specified adapter's position.
* @param headerPosition int. Position of the header item in the adapter.
* @return int. Layout resource id.
*/
int getHeaderLayout(int headerPosition);
/**
* This method gets called by {@link HeaderItemDecoration} to setup the header View.
* @param header View. Header to set the data on.
* @param headerPosition int. Position of the header item in the adapter.
*/
void bindHeaderData(View header, int headerPosition);
/**
* This method gets called by {@link HeaderItemDecoration} to verify whether the item represents a header.
* @param itemPosition int.
* @return true, if item at the specified adapter's position represents a header.
*/
boolean isHeader(int itemPosition);
}