Android 自定义车牌输入框

需求自定义车牌输入框,可以动态添加输入框个数,7位正常车牌,8位新能源车牌。点击可修改输入过的车牌号码,附带点中效果。此输入框是基于一个方框样式的EditText,按照实际需求进行扩展的。

现已更新至 GitHub可直接依赖。传送门-> LicensePlateUtil ,喜欢的给点个星,谢谢啦。。。

动态效果如下:

Android 自定义车牌输入框_第1张图片


实现思路:

   1.用一个透明的 EditText 与 8 个 TextView 重叠,并给 TextView 设置默认背景
   2.监听 EditText 文本变化,获取输入内容,给 TextView 赋值并改变 TextView 背景
   3.修改已输入文本,设置修改回调监听,根据对应的位置修改或删除对应的文本,同时设置选中背景
   4.EditText输入监听,设置对应位置的显示内容,监听输入完成,监听删除键添加删除回调


贴代码,看逻辑处理

注:下面为最新处理逻辑,若有好的建议请在 gitHub 参与。

public class LicensePlateView extends RelativeLayout implements View.OnClickListener {

    private EditText editText;
    private TextView[] TextViews;
    private Activity mActivity;
    private View mNumView;
    private View mProvinceView;

    private int count = 0;
    private int updateViewPosition;
    private static int ITEM_VIEW_COUNT = 7;

    private LayoutInflater mInflater;

    private String inputContent;
    private boolean isUpdateView = false;//是否更新view内容

    private StringBuffer stringBuffer = new StringBuffer();
    private OnFrameTouchListener mTouchListener = new OnFrameTouchListener();

    private static final int[] VIEW_IDS = new int[]{
            R.id.item_code_iv1, R.id.item_code_iv2, R.id.item_code_iv3,
            R.id.item_code_iv4, R.id.item_code_iv5, R.id.item_code_iv6,
            R.id.item_code_iv7, R.id.item_code_iv8
    };

    private static final int[] VIEW_PROVINCE_IDS = new int[]{
            R.id.select_province_11_tv, R.id.select_province_12_tv, R.id.select_province_13_tv,
            R.id.select_province_14_tv, R.id.select_province_15_tv, R.id.select_province_16_tv,
            R.id.select_province_17_tv, R.id.select_province_18_tv, R.id.select_province_19_tv,
            R.id.select_province_110_tv,
            R.id.select_province_21_tv, R.id.select_province_22_tv, R.id.select_province_23_tv,
            R.id.select_province_24_tv, R.id.select_province_25_tv, R.id.select_province_26_tv,
            R.id.select_province_27_tv, R.id.select_province_28_tv, R.id.select_province_29_tv,
            R.id.select_province_210_tv,
            R.id.select_province_31_tv, R.id.select_province_32_tv, R.id.select_province_33_tv,
            R.id.select_province_34_tv, R.id.select_province_35_tv, R.id.select_province_35_tv,
            R.id.select_province_36_tv, R.id.select_province_37_tv, R.id.select_province_38_tv,
            R.id.select_province_41_tv, R.id.select_province_42_tv, R.id.select_province_43_tv,
            R.id.select_province_delete_tv
    };

    private static final int[] VIEW_NUM_IDS = new int[]{
            R.id.select_num_100_tv, R.id.select_num_101_tv, R.id.select_num_102_tv,
            R.id.select_num_103_tv, R.id.select_num_104_tv, R.id.select_num_105_tv,
            R.id.select_num_106_tv, R.id.select_num_107_tv, R.id.select_num_108_tv,
            R.id.select_num_109_tv,
            R.id.select_num_200_tv, R.id.select_num_201_tv, R.id.select_num_202_tv,
            R.id.select_num_203_tv, R.id.select_num_204_tv, R.id.select_num_205_tv,
            R.id.select_num_206_tv, R.id.select_num_207_tv, R.id.select_num_208_tv,
            R.id.select_num_209_tv,
            R.id.select_num_300_tv, R.id.select_num_301_tv, R.id.select_num_302_tv,
            R.id.select_num_303_tv, R.id.select_num_304_tv, R.id.select_num_305_tv,
            R.id.select_num_306_tv, R.id.select_num_307_tv, R.id.select_num_308_tv,
            R.id.select_num_309_tv,
            R.id.select_num_400_tv, R.id.select_num_401_tv, R.id.select_num_402_tv,
            R.id.select_num_403_tv, R.id.select_num_404_tv, R.id.select_num_405_tv,
            R.id.select_num_406_tv,
            R.id.select_num_delete_tv
    };

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

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

    public LicensePlateView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mActivity = (Activity) context;
        TextViews = new TextView[8];
        View.inflate(context, R.layout.layout_license_plate_frame, this);
        int textsLength = VIEW_IDS.length;
        for (int i = 0; i < textsLength; i++) {
            //textview放进数组中,方便修改操作
            TextViews[i] = (TextView) findViewById(VIEW_IDS[i]);
            TextViews[i].setOnTouchListener(mTouchListener);
        }
        editText = (EditText) findViewById(R.id.item_edittext);
        TextViews[0].setBackgroundResource(R.drawable.license_plate_first_view_blue);//第一个输入框默认设置点中效果
        editText.setCursorVisible(false);//将光标隐藏
        setListener();
        hideSoftInputMethod();
    }

    private void setListener() {

        editText.addTextChangedListener(new TextWatcher() {

            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void afterTextChanged(Editable editable) {
                //如果字符不为""时才进行操作
                if (!editable.toString().equals("")) {
                    if (stringBuffer.length() > ITEM_VIEW_COUNT - 1) {
                        //当文本长度大于 ITEM_VIEW_COUNT - 1 位时 EditText 置空
                        editText.setText("");
                        return;
                    } else {
                        //将文字添加到 StringBuffer                         stringBuffer.append(editable);
                        //添加后将 EditText 置空  造成没有文字输入的错局
                        editText.setText("");
                        //记录 stringBuffer 的长度
                        count = stringBuffer.length();
                        inputContent = stringBuffer.toString();
                        if (count == 1) {
                            mProvinceView.setVisibility(GONE);
                            mNumView.setVisibility(VISIBLE);
                        }
                        if (stringBuffer.length() == ITEM_VIEW_COUNT) {
                            //文字长度为 sbLength  则调用完成输入的监听
                            if (inputListener != null) {
                                inputListener.inputComplete(inputContent);
                                mNumView.setVisibility(GONE);
                            }
                        }
                    }
                    for (int i = 0; i < stringBuffer.length(); i++) {
                        TextViews[i].setText(String.valueOf(inputContent.charAt(i)));
                        TextViews[i].setTextColor(onSetTextColor(R.color.colorBlack));
                    }
                    setTextViewsBackground(count);
                }
            }
        });

        editText.setOnKeyListener(new OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                if (keyCode == KeyEvent.KEYCODE_DEL
                        && event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (onKeyDelete()) {
                        return true;
                    }
                    return true;
                }
                return false;
            }
        });
    }

    /**
     * 设置框内字体颜色
     */
    public int onSetTextColor(int resId) {
        return resId;
    }

    public void setKeyboardContainerLayout(RelativeLayout layout) {
        mInflater = LayoutInflater.from(mActivity);
        mProvinceView = mInflater.inflate(R.layout.layout_keyboard_province, null);
        RelativeLayout.LayoutParams rlParams = new RelativeLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        rlParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
        mProvinceView.setLayoutParams(rlParams);
        mNumView = mInflater.inflate(R.layout.layout_keyboard_num, null);
        mNumView.setLayoutParams(rlParams);
        int provinceLength = VIEW_PROVINCE_IDS.length;
        View view;
        for (int i = 0; i < provinceLength; i++) {
            view = mProvinceView.findViewById(VIEW_PROVINCE_IDS[i]);
            view.setOnClickListener(this);
        }
        int numLength = VIEW_NUM_IDS.length;
        for (int i = 0; i < numLength; i++) {
            view = mNumView.findViewById(VIEW_NUM_IDS[i]);
            view.setOnClickListener(this);
        }
        layout.addView(mProvinceView);
        layout.addView(mNumView);
        mNumView.setVisibility(GONE);
    }

    /**
     * 显示 8 个输入框
     */
    public boolean showLastView() {
        TextViews[7].setVisibility(VISIBLE);
        ITEM_VIEW_COUNT = 8;
        if (!TextUtils.isEmpty(TextViews[6].getText())) {
            mProvinceView.setVisibility(GONE);
            mNumView.setVisibility(VISIBLE);
        }
        if (isUpdateView) {
            setTextViewsBackground(updateViewPosition);
        } else {
            setTextViewsBackground(count);
        }
        return true;
    }

    /**
     * 显示 7 个输入框
     */
    public boolean hideLastView() {
        TextViews[7].setVisibility(GONE);
        ITEM_VIEW_COUNT = 7;
        if (stringBuffer.length() == 8 || stringBuffer.length() == 7) {
            TextViews[7].setText("");
            stringBuffer.delete(7, 8);
            inputContent = stringBuffer.toString();
            count = stringBuffer.length();
            inputListener.inputComplete(inputContent);
            if (!isUpdateView) {
                mNumView.setVisibility(GONE);
            }
        }
        if (isUpdateView) {
            setTextViewsBackground(updateViewPosition);
        } else {
            setTextViewsBackground(count);
        }
        return false;
    }

    private boolean onKeyDelete() {
        if (count == 0) {
            count = 7;
            return true;
        }
        if (stringBuffer.length() > 0) {
            //删除相应位置的字符
            stringBuffer.delete((count - 1), count);
            count--;
            if (count == 0) {
                //切换回省份选择
                mProvinceView.setVisibility(VISIBLE);
                mNumView.setVisibility(GONE);
            }
            inputContent = stringBuffer.toString();
            TextViews[stringBuffer.length()].setText("");
            setTextViewsBackground(count);
            //有删除就通知manger
            inputListener.deleteContent();
        }
        return false;
    }

    /**
     * 清空输入内容
     */
    public void clearEditText() {
        stringBuffer.delete(0, stringBuffer.length());
        inputContent = stringBuffer.toString();
        for (int i = 0; i < TextViews.length; i++) {
            TextViews[i].setText("");
            TextViews[i].setBackgroundResource(R.drawable.license_plate_code_gray_bg);
        }
    }

    private @NonNull
    InputListener inputListener;

    public void setInputListener(InputListener inputListener) {
        this.inputListener = inputListener;
    }

    /**
     * 键盘的点击事件
     */
    @Override
    public void onClick(View view) {
        if (view instanceof TextView) {
            TextView tv = (TextView) view;
            tv.setSelected(true);
            String text = tv.getText().toString();
            if (view.getId() == R.id.select_province_delete_tv || view.getId() == R.id.select_num_delete_tv) {
                inputListener.deleteContent();
            }
            setEditContent(text);
        }
    }

    /**
     * 输入完成监听回调接口
     */
    public interface InputListener {

        /**
         * @param content 当输入完成时的全部内容
         */
        void inputComplete(String content);

        /**
         * 删除操作
         */
        void deleteContent();

    }

    /**
     * 获取输入文本
     *
     * @return
     */
    public String getEditContent() {
        return inputContent;
    }

    /**
     * 设置 EditText 的输入内容
     * 根据isUpdateView 判断修改/删除操作
     */
    private void setEditContent(String content) {
        if (!isUpdateView) {
            if (!TextUtils.isEmpty(content)) {
                editText.setText(content);
            } else {
                onKeyDelete();
                setTextViewsEnable(true);
            }
        } else {
            if (!TextUtils.isEmpty(content)) {
                stringBuffer.replace(updateViewPosition, updateViewPosition + 1, content);
                isUpdateView = !isUpdateView;
                setTextViewsEnable(true);
            } else {
                TextViews[updateViewPosition].setText(content);
                if (updateViewPosition + 1 == ITEM_VIEW_COUNT) {
                    isUpdateView = !isUpdateView;
                    stringBuffer.delete(updateViewPosition, updateViewPosition + 1);
                    count--;
                }
                inputListener.deleteContent();
                setTextViewsEnable(false);
                return;
            }
            TextViews[updateViewPosition].setText(content);
            inputContent = stringBuffer.toString();
            count = stringBuffer.length();
            setTextViewsBackground(count);
            //切换数字输入
            mProvinceView.setVisibility(GONE);
            mNumView.setVisibility(VISIBLE);
            if (stringBuffer.length() == ITEM_VIEW_COUNT) {
                //文字长度为sblength  则调用完成输入的监听
                if (inputListener != null) {
                    inputListener.inputComplete(inputContent);
                    mNumView.setVisibility(GONE);
                }
            }
        }
    }

    /**
     * 显示输入框的TouchListener
     */
    private class OnFrameTouchListener implements OnTouchListener {

        @Override
        public boolean onTouch(View view, MotionEvent event) {
            if (view instanceof TextView) {
                TextView tv = (TextView) view;
                tv.setFocusable(true);
                String tvString = (String) tv.getText();
                if (TextUtils.isEmpty(tvString)) {
                    isUpdateView = false;
                    return false;
                }
                int viewId = tv.getId();
                for (int i = 0; i < stringBuffer.length(); i++) {
                    if (viewId == VIEW_IDS[i]) {
                        updateViewPosition = i;
                        if (i == 0) {
                            mProvinceView.setVisibility(VISIBLE);
                            mNumView.setVisibility(GONE);
                        } else {
                            mProvinceView.setVisibility(GONE);
                            mNumView.setVisibility(VISIBLE);
                        }
                        isUpdateView = true;
                        setTextViewsBackground(i);
                    }
                }
            }
            return true;
        }

    }

    /**
     * 当修改选中的某个号码,其他数字不能被选中,防止只改变显示,造成数据错误
     */
    private void setTextViewsEnable(boolean enabled) {
        for (int i = 0; i < TextViews.length; i++) {
            TextViews[i].setEnabled(enabled);
        }
    }

    private void setTextViewsBackground(int position) {
        //第一个框的样式
        if (position == 0) {
            TextViews[0].setBackgroundResource(R.drawable.license_plate_first_view_blue);
        } else {
            TextViews[0].setBackgroundResource(R.drawable.license_plate_first_view_all_gray);
        }
        //从第二个开始,到倒数第二个
        //根据点击选中效果,设置两边的样式
        if (position < ITEM_VIEW_COUNT - 2 && position >= 1) {
            for (int i = 1; i < ITEM_VIEW_COUNT - 2; i++) {
                TextViews[i].setBackgroundResource(R.drawable.license_plate_view_right_gray);
            }
            if (position == 1) {
                TextViews[position - 1].setBackgroundResource(R.drawable.license_plate_first_view_gray);
            } else {
                TextViews[position - 1].setBackgroundResource(R.drawable.license_plate_view_half_gray);
            }
            TextViews[position].setBackgroundResource(R.drawable.license_plate_mid_view_blue);
        } else {
            for (int i = 1; i < ITEM_VIEW_COUNT - 2; i++) {
                TextViews[i].setBackgroundResource(R.drawable.license_plate_view_right_gray);
            }
        }
        //倒数第二个框的样式,根据选中的效果,设置前后两个框的样式
        if (position == ITEM_VIEW_COUNT - 2) {
            TextViews[position].setBackgroundResource(R.drawable.license_plate_mid_view_blue);
            TextViews[position + 1].setBackgroundResource(R.drawable.license_plate_last_view_bg);
            TextViews[position - 1].setBackgroundResource(R.drawable.license_plate_view_half_gray);
        } else {
            TextViews[ITEM_VIEW_COUNT - 2].setBackgroundResource(R.drawable.license_plate_mid_view_bg);
        }
        //最后一个框的样式,根据选中的样式,前面一个样式需要改变
        if (position == ITEM_VIEW_COUNT - 1) {
            TextViews[position].setBackgroundResource(R.drawable.license_plate_last_view_blue);
            TextViews[position - 1].setBackgroundResource(R.drawable.license_plate_view_half_gray);
        } else {
            TextViews[ITEM_VIEW_COUNT - 1].setBackgroundResource(R.drawable.license_plate_last_view_bg);
        }
    }


    /**
     * 禁用系统软键盘
     */
    public void hideSoftInputMethod() {
        mActivity.getWindow().setSoftInputMode(
                WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
        int currentVersion = android.os.Build.VERSION.SDK_INT;
        String methodName = null;
        if (currentVersion >= 16) {
            // 4.2
            methodName = "setShowSoftInputOnFocus";
        } else if (currentVersion >= 14) {
            // 4.0
            methodName = "setSoftInputShownOnFocus";
        }
        if (methodName == null) {
            editText.setInputType(InputType.TYPE_NULL);
        } else {
            Class cls = EditText.class;
            Method setShowSoftInputOnFocus;
            try {
                setShowSoftInputOnFocus = cls.getMethod(methodName,
                        boolean.class);
                setShowSoftInputOnFocus.setAccessible(true);
                setShowSoftInputOnFocus.invoke(editText, false);
            } catch (NoSuchMethodException e) {
                editText.setInputType(InputType.TYPE_NULL);
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}
布局代码

xml version="1.0" encoding="utf-8"?>
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

            android:id="@+id/item_edittext"
        android:layout_width="match_parent"
        android:layout_height="46dp"
        android:background="@android:color/transparent"
        />

            android:layout_width="wrap_content"
        android:layout_height="48dp"
        android:gravity="center"
        android:orientation="horizontal">

                    android:id="@+id/item_code_iv1"
            style="@style/license_plate_editStyle"
            android:layout_weight="1"
            android:background="@drawable/license_plate_first_view_blue"/>

                    android:id="@+id/item_code_iv2"
            style="@style/license_plate_editStyle"
            android:layout_weight="1"
            android:background="@drawable/license_plate_mid_view_bg"/>

                    android:id="@+id/item_code_iv3"
            style="@style/license_plate_editStyle"
            android:layout_weight="1"
            android:background="@drawable/license_plate_mid_view_bg"/>

                    android:id="@+id/item_code_iv4"
            style="@style/license_plate_editStyle"
            android:layout_weight="1"
            android:background="@drawable/license_plate_mid_view_bg"/>

                    android:id="@+id/item_code_iv5"
            style="@style/license_plate_editStyle"
            android:layout_weight="1"
            android:background="@drawable/license_plate_mid_view_bg"/>


                    android:id="@+id/item_code_iv6"
            style="@style/license_plate_editStyle"
            android:layout_weight="1"
            android:background="@drawable/license_plate_mid_view_bg"/>

                    android:id="@+id/item_code_iv7"
            style="@style/license_plate_editStyle"
            android:layout_weight="1"
            android:background="@drawable/license_plate_last_view_bg"/>

                    android:id="@+id/item_code_iv8"
            style="@style/license_plate_editStyle"
            android:layout_weight="1"
            android:visibility="gone"/>

    

键盘样式


实现的逻辑代码已经完成,可根据具体的业务需求进行拓展。

在项目中页面显示自定义的键盘视图,根据接口回调获取输入的内容,进行显示。

你可能感兴趣的:(自定义view)