自定义索引View

本文详细介绍了如何自定义一个索引View,通过继承View并重写构造方法、初始化画笔、利用canvas.drawText绘制文字,以及计算字母位置等步骤,深入理解自定义View的工作原理。同时强调在onDraw中避免频繁创建对象以防止界面卡顿,并实现触摸事件处理及回调接口,以便在实际应用中传递选中项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

不论天气如何变化,该撸码还是要撸的.近期打算好好学习一下自定义View的知识.

这里写图片描述

这是一个自定义的索引条目,虽然网上很多教程,但是纸上来的终觉浅,还是自己写一下.体会深刻,也会学到更多知识.

废话不说,代码以下

public class SpeedIndexView extends View {

    private String[] letters = {"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;//画笔
    private Rect rect;
    private int width;
    private float letterLength;
    private int lastIndex = -1;
    private TouchIndexListener onIndexListener;

    public SpeedIndexView(Context context) {
        this(context, null);
    }

    public SpeedIndexView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public SpeedIndexView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //抗锯齿
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(Color.WHITE);
        //字体
        paint.setTypeface(Typeface.DEFAULT_BOLD);
        paint.setTextSize(DimensUtils.dip2px(context, 16));
        rect = new Rect();
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public SpeedIndexView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //尽量不要做创建对象的操作,防止内存频繁回收,造成界面卡顿
        for (int i = 0; i < letters.length; i++) {
            paint.getTextBounds(letters[i], 0, letters[i].length(), rect);
            float measureText = paint.measureText(letters[i]);//获取字符串的宽度
            float x = width / 2.0f - measureText / 2.0f;
            float y = letterLength + letterLength * i;
            canvas.drawText(letters[i], x, y, paint);
        }
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        //View的Size变化时被调用
        //在onDraw中无法获得准确的宽高
//        width = getMeasuredWidth();
//        height = getMeasuredHeight();
        width = w;
        Log.d("view", "w" + w + "h" + h + "oldw" + oldw + "oldh" + oldh);
        //每个字符串的高度
        letterLength = h * 1.0f / letters.length;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                measuerAndWhitch(event);
                break;
            case MotionEvent.ACTION_MOVE:
                measuerAndWhitch(event);
                break;
            case MotionEvent.ACTION_UP:
                lastIndex = -1;
                break;
        }
        return true;
    }

    private void measuerAndWhitch(MotionEvent event) {
        float y = event.getY();
        int index = (int) (y / letterLength);
        Log.d("view", "" + index);
        //与上次触摸不同
        if (lastIndex != index) {
            if (index >= 0 && index < letters.length) {
                if (onIndexListener != null)
                    onIndexListener.onTouchindexListener(letters[index]);
            }
            lastIndex = index;
        }

    }

    public void setOnTouchIndexListener(TouchIndexListener indexListener) {
        this.onIndexListener = indexListener;

    }

    public interface TouchIndexListener {
        void onTouchindexListener(String letter);
    }
}

1, 继承View,重写3个构造方法,第四个构造方法需要api21以上可以使用,具体每个构造方法先不深究.

2, 初始画笔,设置画笔

3,在onDraw中,使用canvas.drawText方法,传入内容,x,y坐标,和画笔.需要注意的是这个x和y是字体左下角的坐标,并不是中心点

4,要计算出每个字母的位置,可以使用画笔去测量这个字符串的宽度.

5,在onDraw中尽量不要创建过多的对象,因为onDraw过程中创建过多的对象,会造成界面的卡顿.

6,重写onTouchEvent方法,返回true,拦截事件,处理点击事件和滑动以及抬起事件.

7,回调接口,将选中的字符串传递出去,以便调用时对选中的字符串进行其他处理,比如ListView选项.

Tips:该自定义View可以熟悉自定义View的流程,画笔,画布的使用等.还可以经过修改使其动态显示右侧列表选项,但是要注意在数据返回设置给View之前,不能让View进行显示.否则会产生Null.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值