2016-04-14 17:05:27 u011622479 阅读数 7134
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4841 人正在学习 去看看 Frank Lee

资源:点击打开链接

android 获取手机通讯录联系人,模拟通讯录显示
最近做项目,恰好有这样的需求;在网上搜搜,找到了许多相关的文章,但是多多少少有一些出入。现在整理一下,做个总结;有疑问可以@我!主要是获取手机通讯录,模拟手机通讯录的搜索、字母排序显示;
思路:
获取手机通讯录信息,对联系人名称进行处理,获取拼音、大写字母    
详情可以参考:http://blog.csdn.net/csh159/article/details/8955029/
直接上代码
</pre><pre name="code" class="java"><pre name="code" class="java">package com.example.sortlistview;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts.Photo;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.example.sortlistview.SideBar.OnTouchingLetterChangedListener;

public class MainActivity extends Activity {
	private ListView sortListView;
	private SideBar sideBar;
	private TextView dialog;
	private SortAdapter adapter;
	private ClearEditText mClearEditText;
	
	/**
	 * 汉字转换成拼音的类
	 */
	private CharacterParser characterParser;
	private List<SortModel> SourceDateList;
	
	/**
	 * 根据拼音来排列ListView里面的数据类
	 */
	private PinyinComparator pinyinComparator;
	/** 联系人显示名称 **/
	private static final int PHONES_DISPLAY_NAME_INDEX = 0;
	/** 电话号码 **/
	private static final int PHONES_NUMBER_INDEX = 1;
	/** 头像ID **/
	// private static final int PHONES_PHOTO_ID_INDEX = 2;
	/** 联系人的ID **/
	// private static final int PHONES_CONTACT_ID_INDEX = 3;

	/** 库 phone表字段 **/
	private static final String[] PHONES_PROJECTION = new String[] {
			Phone.DISPLAY_NAME, Phone.NUMBER, Photo.PHOTO_ID, Phone.CONTACT_ID };
	
	

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initViews();
	}

	private void initViews() {
		//实例化汉字转拼音类
		characterParser = CharacterParser.getInstance();
		
		pinyinComparator = new PinyinComparator();
		
		sideBar = (SideBar) findViewById(R.id.sidrbar);
		dialog = (TextView) findViewById(R.id.dialog);
		sideBar.setTextView(dialog);
		
		//设置右侧触摸监听
		sideBar.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {
			
			@Override
			public void onTouchingLetterChanged(String s) {
				//该字母首次出现的位置
				int position = adapter.getPositionForSection(s.charAt(0));
				if(position != -1){
					sortListView.setSelection(position);
				}
				
			}
		});
		
		sortListView = (ListView) findViewById(R.id.country_lvcountry);
		sortListView.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> parent, View view,
					int position, long id) {
				//这里要利用adapter.getItem(position)来获取当前position所对应的对象
				Toast.makeText(getApplication(), ((SortModel)adapter.getItem(position)).getName(), Toast.LENGTH_SHORT).show();
			}
		});
		
		SourceDateList = loadPhoneContactData();
		
		// 根据a-z进行排序源数据
		Collections.sort(SourceDateList, pinyinComparator);
		adapter = new SortAdapter(this, SourceDateList);
		sortListView.setAdapter(adapter);
		
		
		mClearEditText = (ClearEditText) findViewById(R.id.filter_edit);
		
		//根据输入框输入值的改变来过滤搜索
		mClearEditText.addTextChangedListener(new TextWatcher() {
			
			@Override
			public void onTextChanged(CharSequence s, int start, int before, int count) {
				//当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
				filterData(s.toString());
			}
			
			@Override
			public void beforeTextChanged(CharSequence s, int start, int count,
					int after) {
				
			}
			
			@Override
			public void afterTextChanged(Editable s) {
			}
		});
	}

	
	/**
	 * 加载手机联系人
	 */
	private List<SortModel>  loadPhoneContactData() {

		List<SortModel> mSortList = new ArrayList<SortModel>();
		
		ContentResolver resolver = this.getContentResolver();
		Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
				PHONES_PROJECTION, null, null, null);

		SortModel sort = null;

		String phoneNumber = "";

		String phoneName = "";

		// Long photoID = 0l;

		if (phoneCursor != null) {

			while (phoneCursor.moveToNext()) {

				// get phone number
				phoneNumber = phoneCursor.getString(PHONES_NUMBER_INDEX)
						.replace(" ", "");

				if (phoneNumber==null||phoneNumber=="")
					continue;

				phoneName = phoneCursor.getString(PHONES_DISPLAY_NAME_INDEX);

				sort = new SortModel();
				sort.setMobile(phoneNumber);
				sort.setName(phoneName);

				// 汉字转换成拼音
				String pinyin = characterParser.getSelling(phoneName);
				String sortString = pinyin.substring(0, 1).toUpperCase();
				sort.setSortLetters(sortString);

				// 正则表达式,判断首字母是否是英文字母
				if (sortString.matches("[A-Z]")) {
					sort.setSortLetters(sortString.toUpperCase());
				} else {
					sort.setSortLetters("#");
				}

				mSortList.add(sort);
			}

			phoneCursor.close();

		}
		
		return mSortList;

	}
	
	/**
	 * 根据输入框中的值来过滤数据并更新ListView
	 * @param filterStr
	 */
	private void filterData(String filterStr){
		List<SortModel> filterDateList = new ArrayList<SortModel>();
		
		if(TextUtils.isEmpty(filterStr)){
			filterDateList = SourceDateList;
		}else{
			filterDateList.clear();
			for(SortModel sortModel : SourceDateList){
				String name = sortModel.getName();
				if(name.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())){
					filterDateList.add(sortModel);
				}
			}
		}
		
		// 根据a-z进行排序
		Collections.sort(filterDateList, pinyinComparator);
		adapter.updateListView(filterDateList);
	}
	
}

