自定义控件之快速索引QuickIndexBar

来源:互联网 发布:益云网络 编辑:程序博客网 时间:2024/04/30 02:32

1.定义个类继承view

主要使用三个方法:

一.onSizeChanged() {计算这个自定义控件的宽和每个字母所占的格子的高}

二.onDraw(){调用canvas.drawText}

三.onTouchEvent(){处理触摸逻辑}

public class QuickIndexBar extends View {private Paint paint;private float cellWidth;private float cellHeight;public QuickIndexBar(Context context) {this(context, null);}public QuickIndexBar(Context context, AttributeSet attrs) {this(context, attrs, 0);}public QuickIndexBar(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init();}private void init() {paint = new Paint();paint.setColor(Color.GRAY);//抗锯齿paint.setAntiAlias(true);paint.setTextSize(20);//设置粗体和斜体paint.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD_ITALIC));}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);for (int i = 0; i < Cheeses.LETTERS.length; i++) {String letter = Cheeses.LETTERS[i];//定义一个矩形Rect rect = new Rect();//把letter装进一个矩形区域内//这个方法将letter进行测量,将letter的宽高设置到Rect中//参数2:字母的开始//参数3:字母的结束paint.getTextBounds(letter, 0, 1, rect);int textWidth = rect.width();int textHeight = rect.height();//等于一个单位宽度/2+文本占用的宽度/2float x = cellWidth / 2 - textWidth / 2;//等于一个单位高度/2+文本占用的高度/2+每个单位高度*ifloat y = cellHeight / 2 + textHeight / 2 + i * cellHeight;//判断绘制的文本是否是当前选择的索引,如果是,则高亮显示paint.setColor(i == currentIndex ? Color.RED : Color.GRAY);paint.setTextSize(i==currentIndex?30:20);canvas.drawText(letter, x, y, paint);}//绘制一个文本在View上//canvas.drawText("#",10f,20f,paint);//canvas.drawText("#",10f,50f,paint);//canvas.drawText("#",10f,80f,paint);//canvas.drawText("#",10f,110f,paint);//canvas.drawText("#",10f,140f,paint);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {super.onSizeChanged(w, h, oldw, oldh);cellWidth = this.getMeasuredWidth();cellHeight = this.getMeasuredHeight() * 1.0f / Cheeses.LETTERS.length;}private int currentIndex = -1;private int preIndex = -1;@Overridepublic boolean onTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:case MotionEvent.ACTION_MOVE:if (listener != null) {preIndex = currentIndex;float y = event.getY();//计算触摸的点所在的位置currentIndex = (int) (y / cellHeight);//识别被触摸到的letterString letter = Cheeses.LETTERS[currentIndex];//检查触摸的位置与上一个位置是否一致,如果不一致,则打印if (preIndex != currentIndex) {Log.i("test", "letter:" + letter);listener.onLetterChanged(letter);}invalidate();}break;case MotionEvent.ACTION_UP:if (listener != null) {listener.onLetterDismiss();}currentIndex=-1;invalidate();break;default:break;}return true;}private OnLetterChangedListener listener;public interface OnLetterChangedListener {void onLetterChanged(String letter);void onLetterDismiss();}public void setOnLetterChangedListener(OnLetterChangedListener listener) {this.listener = listener;}}

2.布局文件

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"                android:layout_width="match_parent"                android:layout_height="match_parent"                android:orientation="vertical">    <ListView        android:id="@+id/lv"        android:layout_width="match_parent"        android:layout_height="match_parent"></ListView>    <com.itheima.quickindexbarhm91.QuickIndexBar        android:id="@+id/qib"        android:layout_width="20dp"        android:layout_height="match_parent"        android:layout_alignParentRight="true"        android:background="#770095ff"/>    <TextView        android:id="@+id/tv_show_letter"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerInParent="true"        android:background="@drawable/tv_bg"        android:gravity="center"        android:textColor="@android:color/white"        android:textSize="20sp"        android:visibility="gone"        /></RelativeLayout>

3.activity

public class MainActivity extends AppCompatActivity {private TextView tv_show_letter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);tv_show_letter = (TextView) findViewById(R.id.tv_show_letter);QuickIndexBar qib = (QuickIndexBar) findViewById(R.id.qib);qib.setOnLetterChangedListener(new QuickIndexBar.OnLetterChangedListener() {@Overridepublic void onLetterChanged(String letter) {tv_show_letter.setVisibility(View.VISIBLE);tv_show_letter.setText(letter);}@Overridepublic void onLetterDismiss() {new Handler().postDelayed(new Runnable() {@Overridepublic void run() {tv_show_letter.setVisibility(View.GONE);}}, 200);}});List<ContactInfo> contacts=new ArrayList<ContactInfo>();for (int i = 0; i < Cheeses.NAMES.length; i++) {contacts.add(new ContactInfo(Cheeses.NAMES[i]));}//让ContactInfo具有可排序性,让Collections对ContactInfo集合进行排序Collections.sort(contacts);ListView lv= (ListView) findViewById(R.id.lv);lv.setAdapter(new ContactAdapter(contacts));}}
4.要显示的数据对象类

public class ContactInfo implements  Comparable<ContactInfo>{private String firstLetter;private String name;public ContactInfo(String name) {this.firstLetter= PinyinUtil.chineseWordToPinyin(name).substring(0, 1);this.name = name;}public String getFirstLetter() {return firstLetter;}public void setFirstLetter(String firstLetter) {this.firstLetter = firstLetter;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "ContactInfo{" +"firstLetter='" + firstLetter + '\'' +", name='" + name + '\'' +'}';}@Overridepublic int compareTo(ContactInfo another) {return this.firstLetter.compareTo(another.firstLetter);}}
5.适配器

public class ContactAdapter extends BaseAdapter {private List<ContactInfo> contacts;public ContactAdapter(List<ContactInfo> contacts) {this.contacts = contacts;}@Overridepublic int getCount() {return contacts == null ? 0 : contacts.size();}@Overridepublic Object getItem(int position) {return null;}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder = null;if (convertView == null) {convertView = View.inflate(parent.getContext(), R.layout.lv_contact_list_item, null);holder = new ViewHolder();holder.tv_first_letter = (TextView) convertView.findViewById(R.id.tv_first_letter);holder.tv_name = (TextView) convertView.findViewById(R.id.tv_name);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}ContactInfo info = contacts.get(position);holder.tv_first_letter.setText(info.getFirstLetter());holder.tv_name.setText(info.getName());if (position == 0) {holder.tv_first_letter.setVisibility(View.VISIBLE);} else {//如果当前条目对应的首字母和上一个一致,则让首字母隐藏ContactInfo lastInfo = contacts.get(position - 1);if (lastInfo.getFirstLetter().equals(info.getFirstLetter())) {holder.tv_first_letter.setVisibility(View.GONE);} else {holder.tv_first_letter.setVisibility(View.VISIBLE);}}return convertView;}private class ViewHolder {private TextView tv_first_letter;private TextView tv_name;}}



6.由于显示数据时要显示每个名字的字母  所以要将汉子转为拼音 提取出首字母  这里用到了一个拼音jar包    pinyin4j-2.5.0.jar

public class PinyinUtil {private static HanyuPinyinOutputFormat format;public static String chineseWordToPinyin(String chineseWord) {if (format == null) {format = new HanyuPinyinOutputFormat();}//设置去除声调format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//将汉语字符串转化为字符数据char[] chars = chineseWord.toCharArray();StringBuffer sb=new StringBuffer();for (char c : chars) {//跨过空格if(Character.isWhitespace(c)){continue;}else{//拼配汉字的正则表达式if(Character.toString(c).matches("[\\u4E00-\\u9FA5]")) {try {String[] results = PinyinHelper.toHanyuPinyinStringArray(c, format);//for (String result : results) {//Log.i("test","result:"+result);//}String result = results[0];sb.append(result);} catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {badHanyuPinyinOutputFormatCombination.printStackTrace();}}else{//如果是字母if(Character.isLetter(c)){//直接变为字母sb.append(c);}else{//如果是"火星文",以#代替sb.append("#");}}}}return sb.toString();}}



0 0