android 自定义view仿通讯录

关于这篇文章 刚开始我心里也不知道从何下手,只能一步步来了。
看下实现效果:
这里写图片描述
先说下我的步骤:
步骤1:学会使用汉语转拼音的第三方jar包; compile ‘com.belerweb:pinyin4j:2.5.0’
步骤2:自定义view实现右侧字母表
步骤3:然后书写普通的listview。(里面用到汉语转拼音)
步骤4:关联listview和右侧的自定义view;

步骤1:
这个没啥好说的,看下代码吧;

package com.app.test.pinyinproject;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;

/**
 * Created by mengqiang on 2017/5/8.
 */

public class PinyinUtils {
    private static StringBuffer stringBuffer = new StringBuffer();
    /**
     * 返回汉语首个汉字的首字母,英文就返回首字母(小写的)
     * 例如:你好→n
     *       nihao→n
     */
    public static String getPinyin(String infoString){
        stringBuffer.setLength(0);
        String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(infoString.toCharArray()[0]);
        if(pinyinArray != null){
            stringBuffer.append(pinyinArray[0].charAt(0));
        }else{
            stringBuffer.append(infoString.toCharArray()[0]);
        }
        return stringBuffer.toString();
    }
    /**
     * 返回汉语首个汉字的首字母,英文就返回首字母(大写的)
     * 例如:你好→N
     *       nihao→N
     */
    public static String getUpPinyin(String infoString){
        stringBuffer.setLength(0);
        String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(infoString.toCharArray()[0]);
        if(pinyinArray != null){
            stringBuffer.append(pinyinArray[0].toUpperCase().charAt(0));
        }else{
            stringBuffer.append(infoString.toUpperCase().toCharArray()[0]);
        }
        return stringBuffer.toString();
    }
    /**
     * 获取汉字字符串的首字母,英文字符不变
     * 例如:你好→nh
     *       nihao→nihao
     */
    public static String getPinYinHeadChar(String headString) {
        stringBuffer.setLength(0);
        char[] chars = headString.toCharArray();
        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        for (int i = 0; i < chars.length; i++) {
            if (chars[i] > 128) {
                try {
                    stringBuffer.append(PinyinHelper.toHanyuPinyinStringArray(chars[i], defaultFormat)[0].charAt(0));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                stringBuffer.append(chars[0]);
            }
        }
        return stringBuffer.toString();
    }
    /**
     * 获取汉字字符串的汉语拼音,英文字符不变
     * 例如:你好→nihao
     *       nihao→nihao
     */
    public static String getPinYinLine(String lineString) {
        stringBuffer.setLength(0);
        char[] nameChar = lineString.toCharArray();
        HanyuPinyinOutputFormat defaultFormat = new HanyuPinyinOutputFormat();
        defaultFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
        defaultFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
        for (int i = 0; i < nameChar.length; i++) {
            if (nameChar[i] > 128) {
                try {
                    stringBuffer.append(PinyinHelper.toHanyuPinyinStringArray(nameChar[i], defaultFormat)[0]);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                stringBuffer.append(nameChar[i]);
            }
        }
        return stringBuffer.toString();
    }
}

步骤2:
(1)首先获取自定义view的height和wigth,然后将height分为27份heightText(26字母 + “#”),然后用canvas.drawText写出每一个字母。其中baselinbe的计算需要掌握。
(2)然后就是点击view怎么获取字母了。我们可以转化一下,我们点击view的时候获取点击的坐标(重写onTouchEvent方法),然后根据坐标计算出应该是哪一个字母。在使用接口回调给activity;

上代码:

package com.app.test.pinyinproject;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * Created by mengqiang on 2017/5/8.
 */

/**
 * 思路:先将height分为27个heightText,然后将分别将字母写在自己的区域;
 * 设置点击事件实际上就是重写view内部的TouchEvent方法,然后根据TouchEvent的不同事件做出不同的反应。
 */
public class PinyinView extends View {
    private Paint paint;
    private int height;
    private int wight;
    private float heightText;
    private OnItemClickListener onItemClickListener;

    private int color = Color.WHITE;
    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    private String[] pinyinArray=  {"#",
            "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"
    };
    public PinyinView(Context context) {
        super(context);
        initView();
    }

    public PinyinView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    public PinyinView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initView();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        height = getMeasuredHeight();
        wight = getMeasuredWidth();
        heightText = ((float)height/(float)27);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(color);
        for(int i = 0;i < pinyinArray.length;i++){
            float x = wight/2 - paint.measureText(pinyinArray[i])/2;
            /**
             * 知识点:baseLine的计算
             */
            Paint.FontMetrics fontMetrics = paint.getFontMetrics();
            float y = i * heightText + heightText/2 - (fontMetrics.top + fontMetrics.bottom)/2;
            canvas.drawText(pinyinArray[i],x,y,paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float coordinateY;
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:{//点击Down是颜色是gray
                color = Color.GRAY;
                postInvalidate();//延伸知识点:1:invalidate()和postInvalidate()的区别 2:view的双缓冲技术
                break;
            }
            case MotionEvent.ACTION_UP:{//UP的时候颜色是white
                coordinateY =  event.getY();
                onItemClickListener.onItemListener(getChar(coordinateY));
                color = Color.WHITE;
                postInvalidate();
                break;
            }
        }
        return true;
    }
    /**
     * 定义接口,用于传递所点击的字母
     */
    interface OnItemClickListener{
        void onItemListener(String infoString);
    }

    /**
     * 计算coordinateY对应的字母
     * @param coordinateY 点击的坐标
     * @return 返回coordinateY对应的字母
     */
    public String getChar(float coordinateY){
        for(int i = 0;i < pinyinArray.length;i++){
            if(heightText * i > coordinateY){
                return pinyinArray[i - 1];
            }
        }
        return pinyinArray[26];
    }
    public void initView(){
        paint = new Paint();
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(Color.BLUE);
        paint.setAntiAlias(true);
        paint.setTextSize(20);
    }
}

步骤3:
其实步骤2也是需要多考虑一些东西,比如:我们是使用两个adapter还是一个adapter,都能实现,再次我们是一个adapter;
我遇到问题一般是这样解决的:首先它是有什么组成?然后拆分成小部分;最后组合一下。
在这里我们需要书写adapter和adapter的数据(数据比较,降序排列)。
先说数据比较。我们需要创建一个User类用,

    private String name;//名称
    private String headChar;//首字母
    private String comparaChar;//第一个汉字的拼音全称

然后根据User类的首个汉字的拼音进行比较。

private String[] name = new String[]{"潘粤明", "戴军", "薛之谦", "蓝雨", "任泉", "张杰", "秦俊杰","陈坤", "田亮", "夏雨", "保剑锋", "陆毅", "乔振宇", "吉杰", "郭敬明", "巫迪文", "欢子", "井柏然","左小祖咒", "段奕宏", "毛宁", "樊凡", "汤潮", "山野", "陈龙", "侯勇", "俞思远", "冯绍峰", "崔健","杜淳", "张翰", "彭坦", "柏栩栩", "蒲巴甲", "凌潇肃", "毛方圆", "武艺", "耿乐", "钱泳辰","aaa","13","123654"};

public void setListData(){
        for(int i = 0;i < name.length;i++){
            User user = new User();
            user.setName(name[i]);
            if(PinyinUtils.getUpPinyin(name[i]).matches("[A-Z]")){//首字母
                user.setHeadChar(PinyinUtils.getUpPinyin(name[i]));
            }else{
                user.setHeadChar(PinyinUtils.getUpPinyin("#"));
            }
            user.setComparaChar(PinyinUtils.getPinYinLine(name[i]));//比较 (此字段用于比较第一个汉字)
            list.add(user);
        }

        Collections.sort(list, new ComparaUser());// 第一个汉字进行拼音比较(降序);
    }

然后就是adapter的实现了。

package com.app.test.pinyinproject;

import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

import java.util.List;

/**
 * Created by mengqiang on 2017/5/8.
 */

public class ListAdapter extends BaseAdapter {
    private List<User> userList ;
    private OnItemClickListener onItemClickListener;

    public OnItemClickListener getOnItemClickListener() {
        return onItemClickListener;
    }

    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        this.onItemClickListener = onItemClickListener;
    }

    public ListAdapter(List<User> userList) {
        this.userList = userList;
    }

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

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

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        ItemViewHolder itemViewHolder;
        if(convertView == null){
            convertView = View.inflate(parent.getContext(), R.layout.item_layout, null);
            itemViewHolder = new ItemViewHolder();
            itemViewHolder.charText = (TextView) convertView.findViewById(R.id.char_text);
            itemViewHolder.nameText = (TextView) convertView.findViewById(R.id.name_text);
            convertView.setTag(itemViewHolder);
        }else{
            itemViewHolder = (ItemViewHolder) convertView.getTag();
        }
        if(position == getPosition(position)){
            itemViewHolder.charText.setVisibility(View.VISIBLE);
            itemViewHolder.charText.setText(userList.get(position).getHeadChar());
        }else{
            itemViewHolder.charText.setVisibility(View.GONE);
        }
        itemViewHolder.nameText.setText(userList.get(position).getName());
        itemViewHolder.nameText.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                onItemClickListener.onItemCLick(position);
            }
        });
        return convertView;
    }

    /**
     * 计算出该luserist中position第一次对应的charAt下标i,然后判断i是否等于position。
     * @param position
     * @return
     */
    public int getPosition(int position){
        char charAt = userList.get(position).getHeadChar().charAt(0);
        for(int i = 0 ;i < userList.size();i++){
            if(charAt == userList.get(i).getHeadChar().charAt(0)){
                return i;
            }
        }
        return -1;
    }
    class ItemViewHolder{
        public TextView nameText;
        public TextView charText;
    }

    /**
     * 用于传递点击了userlist哪一个item。
     */
    interface  OnItemClickListener{
        void onItemCLick(int position);
    }
}

步骤4:
然后就是view和listview怎么关联呢,根据view接口返回的infoString 获取position,然后listview滑动到相应的位置

pinyinView.setOnItemClickListener(new PinyinView.OnItemClickListener() {
            @Override
            public void onItemListener(String infoString) {
                /**
                 * 点击右侧的字母表,listview滑动到相应的位置
                 */
                for(int i = 0;i < list.size();i++){
                    if(infoString.equals(list.get(i).getHeadChar())){
                        listview.setSelection(i);
                        break;
                    }
                }
            }
        });

感觉这都不难,重点是碰见一个问题之后怎么看待这个问题。

最后付上源码下载地址http://download.csdn.net/detail/lmq121210/9836455

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值