汉字转换为拼音,使用pinyin4j-2.5.0.jar库;之前使用的CharacterParser工具库是有bug的,例如“斐”是解析不出来的;

package com.example.sortlistview;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;

public class ChineseToEnglish {
	 // 将汉字转换为全拼  
    public static String getPingYin(String src) {  
  
        char[] t1 = null;  
        t1 = src.toCharArray();  
        String[] t2 = new String[t1.length];  
        HanyuPinyinOutputFormat t3 = new HanyuPinyinOutputFormat();  
          
        t3.setCaseType(HanyuPinyinCaseType.LOWERCASE);  
        t3.setToneType(HanyuPinyinToneType.WITHOUT_TONE);  
        t3.setVCharType(HanyuPinyinVCharType.WITH_V);  
        String t4 = "";  
        int t0 = t1.length;  
        try {  
            for (int i = 0; i < t0; i++) {  
                // 判断是否为汉字字符  
                if (java.lang.Character.toString(t1[i]).matches(  
                        "[\\u4E00-\\u9FA5]+")) {  
                    t2 = PinyinHelper.toHanyuPinyinStringArray(t1[i], t3);  
                    t4 += t2[0];  
                } else  
                    t4 += java.lang.Character.toString(t1[i]);  
            }  
            // System.out.println(t4);  
            return t4;  
        } catch (BadHanyuPinyinOutputFormatCombination e1) {  
            e1.printStackTrace();  
        }  
        return t4;  
    }  
  
    // 返回中文的首字母  
    public static String getPinYinHeadChar(String str) {  
  
        String convert = "";  
        for (int j = 0; j < str.length(); j++) {  
            char word = str.charAt(j);  
            String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);  
            if (pinyinArray != null) {  
                convert += pinyinArray[0].charAt(0);  
            } else {  
                convert += word;  
            }  
        }  
        return convert;  
    }  
  
    // 将字符串转移为ASCII码  
    public static String getCnASCII(String cnStr) {  
        StringBuffer strBuf = new StringBuffer();  
        byte[] bGBK = cnStr.getBytes();  
        for (int i = 0; i < bGBK.length; i++) {  
            strBuf.append(Integer.toHexString(bGBK[i] & 0xff));  
        }  
        return strBuf.toString();  
    }  
}

搜索框 ClearEditText

package com.example.sortlistview;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnFocusChangeListener;
import android.view.animation.Animation;
import android.view.animation.CycleInterpolator;
import android.view.animation.TranslateAnimation;
import android.widget.EditText;

