Phished Taobao Payment Password Input Box

Keywords: Android xml encoding

I believe you should be familiar with the password input box of Payment Insurance (after all, it is often used). Let's first show you Alipay's

Okay, back to the point, yesterday my department boss gave me an APP to show me what's good in it, which can be put into our own APP modules, functions, processes (alas, small companies copy all kinds of things like that). When I see this password entry box in this APP, I want to write one myself, but as a rookie I don't have any good idea, go to the sea of GitHubA circle down the middle of the ocean led several open source projects to find ideas, and eventually got this.

Design ideas:

To do this we need to use a custom View
Step 1: Create a class that inherits EditText (I inherit AppCompatEditText, which is exactly the same)
Step 2: Create an attr file where you can write your own custom attributes.
Step 3: Rewrite the onDraw method drawing interface
Step 4: Write a callback interface to call back the operation completed by the password input.

This is probably the design idea, the most important of which is to draw the interface in the onDraw method, the others are very simple, here is also the main operation in the onDraw method, the other steps will see the complete code (I will post the code at the end of the article)

Drawing interface
The way I think about drawing the interface is this:
Step 1: Draw a background with a light gray background
Step 2: Draw the white content area, which is slightly narrower and shorter than the background, so that you can form the outer border of this input box.
Step 3: Draw a dividing line
Step 4: Draw the input (using small dots instead)

Draw the background with the following code:

  //Paint Background
        RectF bgRect = new RectF(0, 0, width, height);
        //Set the color of the background
        bgPaint.setColor(borderColor);
        canvas.drawRect(bgRect, bgPaint);

Draw the content area with the following code:

  //Picture Content Area
        RectF contentRect = new RectF(bgRect.left + borderWidth, bgRect.top + borderWidth, bgRect.right - borderWidth, bgRect.bottom - borderWidth);
        rectPaint.setColor(chunkColor);
        canvas.drawRect(contentRect, rectPaint);

The borderWidth value in the code above, you can think of it as the width of the outer border. My outer border is actually a large rectangle with a small rectangle inside. The two rectangles have different colors and form the outer border.

Draw a split line with the following code:

        //Draw a dividing line
        bgPaint.setStrokeWidth(linesWidth);//Set the width of the dividing line
        bgPaint.setColor(linesColor);//Set the color of the dividing line
        for (int i = 0; i < defultCount; i++) {
            float x = width / defultCount * i;
            canvas.drawLine(x, borderWidth, x, height - borderWidth, bgPaint);
        }

The most important of the above codes is this sentence: float x = width / defultCount * i;
This means calculating the position of the dividing line. The y-axis of the dividing line is the same as the value of the x-axis. Let's explain this code.
width: the overall length of the control
defultCount: The control has several grids
I:i starts at 0 and increments in the for loop to find the position of the x-axis from the first dividing line to the last one

Draw the password as follows:

    if (textLength > 0) {
            //Draw Password
            int j = getWidth() / defultCount / 2;
            for (int i = 0; i < textLength; i++) {
                int cx = width / defultCount * i + j;
                circleRadius = height / 6;
                canvas.drawCircle(cx, getHeight() / 2, circleRadius, bgPaint);
            }
        }

We start drawing when the length of the password we enter is greater than zero

I won't explain the above code (partners should understand it), even if we finish drawing here, here is the listening and callback of the input.

Listening for input:

To listen for input, we have to override the onTextChanged method with the following code:

  @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        textLength = text.toString().length();
        invalidate();
        if (textLength == defultCount) {
            if (onInputFinishListener != null) {
                onInputFinishListener.inputFinish(text.toString());
            }
        }
    }

Here we need to write a callback interface ourselves, as follows:

//Declare Interface
  private OnInputFinishListener onInputFinishListener;

//set method of interface
    public void setOnInputFinishListener(OnInputFinishListener onInputFinishListener) {
        this.onInputFinishListener = onInputFinishListener;
    }
//The ontology of an interface
    public interface OnInputFinishListener {
        void inputFinish(String text);
    }

- I am the dividing line - I am the dividing line - I am the dividing line - I am the dividing line - I am the dividing line - I am the dividing line - I am the dividing line

If you are not interested in reading the article, you can copy the code directly, as follows:

package com.example.administrator.coo.passwordEditText;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.v7.widget.AppCompatEditText;
import android.util.AttributeSet;
import android.view.ViewGroup;

import com.example.administrator.coo.R;

/**
 * Created by zhanglei on 2017/6/9.
 * Fake Payment Secret Code Input Box
 */

public class PasswordEditText extends AppCompatEditText {


    /**
     * Enter the number of grids
     */
    private int defultCount = 6;

    /**
     * Brush used to draw background
     */
    private Paint bgPaint = new Paint();

    /**
     * Brush used to draw content blocks
     */
    private Paint rectPaint = new Paint();

    /**
     * Length of password
     */
    private int textLength = 0;

    /**
     * The width of the dividing line
     */
    private float linesWidth = 0;

    /**
     * border width
     */
    private float borderWidth = 0;

    /**
     * border color
     */
    private int borderColor = 0xFFCCCCCC;

    /**
     * Color of the dividing line
     */
    private int linesColor = 0xFFCCCCCC;

    /**
     * Radius of password circle
     */
    private int circleRadius;

    /**
     * Content block background color
     */
    private int chunkColor = Color.WHITE;

    public PasswordEditText(Context context) {
        super(context);
    }

    public PasswordEditText(Context context, AttributeSet attrs) {
        super(context, attrs);

        linesWidth = getLinesWidth() - 3;
        borderWidth = getLinesWidth() - 1;

        TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.PasswordEditText, 0, 0);
        defultCount = a.getInteger(R.styleable.PasswordEditText_pe_count, defultCount);
        borderWidth = a.getDimension(R.styleable.PasswordEditText_pe_lineWidth, linesWidth);
        linesWidth = a.getDimension(R.styleable.PasswordEditText_pe_cuttingLineWidth, borderWidth);
        borderColor = a.getColor(R.styleable.PasswordEditText_pe_lineColor, this.borderColor);
        linesColor = a.getColor(R.styleable.PasswordEditText_pe_cuttingLineColor, linesColor);
        chunkColor = a.getColor(R.styleable.PasswordEditText_pe_chunkColor, chunkColor);
        a.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //Get the width of the control
        int width = getWidth();
        //Get the height of the control
        int height = getHeight();

        //Paint Background
        RectF bgRect = new RectF(0, 0, width, height);
        //Set the color of the background
        bgPaint.setColor(borderColor);
        canvas.drawRect(bgRect, bgPaint);

        //Picture Content Area
        RectF contentRect = new RectF(bgRect.left + borderWidth, bgRect.top + borderWidth, bgRect.right - borderWidth, bgRect.bottom - borderWidth);
        rectPaint.setColor(chunkColor);
        canvas.drawRect(contentRect, rectPaint);

        //Draw a dividing line
        bgPaint.setStrokeWidth(linesWidth);
        bgPaint.setColor(linesColor);
        for (int i = 0; i < defultCount; i++) {
            float x = width / defultCount * i;
            canvas.drawLine(x, borderWidth, x, height - borderWidth, bgPaint);
        }

        if (textLength > 0) {
            //Draw Password
            int j = getWidth() / defultCount / 2;
            for (int i = 0; i < textLength; i++) {
                int cx = width / defultCount * i + j;
                circleRadius = height / 6;
                canvas.drawCircle(cx, getHeight() / 2, circleRadius, bgPaint);
            }
        }
    }

    @Override
    protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) {
        super.onTextChanged(text, start, lengthBefore, lengthAfter);
        textLength = text.toString().length();
        invalidate();
        if (textLength == defultCount) {
            if (onInputFinishListener != null) {
                onInputFinishListener.inputFinish(text.toString());
            }
        }
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    private float getLinesWidth() {
        ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) getLayoutParams();
        //Gets the margin value to the left of the control
        int leftMargin = lp.leftMargin;
        //Gets the margin value to the right of the control
        int rightMargin = lp.rightMargin;
        //Width of border and splitter line
        return (leftMargin + rightMargin + getWidth()) / 200;
    }

    private OnInputFinishListener onInputFinishListener;

    public void setOnInputFinishListener(OnInputFinishListener onInputFinishListener) {
        this.onInputFinishListener = onInputFinishListener;
    }

    public interface OnInputFinishListener {
        void inputFinish(String text);
    }
}

Here's one more property you need to copy, which is customized:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <declare-styleable name="PasswordEditText">
        <attr name="pe_count" format="integer" />
        <attr name="pe_lineWidth" format="dimension" />
        <attr name="pe_cuttingLineWidth" format="dimension" />
        <attr name="pe_lineColor" format="color" />
        <attr name="pe_cuttingLineColor" format="color" />
        <attr name="pe_passwordColor" format="color" />
        <attr name="pe_chunkColor" format="color" />
    </declare-styleable>

</resources>

At the end of the article, you can see the effect of this password entry box.

When the input is complete, the inputFinish method in the OnInputFinishListener interface is called back to get the input.

This concludes the article, I hope you can help

Posted by rodin on Sun, 23 Jun 2019 10:08:44 -0700