I am having a listView, so i want to add a sticky header so that it sticks to the top of the listView and when a different category starts in the listView a Different header take its place, Like the contacts, where is "a" as a Sticky header is at the top till "b" comes in. Is there any library to do it?? I am using custom List Adapter to show my List...
this is my custom adapter class
public class NewsRowAdapter extends ArrayAdapter<Item> {
private Activity activity;
private List<Item> items;
private Item objBean;
private int row;
private DisplayImageOptions options;
ImageLoader imageLoader;
public NewsRowAdapter(Activity act, int resource, List<Item> arrayList) {
super(act, resource, arrayList);
this.activity = act;
this.row = resource;
this.items = arrayList;
imageLoader = ImageLoader.getInstance();
File cacheDir1 = StorageUtils.getCacheDirectory(activity);
ImageLoaderConfiguration config = new
ImageLoaderConfiguration.Builder(activity)
.maxImageWidthForMemoryCache(600)
.maxImageHeightForMemoryCache(400)
.httpConnectTimeout(5000)
.httpReadTimeout(20000)
.threadPoolSize(3)
.threadPriority(Thread.MIN_PRIORITY + 3)
.denyCacheImageMultipleSizesInMemory()
.memoryCache(new UsingFreqLimitedMemoryCache(20000)) // You can pass your own memory cache implementation
.discCache(new TotalSizeLimitedDiscCache(cacheDir1, 30000)) // You can pass your own disc cache implementation
.defaultDisplayImageOptions(DisplayImageOptions.createSimple())
.build();
ImageLoader.getInstance().init(config);
// imageLoader = ImageLoader;
//
options = new DisplayImageOptions.Builder()
.showStubImage(R.drawable.icon2x)
.showImageForEmptyUrl(R.drawable.icon2x).cacheInMemory()
.cacheOnDisc().build();
//imageLoader = ImageLoader.getInstance();
}
@Override
public Item getItem(int position)
{
return items.get(position);
}
@Override
public int getCount()
{
return items.size();
}
@Override
public int getViewTypeCount()
{
return 3;
}
@Override
public int getItemViewType(int position)
{
Item item = items.get(position);
if (item.isHeader())
{
return TYPE_SECTION_HEADER;
}
else
{
return TYPE_LIST_ITEM;
}
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = convertView;
ViewHolder holder;
if (view == null) {
LayoutInflater inflater = (LayoutInflater) activity
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(row, null);
holder = new ViewHolder();
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
if ((items == null) || ((position + 1) > items.size()))
return view;
objBean = items.get(position);
holder.tvName = (TextView) view.findViewById(R.id.title);
holder.tvId = (TextView) view.findViewById(R.id.id);
holder.tvFlag = (TextView) view.findViewById(R.id.flag);
holder.tvimageurl=(TextView) view.findViewById(R.id.imageurl);
holder.tvGender = (ImageView) view.findViewById(R.id.image);
//holder.tvAge = (TextView) view.findViewById(R.id.tvage);
holder.pbar = (ProgressBar) view.findViewById(R.id.pbar);
if (holder.tvName != null && null != objBean.getName()
&& objBean.getName().trim().length() > 0) {
holder.tvName.setText(Html.fromHtml(objBean.getName()));
}
if (holder.tvId != null && null != objBean.getId()
&& objBean.getId().trim().length() > 0) {
holder.tvId.setText(Html.fromHtml(objBean.getId()));
}
if (holder.tvFlag != null && null != objBean.getFlag()
&& objBean.getFlag().trim().length() > 0) {
holder.tvFlag.setText(Html.fromHtml(objBean.getFlag()));
}
if (holder.tvimageurl != null && null != objBean.getGender()
&& objBean.getFlag().trim().length() > 0) {
holder.tvimageurl.setText(Html.fromHtml(objBean.getGender()));
}
//if (holder.tvBDate != null && null != objBean.getBirthdate()
// && objBean.getBirthdate().trim().length() > 0) {
// holder.tvBDate.setText(Html.fromHtml(objBean.getBirthdate()));
//}
if (holder.tvGender != null) {
if (null != objBean.getGender()
&& objBean.getGender().trim().length() > 0) {
final ProgressBar pbar = holder.pbar;
imageLoader.displayImage(objBean.getGender(), holder.tvGender,
options, new ImageLoadingListener() {
@Override
public void onLoadingComplete() {
pbar.setVisibility(View.INVISIBLE);
}
@Override
public void onLoadingFailed() {
pbar.setVisibility(View.INVISIBLE);
}
@Override
public void onLoadingStarted() {
pbar.setVisibility(View.INVISIBLE);
}
});
} else {
holder.tvGender.setImageResource(R.drawable.icon2x);
}
}
return view;
}
public class ViewHolder {
public TextView tvimageurl;
public TextView tvFlag;
public TextView tvId;
public ProgressBar pbar;
public TextView tvName, tvCity, tvBDate, tvAge;
ImageView tvGender;
}
}
help needed.....
I struggled quite a long time writing my own StickyHeader as the StickyListHeaders git was not perfectly matching my needs. However, the StickyListHeaders help me a lot in understanding how to finally have it working and therefore the writer of the StickyListHeaders deserve mentioning it.
Many things have to be put together to have a sticky header working.
First, declare the following
private TextView mStickyHeader;
private TextView mStickyHeader2;
private int mCurrentStickyHeaderSection;
in onActivityCreated
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
...
mCurrentStickyHeaderSection = -1;
mStickyHeader = (TextView) getView().findViewById(R.id.textview_sticky_header_section);
mStickyHeader2 = (TextView) getView().findViewById(R.id.textview_sticky_header_section_2);
mListView = (ListView) getView().findViewById(R.id.listView_with_sticky_headers);
mListView.setOnScrollListener(new OnScrollListener() {
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
updateStickyHeader(firstVisibleItem);
}
@Override
public void onScrollStateChanged(AbsListView arg0, int arg1) {
// TODO Auto-generated method stub
}
});
I assume you have written a CustomAdapter with section indexes and will only focus on the sticky headers.
The following method contains all that you need to have the sticky header. The tricky part is determining if the firstVisibleItem is a header (pos = -1) or not and the corresponding section. This part can take you a few times to have it working properly.
private void updateStickyHeader(int firstVisibleItem) {
// here is the tricky part. You have to determine pos and section
// pos is the position within a section pos = -1 means it's the header of the section
// you have to determine if firstVisibleItem is a header or not
// you also have to determine the section to which belongs the first item
int pos = whatIsThePositionOfTheItem[firstVisibleItem];
int section = whatIsTheSectionOfTheItem[firstVisibleItem];
if (section != mCurrentStickyHeaderSection) {
mStickyHeader.setText("Your_Previous_Section_Text");
mStickyHeader2.setText("Your_Next_Section_Text");
mCurrentStickyHeaderSection = section;
}
int stickyHeaderHeight = mStickyHeader.getHeight();
if (stickyHeaderHeight == 0) {
stickyHeaderHeight = mStickyHeader.getMeasuredHeight();
}
View SectionLastView = mListView.getChildAt(0);
if (SectionLastView != null && pos == -1 && SectionLastView.getBottom() <= stickyHeaderHeight) {
int lastViewBottom = SectionLastView.getBottom();
mStickyHeader.setTranslationY(lastViewBottom - stickyHeaderHeight);
mStickyHeader2.setTranslationY(lastViewBottom - stickyHeaderHeight + mStickyHeader.getHeight());
} else if (stickyHeaderHeight != 0) {
mStickyHeader.setTranslationY(0);
mStickyHeader2.setTranslationY(mStickyHeader.getHeight());
}
}
Finally, the layout must contain a FrameLayout and should look like that
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
//this textview is just a global title of your listview if you need one but can be remove
<TextView
android:id="@+id/textview_title"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textIsSelectable="false" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@+id/textview_sticky_header_section"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textIsSelectable="false" />
<TextView
android:id="@+id/textview_sticky_header_section_2"
style="?android:attr/listSeparatorTextViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="6dp"
android:paddingRight="6dp"
android:textIsSelectable="false" />
</FrameLayout>
<ListView
android:id="@+id/listView_with_sticky_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:fastScrollEnabled="true"
android:longClickable="true" >
</ListView>
</LinearLayout>
Update
As asked in the comments here is an explanation of the whatIsThePositionOfTheItem and whatIsTheSectionOfTheItem. These methods have to give back the position and section of a given item.
In my case it was quite simple, my data was already containing the section and position. Actually, I am displaying text, and that text starts with the section and position. So I simply parse that text to determine the section and position.
For others, it is hard to give an example because it really depends on what you are displaying. But to make a long story short whatIsThePositionOfTheItem and whatIsTheSectionOfTheItem have to return the position and section of a given item. You will probably have to fill a table with the position and section of each item in your list and get the position and section from that table.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With