Android カスタム ビューのシンプルな入力ボックス

序文

  日々の業務開発において、長い間さまざまなニーズに遭遇します. Android ネイティブの View で解決できるニーズもあれば、解決できないニーズもあります. このとき、View をカスタマイズする必要があります.この記事のこのカスタム ビューのデモ レンダリング。

ここに画像の説明を挿入

文章

  引き続き EasyView で作成し、com.easy.view下にEasyEditText、 から継承しView、内部で構築メソッドを実装します。

①施工方法

次に、Viewコンストラクターを継承して内部で書き換えます。コードは次のとおりです。

public class EasyEditText extends View implements NumberKeyboardListener {
    
    

    private Context mContext;
    
    public EasyEditText(Context context) {
    
    
        this(context, null);
    }

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

    public EasyEditText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    
    
        super(context, attrs, defStyleAttr);
		mContext = context;
    }
}

以下にスタイルを追加できます。

②XML形式

  スタイルを設定する前に, カスタムビューが何をするかを知る必要があります. これは, 認証コードの入力またはパスワードの入力に使用できる単純な入力ボックスです. 主にデジタル入力用に 4 から 6 個の入力ボックスがあります. ファイル内attrs.xml、内部でカスタム スタイルを記述できます。コードは次のとおりです。

    <!--简易输入框-->
    <declare-styleable name="EasyEditText">
        <!-- 方框大小,宽高一致 -->
        <attr name="boxWidth" />
        <!-- 方框背景颜色 -->
        <attr name="boxBackgroundColor" />
        <!-- 方框描边颜色 -->
        <attr name="boxStrokeColor" />
        <!-- 方框焦点描边颜色 -->
        <attr name="boxFocusStrokeColor" format="color|reference"/>
        <!-- 方框描边宽度 -->
        <attr name="boxStrokeWidth" />
        <!--文字颜色-->
        <attr name="textColor" />
        <!--文字大小-->
        <attr name="textSize" />
        <!-- 方框数量 4-6 个-->
        <attr name="boxNum" format="integer"/>
        <!--是否密文-->
        <attr name="ciphertext" format="boolean"/>
    </declare-styleable>

  この前にまだ 3 つの View スタイルがあるので、繰り返しのスタイルを抽出します。ソース コードを参照して理解してください。

次に、使用するビューに戻りましょう。最初に変数を宣言します。コードは次のとおりです。

    /**
     * 方框大小,因为它是相同的宽度和高度,它只需要一个值
     */
    private int mBoxWidth;
    /**
     * 方框背景颜色
     */
    private int mBoxBackgroundColor;
    /**
     * 方框默认描边颜色
     */
    private int mBoxStrokeColor;
    /**
     * 方框获取焦点描点颜色
     */
    private int mBoxFocusStrokeColor;
    /**
     * 方框描边大小
     */
    private final int mBoxStrokeWidth;
    /**
     * 文字颜色
     */
    private int mTextColor;
    /**
     * 文字大小
     */
    private float mTextSize;
    /**
     * 方框数量,最少4个 - 最多6个
     */
    private int mBoxNum;
    /**
     * 方框之间的间距
     */
    private int mBoxMargin = 4;
    /**
     * 方框画笔
     */
    private Paint mBoxPaint;
    /**
     * 方框描边画笔
     */
    private Paint mBoxStrokePaint;
    /**
     * 文字画笔
     */
    private Paint mTextPaint;
    /**
     * 文字矩形
     */
    private final Rect mTextRect = new Rect();
    /**
     * 方框圆角
     */
    private float mBoxCornerRadius = 8f;
    /**
     * 描边圆角
     */
    private float strokeRadius;

    /**
     * 输入长度
     */
    private final int mInputLength;
    /**
     * 输入数组
     */
    private final String[] inputArray;
    /**
     * 当前输入位置
     */
    private int currentInputPosition = 0;
    /**
     * 焦点边框列表
     */
    private final List<RectF> focusList = new ArrayList<>();
    /**
     * 是否获取焦点
     */
    private boolean isFocus = false;
    /**
     * 是否密文显示
     */
    private boolean ciphertext = false;
    /**
     * 密文显示 *
     */
    private String ciphertextContent = "*";

次に、3 番目のコンストラクターを変更します。コードは次のようになります。

    public EasyEditText(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
    
    
        super(context, attrs, defStyleAttr);
        mContext = context;
        @SuppressLint("CustomViewStyleable")
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.EasyEditText);
        mBoxWidth = (int) typedArray.getDimensionPixelSize(R.styleable.EasyEditText_boxWidth, 48);
        mBoxBackgroundColor = typedArray.getColor(R.styleable.EasyEditText_boxBackgroundColor, ContextCompat.getColor(context, R.color.white));
        mBoxStrokeColor = typedArray.getColor(R.styleable.EasyEditText_boxStrokeColor, ContextCompat.getColor(context, R.color.box_default_stroke_color));
        mBoxFocusStrokeColor = typedArray.getColor(R.styleable.EasyEditText_boxFocusStrokeColor, ContextCompat.getColor(context, R.color.box_default_stroke_color));
        mBoxStrokeWidth = (int) typedArray.getDimensionPixelSize(R.styleable.EasyEditText_boxStrokeWidth, 2);
        mTextColor = typedArray.getColor(R.styleable.EasyEditText_textColor, ContextCompat.getColor(context, R.color.tx_default_color));
        mTextSize = typedArray.getDimensionPixelSize(R.styleable.EasyEditText_textSize, (int) TypedValue
                .applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, getResources().getDisplayMetrics()));
        int number = typedArray.getInteger(R.styleable.EasyEditText_boxNum, 4);
        ciphertext = typedArray.getBoolean(R.styleable.EasyEditText_ciphertext, false);
        mBoxNum = (number > 6 || number < 4) ? 4 : number;
        mInputLength = mBoxNum;
        inputArray = new String[mInputLength];
        typedArray.recycle();
        //初始化画笔
        initPaint();
    }

  ここで、EasyEditText取得を通じてTypedArray、属性のTypedArray取得EasyEditTextを通じて値を割り当てます。入力ボックスのサイズはここで処理され、入力ボックスの数は入力の長さであり、ブラシは初期化され、新しいメソッドが追加されます. コードは次のとおりですinitPaint()

    private void initPaint() {
    
    
        //设置边框画笔
        mBoxPaint = new Paint();
        mBoxPaint.setAntiAlias(true);// anti-aliasing
        mBoxPaint.setColor(mBoxBackgroundColor);//Set color
        mBoxPaint.setStyle(Paint.Style.FILL);//Style filling
        //设置描边画笔
        mBoxStrokePaint = new Paint();
        mBoxStrokePaint.setAntiAlias(true);
        mBoxStrokePaint.setColor(mBoxStrokeColor);
        mBoxStrokePaint.setStyle(Paint.Style.STROKE);//Style stroke
        mBoxStrokePaint.setStrokeWidth(mBoxStrokeWidth);//Stroke width
        //设置文字画笔
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextSize(mTextSize);//Text size
        mTextPaint.setTextAlign(Paint.Align.CENTER);//Center the text
    }

③測定

  変数と属性を介してボックスの数とボックス間の距離を知り、メソッドを書き直しますonMeasure()。コードは次のようになります。

    /**
     * View的测量
     *
     * @param widthMeasureSpec  宽度测量
     * @param heightMeasureSpec 高度测量
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    
    
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = 0;
        int margin = EasyUtils.dp2px(mContext, mBoxMargin);
        switch (MeasureSpec.getMode(widthMeasureSpec)) {
    
    
            case MeasureSpec.UNSPECIFIED:
            case MeasureSpec.AT_MOST:   //wrap_content
                width = mBoxWidth * mBoxNum + margin * (mBoxNum - 1);
                break;
            case MeasureSpec.EXACTLY:   //match_parent
                width = MeasureSpec.getSize(widthMeasureSpec);
                mBoxWidth = (width - margin * (mBoxNum - 1)) / mBoxNum;
                break;
        }
        //设置测量后的值
        setMeasuredDimension(width, mBoxWidth);
    }

④描く

  測定後、以下で描画を開始できます. 描画は紙に描画することと同じです. 描画するには、まずブラシを用意し、最初に変数を宣言する必要があります. コードは次のとおりです:

    private Paint mBoxPaint;
    private Paint mBoxStrokePaint;
    private Paint mTextPaint;
    private final Rect mTextRect = new Rect();

次に、テキストの描画が少し異なるため、3 つのブラシ (ボックス、ボックスの境界線、テキスト) を設定する必要があるので、1 つ追加します. 次に、View でブラシを初期化する新しいメソッドを追加します. コードは次のとおりですRect:

    /**
     * 初始化画笔
     */
    private void initPaint() {
    
    
        //设置方框画笔
        mBoxPaint = new Paint();
        mBoxPaint.setAntiAlias(true);// 抗锯齿
        mBoxPaint.setColor(mBoxBackgroundColor);//设置颜色
        mBoxPaint.setStyle(Paint.Style.FILL);//风格填满
        //设置方框描边画笔
        mBoxStrokePaint = new Paint();
        mBoxStrokePaint.setAntiAlias(true);
        mBoxStrokePaint.setColor(mBoxStrokeColor);
        mBoxStrokePaint.setStyle(Paint.Style.STROKE);//风格描边
        mBoxStrokePaint.setStrokeWidth(mBoxStrokeWidth);//描边宽度
        //设置文字画笔
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setStyle(Paint.Style.FILL);
        mTextPaint.setColor(mTextColor);
        mTextPaint.setTextSize(mTextSize);//文字大小
        mTextPaint.setTextAlign(Paint.Align.CENTER);//文字居中对齐
    }

