欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义字母选择侧边栏

程序员文章站 2022-03-07 23:05:13
本文实例为大家分享了android自定义字母选择侧边栏的具体代码,供大家参考,具体内容如下lettersidebar.javapackage com.zb.customview.widgets; im...

本文实例为大家分享了android自定义字母选择侧边栏的具体代码,供大家参考,具体内容如下

lettersidebar.java

package com.zb.customview.widgets;
 
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.text.textutils;
import android.util.attributeset;
import android.view.motionevent;
import android.view.view;
 
import androidx.annotation.nullable;
 
import com.zb.customview.r;
 
public class lettersidebar extends view {
 
    private paint mpaint;
    private int color, selectedcolor;
    private float textsize, spacing;
    private string mchoosing = "z";
    private onletterselectedlistener listener;
    private int width, height;
 
    private 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"};
 
    public interface onletterselectedlistener {
        //空表示取消选中
        void onselected(string letter);
    }
 
    public void setonletterselectedlistener(onletterselectedlistener listener) {
        this.listener = listener;
    }
 
    public lettersidebar(context context) {
        this(context, null);
    }
 
    public lettersidebar(context context, @nullable attributeset attrs) {
        super(context, attrs);
        if(null != attrs) {
            typedarray ta = context.obtainstyledattributes(attrs, r.styleable.lettersidebar);
            color = ta.getcolor(r.styleable.lettersidebar_lettersidebar_textcolor, color.black);
            selectedcolor = ta.getcolor(r.styleable.lettersidebar_lettersidebar_textselectedcolor, color.red);
            textsize = ta.getdimensionpixelsize(r.styleable.lettersidebar_lettersidebar_textsize, sp2px(12));
            spacing = ta.getdimensionpixelsize(r.styleable.lettersidebar_lettersidebar_spacing, dp2px(5));
            ta.recycle();
        }
        init();
    }
 
    private void init() {
        mpaint = new paint();
        mpaint.setantialias(true);
        mpaint.setcolor(color);
        mpaint.settextsize(textsize);
    }
 
    @override
    protected void ondraw(canvas canvas) {
        drawtext(canvas);
        drawselectedtext(canvas, mchoosing);
    }
 
    private void drawtext(canvas canvas) {
        mpaint.setcolor(color);
        for (int i=0; i<letters.length; i++) {
            drawletterat(canvas, i, letters[i]);
        }
    }
 
    private void drawselectedtext(canvas canvas, string selected) {
        if(textutils.isempty(selected))
            return;
        mpaint.setcolor(selectedcolor);
        int position = -1;
        for(int i=0; i<letters.length; i++) {
            if(selected.equals(letters[i])) {
                position = i;
                break;
            }
        }
        if(position < 0 || position >= letters.length)
            return;
        drawletterat(canvas, position, selected);
    }
 
    @override
    public boolean ontouchevent(motionevent event) {
        int action = event.getaction();
        switch (action) {
            case motionevent.action_down:
            case motionevent.action_move:
                float x = event.getx();
                float y = event.gety();
                if(istouchinsideview(x, y)) {
                    //触摸在控件内
                    int position = caculateposition(y);
                    if(position >= 0 && position < letters.length) {
                        //合规位置
                        string letter = letters[position];
                        if(!letter.equals(mchoosing)) { //与选中的不符 去刷新控件
                            mchoosing = letter;
                            performlistener(mchoosing);
                            invalidate();
                        }
                    } else {
                        //不合规位置
                        if(null != mchoosing) {
                            mchoosing = null;
                            performlistener(mchoosing);
                            invalidate();
                        }
                    }
                } else if(null != mchoosing) { //点击事件不在view内部
                    mchoosing = null;
                    performlistener(mchoosing);
                    invalidate();//触摸在view之外 取消选中
                }
                return true;
            default:
                if(mchoosing != null) {
                    mchoosing = null;
                    performlistener(mchoosing);
                    invalidate();
                }
                break;
        }
        return super.ontouchevent(event);
    }
 
    private void performlistener(string letter) {
        if(null != listener)
            listener.onselected(letter);
    }
 
    private boolean istouchinsideview(float x, float y) {
        //左右可以适当判断在控件内
        if(x >= 0 && x <= width && y >= getpaddingtop() && y < height)
            return true;
        return false;
    }
 
