Android customizes a province abbreviation keyboard

Hello everyone, in this article, we return to the custom View in Android. In fact, we have been working on Flutter recently. The initial idea is to encapsulate the basic components of Flutter first, and then continue with various tools, lists, and networks. , Do it all from the shallower to the deeper. After finishing Flutter, gradually update the technical points in Android. Looking back, let’s intersperse it. The system planning will inevitably change. Write whatever you think of. Just be able to hold on to the output.

Today’s knowledge point is a custom View, the abbreviated keyboard of a province, which is mainly used in places such as license plate input, which is relatively simple. Let’s first look at the final implementation effect:

There are many ways to implement it, and I believe everyone has their own set of implementation mechanisms. Here, I use the combination View and LinearLayout.

Today’s content is roughly as follows:

1. Analyze UI, how to layout

2. Set attributes and develop scalable effects

3. Partial source code analysis

4. Open source address and practical summary

1. Analyze UI, how to layout

After getting the UI renderings, there is actually nothing to analyze. It is nothing more than two pieces, the completion button on the top and the province abbreviation grid at the bottom. At the beginning, I planned to use the RecyclerView grid layout to realize it, but how to place the delete button at the end It became a problem. It is obviously not suitable to directly float on the grid and dynamically calculate the position, and there is no such way to do it. Simply abandon this solution and choose the simplest LinearLayout combined View form.

The so-called simplicity is to continuously add sub-Views to the LinearLayout during the traversal of the province abbreviation array. It should be noted that the own View, that is, our custom View, after inheriting the LinearLayout, defaults to the vertical direction. What the View adds is a LinearLayout with a horizontal attribute, which is also the effect of line breaks, that is, a horizontal LinearLayout per line. Remember, the LinearLayout with a horizontal attribute is the direct parent class that finally adds the View.

The condition of line break is based on the UI effect. When the length is set equal to 0, we will recreate a horizontal LinearLayout. This is all right, isn’t it very simple.

As for the last delete button, make it to the right and occupy the weight settings of two grids.

2. Set attributes to develop scalable effects

After we draw this identity keyboard for short, it must be used by others. Based on flexible and changeable requirements, we also need to configure it dynamically, such as background color, text color, size, and border. distance, and click effects, etc., all of which need to be exposed for users to use selectively. At present, all the attributes are as follows, and you can also set them accordingly when using them.

Attributes

type

overview

lp_background

color

overall background color

lp_rect_spacing

dimension

grid margins

lp_rect_height

dimension

grid height

lp_rect_margin_top

dimension

grid distance top

lp_margin_left_right

dimension

left and right distance

lp_margin_top

dimension

top distance

lp_margin_bottom

dimension

Bottom distance

lp_rect_background

reference

plaid background

lp_rect_select_background

reference

Background after grid selection

lp_rect_text_size

dimension

grid text size

lp_rect_text_color

color

grid text color

lp_rect_select_text_color

color

grid text selection color

lp_is_show_complete

boolean

Whether to show the done button

lp_complete_text_size

dimension

Done button text size

lp_complete_text_color

color

Done button text color

lp_complete_text

string

Done button text content

lp_complete_margin_top

dimension

Done button distance top

lp_complete_margin_bottom

dimension

Done button distance below

lp_complete_margin_right

dimension

Done button distance to the right

lp_text_click_effect

boolean

Whether to trigger the click effect, if true, the background disappears after clicking, and if false, it does not disappear

3. Key source code analysis

Only part of the key code is posted here, and the overall code, you can slide to the bottom to view the source code address.

Define an array of identity abbreviations

 //Province abbreviation data
    private val mLicensePlateList = arrayListOf(
        "Beijing", "Tianjin", "Chongqing", "Shanghai", "Ji", "Jin", "Liao", "Ji", "Black", "Su",
        "Zhe", "Anhui", "Min", "Jiangxi", "Lu", "Yu", "E", "Xiang", "Yue", "Qiong",
        "Sichuan", "Gui", "Cloud", "Shaanxi", "Gan", "Qing", "Mongol", "Gui", "Ning", "Xin",
        "Tibet", "Shi", "Ling", "Study", "Hong Kong", "Macao",
    )

Traverse province abbreviations

