美文网首页
(笔记)Android自定义数字键盘

(笔记)Android自定义数字键盘

作者: zither_ | 来源:发表于2018-08-07 11:11 被阅读0次

    前言

    最近Android开发中用到了自定义数字键盘,网上找的demo不能满足我的需求,比如删除和插入的时候只能在最后删除和插入,不能通过滑动键盘来移动光标。所以现在完成后把它总结写出来。

    概述

    主要实现以下功能:
    (1)只有数字键,包括没有标点符号。
    (2)可以在任意点插入和删除数字。
    (3)可以通过手指左右滑动键盘来改变光标位置。
    (4)输入框右边删除图标和按钮可随着内容有无变化。
    (5)每三个数字空一格,输入框最多输入13个字符(包括空格)。

    先上运行效果(请忽略UI -_-): keyboard.gif

    步骤:
    1、新建一个KeyboardView.java文件。用来自定义所需要的键盘。
    首先初始化绑定布局文件。

    private void init(Context context, AttributeSet attrs, int defStyleAttr) {
            LayoutInflater.from(context).inflate(R.layout.layout_key_board, this);
            recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
            rl_back=findViewById(R.id.rl_back);
            rl_back.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View view) { // 点击关闭键盘
                    dismiss();
                }
            });
            initData();
            initView();
            initAnimation();
        }
    

    填充数据(如果需要标点符号,则在i==9中填充即可)

    private void initData() {
            keyboardWords = new ArrayList<>();
            for (int i = 0; i < 12; i++) {
                if (i < 9) {
                    keyboardWords.add(String.valueOf(i + 1));
                } else if (i == 9) {
                    keyboardWords.add("");
                } else if (i == 10) {
                    keyboardWords.add("0");
                } else {
                    keyboardWords.add("");
                }
            }
        }
    

    设置适配器

     private void initView() {
            int spanCount = 12;
            recyclerView.setLayoutManager(new GridLayoutManager(getContext(), 3));
            recyclerView.setNestedScrollingEnabled(false);
            recyclerView.addItemDecoration(new SpaceItemDecoration(spanCount));
            adapter = new KeyboardAdapter(getContext(), keyboardWords);
            recyclerView.setAdapter(adapter);
        }
    

    对键盘的操作

    //判断软键盘的状态
     public boolean isVisible() {
           if (getVisibility() == VISIBLE) {
               return true;
           }
           return false;
       }       
    //弹出软键盘      
    public void show() {
           startAnimation(animationIn);
           setVisibility(VISIBLE);
       }     
    //关闭软键盘     
    public void dismiss() {
           if (isVisible()) {
               startAnimation(animationOut);
               setVisibility(GONE);
           }
       }
    

    2、Adapter操作。

        private Context context;
        private List<String> datas;
        private OnKeyboardClickListener listener;
    
        public KeyboardAdapter(Context context, List<String> datas) {
            this.context = context;
            this.datas = datas;
        }
    
        @Override
        public KeyboardHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(context).inflate(R.layout.item_key_board, parent, false);
            KeyboardHolder holder = new KeyboardHolder(view);
            setListener(holder);
            return holder;
        }
    
        private void setListener(final KeyboardHolder holder) {
            holder.tvKey.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (listener != null) {
                        if (holder.getAdapterPosition() != 9) {
                            listener.onKeyClick(view, holder, holder.getAdapterPosition());
                        }
                    }
                }
            });
            holder.rlDel.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    if (listener != null) {
                        listener.onDeleteClick(view, holder, holder.getAdapterPosition());
                    }
                }
            });
        }
    
        @Override
        public void onBindViewHolder(KeyboardHolder holder, int position) {
            if (position == 9) {
                holder.setVisibility(false);
            } else if (position == 11) {
                holder.rlDel.setVisibility(View.VISIBLE);
                holder.tvKey.setVisibility(View.GONE);
            } else {
                holder.tvKey.setText(datas.get(position));
            }
        }
    
        @Override
        public int getItemCount() {
            return datas == null ? 0 : datas.size();
        }
    
        class KeyboardHolder extends RecyclerView.ViewHolder {
    
            public TextView tvKey;
            public RelativeLayout rlDel;
            private View convertView;
    
            public KeyboardHolder(View itemView) {
                super(itemView);
                convertView = itemView;
                tvKey = itemView.findViewById(R.id.tv_key);
                rlDel = itemView.findViewById(R.id.rl_del);
            }
    
            public View getconvertView() {
                return convertView;
            }
    
            public void setVisibility(boolean b) {
                RecyclerView.LayoutParams param = (RecyclerView.LayoutParams) itemView.getLayoutParams();
                if (b) {
                    param.height = LinearLayout.LayoutParams.WRAP_CONTENT;
                    param.width = LinearLayout.LayoutParams.MATCH_PARENT;
                    itemView.setVisibility(View.VISIBLE);
                } else {
                    itemView.setVisibility(View.GONE);
                    param.height = 0;
                    param.width = 0;
                }
                itemView.setLayoutParams(param);
            }
        }
    
        public interface OnKeyboardClickListener {
    
            void onKeyClick(View view, RecyclerView.ViewHolder holder, int position);
    
            void onDeleteClick(View view, RecyclerView.ViewHolder holder, int position);
        }
    
        public void setOnKeyboardClickListener(OnKeyboardClickListener listener) {
            this.listener = listener;
        }
    }
    

    3、在Activity中的运用。
    关闭系统键盘

    private void enableSystemKeyboard() {
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN);
            try {
                Class<EditText> cls = EditText.class;
                Method setShowSoftInputOnFocus = cls.getMethod("setShowSoftInputOnFocus", boolean.class);
                setShowSoftInputOnFocus.setAccessible(true);
                setShowSoftInputOnFocus.invoke(videoIdEt, false);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }   
    

    键盘数字按钮的点击事件,并且获取输入当前光标位置

     @SuppressLint("SetTextI18n")
        @Override
        public void onKeyClick(View view, RecyclerView.ViewHolder holder, int position) {
            String editText = videoIdEt.getText().toString();
            switch (position) {
                case 9:
                    break;
                default:
                    //获取当前光标位置
                    int index = videoIdEt.getSelectionStart();
                    if (index != videoIdEt.getText().length()) {
                        //在光标处插入数字
                        String inputEditText = keyboardNumbers.get(position);
                        Log.d(TAG, "inputEditText:" + inputEditText);
                        videoIdEt.getText().insert(index, inputEditText);
                    } else {
                        videoIdEt.setText(videoIdEt.getText().toString().trim() + keyboardNumbers.get(position));
                        videoIdEt.setSelection(videoIdEt.getText().length());
                    }
                    if (videoIdEt.getText().length() > 0) {
                     findViewById(R.id.ai_long_tv_confirm).setBackgroundResource(R.drawable.bg_determine_text);
                        Drawable drawable = getResources().getDrawable(R.drawable.ic_delete1);    
                      //设置 ClickableEditText中只显示左边图标,删除图标可见
                        videoIdEt.setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, drawable,null);
                    }
                    break;
            }
        }          
    

    手指触摸事件:获取手指按下和滑动停止的位置。将结果传给手势监听。

    private View.OnTouchListener onTouchListener = new View.OnTouchListener() {
            @RequiresApi(api = Build.VERSION_CODES.ECLAIR)
            @SuppressLint("ClickableViewAccessibility")
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
                    Log.d(TAG, "MotionEvent.ACTION_DOWN");
                }
                if (motionEvent.getAction() == MotionEvent.ACTION_UP) {
                    Log.d(TAG, "MotionEvent.ACTION_UP");
                    refreshStartPoint = true;
                }
                if (motionEvent.getAction() == MotionEvent.ACTION_MOVE) {
                    if (refreshStartPoint) {
                        startPointEvent = motionEvent.getX(0);
                        curatorIndex = videoIdEt.getSelectionStart();
                    }
                    refreshStartPoint = false;
                    stopPointEvent = motionEvent.getX();
                    Log.d(TAG, "MotionEvent.ACTION_MOVE");
                }
                return mDetector.onTouchEvent(motionEvent);
            }
        };   
    

    用户手势的监测。计算开始和停止滑动距离的大小(滑动前和滑动后的距离),通过计算滑动距离来计算光标移动多少,并通过距离的正负来判断滑动的方向,从而达到在键盘上滑动来控制光标移动的目的。

     @RequiresApi(api = Build.VERSION_CODES.CUPCAKE)
        private void initGestureDetector() {
            mDetector = new GestureDetector(this, new GestureDetector.OnGestureListener() {
                @Override
                public boolean onDown(MotionEvent motionEvent) {
                    Log.d(TAG, "onDown");
                    return true;
                }
    
                @Override
                public void onShowPress(MotionEvent motionEvent) {
                    Log.d(TAG, "onShowPress");
                }
    
                @Override
                public boolean onSingleTapUp(MotionEvent motionEvent) {
                    Log.d(TAG, "onShowPress");
                    return false;
                }
    
                @Override
                public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
                    DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
                    mScreenWidth = displayMetrics.widthPixels;
                    float x = stopPointEvent - startPointEvent;
                    float newPercent = Math.abs(x) / mScreenWidth;
                    int range = (int) ((videoIdEt.getText().length()) * newPercent);
                    int newIndex;
                    if (x > 0) {
                        newIndex = curatorIndex + range;
                        if (curatorIndex == videoIdEt.getText().length()) {
                            videoIdEt.setSelection(curatorIndex);
                        }
                        if (newIndex > videoIdEt.getText().length()) {
                            videoIdEt.setSelection(videoIdEt.getText().length());
                        } else {
                            videoIdEt.setSelection(newIndex);
                        }
                    } else {
                        newIndex = curatorIndex - range;
                        if (curatorIndex == 0) {
                            videoIdEt.setSelection(curatorIndex);
                        }
                        if (newIndex < 0) {
                            videoIdEt.setSelection(0);
                        } else {
                            videoIdEt.setSelection(newIndex);
                        }
                    }
                    return false;
                }
    
                @Override
                public void onLongPress(MotionEvent motionEvent) {
                    Log.d(TAG, "onLongPress");
                }
    
                @Override
                public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
                    // startPointEvent=motionEvent1;
                    Log.d(TAG, "onFling: " + "motionEvent:" + motionEvent + "motionEvent1" + motionEvent1);
                    return false;
                }
            });
        }    
    

    接着我们实现每三个数字输入一个空格。通过对ClickableEditText的监听来达到这一目的。

    private TextWatcher watcher = new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
    
            }
    
            @Override
            public void onTextChanged(CharSequence charSequence, int start, int before, int i2) {
                if (isTextChanging) {
                    isTextChanging = false;
                    return;
                }
                isTextChanging = true;
                String result = "";
                String newStr = charSequence.toString();
                newStr = newStr.replace(" ", "");
                int index = 0;
                while ((index + 3) < newStr.length()) {
                    result += (newStr.substring(index, index + 3) + " ");
                    index += 3;
                }
                result += (newStr.substring(index, newStr.length()));
                int i = videoIdEt.getSelectionStart();
                videoIdEt.setText(result);
                try {
                    if (i % 4 == 0 && before == 0) {
                        if (i + 1 <= result.length()) {
                            videoIdEt.setSelection(i + 1);
                        } else {
                            videoIdEt.setSelection(result.length());
                        }
                    } else if (before == 1 && i < result.length()) {
                        videoIdEt.setSelection(i);
                    } else if (before == 0 && i < result.length()) {
                        videoIdEt.setSelection(i);
                    } else {
                        videoIdEt.setSelection(result.length());
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void afterTextChanged(Editable editable) {
    
            }
        };
    

    对右下角删除按钮的监听,只能删除一个一个删除,不能一下删除所输入的内容

     @Override
        public void onDeleteClick(View view, RecyclerView.ViewHolder holder, int position) {
            int currentIndex = videoIdEt.getSelectionStart();
            if (currentIndex > 0) {
                videoIdEt.getText().delete(currentIndex - 1, currentIndex);
                if (videoIdEt.getText().length() == 0) {
                   //设置 ClickableEditText中只显示左边图标,删除图标不可见
                    videoIdEt.setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null,null);
                    findViewById(R.id.ai_long_tv_confirm).setBackgroundResource(R.drawable.bg_determine_disable);
                }
            }
        }
    

    输入框右边删除按钮的点击事件,点击可消除所有输入的内容。

       @Override
        public void onDrawableRightClick(View view) {
            switch (view.getId()) {
                case R.id.ai_long_et_video_code:
                    videoIdEt.getText().clear();
                     //设置 ClickableEditText中只显示左边图标,删除图标不可见
                    videoIdEt.setCompoundDrawablesWithIntrinsicBounds(mDrawable, null, null,null);           
            findViewById(R.id.ai_long_tv_confirm).setBackgroundResource(R.drawable.bg_determine_disable);
                    break;
                default:
                    break;
            }
        }
    

    结论

    以上就是整个项目的实现过程,注意一点,ClickableEditText是自定义的一个EditText,由于使用ConstraintLayout,在输入框的前后两端加按钮,是为了可以点击右边删除按钮能删除所有输入的内容所写。

    相关文章

      网友评论

          本文标题:(笔记)Android自定义数字键盘

          本文链接:https://www.haomeiwen.com/subject/gccovftx.html