2.模仿小米通讯录的快速索引demo

快速索引 (对View的自定义) 

应用场景: 微信好友列表, 联系人通讯录, 应用管理, 文件管理
功能实现: 

1. A-Z索引的绘制. OK

2. 处理Touch事件. OK 

3. 提供使用监听\回调. OK  

4. 汉字转换成拼音. OK

5. 进行排序展示. OK

6. 进行分组. OK

7. 将自定义控件和ListView合体. OK


1.自定义view  Myindex 类


//自定义一个view,自己画一个索引bar出来
public class Myindex extends View {

	private Paint paint;
	private static final String[] LETTERS = new String[] { "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 float measuredHeight;
	private float measuredWidth;
	private float aveHeight;
	private OntextChangeListener listener;
	
	//定义接口,设置监听,当按下的时候就将按下的那个字母返回给监听方
	public interface OntextChangeListener{
		void getText(String letters);
	}
	
	public void setOntextChangeListener(OntextChangeListener listener){
		this.listener = listener;
	}
	
	public Myindex(Context context) {
		super(context);
		init();
	}

	public Myindex(Context context, AttributeSet attrs) {
		super(context, attrs);
		init();
	}

	public Myindex(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	private void init() {
		//设置画笔的属性
		paint = new Paint(Paint.ANTI_ALIAS_FLAG);//去掉锯齿
		paint.setColor(Color.WHITE);//白色
		paint.setTextSize(30);//大小
		paint.setTypeface(Typeface.DEFAULT_BOLD);//加粗
	}
	
	//重新ondraw方法,设置画布,宽高在xml中定义了
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		for (int i = 0; i < LETTERS.length; i++) {
			
			String text = LETTERS[i];
			//文字的x轴坐标    =   宽度的一半-文字的一半 
			float x = measuredWidth / 2.0f - paint.measureText(text) / 2;

			
			//通过矩形获取文字的高度
			Rect bounds = new Rect();
			paint.getTextBounds(text, 0, text.length(), bounds);
			int textHeight = bounds.height();
			//文字的y坐标
			float y = aveHeight / 2.0f + textHeight / 2.0f + i * aveHeight;
			
			//设置按下的画笔描绘颜色
			paint.setColor(i==preindex?Color.GRAY:Color.WHITE);
			canvas.drawText(text, x, y, paint);
		}
	}
	private int preindex = -1;
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		int index = -1;
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			index = (int) (event.getY() / aveHeight);
			//如果点击的字母和上一个字母不同则让执行监听(没有必要一直执行,因为按的是同一个)
			if (index != preindex) {
				if(listener!=null){
					listener.getText(LETTERS[index]);
				}
				preindex = index;
			}
			break;
		case MotionEvent.ACTION_MOVE:
			//移动和按下一样
			index = (int) (event.getY() / aveHeight);
			if (index != preindex) {
				if(listener!=null){
					listener.getText(LETTERS[index]);
				}
				preindex = index;
			}
			break;
		case MotionEvent.ACTION_UP:
			break;

		default:
			break;
		}
		
		invalidate();//保存一下改变的状态

		return true;//可以一直接收移动的变化

	}

	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// 拿到view的宽高   
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		measuredHeight = getMeasuredHeight();
		measuredWidth = getMeasuredWidth();
		//计算一个字母的高(总共26个字母)
		aveHeight = measuredHeight / LETTERS.length;
	}
}


2.MainActivity类,实现监听,点击跳转到相应联系人


//快速索引
public class MainActivity extends Activity {

	private ArrayList<Person> arrayList;
	private ListView listView;
	private TextView tv_center;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		Myindex myindex = (Myindex) findViewById(R.id.index);
		listView = (ListView)findViewById(R.id.lv_main);
		tv_center = (TextView)findViewById(R.id.tv_center);
		
		//给自定义的view设置监听,这样就可以自定义的view独立存在
		myindex.setOntextChangeListener(new OntextChangeListener() {
			@Override
			public void getText(String letters) {
				//ToastUtil.showToast(MainActivity.this, letters);
				//展示大字母显示
				setLocationShow(letters);
				
				//将索引和listview结合
				for(int i=0;i<arrayList.size();i++){
					String pinyin = arrayList.get(i).getPinyin().charAt(0)+"";
					if(TextUtils.equals(letters, pinyin)){//如果索引的字母和集合中的首字母一样,则跳到该位置
						listView.setSelection(i);
						break;//不加break,则会持续跳转到,该字母组中的最后一个
					}
				}
			}
		});
		