mLength shows how many in one line. When the modulus is 0, it needs to wrap the line, that is, create a horizontal LinearLayout again and add it to the outer vertical LinearLayout. In each horizontal LinearLayout, there are TextViews one by one.

 //The province abbreviation corresponding to each line
        var layout: LinearLayout? = null
        // Loop through license plate numbers
        mLicensePlateList.forEachIndexed { index, s ->
            if (index % mLength == 0) {
                //Recreate and add View
                layout = createLinearLayout()
                layout?.weightSum = 1f
                addView(layout)
                val params = layout?.layoutParams as LayoutParams
                params. apply {
                    topMargin = mRectMarginTop.toInt()
                    height = mRectHeight.toInt()
                    leftMargin = mMarginLeftRight.toInt()
                    rightMargin = mMarginLeftRight.toInt() - mSpacing.toInt()
                    layout?.layoutParams = this
                }
            }

            //Create text view
            val textView = TextView(context).apply {
                text = s
                //Set the properties of the text
                textSize = px2sp(mRectTextSize)
                //whether the last five are forbidden
                if (mNumProhibit & amp; & amp; index > (mLicensePlateList. size - 6)) {
                    setTextColor(mNumProhibitColor)
                    mTempTextViewList. add(this)
                } else {
                    setTextColor(mRectTextColor)
                }

                setBackgroundResource(mRectBackGround)
                gravity = Gravity.CENTER
                setOnClickListener {
                    if (mNumProhibit & amp; & amp; index > (mLicensePlateList. size - 6)) {
                        return @setOnClickListener
                    }
                    //Click event for each grid
                    changeTextViewState(this)
                }
            }

            addRectView(textView, layout, 0.1f)
        }

Append the last View

Since the last view is a picture and occupies the size of two grids, it needs special treatment. What needs to be done is to set the weight and width separately, as shown below:

 /**
     * AUTHOR:AbnerMing
     * INTRODUCE: Append the last View
     */
    private fun addEndView(layout: LinearLayout?) {
        val endViewLayout = LinearLayout(context)
        endViewLayout.gravity = Gravity.RIGHT
        //delete button
        val endView = RelativeLayout(context)
        //add delete button
        val deleteImage = ImageView(context)
        deleteImage.setImageResource(R.drawable.view_ic_key_delete)
        endView. addView(deleteImage)

        val imageParams = deleteImage.layoutParams as RelativeLayout.LayoutParams
        imageParams.addRule(RelativeLayout.CENTER_IN_PARENT)
        deleteImage.layoutParams = imageParams
        endView. setOnClickListener {
            //delete
            mKeyboardDelete?.invoke()
            invalidate()
        }
        endView.setBackgroundResource(mRectBackGround)
        endViewLayout. addView(endView)
        val params = endView.layoutParams as LayoutParams
        params.width = (getScreenWidth() / mLength) * 2 - mMarginLeftRight.toInt()
        params.height = LayoutParams.MATCH_PARENT

        endView.layoutParams = params

        layout?.addView(endViewLayout)
        val endParams = endViewLayout.layoutParams as LayoutParams
        endParams. apply {
            width = (mSpacing * 3).toInt()
            height = LayoutParams.MATCH_PARENT
            weight = 0.4f
            rightMargin = mSpacing. toInt()
            endViewLayout.layoutParams = this
        }


    }

4. Summary of open source addresses and usage

Open source address: https://github.com/AbnerMing888/LicensePlateView

Regarding the use, it is actually a class. You can download the source code, copy it directly and use it. You can also modify the code inside. It is very convenient. If you are too lazy to download the source code, it doesn’t matter. I also uploaded it to the remote Maven. You can follow the steps below way to use.

Maven specific call

1. Under the build.gradle file under your root project, import maven.

allprojects {
    repositories {
        maven { url "https://gitee.com/AbnerAndroid/almighty/raw/master" }
    }
}

2. Under the build.gradle file in the Module you need to use, introduce dependencies.

dependencies {
    implementation 'com.vip:plate:1.0.0'
}

Code usage

 <com.vip.plate.LicensePlateView
        android:id="@ + id/lp_view"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:layout_constraintBottom_toBottomOf="parent"
        app:lp_complete_text_size="14sp"
        app:lp_margin_left_right="10dp"
        app:lp_rect_spacing="6dp"
        app:lp_rect_text_size="19sp"
        app:lp_text_click_effect="false" />

Summary

When you use it, you must use it selectively according to the attribute table; about this province, it is referred to as custom View, and there are many ways to implement it. My current way is not the best way to achieve it, but it is just an implementation plan for me. Let’s use it as a basis for reference. Well, friends, this article will end here first, and I hope it can help everyone.