这篇文章主要讲解下自定义的字母索引,在每个App中一般都会用到的,简单的例子就给大家分享下。首先请看下目录是怎么样的:
首先呢,MainActivity就是用来显示那个导航的页面 Person是用来模拟一个数据类 最主要的还是SideView了 这个是用来自定义一个索引的导航
然后,看看源码是怎么实现的吧 从最主要的来说 SideView:
package com.example.administrator.zimudaohang;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
/**
* Created by Administrator on 2016/2/3 0003.
*/
public class SideView extends View {
private String[] ZiMu = {"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 Paint paint = new Paint();
private Context context;
private Canvas canvas;
private Boolean ShowBG = false;//显示中间小字母?
public SideView(Context context) {
super(context);
this.context = context;
}
public SideView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
@Override
protected void onDraw(Canvas canvas) {
//获取该空间的宽和高
float height = this.getHeight();
float width = this.getWidth();
//设置画笔的属性
paint.setColor(Color.RED);
paint.setTextSize(20);
paint.setTypeface(Typeface.DEFAULT);
//设置每个字母所在的高度
int each_height = (int) (height / ZiMu.length);
for (int i = 0; i < ZiMu.length; i++) {
float x = (width - paint.measureText(ZiMu[i])) / 2;
float y = (1 + i) * each_height;
canvas.drawText(ZiMu[i], x, y, paint);
}
}
private int choose;//用来存储选中字母的索引
private OnTouchLetterChangeListenner listenner;
/**
* 回调方法,注册监听器
*
* @param listenner
*/
public void setOnTouchLetterChangeListenner(
OnTouchLetterChangeListenner listenner) {
this.listenner = listenner;
}
/**
* SlideBar 的监听器接口
*
* @author Folyd
*/
public interface OnTouchLetterChangeListenner {
void onTouchLetterChange(Boolean ShowBG, String s);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float y = event.getY();
final int c = (int) (y / getHeight() * ZiMu.length);//获取点击Y轴坐标总高度的比例*数组的长度就是等于数组中点击的字母索引
// 保存上次点击的字母的索引到oldChoose
final int oldChoose = choose;
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
ShowBG = false;
choose = -1;
if (listenner != null) {
listenner.onTouchLetterChange(ShowBG, ZiMu[c]);
}
setBackgroundResource(android.R.color.transparent);
invalidate();
break;
default:
ShowBG = true;
setBackgroundResource(android.R.color.darker_gray);
if (c >= 0 && c < ZiMu.length) {
if (listenner != null) {
if (oldChoose != c && listenner != null && c >= 0
&& c < ZiMu.length) {
choose = c;
listenner.onTouchLetterChange(ShowBG, ZiMu[c]);
invalidate();
}
choose = c;
}
}
break;
}
return true;
}
}
其实思路是挺简单的 :
首先定义一个SideView类继承View 然后用Android中的绘图技术绘制出该控件的外观,再然后声明他的事件 例如OnTouchEvent事件,该事件要定义监听器 接口之类的 (具体实现方法才找源代码)。
接下来说下主窗口的实现方法:
package com.example.administrator.zimudaohang;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private SideView sideView;
private TextView textView;
private ListView listView;
private List<Person> list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sideView= (SideView) findViewById(R.id.sideview);
textView= (TextView) findViewById(R.id.float_letter);
listView= (ListView) findViewById(R.id.listView);
sideView.setOnTouchLetterChangeListenner(new SideView.OnTouchLetterChangeListenner() {
@Override
public void onTouchLetterChange(Boolean ShowBG, String s) {
textView.setText(s);
if (ShowBG) {
textView.setVisibility(View.VISIBLE);
// Toast.makeText(MainActivity.this,findIndex(s)+"",Toast.LENGTH_SHORT).show();
listView.setSelection(findIndex(s));
} else {
textView.setVisibility(View.GONE);
}
}
});
getData();
MyAdapter myAdapter=new MyAdapter();
listView.setAdapter(myAdapter);
}
//获取数据 这个可以根据自己的个人情况来取舍
private List getData(){
list=new ArrayList<Person>();
Person person4=new Person();
person4.setName("阿门");
person4.setSort("A");
person4.setID(0);
list.add(person4);
Person person1=new Person();
person1.setName("明明");
person1.setSort("M");
person4.setID(1);
list.add(person1);
Person person2=new Person();
person2.setName("明明2");
person2.setSort("M");
person2.setID(2);
list.add(person2);
Person person3=new Person();
person3.setName("明3");
person3.setSort("M");
person3.setID(3);
list.add(person3);
Person person5=new Person();
person5.setName("保罗");
person5.setSort("B");
person5.setID(5);
list.add(person5);
for(int i=6;i<11;i++){
Person person6=new Person();
person6.setName("成功"+i);
person6.setSort("C");
person6.setID(i);
list.add(person6);
}
Person person7=new Person();
person7.setName("成功6");
person7.setSort("C");
person7.setID(11);
list.add(person7);
for(int i=12;i<17;i++){
Person person6=new Person();
person6.setName("打的"+i);
person6.setSort("D");
person6.setID(i);
list.add(person6);
}
for(int i=18;i<25;i++){
Person person6=new Person();
person6.setName("俄方"+i);
person6.setSort("E");
person6.setID(i);
list.add(person6);
}
return list;
}
private StringBuffer buffer = new StringBuffer();//用来第一次保存首字母的索引
private List<String> firdList = new ArrayList<String>();//用来保存所有值得城市名称
//适配器
private class MyAdapter extends BaseAdapter{
@Override
public int getCount() {
return list.size();
}
@Override
public Object getItem(int position) {
return list.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater=getLayoutInflater();
if(convertView==null){
convertView=inflater.inflate(R.layout.item,null);
}
Person person=list.get(position);
String sort=person.getSort();
String name=person.getName();
int ID=person.getID();
TextView textView2= (TextView) convertView.findViewById(R.id.item_sort);
if(buffer.indexOf(sort)==-1){ //索引不存在的话
buffer.append(sort);//将该字母添加进去
firdList.add(ID+"");
}
if(firdList.contains(ID+"")){
textView2.setText(sort);
textView2.setVisibility(View.VISIBLE);
}else{
textView2.setVisibility(View.GONE);
}
TextView textView= (TextView) convertView.findViewById(R.id.item_name);
textView.setText(name);
return convertView;
}
}
//根据索引找到对应的索引位置
private int findIndex(String s){
for(int i=0;i<list.size();i++){
if(s.equals(list.get(i).getSort())){
return i;
}
}
return -1;
}
}
其中这个主窗口都挺简单的,主要是吧ListView中的字母和标题之间的关系处理好 什么时候该显示,什么时候不该显示字母索引这个处理好其余的就好办了。
在具体的代码都有介绍 所以就不废话了。
然后主界面和listitem的布局让大家看看:
<?xml version="1.0" encoding="utf-8"?>
<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.example.administrator.zimudaohang.MainActivity">
<FrameLayout
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cacheColorHint="#00000000"
android:fadingEdge="none"
android:scrollbars="none" >
</ListView>
<TextView
android:id="@+id/float_letter"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:background="#F88701"
android:gravity="center"
android:textSize="40sp"
android:visibility="gone" />
<com.example.administrator.zimudaohang.SideView
android:id="@+id/sideview"
android:layout_width="30dp"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_gravity="right|top" />
</FrameLayout>
</RelativeLayout>
listitem布局:
<?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">
<TextView
android:id="@+id/item_sort"
android:layout_width="match_parent"
android:layout_height="40dp"
android:background="#CCCCCC"
android:padding="8dp"
android:text="C"
android:textColor="#000000"
android:textSize="18dp" />
<TextView
android:id="@+id/item_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="城市名称"
android:textColor="#000000"
android:textSize="15dp" />
</LinearLayout>
最后是一个最简单的数据类的源码
package com.example.administrator.zimudaohang;
/**
* Created by Administrator on 2016/2/20 0020.
*/
public class Person {
private String name;
private String sort;
private int ID;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public String getSort(){
return sort;
}
public void setSort(String sort){
this.sort=sort;
}
public int getID(){
return ID;
}
public void setID(int ID){
this.ID=ID;
}
}
到此为止 自定义的字母索引导航就告一段落了。下面是效果图: