自定义快速索引,仿微信好友查询列表
2015-12-31 13:53
465 查看
自定义视图,快速索引
先从自定义控件代码来看吧import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; /** * 自定义View 快速索引 * @author 李帅帅 * */ public class QuickIndexView extends View { public QuickIndexView(Context context, AttributeSet attrs) { super(context, attrs); paint = new Paint(); paint.setAntiAlias(true); } private float itemWidth;// item的宽度 private float itemHight;// item的高度 private String[] indexArr = { "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 Paint paint; /** * 测量 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); itemWidth = this.getWidth(); itemHight = this.getHeight() / 26f; } /** * 画图 */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < indexArr.length; i++) { if (i != index) {// 如果i不等于选中的item时 paint.setColor(Color.BLACK); paint.setTextSize(16); } else { paint.setColor(Color.RED);// 当前操作的字母 paint.setTextSize(25); } String word = indexArr[i]; // 得到word的宽高 Rect bounds = new Rect(); paint.getTextBounds(word, 0, word.length(), bounds); int wordWidth = bounds.width(); int wordHight = bounds.height(); // 定义左下角的坐标 float x = itemWidth / 2 - wordWidth / 2; float y = itemHight / 2 + wordHight / 2 + i * itemHight; // 画出文本 canvas.drawText(word, x, y, paint); } } private int index = -1;// 操作的字母下标 @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN:// 按下 case MotionEvent.ACTION_MOVE:// 移动 float eventY = event.getY(); int eventindex = (int) (eventY / itemHight); if (index != eventindex) {// 如果操作的index变化了 // 强制更新 invalidate(); index = eventindex; // 通知activity更新textView if (onIndexChangeListener != null) { if(index<26&&index>0){ onIndexChangeListener.OnIndexChanged(indexArr[index]); } } } break; case MotionEvent.ACTION_UP: index = -1; invalidate(); //当离开的时候 if (onIndexChangeListener != null) { // onIndexChangeListener.OnUp(); } break; default: break; } return true;// 消费 } /** * 定义一个接口 * * @author 李帅帅 */ private OnIndexChangeListener onIndexChangeListener; public interface OnIndexChangeListener { // 当操作的下标改变时,按下时调用 public void OnIndexChanged(String word); // //当离开时调用 // public void OnUp(); } public void setOnIndexChangeListener(OnIndexChangeListener onIndexChangeListener) { this.onIndexChangeListener = onIndexChangeListener; } }
第一步我们写一个类来继承View 然后在重写测量方法。再次方法中获得item的宽高
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); itemWidth = this.getWidth(); itemHight = this.getHeight() / 26f; }
第二步:就到我们从写绘制的方法了,在此方法中我们根据选中角标的位置来让绘制字母颜色,以及字母的宽高
private int index = -1;// 操作的字母下标 @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); for (int i = 0; i < indexA fc23 rr.length; i++) { if (i != index) {// 如果i不等于选中的item时 paint.setColor(Color.BLACK); paint.setTextSize(16); } else { paint.setColor(Color.RED);// 当前操作的字母 paint.setTextSize(25); } String word = indexArr[i]; // 得到word的宽高 Rect bounds = new Rect(); paint.getTextBounds(word, 0, word.length(), bounds); int wordWidth = bounds.width(); int wordHight = bounds.height(); // 定义左下角的坐标 float x = itemWidth / 2 - wordWidth / 2; float y = itemHight / 2 + wordHight / 2 + i * itemHight; // 画出文本 canvas.drawText(word, x, y, paint); } }
第三步: 也是最为重要的一步,就是onTouchEvent此方法了。在此方法中我们会判断down move up ,当我们按下和移动的时候动态的获得Y/itemheight ,这就是我们选中字母的坐标,如果选中的角标变化了,那么就调用这个invalidate();方法,让其强制重绘,当然在此方法中我们会写一个接口,供页面回调,也是参照源码监听来写的,up的时候也让其强制重绘,记得角标改成非法值.
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN:// 按下 case MotionEvent.ACTION_MOVE:// 移动 float eventY = event.getY(); int eventindex = (int) (eventY / itemHight); if (index != eventindex) {// 如果操作的index变化了 // 强制更新 invalidate(); index = eventindex; // 通知activity更新textView if (onIndexChangeListener != null) { if(index<26&&index>0){ onIndexChangeListener.OnIndexChanged(indexArr[index]); } } } break; case MotionEvent.ACTION_UP: index = -1; invalidate(); //当离开的时候 if (onIndexChangeListener != null) { // onIndexChangeListener.OnUp(); } break; default: break; } return true;// 消费 }
最后这个是我们写的接口
/** * 定义一个接口 * * @author 李帅帅 */ private OnIndexChangeListener onIndexChangeListener; public interface OnIndexChangeListener { // 当操作的下标改变时,按下时调用 public void OnIndexChanged(String word); // //当离开时调用 // public void OnUp(); } public void setOnIndexChangeListener(OnIndexChangeListener onIndexChangeListener) { this.onIndexChangeListener = onIndexChangeListener; }
MainActivity的代码附上
/** * 页面一 * * @author admin * */ public class OneFragment extends Fragment { private TextView mTextView; private QuickIndexView mQIV; private ListView mListView; private List<Friend> data = new ArrayList<Friend>(); private FriendAdapter adapter; private Context mContext; private Handler handler = new Handler() { public void handleMessage(android.os.Message msg) { // 隐藏自己 mTextView.setVisibility(View.GONE); } }; public OneFragment(FragmentActivity mContext) { this.mContext = mContext; } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_one, container, false); initData(); initViews(view); setListener(); return view; } /** * 初始化试图 */ private void initViews(View view) { // 初始化 mTextView = (TextView) view.findViewById(R.id.tv_main_word); mListView = (ListView) view.findViewById(R.id.lv_main); mQIV = (QuickIndexView) view.findViewById(R.id.qiv_main); // 显示列表 adapter = new FriendAdapter(mContext, data); mListView.setAdapter(adapter); } /** * 设置监听 */ private void setListener() { // 设置监听 mQIV.setOnIndexChangeListener(new QuickIndexView.OnIndexChangeListener() { @Override public void OnIndexChanged(String word) { mTextView.setText(word); mTextView.setVisibility(View.VISIBLE); // 移除未处理的消息 handler.removeCallbacksAndMessages(null); handler.sendEmptyMessageDelayed(1, 1000); // 遍历data for (int i = 0; i < data.size(); i++) { // 得到首字母 String firstPinYin = data.get(i).getPinyin().substring(0, 1); if (word.equals(firstPinYin)) { mListView.setSelection(i); return; } } } }); //设置点击监听 mListView.setOnItemClickListener(new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { Toast.makeText(mContext, data.get(arg2).getName(), 0).show(); } }); } /** * 准备数据 */ private void initData() { data.add(new Friend("张晓飞")); data.add(new Friend("杨光福")); data.add(new Friend("胡继群")); data.add(new Friend("刘畅")); data.add(new Friend("钟泽兴")); data.add(new Friend("尹革新")); data.add(new Friend("安传鑫")); data.add(new Friend("张骞壬")); data.add(new Friend("温松")); data.add(new Friend("李凤秋")); data.add(new Friend("刘甫")); data.add(new Friend("娄全超")); data.add(new Friend("张猛")); data.add(new Friend("王英杰")); data.add(new Friend("李振南")); data.add(new Friend("孙仁政")); data.add(new Friend("唐春雷")); data.add(new Friend("牛鹏伟")); data.add(new Friend("姜宇航")); data.add(new Friend("刘挺")); data.add(new Friend("张洪瑞")); data.add(new Friend("张建忠")); data.add(new Friend("侯亚帅")); data.add(new Friend("刘帅")); data.add(new Friend("乔竞飞")); data.add(new Friend("徐雨健")); data.add(new Friend("吴亮")); data.add(new Friend("王兆霖")); data.add(new Friend("阿三")); Collections.sort(data); } }
注意:我这里是接着上一篇架构的第一个OneFragment写的,如果是Activity页面,那么onCreateView就相当于onCreate方法,就是加载一个布局,然后其他类似.
fragment_one.Xml 代码,就是main_activity.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="${relativePackage}.${activityClass}" > <ListView android:id="@+id/lv_main" android:layout_width="match_parent" android:layout_height="match_parent" > </ListView> <com.example.fragmenttest.views.QuickIndexView android:id="@+id/qiv_main" android:layout_width="30dp" android:layout_height="match_parent" android:layout_alignParentRight="true" android:background="@android:color/transparent" /> <TextView android:id="@+id/tv_main_word" android:layout_width="100dp" android:layout_height="100dp" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:background="#66666666" android:text="A" android:textColor="#EADAA9" android:textSize="40sp" android:gravity="center" android:visibility="gone"/> </RelativeLayout>
FriendAdapter代码
import java.util.List; import com.example.fragmenttest.R; import com.example.fragmenttest.model.Friend; import android.content.Context; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; public class FriendAdapter extends BaseAdapter { private List<Friend> mDatas; private Context mContext; public FriendAdapter(Context mContext, List<Friend> data) { mDatas = data; this.mContext = mContext; } @Override public int getCount() { return mDatas.size(); } @Override public Object getItem(int position) { return mDatas.get(position); } @Override public long getItemId(int position) { return 0; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder holder = null; if (convertView == null) { holder = new ViewHolder(); convertView = View.inflate(mContext, R.layout.item_one_fragment, null); holder.wordTV = (TextView) convertView .findViewById(R.id.tv_main_word); holder.nameTV = (TextView) convertView .findViewById(R.id.tv_item_name); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } Friend friend = mDatas.get(position); String word = friend.getPinyin().substring(0, 1); holder.wordTV.setText(word); holder.nameTV.setText(friend.getName()); // 如果下标为0,那么让其显示 if (position == 0) { holder.wordTV.setVisibility(View.VISIBLE); } else { // 取出上一个friend,并得到第一个word String preWord = mDatas.get(position - 1).getPinyin().substring(0, 1); if (word.equals(preWord)) {// 如果相同,那么就隐藏 holder.wordTV.setVisibility(View.GONE); } else {// 如果不同,显示 holder.wordTV.setVisibility(View.VISIBLE); } } return convertView; } class ViewHolder { public TextView wordTV; public TextView nameTV; } }
item_one_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" > <TextView android:id="@+id/tv_main_word" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="A" android:textSize="18sp" android:background="#66666666" android:padding="5dp"/> <TextView android:id="@+id/tv_item_name" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="阿三" android:textSize="18sp" android:padding="5dp"/> </LinearLayout>
忘记了一个重要的工具类,中文转换为字母,当然我们需要下载一个pinyin4j-2.5.0.jar包
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.exception.BadHanyuPinyinOutputFormatCombination; /** * 将汉字转换为拼音 * @author 李帅帅 * */ public class PinYinUtils { /** * 得到指定汉字的拼音 * 注意:不应该被频繁调用,它消耗一定内存 * @param hanzi * @return */ public static String getPinYin(String hanzi){ String pinyin = ""; HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();//控制转换是否大小写,是否带音标 format.setCaseType(HanyuPinyinCaseType.UPPERCASE);//大写 format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); //由于不能直接对多个汉字转换,只能对单个汉字转换 char[] arr = hanzi.toCharArray(); for (int i = 0; i < arr.length; i++) { if(Character.isWhitespace(arr[i]))continue;//如果是空格,则不处理,进行下次遍历 //汉字是2个字节存储,肯定大于127,所以大于127就可以当为汉字转换 if(arr[i]>127){ try { //由于多音字的存在,单 dan shan String[] pinyinArr = PinyinHelper.toHanyuPinyinStringArray(arr[i], format); if(pinyinArr!=null){ pinyin += pinyinArr[0]; }else { pinyin += arr[i]; } } catch (BadHanyuPinyinOutputFormatCombination e) { e.printStackTrace(); //不是正确的汉字 pinyin += arr[i]; } }else { //不是汉字, pinyin += arr[i]; } } return pinyin; } }
希望能够帮到大家,谢谢
相关文章推荐
- 第七篇 :微信公众平台开发实战Java版之如何获取微信用户基本信息
- php实现微信公众号主动推送消息
- iOS--微信支付
- 微信JSSDK示例代码 笔记
- PHP 微信 Emoji表情处理
- 央行发布支付新规 微信红包过千元需认证
- 微信企业红包发放注意事项记录
- 微信页面阻止android回退键退出
- 微信调用jssdk在网页端实现调用扫一扫,java+jsp
- 微信开发之接入
- 突击部队拼多多
- php实现微信公众号主动推送消息
- 微信JS SDK PHP Demo
- 微信开发之网页授权获取用户基本信息
- 微信分享提示未安装
- 微信开发中网页授权access_token与基础支持的access_token异同
- php实现微信拼手气红包
- 微信自动回复功能开发总结
- 微信支付接入遇到的问题
- 微信公众号接收消息和发送消息开发流程和注意事项