您好,登錄后才能下訂單哦!
仿微信聯(lián)系人列表字母側(cè)滑控件, 側(cè)滑控件參考了以下博客:
Android實現(xiàn)ListView的A-Z字母排序和過濾搜索功能
首先分析一下字母側(cè)滑控件應(yīng)該如何實現(xiàn),根據(jù)側(cè)滑控件的高度和字母的數(shù)量來平均計算每個字母應(yīng)該占據(jù)的高度。
在View的onDraw()方法下繪制每一個字母
protected void onDraw(Canvas canvas) { super.onDraw(canvas); int height = getHeight();// 獲取對應(yīng)高度 int width = getWidth(); // 獲取對應(yīng)寬度 int singleHeight = height / getData().size();// 獲取每一個字母的高度 for (int i = 0; i < getData().size(); i++) { mPaint.setColor(getLetterColor());//繪制字母的顏色 mPaint.setTypeface(Typeface.DEFAULT); mPaint.setAntiAlias(true); mPaint.setTextSize(singleHeight); // 如果是選中的狀態(tài) if (i == mPosition) { mPaint.setColor(getLetterPressedColor()); mPaint.setFakeBoldText(true); } // x坐標等于總體寬度中間的位置減去字符串寬度的一半. float xPos = width / 2 - mPaint.measureText(getData().get(i)) / 2; float yPos = singleHeight * i + singleHeight; canvas.drawText(getData().get(i), xPos, yPos, mPaint); mPaint.reset();// 重置畫筆 } }
然后再看一下觸控事件的攔截處理
@Override public boolean dispatchTouchEvent(MotionEvent event) { final int action = event.getAction(); final float y = event.getY();// 點擊y坐標 final int lastPosition = mPosition;//記錄上一次選中字母的位置 final int position = (int) (y / getHeight() * getData().size());// 點擊y坐標所占總高度的比例*b數(shù)組的長度就等于點擊b中的個數(shù). switch (action) { //當手指離開 case MotionEvent.ACTION_UP: //設(shè)置側(cè)滑控件的背景色 setBackgroundColor(getBackgroundNormalColor()); mPosition = -1; invalidate(); if (getOnTouchLetterListener() != null) { //回調(diào)事件,告知當前手指已經(jīng)離開當前區(qū)域 getOnTouchLetterListener().onTouchOutside(); } break; default: //更改當字母為選中狀態(tài)時控件的背景色 setBackgroundColor(getBackgroundPressedColor()); //如果選中字母的位置不等于上一次選中的位置 if (lastPosition != position) { if (position >= 0 && position < getData().size()) { if (getOnTouchLetterListener() != null) { //回調(diào)事件,返回當前選中的字母 getOnTouchLetterListener().onTouchLetter(getData().get(position)); } mPosition = position; invalidate(); } } break; } return true; } public interface OnTouchLetterListener { /** * 當接觸到某個key的時候會調(diào)用; * @param s */ void onTouchLetter(String s); /** * 當離開控件可觸摸區(qū)域時會調(diào)用; */ void onTouchOutside(); }
側(cè)滑控件完成后, 再分析一下分組界面是怎么實現(xiàn)的,不同分組由不同的字母作為標題,用ListView就可以實現(xiàn),ListView里使用的Adapter里面有一個方法getItemViewType()方法用于區(qū)分返回多種類型的View,這里我們就兩種, 一個是標題,一個是聯(lián)系人信息;頂部里那些新的朋友、群聊等可以用ListView的addHeaderView()實現(xiàn)。但是用最SDK自帶的BaseAdapter實現(xiàn)分組的話也不方便,實際上我們可以進一步包裝;
首先看一下最基本的Adapter封裝:
public abstract class SimpleAdapter<T> extends BaseAdapter { protected Context mContext; protected List<T> mData; public SimpleAdapter(){} public SimpleAdapter(Context context, List<T> data){ init(context, data); } public void init(Context context, List<T> data){ this.mContext = context; this.mData = data; } @Override public int getCount() { return mData.size(); } @Override public T getItem(int position) { if(checkPositionIsOutOfRange(position)){ return null; } return mData.get(position); } @Override public long getItemId(int position) { return position; } @Override public abstract View getView(int position, View convertView, ViewGroup parent); public void refresh(List<T> data){ if(data == null){ this.mData.clear(); }else{ this.mData = data; } notifyDataSetChanged(); } public boolean checkPositionIsOutOfRange(int position){ if(0 <= position && position < mData.size()){ return false; } return true; } public Context getContext(){ return mContext; } public List<T> getData(){ return mData; } }
這個SimpleAdapter實現(xiàn)了數(shù)據(jù)基于List的最基本方法的實現(xiàn),使得每次繼承BaseAdapter不用再實現(xiàn)一些基本的方法,接下來再看一下用于更好實現(xiàn)分組的Adapter的進一步封裝:
public abstract class SortAdapter<K extends SortKey, V, VH_G extends ViewHolder, VH_C extends ViewHolder> extends SimpleAdapter<Object> { public final static int VIEW_TYPE_GROUP = 0; public final static int VIEW_TYPE_CHILD = 1; private HashMap<SortKey, Integer> mKeyIndex = new HashMap<>(); public SortAdapter(Context context, Map<K, List<V>> map) { init(context, convertMapToList(map)); } public SortAdapter(Context context, List<Object> list) { init(context, list); } /** * 轉(zhuǎn)換分組數(shù)據(jù)為List,并且更新鍵值的索引 * @param map * @return */ public List<Object> convertMapToList(Map<K, List<V>> map) { List<Object> mData = new ArrayList<>(); mKeyIndex.clear(); for (Map.Entry<K, List<V>> entry : map.entrySet()) { mData.add(entry.getKey()); mKeyIndex.put(entry.getKey(), mData.size() - 1); for (V v : entry.getValue()) { mData.add(v); } } return mData; } public void refresh(Map<K, List<V>> map) { super.refresh(convertMapToList(map)); } @Override public void refresh(List<Object> data) { super.refresh(data); mKeyIndex.clear(); } /** * 得到鍵值的索引值 * @param k * @return */ public int getKeyIndex(K k){ Integer integer = mKeyIndex.get(k); if(integer == null){ return getKeyIndexFromList(k); } return integer; } public int getKeyIndexFromList(K k){ for(int i = 0; i < getCount(); i++){ Object obj = getItem(i); if(obj != null && obj instanceof SortKey){ if(obj.equals(k)){ mKeyIndex.put(k, i); return i; } } } return -1; } @Override public int getItemViewType(int position) { Object obj = getItem(position); if (obj instanceof SortKey) { return VIEW_TYPE_GROUP; } return VIEW_TYPE_CHILD; } @Override public int getViewTypeCount() { return 2; } @Override public int getCount() { return mData.size(); } @Override public Object getItem(int position) { if (0 <= position && position < mData.size()) { return mData.get(position); } return null; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { int viewType = getItemViewType(position); View view = null; Object obj = getItem(position); switch (viewType) { case VIEW_TYPE_GROUP: view = getGroupView((K)obj, position, convertView, parent); break; case VIEW_TYPE_CHILD: view = getChildView((V)obj, position, convertView, parent); break; } return view; } public View getGroupView(K key, int position, View convertView, ViewGroup parent){ VH_G vh; if(convertView == null){ convertView = LayoutInflater.from(mContext).inflate(getGroupLayoutId(), null); vh = onCreateGroupViewHolder(convertView, parent); convertView.setTag(vh); }else{ vh = (VH_G)convertView.getTag(); } onBindGroupViewHolder(vh, key, position); return convertView; } public View getChildView(V value, int position, View convertView, ViewGroup parent){ VH_C vh; if(convertView == null){ convertView = LayoutInflater.from(mContext).inflate(getChildLayoutId(), null); vh = onCreateChildViewHolder(convertView, parent); convertView.setTag(vh); }else{ vh = (VH_C)convertView.getTag(); } onBindChildViewHolder(vh, value, position); return convertView; } public abstract @LayoutRes int getGroupLayoutId(); public abstract VH_G onCreateGroupViewHolder(View convertView, ViewGroup parent); public abstract void onBindGroupViewHolder(VH_G vh, K key, int position); public abstract @LayoutRes int getChildLayoutId(); public abstract VH_C onCreateChildViewHolder(View convertView, ViewGroup parent); public abstract void onBindChildViewHolder(VH_C vh, V value, int position); public interface SortKey { } public static class ViewHolder{ public View mParent; public ViewHolder(View parent){ mParent = parent; } public View findViewById(@IdRes int id){ return mParent.findViewById(id); } }
本項目Github地址(基于AndroidStudio構(gòu)建):
https://github.com/yuhengye/LetterSort
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。