自定义View实现侧边索引

来源:互联网 发布:淘宝开店实名未认证 编辑:程序博客网 时间:2024/05/17 22:36
 *侧边索引:音乐APP,即时通讯,电商选择城市,短信验证选择城市等都有自定义控件 *  实现步骤: *  1>.绘制 A - Z 的的字母列表(自绘式自定义控件) *  2>.响应触摸时间 *  3>.提供监听回调 *  4>.获取汉子拼音(首字母)  pinyin4J 通过汉字得到拼音,只能一个字符一个字符去转换 *  5>.根据拼音排序 *  6>.根据首字母分组 *  7>.把监听回调和ListView结合起来 
 * 绘制 A - Z 的的字母列表(自绘式自定义控件) 
* author:(Administrator)
* function: 快速索引栏实现思路 * 1.继承View,覆写构造方法,初始化画笔. * 2.OnDrawer方法里绘制字符. * 3.OnMeasure方法里测量高度. * 4.OntouchEven时间知道用户具体按住哪个字母. * 5.定义抽象方法,实现监听回调. *
public class QuickIndexBar extends View{    private Paint mPaint;    //A.要绘制的内容    private static final String[] LETTERS = 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 int mCellWidth;    private float mCellheight;    private float mY;    private int mCurrentIndext;    public QuickIndexBar(Context context) {        this(context,null);    }    public QuickIndexBar(Context context, AttributeSet attrs) {        this(context,attrs,0);    }    public QuickIndexBar(Context context, AttributeSet attrs, int defStyleAttr) {        super(context,attrs,defStyleAttr);        // 初始化画笔        initPaint();    }    private void initPaint() {        // 创建一个抗锯齿的画笔        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);        // 画笔文本加粗        mPaint.setTypeface(Typeface.DEFAULT_BOLD);        // 颜色        mPaint.setColor(Color.WHITE);        mPaint.setTextSize(25);    }    /**     *     * @param canvas 完成侧拉索引     */    @Override    protected void onDraw(Canvas canvas) {        //遍历了二十六个字母,进行坐标计算,才能进行绘制        for (int i = 0; i < LETTERS.length; i++){            // 从数组中取字母(根据I)            String letter = LETTERS[i];            float x = mCellWidth * 0.5f - mPaint.measureText(letter) * 0.5f;            float y = mCellheight * 0.5f + mPaint.measureText(letter) * 0.5f + i * mCellheight;            canvas.drawText(letter,x, y,mPaint);        }    }    /**     * 完成侧拉索引的测量     * @param widthMeasureSpec     * @param heightMeasureSpec     */    @Override    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {        super.onMeasure(widthMeasureSpec, heightMeasureSpec);        // 获取控件的宽高        int mHeight = getMeasuredHeight();        mCellWidth = getMeasuredWidth();        // 获取单元格的高度,由自定义控件总高度,除以所有字母占用的高度        mCellheight = mHeight * 1.0f / LETTERS.length;    }    // 记录用户上一次按下的位置,以便进行判断这一次所按住的位置,是否,还是上一次的位置如果是,不做任何处理    private int lastIndex = -1;    /**     * 重写onTouchEvent触摸事件,返回值为True,方有效果     * @param event     * @return     */    @Override    public boolean onTouchEvent(MotionEvent event) {        switch (event.getAction()){            // 获取被点击到的字母索引            case MotionEvent.ACTION_DOWN:  // 按下时回调            case MotionEvent.ACTION_HOVER_MOVE: // 移动时回调                mY = event.getY();                System.out.println("Y"+ mY);                mCurrentIndext = (int) (mY / mCellheight);                System.out.println("按住了第"+ mCurrentIndext +"单元格");                // 为了防止一个字母按住,不停的重复调用,进行判断,判断是否还是按着上一个字母,是的话,不做任何处理,提高性能;                if(mCurrentIndext != lastIndex){                    // 为了防止角标越界                    if(mCurrentIndext >= 0 && mCurrentIndext < LETTERS.length){                        String letter = LETTERS[mCurrentIndext];                        if(mOnLetterUpdateListener != null){                            mOnLetterUpdateListener.onLetterUpdate(letter);                        }                        //ToastUtil.showToast(getContext(),letter);                        lastIndex = mCurrentIndext;                    }                }                break;        }        return true;    }    /**     * 定义接口     */    public interface OnLetterUpdateListener{        void onLetterUpdate(String letter);    }    /**     * 定义接口的对象     */    private OnLetterUpdateListener mOnLetterUpdateListener;    /**     * 暴露方法,让外界传过来一个实现接口类的对象     */    public void setOnLetterUpdateListener(OnLetterUpdateListener onLetterUpdateListener){        mOnLetterUpdateListener = onLetterUpdateListener;    }}
activity_main.xml:

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    android:id="@+id/activity_main"    android:layout_width="match_parent"    android:layout_height="match_parent">    <com.example.administrator.customview.UI.QuickIndexBar        android:id="@+id/bar"        android:layout_width="30dp"        android:layout_height="match_parent"        android:background="#28f"        android:layout_alignParentRight="true"        />    <ListView        android:layout_toLeftOf="@id/bar"        android:id="@+id/listview"        android:layout_width="match_parent"        android:layout_height="match_parent"></ListView></RelativeLayout>

