声明:部分代码和资源并非原创,而是从互联网上下载。资源和代码经过本人的一些优化,逻辑更清晰易读,加强了使用性,嵌入项目时更容易。
效果类似于
先来看一下右边的SideBar字母索引列表效果如何实现:
package org.initialltouchlist;
import com.example.listsildedel.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.HeaderViewListAdapter;
import android.widget.ListView;
import android.widget.SectionIndexer;
import android.widget.TextView;
public class SideBar extends View {
private char[] l;
private SectionIndexer sectionIndexter = null;
private ListView list;
private TextView mDialogText;
Bitmap mbitmap;
private int type = 1;
private int color = 0xff858c94;
public SideBar(Context context) {
super(context);
init();
}
public SideBar(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
l = new char[] { '!', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '#' };
mbitmap = BitmapFactory.decodeResource(getResources(), R.drawable.scroll_bar_search_icon);
}
public SideBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
public void setListView(ListView _list) {
list = _list;
HeaderViewListAdapter ha = (HeaderViewListAdapter) _list.getAdapter();
NameAdapter ad = (NameAdapter) ha.getWrappedAdapter();
sectionIndexter = (SectionIndexer) ad;
}
public void setTextView(TextView mDialogText) {
this.mDialogText = mDialogText;
}
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
int i = (int) event.getY();
int idx = i / (getMeasuredHeight() / l.length);
if (idx >= l.length) {
idx = l.length - 1;
} else if (idx < 0) {
idx = 0;
}
if (event.getAction() == MotionEvent.ACTION_DOWN || event.getAction() == MotionEvent.ACTION_MOVE) {
setBackgroundResource(R.drawable.scrollbar_bg);
mDialogText.setVisibility(View.VISIBLE);
/**
* 中央显示的提示首字符
*/
if (idx == 0) {
mDialogText.setText("Search");
mDialogText.setTextSize(16);
} else {
mDialogText.setText(String.valueOf(l[idx]));
mDialogText.setTextSize(34);
}
if (sectionIndexter == null) {
sectionIndexter = (SectionIndexer) list.getAdapter();
}
int position = sectionIndexter.getPositionForSection(l[idx]);
if (position == -1) {
return true;
}
list.setSelection(position);
} else {
mDialogText.setVisibility(View.INVISIBLE);
}
if (event.getAction() == MotionEvent.ACTION_UP) {
setBackgroundDrawable(new ColorDrawable(0x00000000));
}
return true;
}
Paint paint = new Paint();
protected void onDraw(Canvas canvas) {
paint.setColor(color);
paint.setTextSize(12);
paint.setStyle(Style.FILL);
paint.setAntiAlias(true);
paint.setTextAlign(Paint.Align.CENTER);
float widthCenter = getMeasuredWidth() / 2;
if (l.length > 0) {
float height = getMeasuredHeight() / l.length;
for (int i = 0; i < l.length; i++) {
if (i == 0 && type != 2) {
canvas.drawBitmap(mbitmap, widthCenter - 7, (i + 1) * height - height / 2, paint);
} else
canvas.drawText(String.valueOf(l[i]), widthCenter, (i + 1) * height, paint);
}
}
this.invalidate();
super.onDraw(canvas);
}
}
onDraw不用说了,绘制右边栏条。
再看下适配器类实现:NameAdapter.java
package org.initialltouchlist;
import java.util.List;
import com.example.listsildedel.R;
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;
public class NameAdapter extends BaseAdapter implements SectionIndexer {
private List<Content> list = null;
private Context mContext;
public NameAdapter(Context mContext, List<Content> list) {
this.mContext = mContext;
this.list = list;
}
public int getCount() {
return this.list.size();
}
public Object getItem(int position) {
return null;
}
public long getItemId(int position) {
return position;
}
public View getView(final int position, View view, ViewGroup arg2) {
ViewHolder viewHolder = null;
if (view == null) {
viewHolder = new ViewHolder();
view = LayoutInflater.from(mContext).inflate(R.layout.item, null);
viewHolder.tvTitle = (TextView) view.findViewById(R.id.title);
viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}
final Content mContent = list.get(position);
if (position == 0) {
viewHolder.tvLetter.setVisibility(View.VISIBLE);
viewHolder.tvLetter.setText(mContent.getLetter());
} else {
String lastCatalog = list.get(position - 1).getLetter();
if (mContent.getLetter().equals(lastCatalog)) {
viewHolder.tvLetter.setVisibility(View.GONE);
} else {
viewHolder.tvLetter.setVisibility(View.VISIBLE);
viewHolder.tvLetter.setText(mContent.getLetter());
}
}
viewHolder.tvTitle.setText(this.list.get(position).getName());
return view;
}
final static class ViewHolder {
TextView tvTitle;
TextView tvLetter;
}
public Object[] getSections() {
return null;
}
public int getSectionForPosition(int position) {
return 0;
}
public int getPositionForSection(int section) {
Content mContent;
String l;
if (section == '!') {
return 0;
} else {
for (int i = 0; i < getCount(); i++) {
mContent = (Content) list.get(i);
l = mContent.getLetter();
char firstChar = l.toUpperCase().charAt(0);
if (firstChar == section) {
return i + 1;
}
}
}
mContent = null;
l = null;
return -1;
}
}
请关注一下上述代码的getPositionForSection方法的实现。
上述代码需要实体类Content.java:
package org.initialltouchlist;
public class Content {
private String letter;//存放首字母属性,我们需要使用这个属性进行对比来对列表进行排序
private String name;
public Content(String letter, String name) {
super();
this.letter = letter;
this.name = name;
}
public String getLetter() {
return letter;
}
public void setLetter(String letter) {
this.letter = letter;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
现在我们要实现Comparator接口来进行首字母对比
package org.initialltouchlist;
import java.util.Comparator;
public class PinyinComparator implements Comparator<Content> {
public int compare(Content o1, Content o2) {
if (o1.getLetter().equals("@")
|| o2.getLetter().equals("#")) {
return -1;
} else if (o1.getLetter().equals("#")
|| o2.getLetter().equals("@")) {
return 1;
} else {
return o1.getLetter().compareTo(o2.getLetter());
}
}
}
如果需要排序的数组当中都是汉字怎么办?我们需要取首个汉字的拼音首字母来进行比较。那我们可以通过以下代码来实现获取汉字的首个汉字的拼音。
注意,这需要需要第三方类库Pinyin4j 下载:
package org.initialltouchlist;
import net.sourceforge.pinyin4j.PinyinHelper;
public class PinyinLetterHelper {
/**
* 获取人名的拼音首字母并且大写化
*
* @param name
* 人名字符串,允许开头包含英文数字和下划线
* @return
*/
public static String getPinyinFirstLetter(String name) {
String firstletter = "#";
if (name != null) {
// 转换前不管是中文还是英文直接取开头字符
char initial = name.charAt(0);
//System.out.print(initial + " ---From: " + name);
if (!((initial >= 'A' && initial <= 'Z')
|| (initial >= 'a' && initial <= 'z')
|| (initial >= '0' && initial <= '9') || initial == '_')) {
firstletter = (PinyinHelper.toHanyuPinyinStringArray(initial))[0];
} else {
firstletter = initial + "";
}
firstletter = firstletter.toUpperCase();
//System.out.print(" -- " + firstletter);
char[] firstChar = new char[1];
firstChar[0] = firstletter.charAt(0);
firstletter = new String(firstChar);
//System.out.println(" --" + firstletter);
}
return firstletter;
}
}
以下是使用Demo:
package org.initialltouchlist;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.example.listsildedel.R;
import android.app.Activity;
import android.content.Context;
import android.graphics.PixelFormat;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
import android.widget.LinearLayout.LayoutParams;
import android.widget.ListView;
import android.widget.TextView;
public class MainActivity extends Activity {
private ListView mListView;
private SideBar indexBar;
private WindowManager mWindowManager;
private TextView mDialogText;
private View head;
@Override
public void onCreate(Bundle savedInstanceState) {
// 启动activity时不自动弹出软键盘
getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) this.findViewById(R.id.list);
indexBar = (SideBar) findViewById(R.id.sideBar);
mDialogText = (TextView) LayoutInflater.from(this).inflate(R.layout.list_position, null);
head = LayoutInflater.from(this).inflate(R.layout.head, null);
mListView.addHeaderView(head);
mDialogText.setVisibility(View.INVISIBLE);
mWindowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.TYPE_APPLICATION, WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
mWindowManager.addView(mDialogText, lp);
indexBar.setTextView(mDialogText);
// 初始化数据
List<Content> list = new ArrayList<Content>();
getDataIntoList(list);
// 根据a-z进行排序
Collections.sort(list, new PinyinComparator());
// 实例化自定义内容适配类
NameAdapter adapter = new NameAdapter(this, list);
// 为listView设置适配
mListView.setAdapter(adapter);
// 设置SideBar的ListView内容实现点击a-z中任意一个进行定位
indexBar.setListView(mListView);
}
/**
* 将内容填充到list中
*
* @param list
*/
public void getDataIntoList(List<Content> list) {
String[] array = getResources().getStringArray(R.array.default_smiley_texts);
for (int i = 0; i < array.length; i++) {
String string = PinyinLetterHelper.getPinyinFirstLetter(array[i]);
list.add(new Content(string, array[i]));
}
}
}
本项目所有代码和资源zip包,可以直接导入Eclipse: