Android 自定义View实现仿通讯录,实现A-Z字母检索

前言

此篇文章利用StickyListHeadersListView和自定义view的方式实现所需效果,所以此篇文章的重点有两个方面,一是介绍StickyListHeadersListView的使用,二则为介绍字母检索的实现方式。其实技术含量不是很高,就算是记录一下吧

实现思路

本来字母检索打算用listview展示,但是网上查了一通资料后发现基本上都是使用的自定义view展示,想也对,字母检索会被频繁的刷新,如果用listview的话,感觉太重了。

效果图
Android 自定义View实现仿通讯录,实现A-Z字母检索_第1张图片
静态页.png
实现功能点

1.粘性显示
2.字母栏显示的只是主数据中含有的字母项
3.主数据滑动,字母栏跟着滑到相应的字母
4.点击字母栏定位到主数据的那一字母族的第一个数据

实现步骤

1.使用StickyListHeadersListView呈现基本数据

mListView = (StickyListHeadersListView) findViewById(R.id.id);
mAdapter = new Adapter(this, datas,letterdata);
mListView.setAdapter(mAdapter);

2.ListView的adapter展示

public class Adapter extends BaseAdapter implements StickyListHeadersAdapter {

    private List countries;
    private LayoutInflater inflater;
    private String chars;//字母栏中所有字母的字符串,为了拿到字母的位置

    public AreaInfoAdapter(Context context, List countries, List letterdata) {
        inflater = LayoutInflater.from(context);
        this.countries = countries;
        chars = ListToString(letterdata);

    }

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

    @Override
    public Object getItem(int position) {
        return countries.get(position);
    }

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

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

        if (convertView == null) {
            holder = new ViewHolder();
            convertView = inflater.inflate(R.layout.layout, parent, false);
            ...findViewById
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
            ...对控件的赋值
        return convertView;
    }

    @Override
    public View getHeaderView(int position, View convertView, ViewGroup parent) {
        HeaderViewHolder holder;
        if (convertView == null) {
            holder = new HeaderViewHolder();
            convertView = inflater.inflate(R.layout.item_layout, parent, false);
              ...findViewById
            convertView.setTag(holder);
        } else {
            holder = (HeaderViewHolder) convertView.getTag();
        }
        ...对控件的赋值
        return convertView;
    }

    //返回header的唯一标识
    @Override
    public long getHeaderId(int position) {
        //拿到集合中的字母值
        String charname = countries.get(position).getChar();
       //拿到字母在字母表中的位置
        int index = chars.indexOf(charname);
        return index;
    }

    class HeaderViewHolder {
        TextView charName;
    }

    class ViewHolder {
        TextView name;
        TextView code;
    }
//获得集合中字母为letter的一族中第一个数据的position
    public int getSelectPosition(String letter) {
        for (int i = 0; i < countries.size(); i++) {
            if (countries.get(i).getChar().equals(letter)) {
                return i;
            }
        }
        return 0;
    }
//获得具体位置的字母,以及字母在显示字母表中的位置
    public int getSectionForPosition(int position) {
        String charname = countries.get(position).getChar();
        return chars.indexOf(charname);
    }
//将集合转变为字符串
    public String ListToString(List list) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < list.size(); i++) {
            sb.append(list.get(i));
        }
        return sb.toString();
    }
}

3.自定义字母检索

public class LetterView extends View {
    //当前手指滑动到的位置
    private int choosedPosition = -1;
    //画文字的画笔
    private Paint paint;
    //右边的所有文字
    private List letters;
    //让信息滑到指定位置
    private UpdateListView updateListView;
    //单个字母的高度
    private float perTextHeight;
    //字母的字体大小
    private float letterSize;

    //页面正中央的TextView,用来显示手指当前滑动到的位置的文本
    //private TextView textViewDialog;
    public LetterIndexView(Context context) {
        this(context, null);
    }

    public LetterIndexView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LetterIndexView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.Letter, defStyleAttr, 0);
        //字母的字体大小
        letterSize = a.getDimension(R.styleable.Letter_letter_size, DisplayUtils.sp2px(getContext(), 10.0f));
        //每个字母的高
        perTextHeight = a.getDimension(R.styleable.Letter_letter_height, DisplayUtils.dp2px(getContext(), 24.0f));
        a.recycle();
        init();

    }

    public void init() {
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setTextSize(letterSize);
        paint.setTypeface(Typeface.DEFAULT_BOLD);
    }

    //测量view的大小,让其有多大显示多大
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);   //获取宽的模式
        int heightMode = MeasureSpec.getMode(heightMeasureSpec); //获取高的模式
        int widthSize = MeasureSpec.getSize(widthMeasureSpec);   //获取宽的尺寸
        int heightSize = MeasureSpec.getSize(heightMeasureSpec); //获取高的尺寸
        int width = 0;
        int height;
        if (widthMode == MeasureSpec.EXACTLY) {
            //如果match_parent或者具体的值,直接赋值
            width = widthSize;
        }
        //高度跟宽度处理方式一样
        if (heightMode == MeasureSpec.EXACTLY) {
            height = heightSize;
        } else {
            float textHeight = perTextHeight;
            height = (int) (getPaddingTop() + textHeight *( letters.size()+1) + getPaddingBottom());
        }
        //保存测量宽度和测量高度
        setMeasuredDimension(width, height);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < letters.size(); i++) {
            if (i == choosedPosition) {
                paint.setColor(Color.parseColor("#AD8748"));
            } else {
                paint.setColor(Color.parseColor("#adadad"));
            }
            //DisplayUtils.dp2px(getContext(), 3.0f) 这段话的含义是 我为了让字母好点击,手动把字母检索的栏的宽度增加了,所以画的时候就不可以居中画了,增加了一个偏移量
            canvas.drawText(letters.get(i), (getWidth() - paint.measureText(letters.get(i))) / 2 + DisplayUtils.dp2px(getContext(), 3.0f), (i + 1) * perTextHeight, paint);
        }
    }

    //根据点击的y值(y的值是根据你自己定义的view的原点为起点的)判断点的是第几项
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float y = event.getY();
        int currentPosition = (int) (y / perTextHeight);
        if (currentPosition < 0) {
            currentPosition = 0;
        }
        if (currentPosition >= letters.size()) {
            return true;
        }
        String letter = letters.get(currentPosition);
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
//                if (textViewDialog != null) {
//                    textViewDialog.setVisibility(View.GONE);
//                }
                break;
            default:
//                setBackgroundColor(Color.parseColor("#cccccc"));
//                    if (textViewDialog != null) {
//                        textViewDialog.setVisibility(View.VISIBLE);
//                        textViewDialog.setText(letter);
//                    }
                if (updateListView != null) {
                    updateListView.updateListView(letter);
                }
                choosedPosition = currentPosition;
                break;
        }
        invalidate();
        return true;
    }

    //主ListView调用重回letterView
    public void updateLetterIndexView(int currentChar) {
        if (currentChar >= 0 && currentChar < letters.size()) {
            choosedPosition = currentChar;
            invalidate();
        }
    }

    public void setUpdateListView(UpdateListView mUpdateListView) {
        this.updateListView = mUpdateListView;
    }

    public void setData(List letters) {
        this.letters = letters;
    }

    //控制主ListView数据滑动到指定的位置
    public interface UpdateListView {
        void updateListView(String letter);
    }
}

4.交互

letterList.setUpdateListView(new LetterIndexView.UpdateListView() {
            @Override
            public void updateListView(String currentChar) {
                int positionForSection = mAdapter.getSelectPosition(currentChar);
                mListView.setSelection(positionForSection);
            }
        });
        mListView.setOnStickyHeaderChangedListener(new StickyListHeadersListView.OnStickyHeaderChangedListener() {
            @Override
            public void onStickyHeaderChanged(StickyListHeadersListView l, View header, int itemPosition, long headerId) {
                int sectionForPosition = mAdapter.getSectionForPosition(itemPosition);
                letterList.updateLetterIndexView(sectionForPosition);
            }
        });
资料

android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索

喵印~~~

你可能感兴趣的:(Android 自定义View实现仿通讯录,实现A-Z字母检索)