`
Everyday都不同
  • 浏览: 723742 次
  • 性别: Icon_minigender_1
  • 来自: 宇宙
社区版块
存档分类
最新评论

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建立完成。。

 

分享到:
评论

相关推荐

    Android自定义View实现通讯录字母索引(仿微信通讯录)

    一、效果:我们看到很多软件的通讯录在右侧都有一个字母索引功能,像微信,小米通讯录,QQ,还有美团选择地区等等。这里我截了一张美团选择城市的图片来看看; 我们今天就来实现图片中右侧模块的索引功能,包括触摸...

    Android 列表字母索引 IndexableListView

    Android代码 实现带字母索引效果的listview列表, 类似Android 通讯录中使用的检索联系人得效果.滑动listview时 旁边会出现一个字母索引条,手指滑动索引条 屏幕中间会出现当前索引字母,同时listview内容会被过滤...

    安卓仿通讯录及微信联系人侧边栏滑动及字母索引

    在Android中,我们可以使用`SlidingPaneLayout`或`DrawerLayout`作为基础,然后进行定制化开发,添加触摸事件监听,实现滑动动画,以及根据当前选中的字母更新联系人列表。 接着,我们需要使用`RecyclerView`来展示...

    字母索引定位,仿联系人列表功能,实现字母A-Z排序

    在Android应用开发中,创建一个类似手机联系人应用的界面是一项常见的任务,其中包括对数据进行字母排序并实现字母索引定位的功能。这个功能允许用户快速浏览和定位到以特定字母开头的数据项,提高用户体验。本篇...

    安卓A-Z字母排序索引相关-拼音检索ListView实现拼音检索ListView的简单功能.rar

    3. **创建索引**:将所有条目的首字母拼音收集到一个新的List中,并去重,形成A-Z的字母索引列表。 4. **实现Adapter**:创建一个自定义的ArrayAdapter或CursorAdapter,扩展其功能以支持拼音检索。在getView()方法...

    带有拼音首字母排序的listview

    在ListView的右侧添加一个垂直的字母索引栏,通常称为侧滑栏或滑动索引。当用户触摸字母时,它会高亮并滚动ListView到相应的分组。这个栏可以自定义实现,也可以使用第三方库如`android-letters-view`。 7. **优化...

    android 通讯录(A-Z)带可模糊查询搜索框

    这篇教程“android 通讯录(A-Z)带可模糊查询搜索框”着重讲解如何创建一个能够进行字母索引排序和模糊查询的通讯录界面。在这个过程中,开发者会接触到Android的UI设计、数据处理以及搜索功能的实现。 首先,UI...

    Android 仿美团网,探索ListView的A-Z字母排序功能实现选择省份或者城市

    记得在我刚开始接触到美团网的时候就对美团网这个城市定位、选择城市功能很感兴趣,觉得它做得很...(3)下面是一个ListView用来显示数据列表,右侧是一个字母索引表,当我们点击不同的字母,ListView会定位到该字母地方

    用Recycleview实现仿微信通讯录的右侧索引

    要实现右侧的字母索引,我们首先需要处理的是将联系人姓名转换为拼音。这里提到了“pinyin4j”包,这是一个Java库,用于汉字转拼音。在项目中引入pinyin4j后,我们可以对每个联系人的姓名进行处理,获取其首字母,...

    android仿微信联系人索引列表功能

    在Android开发中,实现类似微信联系人索引列表的功能是一项常见的需求,主要是为了方便用户快速定位到特定的联系人。这个功能通常包括一个字母栏,显示A到Z的字母,以及一个按照字母顺序排列的列表。以下是实现这个...

    仿美团选择城市、微信通讯录导航悬停分组索引列表。

    然后进入正题:自定义View实现右侧索引导航栏IndexBar,对数据源的排序字段按照拼音排序,最后将RecyclerView和IndexBar联动起来,触摸IndexBar上相应字母,RecyclerView滚动到相应位置。(在屏幕中间显示的其实就是...

    Android字母排序 类似通讯录字母检索.zip

    通讯录应用通常会按照联系人姓名的首字母进行分组,用户可以通过点击屏幕右侧的字母栏快速跳转到对应的字母部分。这种设计被称为“快速索引”或“字母滚动条”。 在Android中,实现这一功能主要涉及以下知识点: 1...

    Android仿微信联系人按字母排序

    创建一个比较器类,重写`compare()`方法,比较两个对象(通常是联系人实体类)的首字母拼音对应的ASCII值。如果首字母是字母,则根据ASCII值排序;如果不是字母,将其排在字母之后。这样,整个列表就会按照拼音的首...

    仿联系人列表 A-Z字母显示 过滤

    在这个案例中,我们需要创建一个自定义的ListView或RecyclerView,以显示联系人列表,并在右侧添加一个A-Z的字母导航栏。这可以通过继承这些视图并重写相关方法来实现,例如`onDraw()`来绘制额外的字母导航栏。 2. ...

    类似于联系人列表的那种选择国家和地区

    标题“类似于联系人列表的那种选择国家和地区”所描述的就是这样一个界面,它具有字母索引功能,用户可以通过点击右侧的字母快速定位到所需国家或地区。 首先,我们需要创建一个数据结构来存储国家和地区的相关信息...

    通信录联系人拼音侧边栏

    它通常出现在通讯录界面的右侧,显示A到Z的字母,用户只需点击相应字母,就能跳转到该字母开头的联系人列表。这一功能对于拥有大量联系人的用户来说非常实用,因为它极大地减少了手动滑动屏幕寻找特定联系人的时间。...

    Android仿微信通讯录列表侧边栏效果

    列表根据首字符的拼音字母来排序,且可以通过侧边栏的字母索引来进行定位。 实现这样一个效果并不难,只要自定义一个索引View,然后引入一个可以对汉字进行拼音解析的jar包——pinyin4j-2.5.0即可 首先,先来定义侧...

    城市列表显示

    本项目旨在实现一个功能完善的Android城市列表,该列表按照字母顺序排列,并且右侧带有字母索引,点击字母可快速跳转至相应字母开头的城市。以下是关于这个功能的详细实现步骤和涉及的关键知识点。 首先,我们需要...

    Android实现ListView的A-Z字母排序和过滤搜索功能 实现汉字转成拼音

    接着,我们创建`SideBar`类,这是一个自定义的View,用于在ListView右侧显示字母索引。`SideBar`包含一个触摸监听器接口`OnTouchingLetterChangedListener`,当用户点击字母时,会触发回调方法`...

Global site tag (gtag.js) - Google Analytics