public class ClearEditText extends EditText implements  
        OnFocusChangeListener, TextWatcher { 
	/**
	 * 删除按钮的引用
	 */
    private Drawable mClearDrawable; 
 
    public ClearEditText(Context context) { 
    	this(context, null); 
    } 
 
    public ClearEditText(Context context, AttributeSet attrs) { 
    	//这里构造方法也很重要,不加这个很多属性不能再XML里面定义
    	this(context, attrs, android.R.attr.editTextStyle); 
    } 
    
    public ClearEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }
    
    
    private void init() { 
    	//获取EditText的DrawableRight,假如没有设置我们就使用默认的图片
    	mClearDrawable = getCompoundDrawables()[2]; 
        if (mClearDrawable == null) { 
        	mClearDrawable = getResources() 
                    .getDrawable(R.drawable.emotionstore_progresscancelbtn); 
        } 
        mClearDrawable.setBounds(0, 0, mClearDrawable.getIntrinsicWidth(), mClearDrawable.getIntrinsicHeight()); 
        setClearIconVisible(false); 
        setOnFocusChangeListener(this); 
        addTextChangedListener(this); 
    } 
 
 
    /**
     * 因为我们不能直接给EditText设置点击事件,所以我们用记住我们按下的位置来模拟点击事件
     * 当我们按下的位置 在  EditText的宽度 - 图标到控件右边的间距 - 图标的宽度  和
     * EditText的宽度 - 图标到控件右边的间距之间我们就算点击了图标,竖直方向没有考虑
     */
    @Override 
    public boolean onTouchEvent(MotionEvent event) { 
        if (getCompoundDrawables()[2] != null) { 
            if (event.getAction() == MotionEvent.ACTION_UP) { 
            	boolean touchable = event.getX() > (getWidth() 
                        - getPaddingRight() - mClearDrawable.getIntrinsicWidth()) 
                        && (event.getX() < ((getWidth() - getPaddingRight())));
                if (touchable) { 
                    this.setText(""); 
                } 
            } 
        } 
 
        return super.onTouchEvent(event); 
    } 
 
    /**
     * 当ClearEditText焦点发生变化的时候,判断里面字符串长度设置清除图标的显示与隐藏
     */
    @Override 
    public void onFocusChange(View v, boolean hasFocus) { 
        if (hasFocus) { 
            setClearIconVisible(getText().length() > 0); 
        } else { 
            setClearIconVisible(false); 
        } 
    } 
 
 
    /**
     * 设置清除图标的显示与隐藏,调用setCompoundDrawables为EditText绘制上去
     * @param visible
     */
    protected void setClearIconVisible(boolean visible) { 
        Drawable right = visible ? mClearDrawable : null; 
        setCompoundDrawables(getCompoundDrawables()[0], 
                getCompoundDrawables()[1], right, getCompoundDrawables()[3]); 
    } 
     
    
    /**
     * 当输入框里面内容发生变化的时候回调的方法
     */
    @Override 
    public void onTextChanged(CharSequence s, int start, int count, 
            int after) { 
        setClearIconVisible(s.length() > 0); 
    } 
 
    @Override 
    public void beforeTextChanged(CharSequence s, int start, int count, 
            int after) { 
         
    } 
 
    @Override 
    public void afterTextChanged(Editable s) { 
         
    } 
    
   
    /**
     * 设置晃动动画
     */
    public void setShakeAnimation(){
    	this.setAnimation(shakeAnimation(5));
    }
    
    
    /**
     * 晃动动画
     * @param counts 1秒钟晃动多少下
     * @return
     */
    public static Animation shakeAnimation(int counts){
    	Animation translateAnimation = new TranslateAnimation(0, 10, 0, 0);
    	translateAnimation.setInterpolator(new CycleInterpolator(counts));
    	translateAnimation.setDuration(1000);
    	return translateAnimation;
    }
 
 
}


右侧字母侧边框 sideBar

package com.example.sortlistview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.graphics.drawable.ColorDrawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;

public class SideBar extends View {
	// 触摸事件
	private OnTouchingLetterChangedListener onTouchingLetterChangedListener;
	// 26个字母
	public static String[] b = { "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 int choose = -1;// 选中
	private Paint paint = new Paint();

	private TextView mTextDialog;

	public void setTextView(TextView mTextDialog) {
		this.mTextDialog = mTextDialog;
	}


	public SideBar(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
	}

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

	public SideBar(Context context) {
		super(context);
	}

	/**
	 * 重写这个方法
	 */
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 获取焦点改变背景颜色.
		int height = getHeight();// 获取对应高度
		int width = getWidth(); // 获取对应宽度
		int singleHeight = height / b.length;// 获取每一个字母的高度
		canvas.drawColor(Color.argb(0,0,0,0));
		
		for (int i = 0; i < b.length; i++) {
			paint.setColor(Color.rgb(33, 65, 98));
			paint.setTypeface(Typeface.DEFAULT_BOLD);
			paint.setAntiAlias(true);
			paint.setTextSize(20);
			// 选中的状态
			if (i == choose) {
				paint.setColor(Color.parseColor("#3399ff"));
				paint.setFakeBoldText(true);
			}
			// x坐标等于中间-字符串宽度的一半.
			float xPos = width / 2 - paint.measureText(b[i]) / 2;
			float yPos = singleHeight * i + singleHeight;
			canvas.drawText(b[i], xPos, yPos, paint);
			paint.reset();// 重置画笔
		}

	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		final int action = event.getAction();
		final float y = event.getY();// 点击y坐标
		final int oldChoose = choose;
		final OnTouchingLetterChangedListener listener = onTouchingLetterChangedListener;
		final int c = (int) (y / getHeight() * b.length);// 点击y坐标所占总高度的比例*b数组的长度就等于点击b中的个数.

		switch (action) {
		case MotionEvent.ACTION_UP:
			setBackgroundDrawable(new ColorDrawable(0x00000000));
//			choose = -1;
//			invalidate();
			if (mTextDialog != null) {
				mTextDialog.setVisibility(View.INVISIBLE);
			}
			break;

		default:
			setBackgroundDrawable(new ColorDrawable(0x00000000));
			if (oldChoose != c) {
				if (c >= 0 && c < b.length) {
					if (listener != null) {
						listener.onTouchingLetterChanged(b[c]);
					}
					if (mTextDialog != null) {
						mTextDialog.setText(b[c]);
						mTextDialog.setVisibility(View.VISIBLE);
					}
					
					choose = c;
					invalidate();
				}
			}

			break;
		}
		return true;
	}

	/**
	 * 向外公开的方法
	 * 
	 * @param onTouchingLetterChangedListener
	 */
	public void setOnTouchingLetterChangedListener(
			OnTouchingLetterChangedListener onTouchingLetterChangedListener) {
		this.onTouchingLetterChangedListener = onTouchingLetterChangedListener;
	}