   * 
(创建工具类)
获取汉子拼音(首字母) pinyin4J 通过汉字得到拼音,只能一个字符一个字符去转换(需要
pinyin4J Jar包 下载地址: http://download.csdn.net/download/ghqzww/9936504
)
public class PinYinUtil {    public static String getPinYin(String string){        HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();        //不要音标        format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);        //设置转换出大写字母        format.setCaseType(HanyuPinyinCaseType.UPPERCASE);        char[] array = string.toCharArray();        StringBuilder builder = new StringBuilder();        for (int x = 0; x < array.length; x++){            char c = array[x];            // 如果是空格,就跳过循环            if(Character.isWhitespace(c)){                continue;            }            // 如果不是汉字,直接拼写            if(c > -128 && c < 127){               builder.append(c);            }else {                try {                    // 获取某个字符的拼音,可以获取到多音字                    String s = PinyinHelper.toHanyuPinyinStringArray(c, format)[0];                    builder.append(s);                } catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {                    badHanyuPinyinOutputFormatCombination.printStackTrace();                }            }        }        return builder.toString();    }}

* 创建一个类,存放数据

public class Cheeses {    public static final String[] NAMES = new String[]{"宋江", "卢俊义", "吴用",            "公孙胜", "关胜", "林冲", "秦明", "呼延灼", "花荣", "柴进", "李应", "朱仝", "鲁智深",            "武松", "董平", "张清", "杨志", "徐宁", "索超", "戴宗", "刘唐", "李逵", "史进", "穆弘",            "雷横", "李俊", "阮小二", "张横", "阮小五", " 张顺", "阮小七", "杨雄", "石秀", "解珍",            " 解宝", "燕青", "朱武", "黄信", "孙立", "宣赞", "郝思文", "韩滔", "彭玘", "单廷珪",            "魏定国", "萧让", "裴宣", "欧鹏", "邓飞", " 燕顺", "杨林", "凌振", "蒋敬", "吕方",            "郭 盛", "安道全", "皇甫端", "王英", "扈三娘", "鲍旭", "樊瑞", "孔明", "孔亮", "项充",            "李衮", "金大坚", "马麟", "童威", "童猛", "孟康", "侯健", "陈达", "杨春", "郑天寿",            "陶宗旺", "宋清", "乐和", "龚旺", "丁得孙", "穆春", "曹正", "宋万", "杜迁", "薛永", "施恩",            "周通", "李忠", "杜兴", "汤隆", "邹渊", "邹润", "朱富", "朱贵", "蔡福", "蔡庆", "李立",            "李云", "焦挺", "石勇", "孙新", "顾大嫂", "张青", "孙二娘", " 王定六", "郁保四", "白胜",            "时迁", "段景柱", "高会全"};}

* 吐司的工具类(使用Java代码在Main方法 Bar 的接口中使用) (可不写/自定义View中已经做好)

// 吐司的工具类public class ToastUtil {    private static Toast sToast;    public static void showToast(Context context,String msg){        if(sToast == null){            sToast  = Toast.makeText(context, "", Toast.LENGTH_SHORT);        }        sToast.setText(msg);        sToast.show();    }}
* 接着来撸 MainActivity 中代码

@Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        // 取消该Demotoolbar        requestWindowFeature(Window.FEATURE_NO_TITLE);        View decorView = getWindow().getDecorView();        int option = View.SYSTEM_UI_FLAG_FULLSCREEN;        decorView.setSystemUiVisibility(option);        ActionBar actionBar = getSupportActionBar();        actionBar.hide();        setContentView(R.layout.activity_main);        final QuickIndexBar bar = (QuickIndexBar) findViewById(R.id.bar);        // D.View         mListView = (ListView)findViewById(R.id.listview);        // D.model         person = new ArrayList<>();        // D.填充并排列顺序        fillAndSortData(person);        // D.controller层 设置适配器        mListView.setAdapter(new   HaoHanAdapter(person,this));                bar.setOnLetterUpdateListener(new QuickIndexBar.OnLetterUpdateListener() {            @Override            public void onLetterUpdate(String letter) {           // Java 代码的吐司           ToastUtil.showToast(MainActivity.this,letter);          // 将 ListView 和 自定义View 相关联                    for (int x = 0; x < person.size(); x++){                    String l = person.get(x).getPinyin().charAt(0) + "";                    if(TextUtils.equals(letter,l)){                        // 找到第一个首字母是letter条目                        mListView.setSelection(x);                        break;                    }                }            }        });    }    private void fillAndSortData(ArrayList<HaoHanBang> person) {        // 填充        for (int i = 0; i < Cheeses.NAMES.length; i++){            String name = Cheeses.NAMES[i];            person.add(new HaoHanBang(name));        }        // 排序        Collections.sort(person);    }}

* 创建适配器,为ListView适配数据

/** * date:2017/8/15 * author:高会全(Administrator) * function: * 完成效果使用的是,判断当前首字母和上一个条目的首字母是否一致,,不一致时,就显示全部界面,一致时,隐藏第一个界面 */public class HaoHanAdapter extends BaseAdapter {    private ArrayList<HaoHanBang> person = new ArrayList<>();    private Context mContext;    public HaoHanAdapter(ArrayList<HaoHanBang> person, Context context) {        this.person = person;        this.mContext = context;    }    @Override    public int getCount() {        return person.size();    }    @Override    public View getView(int position, View conertview, ViewGroup viewGroup) {        View view;        if(conertview == null){            view = View.inflate(mContext,R.layout.item,null);        }else {            view = conertview;        }        TextView tv_index = (TextView) view.findViewById(R.id.tv_index);        TextView tv_name = (TextView) view.findViewById(R.id.tv_name);        HaoHanBang haohan = person.get(position);        String currentStr = haohan.getPinyin().charAt(0) + "";        System.out.println("000000000000000000000000000"+currentStr);        String indexStr = null;        //如果是第一个名字,直接显示        if(position == 0){            indexStr = currentStr;        }else {            // 判断当前首字母是否和上一个首字母是否一致,不一致时显示完整item选项;            String lastStr = person.get(position - 1).getPinyin().charAt(0) + "";            // 判断两个参数是否一致,不一致执行赋值逻辑            if(!TextUtils.equals(lastStr,currentStr)){                // 不一致时赋值indexStr                indexStr = currentStr;            }        }        tv_index.setVisibility(indexStr != null ?View.VISIBLE : View.GONE);        tv_index.setText(currentStr);        tv_name.setText(haohan.getName());        return view;    }    @Override    public Object getItem(int i) {        return null;    }    @Override    public long getItemId(int i) {        return 0;    }}

* ListView 适配器的 Bean 类

public class HaoHanBang implements Comparable<HaoHanBang>{    private String name;    private String pinyin;    public HaoHanBang(String name){        this.name = name;        this.pinyin = PinYinUtil.getPinYin(name);    }    public String getName() {        return name;    }    public String getPinyin() {        return pinyin;    }    @Override    public int compareTo(HaoHanBang haoHanBang) {        return this.pinyin.compareTo(haoHanBang.pinyin);    }}



原创粉丝点击