当前位置: 代码迷 >> Android >> android之带右方字母(拼音)索引的列表
  详细解决方案

android之带右方字母(拼音)索引的列表

热度:65   发布时间:2016-04-28 02:30:43.0
android之带右侧字母(拼音)索引的列表


?在开发app的过程中,如果用到通讯录或者类似的列表,需要快速在其中定位,可以根据列表项的拼音首字母来定位,这时候就需要用到右侧字母索引了。必如现在的微信通讯录界面就是如此。在实现这种功能的过程中,还是挺复杂的,很难我觉得。在网上各种查找资料,困难重重,好在最后终于捯饬出来了,伤不起。。。。特此记录一下写的过程。

?

1、创建自定的view,用作右侧列表索引。

?

public class RulerWidget extends View {		public static String[] indexStr = {		"#", "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"		};	public static int INDEX_LENGTH = indexStr.length;		OnTouchingLetterChangedListener onTouchingLetterChangedListener; 	Paint mPaint = new Paint();	boolean showBkg = false;	int choose = -1;		public RulerWidget(Context context) {		super(context);	}		public RulerWidget(Context context, AttributeSet attrs, int defStyle) {		super(context, attrs, defStyle);	}		public RulerWidget(Context context, AttributeSet attrs) {		super(context, attrs);	}		@Override	protected void onDraw(Canvas canvas) {		super.onDraw(canvas);//		if(showBkg){  			canvas.drawColor(Color.parseColor("#40000000"));  //		 }  			          		int height = getHeight();  		int width = getWidth();  		int singleHeight = height / indexStr.length;  		for(int i=0;i<indexStr.length;i++){  			mPaint.setColor(Color.WHITE);			mPaint.setTextSize(24);			mPaint.setTypeface(Typeface.DEFAULT_BOLD);  			mPaint.setAntiAlias(true);  			if(i == choose){  			    mPaint.setColor(Color.parseColor("#3399ff"));  			    mPaint.setFakeBoldText(true);  			 }  			float xPos = width/2  - mPaint.measureText(indexStr[i])/2;  			float yPos = singleHeight * i + singleHeight;  			canvas.drawText(indexStr[i], xPos, yPos, mPaint);  			mPaint.reset();  		}  	}		  @Override  	    public boolean dispatchTouchEvent(MotionEvent event) {  	        final int action = event.getAction();  	        final float y = event.getY();  	        final int oldChoose = choose;  	        final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;  	        final int c = (int) (y/getHeight()*indexStr.length);  	          	        switch (action) {  	            case MotionEvent.ACTION_DOWN:  	                showBkg = true;  	                if(oldChoose != c && listener != null){  	                    if(c > 0 && c< indexStr.length){  	                        listener.onTouchingLetterChanged(indexStr[c]);  	                        choose = c;  	                        invalidate();  	                    }  	                }  	                  	                break;  	            case MotionEvent.ACTION_MOVE:  	                if(oldChoose != c && listener != null){  	                    if(c > 0 && c< indexStr.length){  	                        listener.onTouchingLetterChanged(indexStr[c]);  	                        choose = c;  	                        invalidate();  	                    }  	                }  	                break;  	            case MotionEvent.ACTION_UP:  //	                showBkg = false;  	                choose = -1;  	                invalidate();  	                break;  	        }  	        return true;  	    }  	  	    @Override  	    public boolean onTouchEvent(MotionEvent event) {  	        return super.onTouchEvent(event);  	    }  	  	    public void setOnTouchingLetterChangedListener(  	            OnTouchingLetterChangedListener onTouchingLetterChangedListener) {  	        this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;  	    }  	  }

?

对应的回调接口定义:

/**   * @date 2014-9-3 * @Description: ruler触摸回调 */public interface OnTouchingLetterChangedListener{      public void onTouchingLetterChanged(String s);  }  

?

?

2、创建fragment片段对应的布局文件:

?

<?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" >    <FrameLayout        android:layout_width="match_parent"        android:layout_height="match_parent"        android:background="#ffffff" >        <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/tv"            android:layout_width="60dp"            android:layout_height="60dp"            android:gravity="center"            android:background="#f0606060"            android:layout_gravity="center"            android:text="A"            android:textColor="#ffffff"            android:textSize="30sp" />         <com.hy.ticket.view.RulerWidget            android:id="@+id/sidrbar"            android:layout_width="30.0dip"            android:layout_height="fill_parent"            android:layout_gravity="right|center"  />      </FrameLayout></LinearLayout>

?

?

3、引入pinyin4j.jar包(版本建议使用最新),写一个工具类,包含获取中文字符串拼音首字母,获取中文拼音等方法。

?

public class StringHelper {		public static String getPingYin(String src) {		char[] t = src.toCharArray();		String[] strs = new String[t.length];		HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();		format.setCaseType(HanyuPinyinCaseType.LOWERCASE);		format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);		format.setVCharType(HanyuPinyinVCharType.WITH_V);		String str = "";		try{			for(int i=0; i<t.length; i++) {				if(java.lang.Character.toString(t[i]).matches(						"[\\u4E00-\\u9FA5]+")) {					strs = PinyinHelper.toHanyuPinyinStringArray(t[i], format);					str += strs[0];				}else{					str += java.lang.Character.toString(t[i]);				}			}			//长沙,长春多音字处理			if(str.equals("zhangsha")) {				str = "changsha";			}			if(str.equals("zhangchun")) {				str = "changchun";			}			return str;		}catch(Exception e) {			e.printStackTrace();		}		return str;	}		public static String getHeaderChar(String src) {		String convert = "";		char word = src.charAt(0);		String[] arr = PinyinHelper.toHanyuPinyinStringArray(word);		if(arr != null) {			convert += arr[0].charAt(0);		}else{			convert += word;		}		return convert.toUpperCase();	}		public static String getPinYinHeaderChar(String src) {		String convert = "";		for(int i=0; i<src.length(); i++) {			char word = src.charAt(i);			String[] arr = PinyinHelper.toHanyuPinyinStringArray(word);			if(arr != null) {				convert += arr[0].charAt(0);			}else{				convert += word;			}		}		return convert.toUpperCase();	}	}

?

?

4、建立一个工具类,用于根据首字母排序,获取大些字母及对应的中文字符串(如A 阿尔法 B 北京 C 长沙 长春 常州等):

?

public class SortUtil {		public static List<Station> sortList(String[] srcNames, List<Station> list) {		List<Station> newList = new ArrayList<Station>();		for(int i=0; i<srcNames.length; i++) {			if(srcNames[i].length() != 1) {				for(int j=0; j<list.size(); j++) {					if(srcNames[i].equals(list.get(j).getPinYinName())) {						Station s = new Station(list.get(j).getName(), list.get(j).getPinYinName());						newList.add(s);					}				}			}else{				newList.add(new Station(srcNames[i]));			}		}		return newList;	}		public static String[] sortIndex(List<Station> stations) {  		        TreeSet<String> set = new TreeSet<String>();  		        // 获取初始化数据源中的首字母,添加到set中  		        for (Station station : stations) {  		            set.add(StringHelper.getPinYinHeaderChar(station.getName()).substring(  		                    0, 1));  		        }  		        // 新数组的长度为原数据加上set的大小  		        String[] names = new String[stations.size() + set.size()];  		        int i = 0;  		        for (String string : set) {  		            names[i] = string;  		            i++;  		        }  		        String[] pinYinNames = new String[stations.size()];  		        for (int j = 0; j < stations.size(); j++) {  		            stations.get(j).setPinYinName(  		                    StringHelper  		                            .getPingYin(stations.get(j).getName().toString()));  		            pinYinNames[j] = StringHelper.getPingYin(stations.get(j).getName()  		                    .toString());  		        }  		        // 将原数据拷贝到新数据中  		        System.arraycopy(pinYinNames, 0, names, set.size(), pinYinNames.length);  		        // 自动按照首字母排序  		        Arrays.sort(names, String.CASE_INSENSITIVE_ORDER);  		        return names;  		    }  }

?

listViewAdapter,填充ListView的适配器:

public class ListViewAdapter extends BaseAdapter {		private Context context;	private List<Station> stations;	private ViewHolder viewHolder;		public ListViewAdapter(Context context, List<Station> stations) {		this.context = context;		this.stations = stations;	}	@Override	public int getCount() {		return stations.size();	}	@Override	public Object getItem(int position) {		return stations.get(position);	}	@Override	public long getItemId(int position) {		return position;	}		@Override  	public boolean isEnabled(int position) {  	    if (stations.get(position).getName().length() == 1)// 如果是字母索引  	       return false;// 表示不能点击  	    return super.isEnabled(position);  	}  		@Override	public View getView(int position, View convertView, ViewGroup parent) {		String item = stations.get(position).getName();		viewHolder = new ViewHolder();		if(item.length() == 1) {			convertView = LayoutInflater.from(context).inflate(R.layout.index, null);			TextView indexTV = (TextView) convertView.findViewById(R.id.indexTV);			indexTV.setText(stations.get(position).getName());			viewHolder.indexTV = indexTV;		}else{			convertView = LayoutInflater.from(context).inflate(R.layout.item, null);			TextView itemTV = (TextView) convertView.findViewById(R.id.itemTV);			itemTV.setText(stations.get(position).getName());			viewHolder.itemTV = itemTV;		}		return convertView;	}		//内部类	private class ViewHolder {		private TextView itemTV;		private TextView indexTV;	}}

?

?

?

5、最后一步,建立布局文件对应的fragment片段(或Activity,这里使用的是fragment):

?

public class ListStation extends Fragment {		private Map<String, Integer> selector;	private LinearLayout layoutIndex;	private ListView listView;	private TextView textView;	private ListViewAdapter adapter;	private String[] sections = {			"#", "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 List<Station> stations;	private List<Station> newStations;	private int height;	private boolean flag = false;	private LinearLayout layout;	private RulerWidget ruler;		private Handler handler;	private OverlayThread overlayThread;		@Override	public View onCreateView(LayoutInflater inflater, ViewGroup container,			Bundle savedInstanceState) {		View view = inflater.inflate(R.layout.station_list, container, false);		listView = (ListView) view.findViewById(R.id.listView);		textView = (TextView) view.findViewById(R.id.tv);		ruler = (RulerWidget) view.findViewById(R.id.sidrbar);		ruler.setOnTouchingLetterChangedListener(new LetterListViewListener());						initOverlay();		return view;	}		@Override	public void onActivityCreated(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);				stations = StationService.getAllStation();		String[] allNames = SortUtil.sortIndex(stations);		newStations = SortUtil.sortList(allNames, stations);				//这个map是建立大写字母对应位于listView位置的索引		selector = new HashMap<String, Integer>();		for(int i=0; i<allNames.length; i++) {			if(allNames[i].length() == 1) {				selector.put(allNames[i], i);			}		}		adapter = new ListViewAdapter(getActivity(), newStations);		listView.setAdapter(adapter);				handler = new Handler();		overlayThread = new OverlayThread();	}		//初始化汉语拼音首字母弹出提示框    private void initOverlay() {    	LayoutInflater inflater = LayoutInflater.from(getActivity());//    	overlay = (TextView) inflater.inflate(R.layout.overlay, null);    	textView.setVisibility(View.INVISIBLE);		WindowManager.LayoutParams lp = new WindowManager.LayoutParams(				LayoutParams.WRAP_CONTENT, 				LayoutParams.WRAP_CONTENT,				WindowManager.LayoutParams.TYPE_APPLICATION,				WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,				PixelFormat.TRANSLUCENT);		WindowManager windowManager = (WindowManager) getActivity().getSystemService(Context.WINDOW_SERVICE);//		windowManager.addView(textView, lp);    }		private class LetterListViewListener implements OnTouchingLetterChangedListener{		@Override		public void onTouchingLetterChanged(final String s) {			if(selector.get(s) != null) {				int position = selector.get(s);				listView.setSelection(position);								textView.setText(s);				textView.setVisibility(View.VISIBLE);				handler.removeCallbacks(overlayThread);				//延迟一秒后执行,让overlay为不可见				handler.postDelayed(overlayThread, 1500);			} 		}    	    }		//设置overlay不可见    private class OverlayThread implements Runnable {		@Override		public void run() {			textView.setVisibility(View.GONE);		}    	    }	/*class GetDataAsyTask extends AsyncTask {				@Override		protected void onPreExecute() {			super.onPreExecute();		}				@Override		protected Object doInBackground(Object... params) {			stations = StationService.getAllStation();			String[] allNames = SortUtil.sortIndex(stations);			newStations = SortUtil.sortList(allNames, stations);			if(newStations != null) {				newStations.clear();				newStations = null;			}			if(stations != null) {				stations.clear();				stations = null;			}			if(allNames != null) {				allNames = null;			}			return null;		}				@Override		protected void onPostExecute(Object result) {//			super.onPostExecute(result);			if(newStations == null) {//				textView.setVisibility(View.VISIBLE);				return;			}			handleSuccessData();		}			}		private Integer getPosition(final int j) {	       Integer pos = null;	       int i = j;	       while (pos == null && i <= RulerWidget.indexStr.length - 1) {	           pos = selector.get(RulerWidget.indexStr[i]);	           i++;	       }	       if (pos == null) {	           pos = newStations.size() - 1;	       }	       return pos;	    }		private void handleSuccessData() {	       listView.setVisibility(View.VISIBLE);	       ruler.setVisibility(View.VISIBLE);	       adapter = new ListViewAdapter(getActivity(), newStations);	       ruler.setOnRulerTouch(new OnRulerTouch() {						@Override			public void onUP() {			}						@Override			public void onOthers() {			}						@Override			public void onMove(int position) {				textView.setText(RulerWidget.indexStr[position]);				listView.setSelection(getPosition(position));			}						@Override			public void onDown(int position) {				textView.setVisibility(View.VISIBLE);				textView.setText(RulerWidget.indexStr[position]);				listView.setSelection(getPosition(position));			}		});	       	       listView.setAdapter(adapter);	       adapter.notifyDataSetChanged();	       	    }*/}

?

?

这样,带拼音索引的listView建立完成。。

?

  相关解决方案