	/**
	 * 接口
	 * 
	 * @author coder
	 * 
	 */
	public interface OnTouchingLetterChangedListener {
		public void onTouchingLetterChanged(String s);
	}

}

 联系人没有首字母特殊处理  PinyinComparator

package com.example.sortlistview;

import java.util.Comparator;

/**
 * 联系人没有首字母特殊处理
 * @author Administrator
 *
 */
public class PinyinComparator implements Comparator<SortModel> {

	public int compare(SortModel o1, SortModel o2) {
		if (o1.getSortLetters().equals("@")
				|| o2.getSortLetters().equals("#")) {
			return -1;
		} else if (o1.getSortLetters().equals("#")
				|| o2.getSortLetters().equals("@")) {
			return 1;
		} else {
			return o1.getSortLetters().compareTo(o2.getSortLetters());
		}
	}

}

联系人对象 SortModel

package com.example.sortlistview;


public class SortModel {


private String name;   //显示的数据
private String mobile;
private String sortLetters;  //显示数据拼音的首字母

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSortLetters() {
return sortLetters;
}
public void setSortLetters(String sortLetters) {
this.sortLetters = sortLetters;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}

}



数据显示格式定义类 SortAdapter 


package com.example.sortlistview;


import java.util.List;


import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.SectionIndexer;
import android.widget.TextView;


public class SortAdapter extends BaseAdapter implements SectionIndexer{
private List<SortModel> list = null;
private Context mContext;

public SortAdapter(Context mContext, List<SortModel> list) {
this.mContext = mContext;
this.list = list;
}

/**
* 当ListView数据发生变化时,调用此方法来更新ListView
* @param list
*/
public void updateListView(List<SortModel> list){
this.list = list;
notifyDataSetChanged();
}


public int getCount() {
return this.list.size();
}


public Object getItem(int position) {
return list.get(position);
}


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


public View getView(final int position, View view, ViewGroup arg2) {
ViewHolder viewHolder = null;
final SortModel mContent = list.get(position);
if (view == null) {
viewHolder = new ViewHolder();
view = LayoutInflater.from(mContext).inflate(R.layout.item, null);
viewHolder.tvTitle = (TextView) view.findViewById(R.id.title);
viewHolder.tvLetter = (TextView) view.findViewById(R.id.catalog);
viewHolder.tvPhone = (TextView) view.findViewById(R.id.phone);
view.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) view.getTag();
}

//根据position获取分类的首字母的Char ascii值
int section = getSectionForPosition(position);

//如果当前位置等于该分类首字母的Char的位置 ,则认为是第一次出现
if(position == getPositionForSection(section)){
viewHolder.tvLetter.setVisibility(View.VISIBLE);
viewHolder.tvLetter.setText(mContent.getSortLetters());
}else{
viewHolder.tvLetter.setVisibility(View.GONE);
}

SortModel sort = this.list.get(position);

viewHolder.tvTitle.setText(sort.getName());
viewHolder.tvPhone.setText(sort.getMobile());

return view;


}





final static class ViewHolder {
TextView tvLetter;
TextView tvTitle;
TextView tvPhone;
}




/**
* 根据ListView的当前位置获取分类的首字母的Char ascii值
*/
public int getSectionForPosition(int position) {
return list.get(position).getSortLetters().charAt(0);
}


/**
* 根据分类的首字母的Char ascii值获取其第一次出现该首字母的位置
*/
public int getPositionForSection(int section) {
for (int i = 0; i < getCount(); i++) {
String sortStr = list.get(i).getSortLetters();
char firstChar = sortStr.toUpperCase().charAt(0);
if (firstChar == section) {
return i;
}
}

return -1;
}

/**
* 提取英文的首字母,非英文字母用#代替。
* 
* @param str
* @return
*/
private String getAlpha(String str) {
String  sortStr = str.trim().substring(0, 1).toUpperCase();
// 正则表达式,判断首字母是否是英文字母
if (sortStr.matches("[A-Z]")) {
return sortStr;
} else {
return "#";
}
}


@Override
public Object[] getSections() {
return null;
}
}


主页activity布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >


    <com.example.sortlistview.ClearEditText
        android:id="@+id/filter_edit"
        android:layout_marginTop="5dip"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:background="@drawable/search_bar_edit_selector"
        android:drawableLeft="@drawable/search_bar_icon_normal"
        android:hint="请输入关键字"
        android:singleLine="true"
        android:textSize="15.0dip" />


    <FrameLayout
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >


        <ListView
            android:id="@+id/country_lvcountry"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:layout_gravity="center"
            android:divider="@null" />


        <TextView
            android:id="@+id/dialog"
            android:layout_width="80.0dip"
            android:layout_height="80.0dip"
            android:layout_gravity="center"
            android:background="@drawable/show_head_toast_bg"
            android:gravity="center"
            android:textColor="#ffffffff"
            android:textSize="30.0dip"
            android:visibility="invisible" />


        <com.example.sortlistview.SideBar
            android:id="@+id/sidrbar"
            android:layout_width="30.0dip"
            android:layout_height="fill_parent"
            android:layout_gravity="right|center" />
    </FrameLayout>


</LinearLayout>


数据显示item 布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center_vertical"
    android:orientation="vertical" >


    <TextView
        android:id="@+id/catalog"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#E0E0E0"
        android:textColor="#454545"
        android:layout_weight="1.0"
        android:paddingLeft="5dip"
        android:paddingTop="5dip"
        android:paddingBottom="5dip"
        android:text="A"/>


    <LinearLayout
        android:id="@+id/contachInfo"
    android:layout_width="fill_parent"
    android:layout_height="50dip"
    android:gravity="center_vertical"
    android:orientation="horizontal" >


        <ImageView
            android:id="@+id/imgHead"
            android:layout_width="40dip"
            android:layout_height="40dip"
            android:src="@drawable/default_avatar"
            android:paddingLeft="5dip" />
    
        <LinearLayout
        android:id="@+id/phoneLayout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_vertical"
    android:orientation="vertical"
    android:paddingLeft="5dip"
    android:layout_marginLeft="5dip" >
        
    <TextView
        android:id="@+id/title"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center_vertical"
        android:gravity="bottom"
        android:layout_weight="1.0"
        android:textColor="#000000"
        android:textSize="12sp"
        android:text="hhhh"/>
    
      <TextView
        android:id="@+id/phone"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_gravity="center_vertical"
        android:gravity="center_vertical"
        android:layout_weight="1.0"
        android:textColor="#000000"
        android:textSize="12sp"
        android:text="电话号码"/>
    </LinearLayout>
    </LinearLayout>


</LinearLayout>


活动窗口:

package com.example.sortlistview;


import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts.Photo;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;


import com.example.sortlistview.SideBar.OnTouchingLetterChangedListener;


public class MainActivity extends Activity {
private ListView sortListView;
private SideBar sideBar;
private TextView dialog;
private SortAdapter adapter;
private ClearEditText mClearEditText;

/**
* 汉字转换成拼音的类
*/
private CharacterParser characterParser;
private List<SortModel> SourceDateList;

/**
* 根据拼音来排列ListView里面的数据类
*/
private PinyinComparator pinyinComparator;
/** 联系人显示名称 **/
private static final int PHONES_DISPLAY_NAME_INDEX = 0;
/** 电话号码 **/
private static final int PHONES_NUMBER_INDEX = 1;
/** 头像ID **/
// private static final int PHONES_PHOTO_ID_INDEX = 2;
/** 联系人的ID **/
// private static final int PHONES_CONTACT_ID_INDEX = 3;


/** 库 phone表字段 **/
private static final String[] PHONES_PROJECTION = new String[] {
Phone.DISPLAY_NAME, Phone.NUMBER, Photo.PHOTO_ID, Phone.CONTACT_ID };




@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}


private void initViews() {
//实例化汉字转拼音类
characterParser = CharacterParser.getInstance();

pinyinComparator = new PinyinComparator();

sideBar = (SideBar) findViewById(R.id.sidrbar);
dialog = (TextView) findViewById(R.id.dialog);
sideBar.setTextView(dialog);

//设置右侧触摸监听
sideBar.setOnTouchingLetterChangedListener(new OnTouchingLetterChangedListener() {

@Override
public void onTouchingLetterChanged(String s) {
//该字母首次出现的位置
int position = adapter.getPositionForSection(s.charAt(0));
if(position != -1){
sortListView.setSelection(position);
}

}
});

sortListView = (ListView) findViewById(R.id.country_lvcountry);
sortListView.setOnItemClickListener(new OnItemClickListener() {


@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {
//这里要利用adapter.getItem(position)来获取当前position所对应的对象
Toast.makeText(getApplication(), ((SortModel)adapter.getItem(position)).getName(), Toast.LENGTH_SHORT).show();
}
});

SourceDateList = loadPhoneContactData();

// 根据a-z进行排序源数据
Collections.sort(SourceDateList, pinyinComparator);
adapter = new SortAdapter(this, SourceDateList);
sortListView.setAdapter(adapter);


mClearEditText = (ClearEditText) findViewById(R.id.filter_edit);

//根据输入框输入值的改变来过滤搜索
mClearEditText.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
//当输入框里面的值为空,更新为原来的列表,否则为过滤数据列表
filterData(s.toString());
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count,
int after) {

}

@Override
public void afterTextChanged(Editable s) {
}
});
}



/**
* 加载手机联系人
*/
private List<SortModel>  loadPhoneContactData() {


List<SortModel> mSortList = new ArrayList<SortModel>();

ContentResolver resolver = this.getContentResolver();
Cursor phoneCursor = resolver.query(Phone.CONTENT_URI,
PHONES_PROJECTION, null, null, null);


SortModel sort = null;


String phoneNumber = "";


String phoneName = "";


// Long photoID = 0l;


if (phoneCursor != null) {


while (phoneCursor.moveToNext()) {


// get phone number
phoneNumber = phoneCursor.getString(PHONES_NUMBER_INDEX)
.replace(" ", "");


if (phoneNumber==null||phoneNumber=="")
continue;


phoneName = phoneCursor.getString(PHONES_DISPLAY_NAME_INDEX);


sort = new SortModel();
sort.setMobile(phoneNumber);
sort.setName(phoneName);


// 汉字转换成拼音
String pinyin = characterParser.getSelling(phoneName);
String sortString = pinyin.substring(0, 1).toUpperCase();
sort.setSortLetters(sortString);


// 正则表达式,判断首字母是否是英文字母
if (sortString.matches("[A-Z]")) {
sort.setSortLetters(sortString.toUpperCase());
} else {
sort.setSortLetters("#");
}


mSortList.add(sort);
}


phoneCursor.close();


}

return mSortList;


}

/**
* 根据输入框中的值来过滤数据并更新ListView
* @param filterStr
*/
private void filterData(String filterStr){
List<SortModel> filterDateList = new ArrayList<SortModel>();

if(TextUtils.isEmpty(filterStr)){
filterDateList = SourceDateList;
}else{
filterDateList.clear();
for(SortModel sortModel : SourceDateList){
String name = sortModel.getName();
if(name.indexOf(filterStr.toString()) != -1 || characterParser.getSelling(name).startsWith(filterStr.toString())){
filterDateList.add(sortModel);
}
}
}

// 根据a-z进行排序
Collections.sort(filterDateList, pinyinComparator);
adapter.updateListView(filterDateList);
}

}


AndroidManifest.xml文件,说明一下,获取手机通讯录,必须添加通讯录访问权限;即 

 <uses-permission android:name="android.permission.READ_CONTACTS" />

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.sortlistview"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="23" />
    
    <uses-permission android:name="android.permission.READ_CONTACTS" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.example.sortlistview.MainActivity"
            android:windowSoftInputMode = "adjustPan"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>



运行效果图:

 

2016-08-06 00:39:48 linxi7 阅读数 1533
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4841 人正在学习 去看看 Frank Lee

最近在练习自定义view,找了一些资料,模仿了一下微信通讯录的实现效果,首先看一下效果图:
这里写图片描述

记录下来当做笔记以备后用。
第一步:是绘制26个字母的view:
在每个构造方法中调用下面的init()方法实现画笔的初始化

private void init() {
        //去掉字母锯齿的参数
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(Color.WHITE);
        // mPaint.setTypeface(Typeface.DEFAULT_BOLD);
        mPaint.setTextSize(40);//设置字母大小
    }

然后是onDraw()方法进行绘制:

@Override
    protected void onDraw(Canvas canvas) {
        //这里用来绘制背景,当字母被触摸的时候会变成灰色
        if (mTouched) {
            canvas.drawColor(0x30000000);
        }

        for (int i = 0; i < letterLength; i++) {
            String text = LETTERS[i];
            // 计算坐标
            int x = (int) (cellWidth / 2.0f - mPaint.measureText(text) / 2.0f);
            // 获取文本的高度
            Rect bounds = new Rect();// 矩形
            mPaint.getTextBounds(text, 0, text.length(), bounds);
            int textHeight = bounds.height();
            int y = (int) (cellHeight / 2.0f + textHeight / 2.0f + i* cellHeight);

            // 设置文本颜色
            mPaint.setColor(Color.BLACK);


            // 绘制文本A-Z
            canvas.drawText(text, x, y, mPaint);
        }
    }

根据注释可以清楚的知道绘制的原理,就是计算26个字母的x和y坐标,x左边不变的,y坐标规律的增加。

接下来重写onTouchEvent()方法

boolean mTouched = false;
int touchIndex = -1;

    @Override
public boolean onTouchEvent(MotionEvent event) {
        int index = -1;
        switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            // 获取当前触摸到的字母索引
            index = (int) (event.getY() / cellHeight);
            if (index >= 0 && index < LETTERS.length) {
                // 判断是否跟上一次触摸到的一样
            if (index != touchIndex) {

                if (listener != null) {
                                    listener.onLetterUpdate(LETTERS[index]);
                    }

                    touchIndex = index;
                }
            }
            mTouched = true;
            break;
        case MotionEvent.ACTION_UP:
            if (listener != null) {
                listener.onFinished();
            }
            touchIndex = -1;
            mTouched = false;
            break;

        default:
            break;
        }
        invalidate();

        return true;
    }

原理就是根据两个索引值,即当前按下字母的索引是否和上次的一样,如果不一样才会调用接口把字母暴露给调用方,否则如果不进行判断的话,就会导致当手指在快速索引条上移动的时候总是会弹出相同的字母。还有就是记录了一个按下的mTouched值,如果按下或者移动设置为true,否则为false。这样就可以根据是否按下来绘制背景改变颜色了。再看一下ACTION_UP事件中暴露onFinished()方法给调用方,主要是为了将弹出的字母隐藏掉。这样当手指按下的时候会弹出当前的字母,当手指抬起就会立即消失。

当view的大小发生变化时获取单元格的宽和高

@Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        // 获取单元格的宽和高

        cellWidth = getMeasuredWidth();

        int mHeight = getMeasuredHeight();
        cellHeight = mHeight * 1.0f / LETTERS.length;

    }

接下来就是回调接口:

    /**
     * 暴露一个字母的监听
     */
    public interface OnLetterUpdateListener {
        void onLetterUpdate(String letter);

        void onFinished();
    }

    private OnLetterUpdateListener listener;

    /**
     * 设置字母更新监听
     * 
     * @param listener
     */
    public void setListener(OnLetterUpdateListener listener) {
        this.listener = listener;
    }

以上就是快速索引条的绘制过程。

接下来看一下MainActivity.java的主要代码:

// 设置监听
bar.setListener(new OnLetterUpdateListener() {
            @Override
    public void onLetterUpdate(String letter) {
        showLetter(letter);
        // 根据字母定位ListView, 找到集合中第一个以letter为拼音首字母的对象,得到索引
        for (int i = 0; i < persons.size(); i++) {
            Person person = persons.get(i);
            String l = person.getPinyin().charAt(0) + "";
            if (TextUtils.equals(letter, l)) {
                // 匹配成功
                mMainList.setSelection(i);
                break;
            }
        }
    }

    @Override
    public void onFinished() {
        tv_center.setVisibility(View.GONE);
    }
});

这就是实现回调方法,弹出显示字母框和隐藏字母的功能。
还有一个就是对ListView中联系人拼音的第一个字母和手指此刻按下的字母进行比较,如果相等的话,就会将ListView位置定位到这个字母,也就是把该字母显示在第一个位置。

这个是显示字母的代码:

/**
* 显示字母
*/
protected void showLetter(String letter) {
    tv_center.setVisibility(View.VISIBLE);
    tv_center.setText(letter);
}

这个是对通讯录进行排序的方法:

private void fillAndSortData(ArrayList<Person> persons) {
    List<String> nameList = PhoneContactsUtils.getContactsName(this);
    // 填充数据
    for (int i = 0; i < nameList.size(); i++) {
        String name = nameList.get(i);
        persons.add(new Person(name));
    }

    // 进行排序
    Collections.sort(persons);
    }

以上就是主要的代码,还有工具类、实体类和适配器的代码没有贴出来,感觉太多了贴出来不方便阅读。实体类就是一个名字和拼音两个成员变量,并且要实现Comparable接口以便进行联系人根据字母排序。还有读取手机通讯录联系人等没什么好讲的,直接放到源码包中就好了。

源码下载地址:Android自定义view实现微信通讯录一模一样效果

2015-08-03 08:46:27 zhangphil 阅读数 5487
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4841 人正在学习 去看看 Frank Lee

本文给出了Android读取通讯录联系人的一般方法,且在读取Android通讯录联系人时候,将结果有序化(按照联系人姓名的首字符依次顺序读取:A ~ Z)。

读取的结果如图所示:


现给出实现该种Android通讯录读取的代码:

package zhangphil.contacts;

import java.util.ArrayList;

import android.app.ListActivity;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