		arrayList = new ArrayList<Person>();
		
		fillData(arrayList);
		
		listView.setAdapter(new haohanAdapter(MainActivity.this,arrayList));
	}
	
	Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			if(msg.what==0){
				tv_center.setVisibility(View.GONE);
			}
		};
	};
	
	protected void setLocationShow(String letters) {
		tv_center.setText(letters);
		tv_center.setVisibility(View.VISIBLE);
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			@Override
			public void run() {
				handler.sendEmptyMessage(0);
			}
		}, 1000);
		
	}
	
	//填充数据到集合中
	private void fillData(ArrayList<Person> arrayList) {
		for(int i=0;i<Cheeses.NAMES.length;i++){
			arrayList.add(new Person(Cheeses.NAMES[i]));
		}
		Collections.sort(arrayList);
	}
	
}

3.适配器

public class haohanAdapter extends BaseAdapter{
	private Context context;
	private ArrayList<Person> arrayList;
	private Viewholder viewholder;
	public haohanAdapter(Context context, ArrayList<Person> arrayList) {
		this.context = context;
		this.arrayList = arrayList;
	}

	@Override
	public int getCount() {
		return arrayList.size();
	}

	@Override
	public Object getItem(int position) {
		return arrayList.get(position);
	}

	@Override
	public long getItemId(int position) {
		return position;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) {
		View view;
		
		if(convertView == null){
			viewholder = new Viewholder();
			view = View.inflate(context, R.layout.item_list, null);
			viewholder.head = (TextView) view.findViewById(R.id.tv_index);
			viewholder.content = (TextView) view.findViewById(R.id.tv_name);
			view.setTag(viewholder);
		}else{
			view = convertView;
			viewholder = (Viewholder) view.getTag();
		}
		Person person = arrayList.get(position);
		String letter = person.getPinyin().charAt(0)+"";
		
		if(position==0){
			viewholder.head.setVisibility(View.VISIBLE);//如果位置为0,显示首字母
		}else{
			String preletter = arrayList.get(position-1).getPinyin().charAt(0)+"";
			if(TextUtils.equals(letter, preletter)){//如果上一个和下一个相同,下一个的首字母不显示
				viewholder.head.setVisibility(View.GONE);
			}else{
				viewholder.head.setVisibility(View.VISIBLE);
			}
		}
		viewholder.head.setText(letter);
		viewholder.content.setText(person.getName());
		return view;
	}
	
	static class Viewholder{
		TextView head;
		TextView content;
	}
}	


4.文字转换成拼音  

public class PinyinUtils {

	/**
	 * 根据传入的字符串(包含汉字),得到拼音
	 * 罗大爷 -> LUODAYE
	 * 罗 大爷*& -> LUODAYE
	 * 罗 大爷f5 -> LUODAYE
	 * @param str 字符串
	 * @return
	 */
	public static String getPinyin(String str) {
		
		HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
		format.setCaseType(HanyuPinyinCaseType.UPPERCASE);
		format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
		
		StringBuilder sb = new StringBuilder();
		
		char[] charArray = str.toCharArray();
		for (int i = 0; i < charArray.length; i++) {
			char c = charArray[i];
			// 如果是空格, 跳过
			if(Character.isWhitespace(c)){
				continue;
			}
			if(c >= -127 && c < 128){
				// 肯定不是汉字
				sb.append(c);
			}else {
				String s = "";
				try {
					// 通过char得到拼音集合. 单 -> dan, shan 
					s = PinyinHelper.toHanyuPinyinStringArray(c, format)[0];//获得首字母
					sb.append(s);
				} catch (BadHanyuPinyinOutputFormatCombination e) {
					e.printStackTrace();
					sb.append(s);
				}
			}
		}
		
		return sb.toString();
	}

}


5.Person类,实现了接口,设置排序

public class Person implements Comparable<Person>{
	private String name;
	private String pinyin;
	
	public Person(String name) {
		super();
		this.name = name;
		this.pinyin = PinyinUtils.getPinyin(name);
	}
	
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPinyin() {
		return pinyin;
	}
	public void setPinyin(String pinyin) {
		this.pinyin = pinyin;
	}

	@Override
	public int compareTo(Person another) {
		return this.pinyin.compareTo(another.getPinyin());
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值