mirror of
https://github.com/nextcloud/android.git
synced 2024-11-23 05:35:39 +03:00
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:
parent
13e7aff0a5
commit
792a6b95a6
4 changed files with 149 additions and 22 deletions
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in a new issue