Android Custom Controls - Alphabetical Index

1. Create LetterSildeView to inherit View

  First define two brushes, one is used to draw untouched painting letters, and the other is to paint painted letters after touching

 private Paint paint;//未触摸
 private Paint touchPaint;//触摸

  Then define a char array that stores 26 letters

 private char[] letters = new char[26];//存放字母数组

 Data initialization is performed in the constructor, the code is as follows:

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

public LetterSildeView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
}

public LetterSildeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化未触摸画笔
        paint = new Paint(); 
        paint.setAntiAlias(true);
        paint.setColor(Color.BLACK);
        paint.setTextSize(sp2px(12));
        //初始化触摸画笔
        touchPaint = new Paint();
        touchPaint.setAntiAlias(true);
        touchPaint.setColor(Color.RED);
        touchPaint.setTextSize(sp2px(12));
        getLetters();
}
/**初始化26个字母*/
private void getLetters(){
     for(int i=0;i<26;i++){
        letters[i] = (char)(i+65);
     }
}

sp to px:

private float sp2px(int sp){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());
    }

Measure the width of the entire control:

@Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        textWitdh = (int) paint.measureText("A");//测量单个字母的宽度,这里以A为例子
        int width = getPaddingLeft() + textWitdh + getPaddingRight();//整个控件的宽度应该是A字母+paddingLeft左边的距离+paddingRight右边的距离
        setMeasuredDimension(width,MeasureSpec.getMode(heightMeasureSpec));//设置控件宽高度
}

Draw letters through the onDraw method:

@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int itemHeight = getHeight()/letters.length;//每个控件的宽度
        int dx = getPaddingLeft();//绘画字母x轴的位置
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        int dy = (int) ((fontMetrics.bottom-fontMetrics.top)/2 - fontMetrics.bottom);//获取字母中线
        for(int i=0;i<letters.length;i++){
            int baseLine = i * itemHeight + itemHeight/2 +dy; //获取每个字母的基线
            if(currentNum==i){ //判断这个字母是否被触摸
                canvas.drawText(String.valueOf(letters[i]),dx,baseLine,touchPaint);//绘画被触摸的字母
            }else{//没有被触摸
                canvas.drawText(String.valueOf(letters[i]),dx,baseLine,paint);//绘画未触摸的字母
            }
        }
    }

Perform touch judgment in the onTouchu event:

 @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                    float y = event.getY();
                    float itemHeight = getHeight()/26;//每个控件的高度
                    currentNum =  (int) (y/itemHeight);//获取当前触摸是哪个字母
                    //获取被触摸的字母
                    if(currentNum>=letters.length){
                        currentNum = letters.length-1;
                    }if(currentNum<0){
                        currentNum = 0;
                    }
                    //将触摸的数据通过接口回调给调用者
                    if(onLetterStrBackListener!=null)
                        onLetterStrBackListener.onLetterTouchStrBack(String.valueOf(letters[currentNum]),getLeft()-getWidth()-30,y>getHeight()?getHeight()-25:y-25);
                    invalidate();
                    break;
            case MotionEvent.ACTION_UP:
                    if(onLetterStrBackListener!=null)
                        onLetterStrBackListener.onTouchCanleListener();
                    currentNum = -1;
                    invalidate();
                    break;
        }
        return true;
    }

Define the callback event code:

OnLetterStrBackListener onLetterStrBackListener;
    public void setOnLetterStrBackListener(OnLetterStrBackListener onLetterStrBackListener2){
        this.onLetterStrBackListener = onLetterStrBackListener2;
    }
    public interface OnLetterStrBackListener{
        void onLetterTouchStrBack(String letter,float x,float y);//触摸字母的回传,以及x轴,y轴的位置
        void onTouchCanleListener();
    }

Full code:


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.util.TypedValue;
import android.view.MotionEvent;
import android.view.View;
import androidx.annotation.Nullable;

public class LetterSildeView extends View {
    private Paint paint;
    private Paint touchPaint;
    private char[] letters = new char[26];
    private int textWitdh=0;
    private int currentNum = -1;
    public LetterSildeView(Context context) {
        this(context,null);
    }

    public LetterSildeView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public LetterSildeView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setColor(Color.BLACK);
        paint.setTextSize(sp2px(12));

        touchPaint = new Paint();
        touchPaint.setAntiAlias(true);
        touchPaint.setColor(Color.RED);
        touchPaint.setTextSize(sp2px(12));
        getLetters();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        textWitdh = (int) paint.measureText("A");//测量单个字母的宽度,这里以A为例子
        int width = getPaddingLeft() + textWitdh + getPaddingRight();//整个控件的宽度应该是A字母+paddingLeft左边的距离+paddingRight右边的距离
        setMeasuredDimension(width,MeasureSpec.getMode(heightMeasureSpec));//设置控件宽高度
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        int itemHeight = getHeight()/letters.length;//每个控件的宽度
        int dx = getPaddingLeft();//绘画字母x轴的位置
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        int dy = (int) ((fontMetrics.bottom-fontMetrics.top)/2 - fontMetrics.bottom);//获取字母中线
        for(int i=0;i<letters.length;i++){
            int baseLine = i * itemHeight + itemHeight/2 +dy; //获取每个字母的基线
            if(currentNum==i){ //判断这个字母是否被触摸
                canvas.drawText(String.valueOf(letters[i]),dx,baseLine,touchPaint);//绘画被触摸的字母
            }else{//没有被触摸
                canvas.drawText(String.valueOf(letters[i]),dx,baseLine,paint);//绘画未触摸的字母
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                    float y = event.getY();
                    float itemHeight = getHeight()/26;
                    currentNum =  (int) (y/itemHeight);
                    if(currentNum>=letters.length){
                        currentNum = letters.length-1;
                    }if(currentNum<0){
                        currentNum = 0;
                    }
                    if(onLetterStrBackListener!=null)
                        onLetterStrBackListener.onLetterTouchStrBack(String.valueOf(letters[currentNum]),getLeft()-getWidth()-30,y>getHeight()?getHeight()-25:y-25);
                    invalidate();
                    break;
            case MotionEvent.ACTION_UP:
                    if(onLetterStrBackListener!=null)
                        onLetterStrBackListener.onTouchCanleListener();
                    currentNum = -1;
                    invalidate();
                    break;
        }
        return true;
    }


    private float sp2px(int sp){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources().getDisplayMetrics());
    }

    private void getLetters(){
        for(int i=0;i<26;i++){
            letters[i] = (char)(i+65);
        }
    }

    OnLetterStrBackListener onLetterStrBackListener;
    public void setOnLetterStrBackListener(OnLetterStrBackListener onLetterStrBackListener2){
        this.onLetterStrBackListener = onLetterStrBackListener2;
    }
    public interface OnLetterStrBackListener{
        void onLetterTouchStrBack(String letter,float x,float y);
        void onTouchCanleListener();
    }
}

Use in layouts:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.xlkj.custom_view.LetterSildeView
        android:id="@+id/letter_slide"
        android:paddingRight="3dp"
        android:paddingLeft="3dp"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.977"
        app:layout_constraintStart_toStartOf="parent"
        tools:layout_editor_absoluteY="16dp" />

    <TextView
        android:id="@+id/tv_show"
        android:gravity="center"
        android:background="@drawable/tv_show_bg"
        android:textColor="#fff"
        android:textSize="20sp"
        android:layout_width="30dp"
        android:layout_height="30dp"
        android:text="A"
        app:layout_constraintBottom_toTopOf="@+id/waatting_view"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/ratingBar" />
</androidx.constraintlayout.widget.ConstraintLayout>

Called in code:

public class MainActivity extends AppCompatActivity implements LetterSildeView.OnLetterStrBackListener {
    private LetterSildeView letterSildeView;
    private TextView showLetter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        showLetter = this.findViewById(R.id.tv_show);
        letterSildeView = this.findViewById(R.id.letter_slide);
        letterSildeView.setOnLetterStrBackListener(this);
    }

    @Override
    public void onLetterTouchStrBack(String letter,float x,float y) {
        showLetter.setVisibility(View.VISIBLE);
        showLetter.setText(letter);
        showLetter.setX(x);
        showLetter.setY(y);
    }

    @Override
    public void onTouchCanleListener() {
        showLetter.setVisibility(View.GONE);
    }
}

The running effect is as follows:

 

Guess you like

Origin blog.csdn.net/h5630/article/details/116486084