public class MainActivity extends ListActivity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		ArrayList<Contact> contacts = new ArrayList<Contact>();
		readContacts(contacts);

		ListView listView = this.getListView();
		ArrayAdapter<Contact> adapter = new MyAdapter(this,
				android.R.layout.simple_list_item_2, contacts);
		listView.setAdapter(adapter);
	}

	private class MyAdapter extends ArrayAdapter<Contact> {

		private int resource;
		private LayoutInflater inflater = null;
		private ArrayList<Contact> contacts;

		public MyAdapter(Context context, int resource,
				ArrayList<Contact> contacts) {
			super(context, resource);
			this.resource = resource;
			this.contacts = contacts;

			inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {

			if (convertView == null)
				convertView = inflater.inflate(resource, null);

			Contact c = getItem(position);

			TextView text1 = (TextView) convertView
					.findViewById(android.R.id.text1);
			TextView text2 = (TextView) convertView
					.findViewById(android.R.id.text2);

			//首字符,分组的依据。
			text1.setText(c.firstLetterOfName());
			
			//详情。
			text2.setText(c.name + " " + c.getPhoneNumbers());

			return convertView;
		}

		@Override
		public Contact getItem(int pos) {
			return contacts.get(pos);
		}

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

	// 读取设备联系人的一般方法。大致流程就是这样,模板化的操作代码。
	private void readContacts(ArrayList<Contact> contacts) {
		Uri uri = Uri.parse("content://com.android.contacts/contacts");
		ContentResolver reslover = this.getContentResolver();

		// 在这里我们给query传递进去一个SORT_KEY_PRIMARY。
		// 告诉ContentResolver获得的结果安装联系人名字的首字母有序排列。
		Cursor cursor = reslover.query(uri, null, null, null,
				android.provider.ContactsContract.Contacts.SORT_KEY_PRIMARY);

		while (cursor.moveToNext()) {

			// 联系人ID
			String id = cursor
					.getString(cursor
							.getColumnIndex(android.provider.ContactsContract.Contacts._ID));

			// Sort Key,读取的联系人按照姓名从 A->Z 排序分组。
			String sort_key_primary = cursor
					.getString(cursor
							.getColumnIndex(android.provider.ContactsContract.Contacts.SORT_KEY_PRIMARY));

			// 获得联系人姓名
			String name = cursor
					.getString(cursor
							.getColumnIndex(android.provider.ContactsContract.Contacts.DISPLAY_NAME));

			Contact mContact = new Contact();
			mContact.id = id;
			mContact.name = name;
			mContact.sort_key_primary = sort_key_primary;

			// 获得联系人手机号码
			Cursor phone = reslover.query(
					ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
					ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "="
							+ id, null, null);

			// 取得电话号码(可能存在多个号码)
			// 因为同一个名字下,用户可能存有一个以上的号,
			// 遍历。
			ArrayList<String> phoneNumbers = new ArrayList<String>();
			while (phone.moveToNext()) {
				int phoneFieldColumnIndex = phone
						.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
				String phoneNumber = phone.getString(phoneFieldColumnIndex);
				phoneNumbers.add(phoneNumber);
			}

			mContact.phoneNumbers = phoneNumbers;

			contacts.add(mContact);
		}
	}

	// 用于装载从联系人数据库中读取到的数据。
	// 结构化数据,便于数据操作和访问。
	private class Contact {
		public String id;
		public String name;
		public String sort_key_primary;
		public ArrayList<String> phoneNumbers;
		
		//获得一个联系人名字的首字符。
		//比如一个人的名字叫“安卓”,那么这个人联系人的首字符是:A。
		public	String	firstLetterOfName(){
			String s=sort_key_primary.charAt(0)+"";
			return	s.toUpperCase();
		}

		public String getPhoneNumbers() {
			String phones = " ";
			for (int i = 0; i < phoneNumbers.size(); i++) {
				phones += "号码" + i + ":" + phoneNumbers.get(i);
			}

			return phones;
		}
	}
}


不要忘记在项目的AndroidManifest.xml文件中添加Android读写通讯录联系人的权限:

 <!-- 写权限 -->
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <!-- 读权限 -->
    <uses-permission android:name="android.permission.READ_CONTACTS" />



2016-09-14 11:08:46 duke_knight 阅读数 987
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4841 人正在学习 去看看 Frank Lee

      项目中经常会用到一些获取手机里通讯录的功能,这边对其进行了排序

	// 读取通讯录
	private void readMail() {
		mallBuffer.setLength(0);
		mallBuffer.append("[");
		// 获取手机联系人:最后一个筛选条件就是按时间排序,可以获得最新的
		Cursor cursor = getApplicationContext().getContentResolver().query(
				Phone.CONTENT_URI, null, null, null, Phone._ID + " desc");
				
				
		// moveToNext方法返回的是一个boolean类型的数据
		
				if (cursor.getCount() >= 50) {

					int i = 0;
					while (cursor.moveToNext()) {

						if (i != 0 && i % 50 == 0) {
						 //判断每50条上传一次
							mallString = mallBuffer.toString().substring(0,
									mallBuffer.length());
							mallString = mallString + "]";
							 sendPhoneInfo("1", mallString);
							mallBuffer.setLength(0);
							mallBuffer.append("[");

						} else if (i == cursor.getCount() - 1) {
							mallString = mallBuffer.toString().substring(0,
									mallBuffer.length());
							mallString = mallString + "]";
							Log.d("duke", "mallString------" + mallString);
							 sendPhoneInfo("1", mallString);
						}

						// 读取通讯录的姓名
						String name = cursor.getString(cursor
								.getColumnIndex(Phone.DISPLAY_NAME));
						// 读取通讯录的号码
						String number = cursor.getString(cursor
								.getColumnIndex(Phone.NUMBER));
						//将查询的每一条变成一个json对象
						JSONObject jbJsonObject = new JSONObject();

						try {
							jbJsonObject.put(name, number);
							
							//对json对象进行拼接成字符json的字符串
							mallBuffer.append(jbJsonObject + "
"); i++; } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } else { while (cursor.moveToNext()) { if (cursor.getCount() > 0) { // 读取通讯录的姓名 String name = cursor.getString(cursor .getColumnIndex(Phone.DISPLAY_NAME)); // 读取通讯录的号码 String number = cursor.getString(cursor .getColumnIndex(Phone.NUMBER)); Log.d("duke", "name=" + name + "number=" + number); JSONObject jbJsonObject = new JSONObject(); try { jbJsonObject.put(name, number); mallBuffer.append(jbJsonObject + "
"); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } mallString = mallBuffer.toString().substring(0, mallBuffer.length()); mallString = mallString + "]"; Log.d("duke", "mallString%%%%%%%%%%%%%%" + mallString); sendPhoneInfo("1", mallString); } }

2019-09-04 17:33:40 qq_30998053 阅读数 27
  • Android 开发 第三方SDK 百度定位SDK

    百度地图Android定位SDK是为Android移动端应用提供的一套简单易用的LBS定位服务接口,专注于为广大开发者提供好的综合定位服务,通过使用百度定位SDK,开发者可以轻松为应用程序实现智能、、高效的定位功能。 主要内容包括简介 密钥申请 环境配置、定位SDK使用,获取当前位置信息 等知识

    4841 人正在学习 去看看 Frank Lee

Android获取手机联系人、通讯录,重组a_z排序搜索;

下面是效果图:

github链接:https://github.com/764990722/GetPhone_Contacts

Android模仿通讯录

阅读数 527

没有更多推荐了,返回首页