Android 自定义View 之 Mac地址输入框(下)

简介: Android 自定义View 之 Mac地址输入框(下)

Android 自定义View 之 Mac地址输入框(上)https://developer.aliyun.com/article/1407633


下面要进行绘制了,绘制分为两步,绘制方框和绘制文字。


1. 绘制方框

  首先是绘制方框,在自定义View中新增一个drawBox()方法,代码如下:

    /**
     * 绘制方框
     */
    private void drawBox(Canvas canvas) {
        //每个方框的间距
        int margin = Utils.dp2px(mContext, mBoxMargin);
        for (int i = 0; i < mBoxNum; i++) {
            //绘制矩形框,需要左、上、右、下四个点的位置
            float left = i * mBoxWidth + i * margin;
            float top = 0f;
            float right = (i + 1) * mBoxWidth + i * margin;
            float bottom = mBoxWidth;
            RectF rectF = new RectF(left, top, right, bottom);
            //绘制圆角矩形框
            int radius = Utils.dp2px(mContext, mBoxCornerRadius);
            canvas.drawRoundRect(rectF, radius, radius, mBoxPaint);
            //绘制圆角矩形边框
            float strokeWidth = mBoxStrokeWidth / 2;
            RectF strokeRectF = new RectF(left + strokeWidth, top + strokeWidth, right - strokeWidth, bottom - strokeWidth);
            float strokeRadius = radius - strokeWidth;
            canvas.drawRoundRect(strokeRectF, strokeRadius, strokeRadius, mBoxStrokePaint);
        }
    }


  这里绘制方框有必要好好说明一下,首先是这个间距,就是方框的间距,已经说过了,然后我们根据设置的方框数量就行遍历,需要绘制6个方框,那么,int = 0,进入循环,绘制第一个方框,首先我们需要确定方框左、上、右、下4个坐标点的坐标,那么我们将值代入到代码中看看。

float left = 0 * 48 + 0 * 4;
float top = 0f;
float right = (0 + 1) * 48 + 0 * 4;
float bottom = 48;


  得出的结果就是:left :0、top:0、right :48、bottom :48,然后通过四个点得到一个矩形,因为是圆角方框,所以在自定义View中声明变量:

    private float mBoxCornerRadius = 8f;


  然后得到px的radiu,再通过canvas.drawRoundRect()方法绘制一个圆角矩形,圆角矩形绘制好之后,我们可以顺便绘制圆角矩形的圆角边框,注意看下面这几行代码:

float strokeWidth = mBoxStrokeWidth / 2;
RectF strokeRectF = new RectF(left + strokeWidth, top + strokeWidth, right - strokeWidth, bottom - strokeWidth);
float strokeRadius = radius - strokeWidth;


  首先是这个mBoxStrokeWidth / 2,为什么要这么做呢?这是因为绘制边框的时候实际上不是居内绘制,而是居中往两侧绘制,而我要做的是居内绘制,为了保持绘制的边框不至于太粗我就除以2,只用一半的宽度,然后就是绘制边框的时候,左、上都加上了这个边框的宽,右、下都减去了这个边框的宽,这样做是为了让边框完整置于圆角矩形里面,下面的图中右侧的示例就是我想要的。

413ebdb42a9847c798094c83df9c0f69.png

那么第一个方框绘制后如下图所示。

56ad58f2a38c4659830301348780e3d6.png

  方框的背景颜色我默认设置成白色了,可以自行修改,或者在xml中进行属性设置,那么按照刚才的思路,现在循环第2次,i = 1;

float left = 1 * 48 + 1 * 4;
float top = 0f;
float right = (1 + 1) * 48 + 1 * 4;
float bottom = 48;


得出的结果就是:left :52、top:0、right :100、bottom :48,那么绘制出来第二个框如下图所示:

778c34a75bc5407b9638ec32eebe498b.png

那么按照上述的说明我相信你已经知道是怎么绘制的了,那么下面我们就可以绘制文字了。


2. 绘制文字

  现在方框有了,而文字绘制我们需要绘制在方框的中间,首先我们声明变量,代码如下:

    private final int mMacLength = 6;
    private final String[] macAddressArray = new String[mMacLength];


然后我们在自定义View中新增一个drawMacAddress()方法。

    /**
     * 绘制Mac地址
     */
    private void drawMacAddress(Canvas canvas) {
        int boxMargin = Utils.dp2px(mContext, mBoxMargin);
        for (int i = 0; i < macAddressArray.length; i++) {
            if (macAddressArray[i] != null) {
                //绘制的文字
                String content = macAddressArray[i];
                //获取绘制的文字边界
                mTextPaint.getTextBounds(content, 0, content.length(), mTextRect);
                //绘制的位置
                int offset = (mTextRect.top + mTextRect.bottom) / 2;
                //绘制文字,需要确定起始点的X、Y的坐标点
                float x = (float) (getPaddingLeft() + mBoxWidth * i + boxMargin * i + mBoxWidth / 2);
                float y = (float) (getPaddingTop() + mBoxWidth / 2) - offset;
                //绘制文字
                canvas.drawText(content, x, y, mTextPaint);
            }
        }
    }


假设地址数组第一个值是0A,然后通过mTextPaint.getTextBounds()得到这个文字的边界,就相当于得到一个文字的边界框,然后就是通过边界框的上+下的坐标 / 2的边界框的中间位置,因为文字的绘制是从左下角到右上角进行绘制的。最重要的就是去顶起始点的x、y轴坐标,

f21617781c6d4946a957fe7d81585322.png

将 i = 0 ,offset = 12代入进去。

float x = (float) (0 + 48 * 0 + 4 * 0 + 48 / 2);
float y = (float) (0 + 48 / 2) - 12;


最终 x = 24,y = 36。

然后绘制出来的结果如下图所示:

429e7c3f9d704d30873ef956a645ef73.png

  后面的绘制也是一样的道理,现在两个绘制方法都写好了,需要在onDraw()中调用,在自定义View中新增如下代码:

    /**
     * View的绘制
     *
     * @param canvas 画布
     */
    @Override
    protected void onDraw(Canvas canvas) {
        //绘制方框
        drawBox(canvas);
        //绘制Mac地址
        drawMacAddress(canvas);
    }


⑤ 输入

  绘制的处理已经完成了,那么作为一个蓝牙Mac地址输入框,我们需要输入的数据是什么呢?0、1、2、3、4、5、6、7、8、9、A、B、C、E、F、G,像上述的这些数据表示16进制的,那么如果使用系统的软键盘进行输入,我们可能需要在输入的过程中选择字符键盘,而这个字符键盘上其他的英文字母或者标点符号右不是我所需要的,那么为了方便,我打算自己做一个键盘来进行输入。


1. 键盘布局

  首先在layout下创建一个lay_hex_keyboard.xml,用于作为键盘的布局,代码如下所示:

<?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="wrap_content"
    android:background="#eff4f9">
    <Button
        android:id="@+id/btn_a"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="A"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_9"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/btn_9"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="9"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_8"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_a"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/btn_8"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="8"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_7"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_9"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/btn_7"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="7"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_del"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_8"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/btn_del"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:layout_marginEnd="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="删除"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_7"
        app:layout_constraintTop_toTopOf="parent" />
    <Button
        android:id="@+id/btn_b"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="B"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_6"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@+id/btn_a"
        app:layout_constraintTop_toBottomOf="@+id/btn_a" />
    <Button
        android:id="@+id/btn_6"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="6"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_5"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_b"
        app:layout_constraintTop_toBottomOf="@+id/btn_a" />
    <Button
        android:id="@+id/btn_5"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="5"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_4"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_6"
        app:layout_constraintTop_toBottomOf="@+id/btn_a" />
    <Button
        android:id="@+id/btn_4"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="4"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_delete_all"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_5"
        app:layout_constraintTop_toBottomOf="@+id/btn_a" />
    <Button
        android:id="@+id/btn_delete_all"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="全删"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="@+id/btn_del"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_4"
        app:layout_constraintTop_toBottomOf="@+id/btn_a" />
    <Button
        android:id="@+id/btn_c"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="C"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_3"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@+id/btn_b"
        app:layout_constraintTop_toBottomOf="@+id/btn_b" />
    <Button
        android:id="@+id/btn_3"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="3"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_2"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_c"
        app:layout_constraintTop_toBottomOf="@+id/btn_b" />
    <Button
        android:id="@+id/btn_2"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="2"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_1"
        app:layout_constraintStart_toEndOf="@+id/btn_3"
        app:layout_constraintTop_toBottomOf="@+id/btn_b" />
    <Button
        android:id="@+id/btn_1"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="1"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="@+id/btn_4"
        app:layout_constraintStart_toEndOf="@+id/btn_2"
        app:layout_constraintTop_toBottomOf="@+id/btn_b" />
    <Button
        android:id="@+id/btn_d"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginTop="4dp"
        android:layout_marginBottom="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="D"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btn_e"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@+id/btn_c"
        app:layout_constraintTop_toBottomOf="@+id/btn_c" />
    <Button
        android:id="@+id/btn_e"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="E"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_f"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_d"
        app:layout_constraintTop_toBottomOf="@+id/btn_c" />
    <Button
        android:id="@+id/btn_f"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="F"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_0"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_e"
        app:layout_constraintTop_toBottomOf="@+id/btn_c" />
    <Button
        android:id="@+id/btn_0"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="0"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toStartOf="@+id/btn_complete"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_f"
        app:layout_constraintTop_toBottomOf="@+id/btn_c" />
    <com.google.android.material.button.MaterialButton
        android:id="@+id/btn_complete"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="4dp"
        android:layout_marginTop="4dp"
        android:backgroundTint="@color/key_complete_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="完成"
        android:textColor="@color/white"
        android:textSize="16sp"
        app:iconGravity="start|end"
        app:layout_constraintBottom_toBottomOf="@+id/btn_0"
        app:layout_constraintEnd_toEndOf="@+id/btn_delete_all"
        app:layout_constraintStart_toEndOf="@+id/btn_0"
        app:layout_constraintTop_toBottomOf="@+id/btn_delete_all" />
</androidx.constraintlayout.widget.ConstraintLayout>


布局的预览效果如下图所示:

a11ea0fb014f43aa97b52367f3ff74d7.png


  这个布局从使用上来说就很简单了,基本上一目了然,这里我们可以写一个接口用来处理键盘上按钮点击的事件。


2. 键盘接口

  在com.llw.easyview下新建一个HexKeyboardListener接口,代码如下所示:

public interface HexKeyboardListener {
    /**
     * Hex字符
     * @param hex 0~9,A~F
     */
    void onHex(String hex);
    /**
     * 删除
     */
    void onDelete();
    /**
     * 全删
     */
    void onDeleteAll();
    /**
     * 完成
     */
    void onComplete();
}


  现在接口有了,接口中的方法基本上覆盖了键盘上所有按钮点击时触发的事件处理,下面我们来写一个弹窗,用来点击Mac地址输入框时弹出这个键盘。


3. 键盘弹窗

  这个弹窗,我就写在Utils类中了,在里面新增如下方法代码:

    /**
     * 显示Hex键盘弹窗
     *
     * @param context  上下文
     * @param listener Hex键盘按键监听
     */
    public static void showHexKeyboardDialog(@NonNull Context context, @NonNull HexKeyboardListener listener) {
        BottomSheetDialog dialog = new BottomSheetDialog(context);
        //根据xml获取布局视图
        View view = LayoutInflater.from(context).inflate(R.layout.lay_hex_keyboard, null, false);
        //点击按键触发接口回调
        view.findViewById(R.id.btn_a).setOnClickListener(v -> listener.onHex("A"));
        view.findViewById(R.id.btn_b).setOnClickListener(v -> listener.onHex("B"));
        view.findViewById(R.id.btn_c).setOnClickListener(v -> listener.onHex("C"));
        view.findViewById(R.id.btn_d).setOnClickListener(v -> listener.onHex("D"));
        view.findViewById(R.id.btn_e).setOnClickListener(v -> listener.onHex("E"));
        view.findViewById(R.id.btn_f).setOnClickListener(v -> listener.onHex("F"));
        view.findViewById(R.id.btn_0).setOnClickListener(v -> listener.onHex("0"));
        view.findViewById(R.id.btn_1).setOnClickListener(v -> listener.onHex("1"));
        view.findViewById(R.id.btn_2).setOnClickListener(v -> listener.onHex("2"));
        view.findViewById(R.id.btn_3).setOnClickListener(v -> listener.onHex("3"));
        view.findViewById(R.id.btn_4).setOnClickListener(v -> listener.onHex("4"));
        view.findViewById(R.id.btn_5).setOnClickListener(v -> listener.onHex("5"));
        view.findViewById(R.id.btn_6).setOnClickListener(v -> listener.onHex("6"));
        view.findViewById(R.id.btn_7).setOnClickListener(v -> listener.onHex("7"));
        view.findViewById(R.id.btn_8).setOnClickListener(v -> listener.onHex("8"));
        view.findViewById(R.id.btn_9).setOnClickListener(v -> listener.onHex("9"));
        view.findViewById(R.id.btn_del).setOnClickListener(v -> listener.onDelete());
        view.findViewById(R.id.btn_delete_all).setOnClickListener(v -> listener.onDeleteAll());
        view.findViewById(R.id.btn_complete).setOnClickListener(v -> {
            listener.onComplete();
            dialog.dismiss();
        });
        //点击外部不消失
        dialog.setCancelable(false);
        //设置内容视图
        dialog.setContentView(view);
        if (dialog.getWindow() != null) {
            //去掉弹窗背景透明
            WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
            params.dimAmount = 0.0f;
            dialog.getWindow().setAttributes(params);
        }
        //显示弹窗
        dialog.show();
    }


  这里就是一个底部弹窗,然后设置布局视图,设置接口回调,设置背景透明,最后显示出来。那么下一步要做的就是点击输入框调用这个弹窗显示键盘。


4. 显示键盘

  在View中是可以获取到点击触摸事件的,那么我们可以在自定义View中新增如下代码:

    /**
     * 触摸事件
     */
    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event != null) {
            if (event.getAction() == MotionEvent.ACTION_DOWN) {
                //显示Hex键盘弹窗
                Utils.showHexKeyboardDialog(mContext, this);
                return true;
            }
        }
        return super.onTouchEvent(event);
    }


  这里的代码就是当我们的手机点击这个Mac地址输入框的时候,会先触发触摸事件,然后才是点击事件,而在这里我们就是在触摸到的时候显示键盘弹窗,然后返回 true,这里就会进行事件的拦截,这里的这个this,就是我们当前的自定义View需要实现的回调接口,将鼠标放在这个this后面,然后Alt + Enter的组合键,会出现弹窗,如下图所示:

c559d15e49734fd4841133de8d14611e.png

这里点击第四项,会出现一个弹窗,如图所示:

b1bdf5a8af704b6984e0f61c1687c1e4.png

  点击OK就可以快速实现这个接口的回调,重写接口的方法,你会看到自定义View新增了四个方法,代码如下:

    @Override
    public void onHex(String hex) {
    }
    @Override
    public void onDelete() {
    }
    @Override
    public void onDeleteAll() {
    }
    @Override
    public void onComplete() {
    }


5. 处理输入

  现在自定义View已经实现了键盘的点击事件回调,那么下面就是怎么处理这些事件,首先我们需要声明两个变量

    private final int mInputLength = 12;
    private final String[] inputArray = new String[mInputLength];
    private int currentInputPosition = 0;
    /**
     * 操作标识
     * -1:添加,
     * 0:删除,
     * 1:全删
     */
    private int flag = -1;


  这个地方就是输入的长度、保存输入的数组、当前输入的位置,这里的12,就是我们实际上输入一个完整的Mac地址,去掉分隔符实际长度是12,而分隔符我们可以自己去设置要用什么分隔符。首先是修改绘制文字的处理,什么时候会触发绘制文字呢?当我们修改inputArray的内容时,添加、删除之类的操作,这里还有一个标识位用来记录当前的绘制文字方式,在自定义View中添加一个处理Mac文字绘制的方法,代码如下:

    /**
     * 处理Mac地址绘制
     */
    private void processMacDraw() {
        if (flag == 1) {    //全删
            currentInputPosition = 0;
            Arrays.fill(inputArray,null);
            Arrays.fill(macAddressArray,"");
        } else {    //添加或删除
            String hex = "";
            int hexPos = 0;
            for (String input : inputArray) {
                if (input == null) {
                    input = "";
                }
                hex = hex + input;
                macAddressArray[hexPos] = hex;
                if (hex.length() == 2) {
                    hexPos++;
                    hex = "";
                }
            }
        }
        //刷新View
        postInvalidate();
    }


  这个方法就是当inputArray发生变化时,同时改变macAddressArray,而我们的文字绘制是根据macAddressArray来的。当点击全删的时候就两个数组置为null和空字符串。然后就是添加或删除的时候遍历inputArray,满足两个字符长度就给macAddressArray进行一次赋值,最后调用postInvalidate()刷新View,会重新调用onDraw进行绘制。下面我们再修改一下onHex()方法,代码如下:

    @Override
    public void onHex(String hex) {
        //输入长度满足12
        if (currentInputPosition == mInputLength) return;
        //不满足12
        inputArray[currentInputPosition] = hex;
        currentInputPosition++;
        flag = -1;
        processMacDraw();   //添加时绘制
    }


  这里的代码就是在inputArray中添加数据,然后调用绘制文字方法,下面再修改一下onDelete()方法,代码如下:

    @Override
    public void onDelete() {
        if (currentInputPosition == 0) return;
        currentInputPosition--;
        inputArray[currentInputPosition] = null;
        flag = 0;
        processMacDraw();   //删除时绘制
    }


  删除后绘制,最后我们修改一下onDeleteAll()方法,代码如下:

    @Override
    public void onDeleteAll() {
        flag = 1;
        processMacDraw();   //全删时绘制
    }


  最后就是在输入完成的时候获取当前输入的Mac地址数据,在自定义View中新增getMacAddress()方法。

    /**
     * 获取Mac地址
     * @return 完整的Mac地址
     */
    public String getMacAddress() {
        StringBuilder builder = new StringBuilder();
        for (String macAddress : macAddressArray) {
            if (macAddress == null) continue;
            if (macAddress.isEmpty()) continue;
            if (builder.toString().isEmpty()) {
                builder.append(macAddress);
            } else {
                builder.append(mSeparator == null ? ":" : mSeparator).append(macAddress);
            }
        }
        return builder.toString();
    }


  最后我们修改onComplete()方法,在里面进行打印,代码如下所示:

    @Override
    public void onComplete() {
        Log.d("TAG", "onComplete: " + getMacAddress());
    }


四、使用自定义View


  现在自定义View写好了,可以使用了,修改activity_main.xml中的代码,如下所示:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="16dp"
    tools:context=".MainActivity">
    <com.llw.easyview.MacAddressEditText
        android:id="@+id/mac_et"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
    <Button
        android:id="@+id/btn_mac"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="获取地址" />
</LinearLayout>


  如果你发现XML预览不了,看不到这个自定义View,就Rebuild Project一下,就能看到了,预览效果如下图所示:

ee1697d7dc254383ac4d7343470946ef.png

  下面进入到MainActivity中去使用,修改代码如下所示:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MacAddressEditText macEt = findViewById(R.id.mac_et);
        Button btnMac = findViewById(R.id.btn_mac);
        btnMac.setOnClickListener(v -> {
            String macAddress = macEt.getMacAddress();
            if (macAddress.isEmpty()){
                Toast.makeText(this, "请输入Mac地址", Toast.LENGTH_SHORT).show();
                return;
            }
            btnMac.setText(macAddress);
        });
    }
}


  这里的代码就很简单,获取View,然后点击按钮时获取输入框的值,获取到值显示在按钮上,下面运行测试一下。

86ac87104f894aa9bb254a478d806e25.gif


五、源码


如果对你有所帮助的话,不妨 Star 或 Fork,山高水长,后会有期~

源码地址:EasyView

相关文章
|
4天前
|
Android开发 异构计算 前端开发
Android显示原理,安卓自定义view面试
Android显示原理,安卓自定义view面试
|
4天前
|
Android开发 开发者 容器
Android自定义View:MeasureSpec的真正意义与View大小控制
Android自定义View:MeasureSpec的真正意义与View大小控制
|
5天前
|
Java Android开发
Android 12 自定义底部导航栏
Android 12 自定义底部导航栏
22 4
|
6天前
|
存储 消息中间件 缓存
Android应用开发:实现自定义View的高效绘制
【5月更文挑战第12天】 在Android开发中,创建高性能的自定义视图是一项挑战,它要求开发者深入理解Android的绘图机制以及UI渲染过程。本文将探讨如何优化自定义View的绘制流程,减少不必要的重绘和布局计算,以提升应用的响应速度和流畅度。我们将介绍几种关键策略,包括利用硬件加速、缓存绘制内容和使用高效的数据结构来存储视图状态。通过实例分析和性能对比,读者将学会如何在自己的应用中运用这些技巧,从而打造出更加流畅和响应迅速的用户界面。
|
6天前
|
XML Android开发 数据格式
Android下自定义Button样式
Android下自定义Button样式
13 3
|
Android开发
Android Studio 自定义设置注释模板
Android Studio 自定义设置注释模板
383 0
Android Studio 自定义设置注释模板
|
4天前
|
设计模式 算法 前端开发
Android面经分享,失业两个月,五一节前拿到Offer,设计思想与代码质量优化+程序性能优化+开发效率优化
Android面经分享,失业两个月,五一节前拿到Offer,设计思想与代码质量优化+程序性能优化+开发效率优化
|
2天前
|
编解码 数据库 Android开发
安卓应用开发:打造高效用户界面的五大技巧
【5月更文挑战第18天】在竞争激烈的应用市场中,一个流畅且直观的用户界面(UI)对于安卓应用的成功至关重要。本文将探讨五种提升安卓应用用户界面性能的技巧,包括合理布局设计、优化资源使用、利用硬件加速、内存管理以及响应式编程。通过这些方法,开发者可以创建出既美观又高效的应用体验,从而吸引和保留用户。
|
4天前
|
XML Android开发 数据格式
ConstraintLayout 2,Android高级开发面试
ConstraintLayout 2,Android高级开发面试
|
4天前
|
JSON Android开发 数据格式
Android框架-Google官方Gson解析,android开发实验报告总结
Android框架-Google官方Gson解析,android开发实验报告总结