次に、次の図に示すように、3 番目の構築メソッドで呼び出します。

ここに画像の説明を挿入

次のステップは描画です。

    @Override
    protected void onDraw(Canvas canvas) {
    
    
        //绘制边框
        drawBox(canvas);
        //绘制文字
        drawText(canvas);
    }

ここでの描画は、ボックスの描画とテキストの描画の 2 つのステップに分かれています。

1.箱を描く

  1 つ目は、ボックスを描画し、カスタム View に新しいメソッドを追加することですdrawBox()。コードは次のとおりです。

    /**
     * 绘制方框
     */
    private void drawBox(Canvas canvas) {
    
    
        //每个方框的间距
        int margin = EasyUtils.dp2px(mContext, mBoxMargin);
        int radius = EasyUtils.dp2px(mContext, mBoxCornerRadius);
        //Draw a rounded rectangle border
        float strokeWidth = mBoxStrokeWidth / 2;
        for (int i = 0; i < mBoxNum; i++) {
    
    
            //To draw a rectangular box, you need the positions of the left, top, right and bottom points
            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);
            //画一个圆角矩形框
            canvas.drawRoundRect(rectF, radius, radius, mBoxPaint);
            RectF strokeRectF = new RectF(left + strokeWidth, top + strokeWidth, right - strokeWidth, bottom - strokeWidth);
            //添加到列表
            focusList.add(strokeRectF);
        }

        for (int i = 0; i < mBoxNum; i++) {
    
    
            strokeRadius = radius - strokeWidth;
            //根据当前绘制位置和是否获取焦点设置画笔颜色
            if (i <= currentInputPosition && isFocus) {
    
    
                mBoxStrokePaint.setColor(mBoxFocusStrokeColor);
            } else {
    
    
                mBoxStrokePaint.setColor(mBoxStrokeColor);
            }
            //绘制边框
            canvas.drawRoundRect(focusList.get(i), strokeRadius, strokeRadius, mBoxStrokePaint);
        }
    }

  ここでは、最初に丸みを帯びた背景を描画し、次に背景を描画するパラメーターを介して描画された境界線を取得し、境界線を保存してから、現在の描画位置とフォーカスを取得するかどうかに応じてブラシの色を設定します。現在の入力ボックスを実現することができます. たとえば、私は持っていません 入力すると、黒い境界線があります. 最初の値を入力すると、最初の入力ボックスの境界線の色が緑色に変わります. 最初の入力ボックスを入力すると、 2 番目のボックスの境界線が緑色に変わり、最初の値を入力する必要があることを示します。2 つのボックスがあるため、ユーザーはわかりやすい方法でプロンプトを表示できます。

2.テキストを描く

  ボックスができたので、ボックスの中央にテキストを描画し、カスタム View に新しいdrawText()メソッドを追加する必要があります。

    /**
     * 绘制文字
     */
    private void drawText(Canvas canvas) {
    
    
        int boxMargin = EasyUtils.dp2px(mContext, mBoxMargin);
        for (int i = 0; i < inputArray.length; i++) {
    
    
            if (inputArray[i] != null) {
    
    
                //绘制的文字
                String content = ciphertext ? ciphertextContent : inputArray[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);
            }
        }
    }

テキストの描画は、先ほどの MacAddressEditText での操作と似ているので、繰り返しませんが、入力を見てみましょう。

⑤入力

  先ほどの簡単な住所入力ボックスは数字だけで、入力データは : なので、0、1、2、3、4、5、6、7、8、9便宜上、入力用のキーボードを作る予定です。

1.キーボード配列

lay_number_keyboard.xmlまず、キーボードのレイアウトとして使用される  layout の下に 1 つ作成します。コードは次のとおりです。

<?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"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#eff4f9">

    <Button
        android:id="@+id/btn_1"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginTop="8dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/num_1"
        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_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/btn_2"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/num_2"
        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_toEndOf="@+id/btn_1"
        app:layout_constraintTop_toTopOf="@+id/btn_1" />

    <Button
        android:id="@+id/btn_3"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/num_3"
        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_2"
        app:layout_constraintTop_toTopOf="@+id/btn_2" />

    <Button
        android:id="@+id/btn_4"
        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="@string/num_4"
        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_toStartOf="@+id/btn_1"
        app:layout_constraintTop_toBottomOf="@+id/btn_1" />

    <Button
        android:id="@+id/btn_5"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/num_5"
        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_toEndOf="@+id/btn_4"
        app:layout_constraintTop_toTopOf="@+id/btn_4" />

    <Button
        android:id="@+id/btn_6"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/num_6"
        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_5"
        app:layout_constraintTop_toTopOf="@+id/btn_5" />

    <Button
        android:id="@+id/btn_7"
        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="@string/num_7"
        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_toStartOf="@+id/btn_4"
        app:layout_constraintTop_toBottomOf="@+id/btn_4" />

    <Button
        android:id="@+id/btn_8"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/num_8"
        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_toEndOf="@+id/btn_7"
        app:layout_constraintTop_toTopOf="@+id/btn_7" />

    <Button
        android:id="@+id/btn_9"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/num_9"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintEnd_toEndOf="@+id/btn_6"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_8"
        app:layout_constraintTop_toTopOf="@+id/btn_8" />

    <Button
        android:id="@+id/btn_del"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginTop="4dp"
        android:layout_marginBottom="8dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/delete"
        android:textColor="@color/key_tx_color"
        android:textSize="16sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/btn_0"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="@+id/btn_7"
        app:layout_constraintTop_toBottomOf="@+id/btn_7" />

    <Button
        android:id="@+id/btn_0"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:backgroundTint="@color/key_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/num_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_del"

        app:layout_constraintTop_toTopOf="@+id/btn_del" />

    <com.google.android.material.button.MaterialButton
        android:id="@+id/btn_complete"
        android:layout_width="0dp"
        android:layout_height="48dp"
        android:layout_marginStart="4dp"
        android:layout_marginLeft="4dp"
        android:backgroundTint="@color/key_complete_bg_color"
        android:insetTop="0dp"
        android:insetBottom="0dp"
        android:text="@string/complete"
        android:textColor="@color/white"
        android:textSize="16sp"
        app:iconGravity="start|end"
        app:layout_constraintEnd_toEndOf="@+id/btn_9"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/btn_0"
        app:layout_constraintTop_toTopOf="@+id/btn_0" />

</androidx.constraintlayout.widget.ConstraintLayout>

レイアウトのプレビュー効果を次の図に示します。

ここに画像の説明を挿入

  このレイアウトは使い方が非常にシンプルで、基本的には一目瞭然です. ここでは、キーボードのボタン クリック イベントを処理するためのインターフェイスを記述できます。

2.キーボードインターフェース

com.llw.easyview以下に  新しいNumberKeyboardListenerインターフェイスを作成します。コードは次のとおりです。

public interface NumberKeyboardListener {
    
    

    /**
     * 数字字符
     * @param num 0~9
     */
    void onNum(String num);

    /**
     * 删除
     */
    void onDelete();

    /**
     * 完成
     */
    void onComplete();

    /**
     * 弹窗关闭
     */
    void onDialogDismiss();

    /**
     * 弹窗显示
     */
    void onDialogShow();
}

  インターフェースが使えるようになったので、インターフェースのメソッドは、基本的にキーボードのすべてのボタンがクリックされたときにトリガーされるイベント処理をカバーし、ポップアップ ウィンドウの閉じと表示を処理します。 、入力するかどうかのステータスを取得する必要があるため、簡易入力ボックスをクリックするとキーボードがポップアップするポップアップウィンドウを作成しましょう。

3.キーボードポップアップ

  このポップアップ ウィンドウをEasyUtilsクラスに記述し、次のメソッド コードを追加しました。

    /**
     * 显示数字键盘弹窗
     *
     * @param listener 数字键盘监听
     */
    public static void showNumKeyboardDialog(@NonNull Context context, @NonNull NumberKeyboardListener listener) {
    
    
        BottomSheetDialog dialog = new BottomSheetDialog(context);
        //从xml中获取布局视图
        View view = LayoutInflater.from(context).inflate(R.layout.lay_number_keyboard, null, false);
        //单击按钮触发接口回调
        view.findViewById(R.id.btn_0).setOnClickListener(v -> listener.onNum("0"));
        view.findViewById(R.id.btn_1).setOnClickListener(v -> listener.onNum("1"));
        view.findViewById(R.id.btn_2).setOnClickListener(v -> listener.onNum("2"));
        view.findViewById(R.id.btn_3).setOnClickListener(v -> listener.onNum("3"));
        view.findViewById(R.id.btn_4).setOnClickListener(v -> listener.onNum("4"));
        view.findViewById(R.id.btn_5).setOnClickListener(v -> listener.onNum("5"));
        view.findViewById(R.id.btn_6).setOnClickListener(v -> listener.onNum("6"));
        view.findViewById(R.id.btn_7).setOnClickListener(v -> listener.onNum("7"));
        view.findViewById(R.id.btn_8).setOnClickListener(v -> listener.onNum("8"));
        view.findViewById(R.id.btn_9).setOnClickListener(v -> listener.onNum("9"));
        view.findViewById(R.id.btn_del).setOnClickListener(v -> listener.onDelete());
        view.findViewById(R.id.btn_complete).setOnClickListener(v -> {
    
    
            listener.onComplete();
            dialog.dismiss();
        });
        //点击外面消失
        dialog.setCancelable(true);
        //设置内容视图
        dialog.setContentView(view);
        if (dialog.getWindow() != null) {
    
    
            //设置弹出窗口背景透明
            WindowManager.LayoutParams params = dialog.getWindow().getAttributes();
            params.dimAmount = 0.0f;
            dialog.getWindow().setAttributes(params);
        }
        dialog.setOnShowListener(dialog1 -> listener.onDialogShow());
        dialog.setOnCancelListener(dialog12 -> listener.onDialogDismiss());
        dialog.setOnDismissListener(dialog13 -> listener.onDialogDismiss());
        dialog.show();
    }

  下部にポップアップ ウィンドウが表示され、レイアウト ビューを設定し、インターフェイス コールバックを設定し、背景を透明に設定して、最後に表示します。次に、入力ボックスをクリックしてこのポップアップ ウィンドウを呼び出し、キーボードを表示します。

4. キーボードを表示

  クリック イベントとタッチ イベントはビューで取得できるため、カスタム ビューに次のコードを追加できます。

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

  ここのコードは、携帯電話がこの単純な入力ボックスをクリックすると、最初にタッチ イベントがトリガーされ、次にクリック イベントがトリガーされます。ここでは、タッチされたときにキーボード ポップアップ ウィンドウを表示し、true を返します。 、ここにインターセプト イベントがあります。これは、現在のカスタム ビューが実装する必要があるコールバック インターフェイスです。マウスをこれの後ろに置き、キーの組み合わせを押すと、次の図に示すように、ポップアップ ウィンドウが表示されますAlt + Enter。形:

ここに画像の説明を挿入

  ここで 4 番目の項目をクリックすると、ポップアップ ウィンドウが表示されます。すべてのメソッドを確認し、[OK] をクリックして、このインターフェイスのコールバックをすばやく実現し、インターフェイスのメソッドを書き換えると、カスタム ビューに 5 が追加されていることがわかります。メソッド、コードは以下のように表示されます:

    @Override
    public void onNum(String num) {
    
    
        if (currentInputPosition == mInputLength) return;
        inputArray[currentInputPosition] = num;
        currentInputPosition++;
        //Refresh View
        postInvalidate();
    }

    @Override
    public void onDelete() {
    
    
        if (currentInputPosition == 0) return;
        currentInputPosition--;
        inputArray[currentInputPosition] = null;
        //Refresh View
        postInvalidate();
    }

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

    @Override
    public void onDialogShow() {
    
    
        isFocus = true;
        postInvalidate();
    }

    @Override
    public void onDialogDismiss() {
    
    
        isFocus = false;
        postInvalidate();
    }

  メソッドが呼び出されるとpostInvalidate()再描画されるので、前のロジックに従います。

5. 関連する API

  次のように、コードで呼び出すことができる API メソッドをさらにいくつか追加しましょう。

    /**
     * 设置输入框个数
     */
    public void setBoxNum(int num) {
    
    
        if (num < 4 || num > 6) {
    
    
            throw new IllegalArgumentException("The number of input boxes ranges from 4 to 6");
        }
        mBoxNum = num;
    }

    /**
     * 获取输入总长度
     */
    public int getBoxNum() {
    
    
        return mBoxNum;
    }

    /**
     * 设置是否密文
     * @param flag true 密文、false 明文
     */
    public void setCiphertext(boolean flag) {
    
    
        ciphertext = flag;
        postInvalidate();
    }

    /**
     * 设置密文时显示的内容
     * @param content 密文内容,默认是 *
     */
    public void setCiphertextContent(String content) {
    
    
        if (content == null) return;
        if (content.isEmpty()) return;
        if (content.length() > 1) return;
        ciphertextContent = content;
    }

    /**
     * 获取输入内容
     */
    public String getText() {
    
    
        StringBuilder builder = new StringBuilder();
        for (String number : inputArray) {
    
    
            if (number == null) continue;
            if (number.isEmpty()) continue;
            builder.append(number);
        }
        return builder.toString();
    }

4 番目に、カスタム ビューを使用します。

app使い方については、この記事を読んだ時点でこのカスタム View がウェアハウスに追加されていたので、モジュール内で使用するなどの依存関係を導入してから、アプリ モジュールbuild.gradleを開いてdependencies{}クロージャーの下に追加すること   で使用できます。Sync Now

dependencies {
    
    
    implementation 'io.github.lilongweidev:easyview:1.0.3'
}

   または、自分のプロジェクトで上記のすべての手順を完了している場合は、依存関係を導入する必要はありません。直接呼び出すだけですが、対応するパッケージ名を変更することに注意してください。そうしないと、人気が高まります。

これを使用するには、次のように activity_easy_edittext.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"
    tools:context=".used.EasyEditTextActivity">

    <!--简易输入框-->
    <com.easy.view.EasyEditText
        android:id="@+id/et_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:boxBackgroundColor="@color/white"
        app:boxFocusStrokeColor="@color/green"
        app:boxNum="6"
        app:boxStrokeColor="@color/black"
        app:boxStrokeWidth="2dp"
        app:boxWidth="48dp"
        app:ciphertext="false"
        app:textColor="@color/black"
        app:textSize="16sp" />

    <CheckBox
        android:id="@+id/cb_flag"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="明文" />

    <Button
        android:id="@+id/btn_get_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="12dp"
        android:text="获取内容" />
</LinearLayout>

  XML をプレビューできないことがわかった場合、このカスタム ビューは表示されません。Rebuild Projectクリックするだけで表示できます。プレビュー効果を次の図に示します。

ここに画像の説明を挿入

  次に、使用する EasyEditTextActivity を入力し、次のようにコードを変更します。

public class EasyEditTextActivity extends EasyActivity<ActivityEasyEdittextBinding> {
    
    

    @Override
    protected void onCreate() {
    
    
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        binding.cbFlag.setOnCheckedChangeListener((buttonView, isChecked) -> {
    
    
            binding.etContent.setCiphertext(isChecked);
            binding.cbFlag.setText(isChecked ? "密文" : "明文");
        });
        //输入框
        binding.btnGetContent.setOnClickListener(v -> {
    
    
            String content = binding.etContent.getText();
            if (content.isEmpty()) {
    
    
                showMsg("请输入内容");
                return;
            }
            if (content.length() < binding.etContent.getBoxNum()) {
    
    
                showMsg("请输入完整内容");
                return;
            }
            showMsg("输入内容为:" + content);
        });
    }
}

  ここでのコードは非常に単純です. ビューを取得し、ボタンがクリックされたときに入力ボックスの値を取得し、その値をボタンに表示します. 以下のテストを実行します.

ここに画像の説明を挿入

五、ソースコード

参考になれば、スターまたはフォークを希望する場合があります。山は高く、水は長く、後で期間があります〜

ソースアドレス: EasyView

おすすめ

転載: blog.csdn.net/qq_38436214/article/details/130426736