編輯:關於Android編程
仿微信聯系人列表字母側滑控件, 側滑控件參考了以下博客:
Android實現ListView的A-Z字母排序和過濾搜索功能
首先分析一下字母側滑控件應該如何實現,根據側滑控件的高度和字母的數量來平均計算每個字母應該占據的高度。
在View的onDraw()方法下繪制每一個字母
protected void onDraw(Canvas canvas) { super.onDraw(canvas); int height = getHeight();// 獲取對應高度 int width = getWidth(); // 獲取對應寬度 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); // 如果是選中的狀態 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數組的長度就等於點擊b中的個數. switch (action) { //當手指離開 case MotionEvent.ACTION_UP: //設置側滑控件的背景色 setBackgroundColor(getBackgroundNormalColor()); mPosition = -1; invalidate(); if (getOnTouchLetterListener() != null) { //回調事件,告知當前手指已經離開當前區域 getOnTouchLetterListener().onTouchOutside(); } break; default: //更改當字母為選中狀態時控件的背景色 setBackgroundColor(getBackgroundPressedColor()); //如果選中字母的位置不等於上一次選中的位置 if (lastPosition != position) { if (position >= 0 && position < getData().size()) { if (getOnTouchLetterListener() != null) { //回調事件,返回當前選中的字母 getOnTouchLetterListener().onTouchLetter(getData().get(position)); } mPosition = position; invalidate(); } } break; } return true; } public interface OnTouchLetterListener { /** * 當接觸到某個key的時候會調用; * @param s */ void onTouchLetter(String s); /** * 當離開控件可觸摸區域時會調用; */ void onTouchOutside(); }
側滑控件完成後, 再分析一下分組界面是怎麼實現的,不同分組由不同的字母作為標題,用ListView就可以實現,ListView裡使用的Adapter裡面有一個方法getItemViewType()方法用於區分返回多種類型的View,這裡我們就兩種, 一個是標題,一個是聯系人信息;頂部裡那些新的朋友、群聊等可以用ListView的addHeaderView()實現。但是用最SDK自帶的BaseAdapter實現分組的話也不方便,實際上我們可以進一步包裝;
首先看一下最基本的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實現了數據基於List的最基本方法的實現,使得每次繼承BaseAdapter不用再實現一些基本的方法,接下來再看一下用於更好實現分組的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); } /** * 轉換分組數據為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構建):
https://github.com/yuhengye/LetterSort
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。
微信轉賬輸入框規則(可能不全)1、小數點後兩位2、起始輸入小數點,顯示0.3、刪除到第一個位置是小數點的時候,第一個位置為0 ,避免出現小數點在第一個位置的情況修改這個朋
一、前言關於Android中的分包技術,已經不是什麼新的技術了,網上也有很多解析了,但是他們都是給了理論上的知道和原理解析,並沒有詳細的案例說明,所以這裡我們就來詳細講解
View類是android中非常重要的一個類.view是應用程序界面的直觀體現,我們看到的應用程序界面就可以看作是View(視圖)組成的.那麼我們應用程序的界面是怎麼創建
這個實例可以幫助我們學習旋轉動畫和計時器這兩個知識點,廢話不多說,上主程序: package com.bear.lotterywheel; import java.u