我们都知道在手机通讯录中有这么一个神奇的功能,就是在联系人列表右侧有一列字母,你点到哪个字母就可以显示对应的联系人的姓名,这个神奇的东西就叫做索引条,那么我们在Android中是如何实现索引条功能的呢 下面我就来介绍一下
首先我们最最重要的事情就是知道这个索引条是一个自定义组件 所以说我们创建一个类要继承View,并且要复写它的一些方法,画笔画布我在这里就不多介绍了,我们来看看代码
public class IndexView extends View {
//首先我把所有字母放到一个数组里
public static final String[] WORDS = {"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"};
private int preHeight = 18;//每一个字母的高度
private MainAdapter mainAdapter;
//设置ListView
public void setmListView(ListView mListView) {
this.mListView = mListView;
mainAdapter = (MainAdapter) mListView.getAdapter();//获得ListView关联的Adapter
}
private ListView mListView;//我们需要要设置索引的ListView
private Paint mPaint;//画笔
private int blankHeight;//空白的高度,留着计算
public IndexView(Context context) {
super(context);
init();
}
public IndexView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
//初始化
private void init() {
mPaint = new Paint();
mPaint.setColor(Color.BLACK);
//文字的对齐方式是居中
mPaint.setTextAlign(Paint.Align.CENTER);
//将高度从dp转换成px
preHeight = dpToPx(preHeight, getContext());
//设置字体大小的时候,需要px
mPaint.setTextSize(preHeight);
mPaint.setAntiAlias(true);//抗锯齿
}
//在该声明周期中,会测量控件的宽高
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//getMeasuredHeight 获得该组件的高度
blankHeight = (getMeasuredHeight() - (WORDS.length * preHeight))
/ (WORDS.length - 1);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int i = 0; i < WORDS.length; i++) {
//在该组件上画文字
canvas.drawText(WORDS[i], getMeasuredWidth() / 2,
(i + 1) * (preHeight + blankHeight), mPaint);
}
}
//该方法会处理用户的点击事件
@Override
public boolean onTouchEvent(MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
//当用户按下的时候
int index = (int) (event.getY() / (preHeight + blankHeight));
if (index >= WORDS.length) {
//做一个修正
index = WORDS.length - 1;
} else if (index < 0) {
index = 0;
}
Log.d("Sysout","word"+WORDS[index]);
//通过字母 获得ListView的条数,并滚动到该位置
int pos = mainAdapter.getIndexFromString(WORDS[index]);
if (pos >= 0) {
mListView.setSelection(pos);//ListView滚动到pos位置
}
}
return super.onTouchEvent(event);
}
//在这里我们需要将dp单位转化成px单位
//将dp转换成px方法如下
private int dpToPx(int dp, Context context) {
int px = 0;
//获得屏幕的dpi 需要通过Resources下得DisplayMetrics中的destiyDip
Resources resources = context.getResources();
DisplayMetrics metrics = resources.getDisplayMetrics();
//+0.5f 是为了 四舍五入
px = (int) (dp * metrics.densityDpi / 160f + 0.5f);
return px;
}
}
然后我们来看看我们是如何写ListView的适配器的
public class MainAdapter extends BaseAdapter {
private Context context;
private List<String> data;
public MainAdapter(Context context) {
this.context = context;
initData();
}
//添加数据
private void initData() {
data = new ArrayList<>();
for (char j = 'A'; j <= 'Z'; j++) {
for (int i = 0; i < 15; i++) {
data.add(String.valueOf(j));
}
}
}
@Override
public int getCount() {
return data.size();
}
@Override
public Object getItem(int position) {
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
MyViewHolder myViewHolder;
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(
R.layout.item_lv, parent, false);
myViewHolder = new MyViewHolder(convertView);
convertView.setTag(myViewHolder);
} else {
myViewHolder = (MyViewHolder) convertView.getTag();
}
myViewHolder.textView.setText(data.get(position));
return convertView;
}
class MyViewHolder {
TextView textView;
public MyViewHolder(View view) {
textView = (TextView) view.findViewById(R.id.tv_item);
}
}
//通过字母返回相对应的位置
public int getIndexFromString(String s) {
Log.d("Sysout", "s:" + s);
for (int i = 0; i < data.size(); i++) {
Log.d("Sysout", "data:" + data.get(i));
if (data.get(i).equals(s)) {
//找到了该字母,立即返回索引
Log.d("Sysout", "i = " + i);
return i;
}
}
//没有找到 返回-1
return -1;
}
}
我们再来看一看MainActivity是如何来写的
public class MainActivity extends AppCompatActivity {
private ListView listView;
private MainAdapter mainAdapter;
private IndexView indexView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.lv_main);
mainAdapter = new MainAdapter(this);
listView.setAdapter(mainAdapter);
indexView = (IndexView) findViewById(R.id.main_index);
indexView.setmListView(listView);
}
}
我们再看一看布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.lanou.chenfengyao.indexdemo.MainActivity">
<com.lanou3g.indexdemo.IndexView
android:id="@+id/main_index"
android:layout_width="33dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"/>
<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/lv_main"
android:layout_toLeftOf="@id/main_index"/>
</RelativeLayout>
在这里ListView的行布局我就不贴出来了 很简单 我相信大家都知道.
这就是自定义的索引条,希望对大家有所帮助.