New list with sticky list headers library
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
package se.emilsjolander.stickylistheaders;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.ActionBarDrawerToggle;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBarActivity;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.*;
|
||||
|
||||
/**
|
||||
* @author Emil Sjölander
|
||||
*/
|
||||
public class TestActivity extends ActionBarActivity implements
|
||||
AdapterView.OnItemClickListener, StickyListHeadersListView.OnHeaderClickListener,
|
||||
StickyListHeadersListView.OnStickyHeaderOffsetChangedListener {
|
||||
|
||||
private TestBaseAdapter mAdapter;
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private ActionBarDrawerToggle mDrawerToggle;
|
||||
private boolean fadeHeader = true;
|
||||
|
||||
private StickyListHeadersListView stickyList;
|
||||
|
||||
private Button restoreButton;
|
||||
private Button updateButton;
|
||||
private Button clearButton;
|
||||
|
||||
private CheckBox stickyCheckBox;
|
||||
private CheckBox fadeCheckBox;
|
||||
private CheckBox drawBehindCheckBox;
|
||||
private CheckBox fastScrollCheckBox;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.main);
|
||||
|
||||
mAdapter = new TestBaseAdapter(this);
|
||||
|
||||
stickyList = (StickyListHeadersListView) findViewById(R.id.list);
|
||||
stickyList.setOnItemClickListener(this);
|
||||
stickyList.setOnHeaderClickListener(this);
|
||||
stickyList.setOnStickyHeaderOffsetChangedListener(this);
|
||||
// mStickyList.addHeaderView(inflater.inflate(R.layout.list_header, null));
|
||||
// mStickyList.addFooterView(inflater.inflate(R.layout.list_footer, null));
|
||||
stickyList.setEmptyView(findViewById(R.id.empty));
|
||||
stickyList.setDrawingListUnderStickyHeader(true);
|
||||
stickyList.setAreHeadersSticky(true);
|
||||
stickyList.setAdapter(mAdapter);
|
||||
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
mDrawerToggle = new ActionBarDrawerToggle(
|
||||
this, /* host Activity */
|
||||
mDrawerLayout, /* DrawerLayout object */
|
||||
R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */
|
||||
R.string.drawer_open, /* "open drawer" description */
|
||||
R.string.drawer_close /* "close drawer" description */
|
||||
);
|
||||
|
||||
// Set the drawer toggle as the DrawerListener
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
|
||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getSupportActionBar().setHomeButtonEnabled(true);
|
||||
|
||||
restoreButton = (Button) findViewById(R.id.restore_button);
|
||||
restoreButton.setOnClickListener(buttonListener);
|
||||
updateButton = (Button) findViewById(R.id.update_button);
|
||||
updateButton.setOnClickListener(buttonListener);
|
||||
clearButton = (Button) findViewById(R.id.clear_button);
|
||||
clearButton.setOnClickListener(buttonListener);
|
||||
|
||||
stickyCheckBox = (CheckBox) findViewById(R.id.sticky_checkBox);
|
||||
stickyCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||
fadeCheckBox = (CheckBox) findViewById(R.id.fade_checkBox);
|
||||
fadeCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||
drawBehindCheckBox = (CheckBox) findViewById(R.id.draw_behind_checkBox);
|
||||
drawBehindCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||
fastScrollCheckBox = (CheckBox) findViewById(R.id.fast_scroll_checkBox);
|
||||
fastScrollCheckBox.setOnCheckedChangeListener(checkBoxListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
// Sync the toggle state after onRestoreInstanceState has occurred.
|
||||
mDrawerToggle.syncState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
mDrawerToggle.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (mDrawerToggle.onOptionsItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
CompoundButton.OnCheckedChangeListener checkBoxListener = new CompoundButton.OnCheckedChangeListener() {
|
||||
|
||||
@Override
|
||||
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
|
||||
switch (buttonView.getId()) {
|
||||
case R.id.sticky_checkBox:
|
||||
stickyList.setAreHeadersSticky(isChecked);
|
||||
break;
|
||||
case R.id.fade_checkBox:
|
||||
fadeHeader = isChecked;
|
||||
break;
|
||||
case R.id.draw_behind_checkBox:
|
||||
stickyList.setDrawingListUnderStickyHeader(isChecked);
|
||||
break;
|
||||
case R.id.fast_scroll_checkBox:
|
||||
stickyList.setFastScrollEnabled(isChecked);
|
||||
stickyList.setFastScrollAlwaysVisible(isChecked);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
View.OnClickListener buttonListener = new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
switch (view.getId()) {
|
||||
case R.id.restore_button:
|
||||
mAdapter.restore();
|
||||
break;
|
||||
case R.id.update_button:
|
||||
mAdapter.notifyDataSetChanged();
|
||||
break;
|
||||
case R.id.clear_button:
|
||||
mAdapter.clear();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position,
|
||||
long id) {
|
||||
Toast.makeText(this, "Item " + position + " clicked!",
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHeaderClick(StickyListHeadersListView l, View header,
|
||||
int itemPosition, long headerId, boolean currentlySticky) {
|
||||
Toast.makeText(this, "Header " + headerId + " currentlySticky ? " + currentlySticky,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
@Override
|
||||
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
|
||||
public void onStickyHeaderOffsetChanged(StickyListHeadersListView l, View header, int offset) {
|
||||
if (fadeHeader && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
|
||||
header.setAlpha(1 - (offset / (float) header.getMeasuredHeight()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
package se.emilsjolander.stickylistheaders;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.SectionIndexer;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* @author Emil Sjölander
|
||||
*/
|
||||
public class TestBaseAdapter extends BaseAdapter implements
|
||||
StickyListHeadersAdapter, SectionIndexer {
|
||||
|
||||
private final Context mContext;
|
||||
private String[] mCountries;
|
||||
private int[] mSectionIndices;
|
||||
private Character[] mSectionLetters;
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
public TestBaseAdapter(Context context) {
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mCountries = context.getResources().getStringArray(R.array.countries);
|
||||
mSectionIndices = getSectionIndices();
|
||||
mSectionLetters = getSectionLetters();
|
||||
}
|
||||
|
||||
private int[] getSectionIndices() {
|
||||
ArrayList<Integer> sectionIndices = new ArrayList<Integer>();
|
||||
char lastFirstChar = mCountries[0].charAt(0);
|
||||
sectionIndices.add(0);
|
||||
for (int i = 1; i < mCountries.length; i++) {
|
||||
if (mCountries[i].charAt(0) != lastFirstChar) {
|
||||
lastFirstChar = mCountries[i].charAt(0);
|
||||
sectionIndices.add(i);
|
||||
}
|
||||
}
|
||||
int[] sections = new int[sectionIndices.size()];
|
||||
for (int i = 0; i < sectionIndices.size(); i++) {
|
||||
sections[i] = sectionIndices.get(i);
|
||||
}
|
||||
return sections;
|
||||
}
|
||||
|
||||
private Character[] getSectionLetters() {
|
||||
Character[] letters = new Character[mSectionIndices.length];
|
||||
for (int i = 0; i < mSectionIndices.length; i++) {
|
||||
letters[i] = mCountries[mSectionIndices[i]].charAt(0);
|
||||
}
|
||||
return letters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mCountries.length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return mCountries[position];
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
ViewHolder holder;
|
||||
|
||||
if (convertView == null) {
|
||||
holder = new ViewHolder();
|
||||
convertView = mInflater.inflate(R.layout.test_list_item_layout, parent, false);
|
||||
holder.text = (TextView) convertView.findViewById(R.id.text);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (ViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
holder.text.setText(mCountries[position]);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getHeaderView(int position, View convertView, ViewGroup parent) {
|
||||
HeaderViewHolder holder;
|
||||
|
||||
if (convertView == null) {
|
||||
holder = new HeaderViewHolder();
|
||||
convertView = mInflater.inflate(R.layout.header, parent, false);
|
||||
holder.text = (TextView) convertView.findViewById(R.id.text1);
|
||||
convertView.setTag(holder);
|
||||
} else {
|
||||
holder = (HeaderViewHolder) convertView.getTag();
|
||||
}
|
||||
|
||||
// set header text as first char in name
|
||||
CharSequence headerChar = mCountries[position].subSequence(0, 1);
|
||||
holder.text.setText(headerChar);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remember that these have to be static, postion=1 should always return
|
||||
* the same Id that is.
|
||||
*/
|
||||
@Override
|
||||
public long getHeaderId(int position) {
|
||||
// return the first character of the country as ID because this is what
|
||||
// headers are based upon
|
||||
return mCountries[position].subSequence(0, 1).charAt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPositionForSection(int section) {
|
||||
if (section >= mSectionIndices.length) {
|
||||
section = mSectionIndices.length - 1;
|
||||
} else if (section < 0) {
|
||||
section = 0;
|
||||
}
|
||||
return mSectionIndices[section];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionForPosition(int position) {
|
||||
for (int i = 0; i < mSectionIndices.length; i++) {
|
||||
if (position < mSectionIndices[i]) {
|
||||
return i - 1;
|
||||
}
|
||||
}
|
||||
return mSectionIndices.length - 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] getSections() {
|
||||
return mSectionLetters;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mCountries = new String[0];
|
||||
mSectionIndices = new int[0];
|
||||
mSectionLetters = new Character[0];
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void restore() {
|
||||
mCountries = mContext.getResources().getStringArray(R.array.countries);
|
||||
mSectionIndices = getSectionIndices();
|
||||
mSectionLetters = getSectionLetters();
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
class HeaderViewHolder {
|
||||
TextView text;
|
||||
}
|
||||
|
||||
class ViewHolder {
|
||||
TextView text;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package se.emilsjolander.stickylistheaders.views;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.TypedValue;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* @author Eric Frohnhoefer
|
||||
*/
|
||||
public class UnderlineTextView extends TextView {
|
||||
private final Paint mPaint = new Paint();
|
||||
private int mUnderlineHeight = 0;
|
||||
|
||||
public UnderlineTextView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public UnderlineTextView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public UnderlineTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
Resources r = getResources();
|
||||
mUnderlineHeight = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 2, r.getDisplayMetrics());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPadding(int left, int top, int right, int bottom) {
|
||||
super.setPadding(left, top, right, bottom + mUnderlineHeight);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
// Draw the underline the same color as the text
|
||||
mPaint.setColor(getTextColors().getDefaultColor());
|
||||
canvas.drawRect(0, getHeight() - mUnderlineHeight, getWidth(), getHeight(), mPaint);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user