Last active
February 20, 2017 09:39
-
-
Save pcqpcq/a15005e3715b27627402 to your computer and use it in GitHub Desktop.
PinnedHeaderExpListView. Check it out here: http://stackoverflow.com/questions/10613552/pinned-groups-in-expandablelistview
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.pcqpcq.android.widget; | |
import android.view.View; | |
/** | |
* Adapter interface. The list adapter must implement this interface. | |
* | |
* @see <a href="http://stackoverflow.com/questions/10613552/pinned-groups-in-expandablelistview">source</a> | |
*/ | |
public interface PinnedHeaderAdapter { | |
/** | |
* Pinned header state: don't show the header. | |
*/ | |
public static final int PINNED_HEADER_GONE = 0; | |
/** | |
* Pinned header state: show the header at the top of the list. | |
*/ | |
public static final int PINNED_HEADER_VISIBLE = 1; | |
/** | |
* Pinned header state: show the header. If the header extends beyond | |
* the bottom of the first shown element, push it up and clip. | |
*/ | |
public static final int PINNED_HEADER_PUSHED_UP = 2; | |
/** | |
* Configures the pinned header view to match the first visible list item. | |
* | |
* @param header pinned header view. | |
* @param position position of the first visible list item. | |
* @param alpha fading of the header view, between 0 and 255. | |
*/ | |
void configurePinnedHeader(View header, int position, int alpha); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.pcqpcq.android.widget; | |
import android.widget.AbsListView; | |
import android.widget.BaseExpandableListAdapter; | |
/** | |
* A simple adapter which maintains an ArrayList of photo resource Ids. | |
* Each photo is displayed as an image. This adapter supports clearing the | |
* list of photos and adding a new photo. | |
* | |
* @see <a href="http://stackoverflow.com/questions/10613552/pinned-groups-in-expandablelistview">source</a> | |
*/ | |
public abstract class PinnedHeaderExpListAdapter extends BaseExpandableListAdapter implements PinnedHeaderAdapter, AbsListView.OnScrollListener { | |
@Override | |
public boolean isChildSelectable(int groupPosition, int childPosition) { | |
return true; | |
} | |
@Override | |
public boolean hasStableIds() { | |
return true; | |
} | |
@Override | |
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { | |
if (view instanceof PinnedHeaderExpListView) { | |
((PinnedHeaderExpListView) view).configureHeaderView(firstVisibleItem); | |
} | |
} | |
@Override | |
public void onScrollStateChanged(AbsListView view, int scrollState) { | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package me.pcqpcq.android.widget; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.util.AttributeSet; | |
import android.view.View; | |
import android.widget.ExpandableListAdapter; | |
import android.widget.ExpandableListView; | |
/** | |
* A ListView that maintains a header pinned at the top of the list. The | |
* pinned header can be pushed up and dissolved as needed. | |
* | |
* @see <a href="http://stackoverflow.com/questions/10613552/pinned-groups-in-expandablelistview">source</a> | |
*/ | |
public class PinnedHeaderExpListView extends ExpandableListView { | |
private static final int MAX_ALPHA = 255; | |
private PinnedHeaderExpListAdapter mAdapter; | |
private View mHeaderView; | |
private boolean mHeaderViewVisible; | |
private int mHeaderViewWidth; | |
private int mHeaderViewHeight; | |
public PinnedHeaderExpListView(Context context) { | |
super(context); | |
} | |
public PinnedHeaderExpListView(Context context, AttributeSet attrs) { | |
super(context, attrs); | |
} | |
public PinnedHeaderExpListView(Context context, AttributeSet attrs, int defStyle) { | |
super(context, attrs, defStyle); | |
} | |
public void setPinnedHeaderView(View view) { | |
mHeaderView = view; | |
// Disable vertical fading when the pinned header is present | |
// TODO change ListView to allow separate measures for top and bottom fading edge; | |
// in this particular case we would like to disable the top, but not the bottom edge. | |
if (mHeaderView != null) { | |
setFadingEdgeLength(0); | |
} | |
requestLayout(); | |
} | |
@Override | |
public void setAdapter(ExpandableListAdapter adapter) { | |
super.setAdapter(adapter); | |
mAdapter = (PinnedHeaderExpListAdapter)adapter; | |
} | |
@Override | |
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |
super.onMeasure(widthMeasureSpec, heightMeasureSpec); | |
if (mHeaderView != null) { | |
measureChild(mHeaderView, widthMeasureSpec, heightMeasureSpec); | |
mHeaderViewWidth = mHeaderView.getMeasuredWidth(); | |
mHeaderViewHeight = mHeaderView.getMeasuredHeight(); | |
} | |
} | |
@Override | |
protected void onLayout(boolean changed, int left, int top, int right, int bottom) { | |
super.onLayout(changed, left, top, right, bottom); | |
if (mHeaderView != null) { | |
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight); | |
configureHeaderView(getFirstVisiblePosition()); | |
} | |
} | |
/** | |
* animating header pushing | |
* @param position | |
*/ | |
public void configureHeaderView(int position) { | |
final int group = getPackedPositionGroup(getExpandableListPosition(position)); | |
int groupView = getFlatListPosition(getPackedPositionForGroup(group)); | |
if (mHeaderView == null) { | |
return; | |
} | |
// init header | |
mAdapter.configurePinnedHeader(mHeaderView, group, 0); | |
mHeaderView.setOnClickListener(new OnClickListener() { | |
public void onClick(View header) { | |
if(!expandGroup(group)) collapseGroup(group); | |
} | |
}); | |
int state,nextSectionPosition = getFlatListPosition(getPackedPositionForGroup(group+1)); | |
if (mAdapter.getGroupCount()== 0) { | |
state = PinnedHeaderAdapter.PINNED_HEADER_GONE; | |
}else if (position < 0) { | |
state = PinnedHeaderAdapter.PINNED_HEADER_GONE; | |
}else if (nextSectionPosition != -1 && position == nextSectionPosition - 1) { | |
state=PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP; | |
}else state=PinnedHeaderAdapter.PINNED_HEADER_VISIBLE; | |
switch (state) { | |
case PinnedHeaderAdapter.PINNED_HEADER_GONE: { | |
mHeaderViewVisible = false; | |
break; | |
} | |
case PinnedHeaderAdapter.PINNED_HEADER_VISIBLE: { | |
mAdapter.configurePinnedHeader(mHeaderView, group, MAX_ALPHA); | |
if (mHeaderView.getTop() != 0) { | |
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight); | |
} | |
mHeaderViewVisible = true; | |
break; | |
} | |
case PinnedHeaderAdapter.PINNED_HEADER_PUSHED_UP: { | |
View firstView = getChildAt(0); | |
if(firstView==null){ | |
if (mHeaderView.getTop() != 0) { | |
mHeaderView.layout(0, 0, mHeaderViewWidth, mHeaderViewHeight); | |
} | |
mHeaderViewVisible = true; | |
break; | |
} | |
int bottom = firstView.getBottom(); | |
int itemHeight = firstView.getHeight(); | |
int headerHeight = mHeaderView.getHeight(); | |
int y; | |
int alpha; | |
if (bottom < headerHeight) { | |
y = (bottom - headerHeight); | |
alpha = MAX_ALPHA * (headerHeight + y) / headerHeight; | |
} else { | |
y = 0; | |
alpha = MAX_ALPHA; | |
} | |
mAdapter.configurePinnedHeader(mHeaderView, group, alpha); | |
//выползание | |
if (mHeaderView.getTop() != y) { | |
mHeaderView.layout(0, y, mHeaderViewWidth, mHeaderViewHeight + y); | |
} | |
mHeaderViewVisible = true; | |
break; | |
} | |
} | |
} | |
@Override | |
protected void dispatchDraw(Canvas canvas) { | |
super.dispatchDraw(canvas); | |
if (mHeaderViewVisible) { | |
drawChild(canvas, mHeaderView, getDrawingTime()); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment