关于android实现fastindexbar(快速索引)详解

首先看下自定义viewfastindex的实现

package cn.yuan.yu.view;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.support.v4.view.MotionEventCompat;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;

import cn.yuan.yu.R;

/**
 * Created by yukuo on 2016/4/7.
 * 这是一个自定义的一个快速索引的自定义的控件
 */
public class FastIndexBar extends View {
    /**
     * 上下文
     */
    private Context context;
    /**
     * 宽度
     */
    private int Width;
    /**
     * 高度
     */
    private int Height;
    /**
     * 字体的颜色
     */
    private int TextColor;
    /**
     * 字体大小
     */
    private int TextSize;
    /**
     * 控件的背景色
     */
    private int BackgroundColor;

    /**
     * 单元格高度
     */
    private float cellHeight;
    private static final String[] WORDS = new String[]{"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;
    //这是一个索引
    int index = -1;
    //监听器
    private OnLetterChangeListener onLetterChangeListener;

    /**
     * 字母更新监听
     */
    public interface OnLetterChangeListener {
        /**
         * 当手指移动或者按下的时候调用的方法
         *
         * @param letter
         */
        void onLetterChange(String letter);

        /**
         * 当手指离开这个控件的时候调用的方法
         */
        void onUp();
    }

    public void setOnLetterChangeListener(
            OnLetterChangeListener onLetterChangeListener) {
        this.onLetterChangeListener = onLetterChangeListener;
    }

    public FastIndexBar(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        this.context = context;
    }

    public FastIndexBar(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.context = context;
        init(attrs, defStyleAttr);
    }

    /**
     * 初始化各种属性
     */
    private void init(AttributeSet attrs, int defStyleAttr) {
        /**
         * 获得我们所定义的自定义样式属性
         */
        TypedArray typedArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FastIndexBar, defStyleAttr, 0);
        for (int i = 0; i < typedArray.getIndexCount(); i++) {
            int attr = typedArray.getIndex(i);
            if (attr == R.styleable.FastIndexBar_BackgroundColor) {
                BackgroundColor = typedArray.getColor(attr, Color.WHITE);
            } else if (attr == R.styleable.FastIndexBar_TextColor) {
                TextColor = typedArray.getColor(attr, Color.BLUE);
            } else if (attr == R.styleable.FastIndexBar_TextSize) {
                TextSize = typedArray.getDimensionPixelSize(attr, (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 10, getResources().getDisplayMetrics()));
            }
        }
        //释放资源
        typedArray.recycle();
        /**
         * 初始化一个画笔
         */
        paint = new Paint();
        paint.setColor(TextColor);//设置画笔的颜色
        paint.setTextSize(TextSize);//设置字体的大小
    }

    /**
     * 绘制
     *
     * @param canvas
     */
    @Override
    protected void onDraw(Canvas canvas) {
        for (int i = 0; i < WORDS.length; i++) {
            String text = WORDS[i];
            float x = (int) (Width * 0.5f - paint.measureText(text) * 0.5f);
            Rect bounds = new Rect();
            // 把矩形对象赋值
            paint.getTextBounds(text, 0, text.length(), bounds);
            int textHeight = bounds.height();
            float y = (int) (cellHeight * 0.5f + textHeight * 0.5 + cellHeight
                    * i);
            // 如果当前绘制的字母和按下的字母索引一样, 用灰色的画笔
            //  paint.setColor(i == index ? Color.GRAY : Color.BLACK);
            canvas.drawColor(BackgroundColor);
            canvas.drawText(text, x, y, paint);
        }
    }

    /**
     * 控件的手指触摸事件的监听
     *
     * @param event
     * @return
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float y = -1;
        //选择的索引
        int currentIndex = -1;
        switch (MotionEventCompat.getActionMasked(event)) {
            case MotionEvent.ACTION_DOWN://按下的时候
                y = event.getY();//获得当时按下的y                currentIndex = (int) (y / cellHeight);
                if (currentIndex >= 0 && currentIndex < WORDS.length) {
                    // 健壮性处理, 在正常范围内
                    if (index != currentIndex) {
                        // 字母的索引发生了变化
                        if (onLetterChangeListener != null) {
                            onLetterChangeListener
                                    .onLetterChange(WORDS[currentIndex]);
                        }
                        index = currentIndex;
                    }
                }
                break;
            case MotionEvent.ACTION_MOVE://移动的时候
                y = event.getY();
                currentIndex = (int) (y / cellHeight);
                if (currentIndex >= 0 && currentIndex < WORDS.length) {
                    // 健壮性处理, 在正常范围内
                    if (index != currentIndex) {
                        // 字母的索引发生了变化
                        if (onLetterChangeListener != null) {
                            onLetterChangeListener
                                    .onLetterChange(WORDS[currentIndex]);
                        }
                        index = currentIndex;
                    }
                }
                break;
            case MotionEvent.ACTION_UP://离开的时候
                index = -1;
                if (onLetterChangeListener != null) {
                    onLetterChangeListener
                            .onUp();
                }
                break;
        }
        invalidate();
        return true;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //单元格宽度
        Width = getMeasuredWidth();
        Height = getMeasuredHeight();
        //单元格高度
        cellHeight = Height * 1.0f / WORDS.length;
    }
}
布局如何应用呢?如下:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <cn.yuan.yu.view.ElasticListView
        android:id="@+id/lv_mylistview"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <cn.yuan.yu.view.FastIndexBar
        android:id="@+id/fib_demo"
        android:layout_width="30dp"
        android:layout_height="280dp"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        app:TextColor="@color/themecolor"
        app:TextSize="9sp" />

    <TextView
        android:id="@+id/tv_tip"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_centerInParent="true"
        android:background="@drawable/text_bg_tip"
        android:gravity="center"
        android:textColor="@android:color/white"
        android:textSize="100sp"
        android:visibility="gone" />
</RelativeLayout>
定义这个列表的适配器

package cn.yuan.qi.demomodule.adapter;

import android.content.Context;
import android.text.TextUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

import cn.yuan.qi.R;
import cn.yuan.yu.bean.PhoneNumber;

/**
 * Created by yukuo on 2016/4/12.
 */
public class PhoneNumberAdapter extends BaseAdapter {
    private List<PhoneNumber> list;
    private Context context;

    public PhoneNumberAdapter(Context context, List<PhoneNumber> list) {
        this.list = list;
        this.context = context;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        MyHolder myHolder;
        if (convertView == null) {
            myHolder = new MyHolder();
            convertView = View.inflate(context, R.layout.item_fastindex, null);
            myHolder.textViewname = (TextView) convertView.findViewById(R.id.tv_item_phone_name);
            myHolder.textViewphone = (TextView) convertView.findViewById(R.id.tv_item_phone_number);
            myHolder.index = (TextView) convertView.findViewById(R.id.tv_index);
            convertView.setTag(myHolder);
        } else {
            myHolder = (MyHolder) convertView.getTag();
        }
        // 进行分组, 比较上一个拼音的首字母和自己是否一致, 如果不一致, 就显示tv_index
        String currentLetter = list.get(position).getPinyin();
        String indexStr = null;
        if (position == 0) {
            // 1. 如果是第一位
            indexStr = currentLetter;
        } else {
            // 获取上一个拼音
            String preLetter = list.get(position-1).getPinyin();
            if (!TextUtils.equals(currentLetter, preLetter)) {
                // 2. 当跟上一个不同时, 赋值, 显示
                indexStr = currentLetter;
            }
        }
        myHolder.index.setVisibility(indexStr == null ? View.GONE
                : View.VISIBLE);
        myHolder.index.setText(indexStr == null ? "" : list.get(position).getPinyin());
        myHolder.textViewname.setText(list.get(position).getName());
        myHolder.textViewphone.setText(list.get(position).getNumber());
        return convertView;
    }

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

    @Override
    public Object getItem(int position) {
        return null;
    }

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

    class MyHolder {
        TextView textViewname;
        TextView textViewphone;
        TextView index;
    }
}
条目布局文件

<?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_index"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:background="@color/themecolor"
        android:gravity="center_vertical"
        android:paddingLeft="10dp"
        android:text="A"
        android:textColor="@android:color/white"
        android:textSize="15sp" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="horizontal">

        <TextView
            android:id="@+id/tv_item_phone_name"
            android:layout_width="100dp"
            android:layout_height="match_parent"
            android:layout_marginLeft="15dp"
            android:gravity="center_vertical" />

        <TextView
            android:id="@+id/tv_item_phone_number"
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_marginLeft="50dp"
            android:gravity="center_vertical" />
    </LinearLayout>

</LinearLayout>
Activity界面业务代码

package cn.yuan.qi.demomodule.activity;

import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import butterknife.Bind;
import cn.yuan.qi.R;
import cn.yuan.qi.common.activity.BaseActivity;
import cn.yuan.qi.common.application.QiApplication;
import cn.yuan.qi.demomodule.adapter.PhoneNumberAdapter;
import cn.yuan.yu.bean.PhoneNumber;
import cn.yuan.yu.utils.GetPhoneData;
import cn.yuan.yu.view.ElasticListView;
import cn.yuan.yu.view.FastIndexBar;

/**
 * Created by yukuo on 2016/4/4.
 */
public class FastIndexOfActivity extends BaseActivity {

    @Bind(R.id.lv_mylistview)
    ElasticListView lvMylistview;
    @Bind(R.id.fib_demo)
    FastIndexBar fibDemo;
    @Bind(R.id.tv_tip)
    TextView tvTip;
    private PhoneNumberAdapter phoneNumberAdapter;
    private List<PhoneNumber> lists;

    @Override
    public void initdata(Bundle extras) {
        //     WeekGridAdapter weekGridAdapter = new WeekGridAdapter(this);
        fibDemo.setOnLetterChangeListener(new FastIndexBar.OnLetterChangeListener() {
            @Override
            public void onLetterChange(String letter) {
                tvTip.setText(letter);
                tvTip.setVisibility(View.VISIBLE);
                if (lists != null) {
                    for (int i = 0; i < lists.size(); i++) {
                        if (letter.equals(lists.get(i).getPinyin())) {
                            lvMylistview.setSelection(i);
                            return;
                        }
                    }
                }

            }

            @Override
            public void onUp() {
                tvTip.setVisibility(View.GONE);
            }
        });
        GetPhoneData.getPhoneNumberData(this, new GetPhoneData.OnLoadSuccessListener() {


            @Override
            public void onSuccess(final List<PhoneNumber> list) {
                QiApplication.mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        lists = list;
                        // 排序
                        Collections.sort(list, new Comparator<PhoneNumber>() {
                            @Override
                            public int compare(PhoneNumber lhs, PhoneNumber rhs) {
                                return lhs.getPinyin().compareToIgnoreCase(rhs.getPinyin());
                            }
                        });
                        phoneNumberAdapter = new PhoneNumberAdapter(FastIndexOfActivity.this, list);
                        lvMylistview.setAdapter(phoneNumberAdapter);
                    }
                });

            }

            @Override
            public void onFailure() {

            }
        });
    }

    @Override
    public int getContentLayout() {
        return R.layout.activity_fastindex;
    }

}
用到的工具类和实体

package cn.yuan.yu.utils;

import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.provider.ContactsContract;

import java.util.ArrayList;
import java.util.List;

import cn.yuan.yu.bean.PhoneNumber;

/**
 * Created by yukuo on 2016/4/12.
 * 这是一个获取手机联系人等信息的工具类
 */
public class GetPhoneData {
    public interface OnLoadSuccessListener {
        void onSuccess(List<PhoneNumber> list);

        void onFailure();
    }

    /**
     * 这是一个返回一个联系人信息列表集合的方法
     *
     * @param context 上下文
     * @return
     */
    public static void getPhoneNumberData(final Context context, final OnLoadSuccessListener onLoadSuccessListener) {
        new Thread() {
            @Override
            public void run() {
                List<PhoneNumber> list = new ArrayList<PhoneNumber>();
                ContentResolver cr = context.getContentResolver();
                Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
                if (cursor != null) {
                    while (cursor.moveToNext()) {
                        int PhoneName = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
                        int phoneNumbe = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
                        PhoneNumber phoneNumber = new PhoneNumber();
                        //电话号码
                        phoneNumber.setNumber(cursor.getString(phoneNumbe));
                        L.i("手机号码", cursor.getString(phoneNumbe));
                        //名字
                        phoneNumber.setName(cursor.getString(PhoneName));
                        L.i("名字", cursor.getString(PhoneName));
                        list.add(phoneNumber);
                    }
                    if (onLoadSuccessListener != null) {
                        onLoadSuccessListener.onSuccess(list);
                    }
                } else {
                    if (onLoadSuccessListener != null) {
                        onLoadSuccessListener.onFailure();
                    }
                }
            }
        }.start();
    }
}
实体

package cn.yuan.yu.bean;

import net.sourceforge.pinyin4j.PinyinHelper;

/**
 * Created by yukuo on 2016/4/12.
 * 这是一个联系人的实体类
 */
public class PhoneNumber {
    private String number;
    private String name;
    private String email;
    /**
     * 这是一个存储每个名字首字母的变量
     */
    private String pinyin;

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        this.pinyin = getHeadChar(name);

    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPinyin() {
        return pinyin;
    }

    public void setPinyin(String pinyin) {
        this.pinyin = pinyin;
    }

    /**
     * 得到首字母
     *
     * @param str
     * @return
     */
    public String getHeadChar(String str) {
        String convert = "";
        char word = str.charAt(0);
        String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(word);
        if (pinyinArray != null) {
            convert += pinyinArray[0].charAt(0);
        } else {
            convert += word;
        }
        return convert.toUpperCase();
    }

}
最后的效果图

图片图片

选中效果选中效果

ok祝小伙伴成功吧


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值