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);
// 如果是選中的狀態(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數組的長度就等于點擊b中的個數.
switch (action) {
//當手指離開
case MotionEvent.ACTION_UP:
//設置側滑控件的背景色
setBackgroundColor(getBackgroundNormalColor());
mPosition = -1;
invalidate();
if (getOnTouchLetterListener() != null) {
//回調事件,告知當前手指已經離開當前區(qū)域
getOnTouchLetterListener().onTouchOutside();
}
break;
default:
//更改當字母為選中狀態(tài)時控件的背景色
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);
/**
* 當離開控件可觸摸區(qū)域時會調用;
*/
void onTouchOutside();
}
側滑控件完成后, 再分析一下分組界面是怎么實現的,不同分組由不同的字母作為標題,用ListView就可以實現,ListView里使用的Adapter里面有一個方法getItemViewType()方法用于區(qū)分返回多種類型的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
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
詳解Android開啟OTG功能/USB?Host?API功能
這篇文章主要介紹了Android開啟OTG功能/USB?Host?API功能,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07