    /**
     * 计算触摸的位置
     * @param y
     * @return
     */
    private int caculateposition(float y) {
        float heightwithoutpadding = height - getpaddingtop() - getpaddingbottom();
        float eachelementheight = heightwithoutpadding / letters.length;
        y -= getpaddingtop();
        int position = (int) (y / eachelementheight);
        return position;
    }
 
    private void drawletterat(canvas canvas, int position, string letter) {
 
        float heightforeach = ((height * 1f - getpaddingtop() - getpaddingbottom())
                - (letters.length - 1) * spacing) / letters.length;
        float spacinginup = spacing * (position - 1);
        if(spacinginup < 0)
            spacinginup = 0;
        float currenttop = getpaddingtop() + (heightforeach * position) + spacinginup;
        float currentbottom = currenttop + heightforeach;
        paint.fontmetrics fmi = mpaint.getfontmetrics();
        float x = (width - getpaddingleft() - getpaddingright() - mpaint.measuretext(letter)) / 2f + getpaddingleft();
        float baseline = (fmi.descent + math.abs(fmi.ascent)) / 2f - fmi.descent;
        float y = (currentbottom + currenttop) / 2f + baseline;
        canvas.drawtext(letter, 0, 1, x, y, mpaint);
    }
 
    @override
    protected void onlayout(boolean changed, int left, int top, int right, int bottom) {
        super.onlayout(changed, left, top, right, bottom);
        if(changed) {
            width = getwidth();
            height = getheight();
        }
    }
 
    @override
    protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
        super.onmeasure(widthmeasurespec, heightmeasurespec);
        int textwidth = (int) (getpaddingleft() + getpaddingright() + mpaint.measuretext("a"));
        rect textbounds = new rect();
        mpaint.gettextbounds("a", 0, 1, textbounds);
        int singletextheight = textbounds.height();
        int totalheight = (int) (27f * singletextheight + 26f * spacing) + getpaddingbottom() + getpaddingtop();//26个字母+1个#
 
        int widthmode = measurespec.getmode(widthmeasurespec);
        int heightmode = measurespec.getmode(widthmeasurespec);
        int specwidth = measurespec.getsize(widthmeasurespec);
        int specheight = measurespec.getsize(widthmeasurespec);
        int realwidth, realheight;
        if(widthmode == measurespec.exactly) {
            realwidth = specwidth;
        } else {
            realwidth = textwidth;
        }
        if(heightmode == measurespec.exactly) {
            realheight = specheight;
        } else {
            realheight = totalheight;
        }
        setmeasureddimension(realwidth, realheight);
    }
 
    protected int dp2px(int dp) {
        return (int) (getcontext().getresources().getdisplaymetrics().density * dp + 0.5);
    }
    protected int sp2px(int sp) {
        return (int) (getcontext().getresources().getdisplaymetrics().scaleddensity * sp + 0.5);
    }
}

attrs.xml

<declare-styleable name="lettersidebar"> 
<attr name="lettersidebar_textcolor" format="color"/> 
<attr name="lettersidebar_textselectedcolor" format="color"/> 
<attr name="lettersidebar_textsize" format="dimension"/> 
<attr name="lettersidebar_spacing" format="dimension"/> 
</declare-styleable>

layout.xml

<com.zb.customview.widgets.lettersidebar
        android:id="@+id/lettersidebar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:lettersidebar_textsize="14sp"
        app:lettersidebar_textcolor="#ffffff"
        android:padding="10dp"
        app:lettersidebar_textselectedcolor="#ff0000"
        app:lettersidebar_spacing="2dp"
        app:layout_constraintright_torightof="parent"
        app:layout_constrainttop_totopof="parent"
        app:layout_constraintbottom_tobottomof="parent"
        android:background="#a4a4a4"/>

代码中使用

sidebar.setonletterselectedlistener(new lettersidebar.onletterselectedlistener() {
            @override
            public void onselected(string letter) {
                if(textutils.isempty(letter)) {
                    p.p("取消选中");
                    lettertxt.setvisibility(view.gone);
                } else {
                    p.p("选中" + letter);
                    lettertxt.settext(letter);
                    lettertxt.setvisibility(view.visible);
                }
            }
        });

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。