Kotlin学习 01

之前因为工作没有转型kotlin的必要,并且一些杂事较多,一直没有好好深入学习kotlin。现在放眼看去,kotlin已经是统治地位了,不会kotlin,真不好意思说自己会做安卓开发。

非常遗憾,现在重新开始,我任是一个爱学新技术的追风少年。

我的学习方法是:

  • 看语法讲解
  • 看代码
  • 修改代码或者自己实现一遍

 

在网上看了分享的一个车牌省份选择控件,使用kotlin实现的,可以作为学习资料。

项目地址https://github.com/AbnerMing888/LicensePlateView。感兴趣的小伙伴可以去看原项目。

 

效果图

贴上代码

package com.example.mylogindemomvp.ui.carnumber

import android.content.Context
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.util.AttributeSet
import android.view.Gravity
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.example.mylogindemomvp.R

/**
 * 自定义车牌号选择器
 */
class LicensePlateView: LinearLayout {

    companion object {
        val mLicensePlateList = arrayListOf(
            "京", "津", "渝", "沪", "冀", "晋", "辽", "吉", "黑", "苏",
            "浙", "皖", "闽", "赣", "鲁", "豫", "鄂", "湘", "粤", "琼",
            "川", "贵", "云", "陕", "甘", "青", "蒙", "桂", "宁", "新",
            "藏", "使", "领", "学", "港", "澳",
        )
    }

    private var mSpacing = 10f          // 间隔
    private var mMarginLeftRight = 10f  // 左边距
    private var mMarginBottom = 0f      // 下边距
    private var mMarginTop = 60f        // 上边距

    private var mLength = 10            // 长度
    private var mRectHeight = 88f       // 每个格子高度
    private var mRectMarginTop = 16f    // 距离上边高度

    private var mBackGroundColor = Color.TRANSPARENT  // 背景颜色
    private var mBackGroundImageRes:Int ?= null // 背景图片资源
    private var mRectBackGround = R.drawable.view_shape_stroke_8548d2_radius_2      // 格子背景
    private var mRectSelectBackGround = R.drawable.view_shape_stroke_8548d2_radius_2// 格子选中背景

    private var mIsShowComplete = true//是否显示完成按钮

    private var mCompleteTextColor = Color.BLACK//完成按钮文字颜色

    private var mCompleteTextSize = 36f//完成文字大小

    private var mCompleteText = "完成"//完成文字内容

    private var mCompleteMarginTop = 20f//完成距离上边

    private var mCompleteMarginBottom = 20f//完成距离上边

    private var mCompleteMarginRight = 20f//完成距离右边

    private var mRectTextSize = 56f//格子的文字大小

    private var mRectTextColor = ContextCompat.getColor(context, R.color.text_333333)//格子文字的默认颜色

    private var mRectSelectTextColor = ContextCompat.getColor(context, R.color.text_8548D2) // 格子文字的选中颜色

    private var mNumProhibit = true // 默认禁止选择
    private var mNumProhibitColor = ContextCompat.getColor(context, R.color.text_999999)

    private var mTempTextViewList = ArrayList<TextView>() // 存储临时View
    private var mTextClickEffect = true // 是否触发点击效果

    private var mOldTextView:TextView = TextView(context)

    constructor(context: Context): super(context) {
        initData(context)
    }

    constructor(context: Context, attrs: AttributeSet?): super(context, attrs) {
        context.obtainStyledAttributes(attrs, R.styleable.LicensePlateView)
            .apply {
                // 整理的背景颜色
                mBackGroundColor = getColor(R.styleable.LicensePlateView_lp_background, Color.parseColor("#F5F5F5"))
                mBackGroundImageRes = getResourceId(R.styleable.LicensePlateView_lp_background_img, -1)
                // 每个格子的默认背景
                mRectBackGround = getResourceId(R.styleable.LicensePlateView_lp_rect_background, mRectBackGround)

                // 每个格子的选中背景
                mRectSelectBackGround = getResourceId(R.styleable.LicensePlateView_lp_rect_background, mRectSelectBackGround)

                // 格子的文字大小
                mRectTextSize = getDimension(R.styleable.LicensePlateView_lp_rect_text_size, mRectTextSize)
                // 格子的文字颜色
                mRectTextColor = getColor(R.styleable.LicensePlateView_lp_rect_text_color, mRectTextColor)
                //格子的选中文字颜色
                mRectSelectTextColor = getColor(R.styleable.LicensePlateView_lp_rect_select_text_color, mRectSelectTextColor)
                //每个格子的边距
                mSpacing = getDimension(R.styleable.LicensePlateView_lp_rect_spacing, mSpacing)
                //每个格子的高度
                mRectHeight = getDimension(R.styleable.LicensePlateView_lp_rect_height, mRectHeight)
                // 格子距离上边的距离
                mRectMarginTop = getDimension(R.styleable.LicensePlateView_lp_rect_margin_top, mRectMarginTop)
                // 视图距离左右的距离
                mMarginLeftRight = getDimension(R.styleable.LicensePlateView_lp_margin_left_right, mMarginLeftRight)
                //视图距离上边的距离
                mMarginTop =
                    getDimension(R.styleable.LicensePlateView_lp_margin_top, mMarginTop)
                //视图距离下边的距离
                mMarginBottom =
                    getDimension(R.styleable.LicensePlateView_lp_margin_bottom, mMarginBottom)
                //视图距离左右的距离
                mMarginLeftRight = getDimension(R.styleable.LicensePlateView_lp_margin_left_right, mMarginLeftRight)
                //是否显示完成按钮
                mIsShowComplete = getBoolean(R.styleable.LicensePlateView_lp_is_show_complete, true)
                //完成按钮文字颜色
                mCompleteTextColor =
                    getColor(R.styleable.LicensePlateView_lp_complete_text_color, Color.parseColor("#087EFD"))
                //完成按钮文字大小
                mCompleteTextSize =
                    getDimension(
                        R.styleable.LicensePlateView_lp_complete_text_size,
                        mCompleteTextSize
                    )
                //完成按钮文字内容
                getString(R.styleable.LicensePlateView_lp_complete_text)?.let {
                    mCompleteText = it
                }
                //完成按钮距离上边
                mCompleteMarginTop =
                    getDimension(
                        R.styleable.LicensePlateView_lp_complete_margin_top,
                        mCompleteMarginTop
                    )
                //完成按钮距离下边
                mCompleteMarginBottom =
                    getDimension(
                        R.styleable.LicensePlateView_lp_complete_margin_bottom,
                        mCompleteMarginBottom
                    )
                //完成按钮距离上边
                mCompleteMarginRight =
                    getDimension(
                        R.styleable.LicensePlateView_lp_complete_margin_right,
                        mCompleteMarginRight
                    )
                //是否触发点击效果
                mTextClickEffect =
                    getBoolean(
                        R.styleable.LicensePlateView_lp_text_click_effect,
                        mTextClickEffect
                    )
                this.recycle()
            }

        initData(context)
    }

    /**
     * 初始化数据
     */
    private fun initData(context: Context) {
        // 设置背景颜色
        setBackgroundColor(mBackGroundColor)
        if(mBackGroundImageRes != -1) {
            mBackGroundImageRes?.let { setBackgroundResource(it) }
        }

        orientation = VERTICAL
        // 设置距离底部
        setPadding(0, mMarginTop.toInt(), 0, mMarginBottom.toInt())

        // “完成” 按钮是否显示?
        if(mIsShowComplete) {
            // 添加完成的View视图
            val textView = TextView(context)
            textView.apply {
                setOnClickListener() {
                    mKeyboardCompleted?.invoke()
                }
                gravity = Gravity.END
                text = mCompleteText
                setTextColor(mCompleteTextColor)
                textSize = px2sp(mCompleteTextSize)
            }

            addView(textView)
            val submitParams = textView.layoutParams as LayoutParams
            submitParams.apply {
                width = LayoutParams.MATCH_PARENT
                topMargin = mCompleteMarginTop.toInt()
                bottomMargin = (mCompleteMarginBottom - mRectMarginTop).toInt()
                rightMargin = mCompleteMarginRight.toInt()
                textView.layoutParams = this
            }
        }

        // 每行对应的省份简称
        var layout: LinearLayout? = null
        mLicensePlateList.forEachIndexed{ index, s ->
            if(index % mLength == 0) {
                // 重新创建,并添加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
                }
            }

            //创建文字视图
            val textView = TextView(context).apply {
                text = s
                //设置文字的属性
                textSize = px2sp(mRectTextSize)
                //最后五个是否禁止
                if (mNumProhibit && index > (mLicensePlateList.size - 6)) {
                    setTextColor(mNumProhibitColor)
                    mTempTextViewList.add(this)
                } else {
                    setTextColor(mRectTextColor)
                }

                setBackgroundResource(mRectBackGround)
                gravity = Gravity.CENTER
                setOnClickListener {
                    if (mNumProhibit && index > (mLicensePlateList.size - 6)) {
                        return@setOnClickListener
                    }
                    //每个格子的点击事件
                    changeTextViewState(this)
                }
            }
            addRectView(textView, layout, 0.1f)
        }

        //追加最后一个删除按钮View,动态计算宽度
        addEndView(layout)
    }

    /**
     * AUTHOR:AbnerMing
     * INTRODUCE:追加最后一个View
     */
    private fun addEndView(layout: LinearLayout?) {
        val endViewLayout = LinearLayout(context)
        endViewLayout.gravity = Gravity.END
        //删除按钮
        val endView = RelativeLayout(context)
        //添加删除按钮
        val deleteImage = ImageView(context)
        deleteImage.setImageResource(R.mipmap.icon_left)
        endView.addView(deleteImage)

        val imageParams = deleteImage.layoutParams as RelativeLayout.LayoutParams
        imageParams.addRule(RelativeLayout.CENTER_IN_PARENT)
        deleteImage.layoutParams = imageParams
        endView.setOnClickListener {
            //删除
            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
        }
    }

    private fun addRectView(view: TextView, layout: LinearLayout?, w: Float) {
        layout?.addView(view)
        val textParams = view.layoutParams as LayoutParams
        textParams.apply {
            weight = w
            width = 0
            height = LayoutParams.MATCH_PARENT
            //每行的最后一个
            rightMargin = mSpacing.toInt()
            view.layoutParams = this
        }

    }

    private fun changeTextViewState(textView: TextView) {
        if (mTextClickEffect) {
            //点击设置成效果
            textView.setSelectTextStyle()
            textView.postDelayed({
                textView.setUnSelectTextStyle()
            }, 300)
        } else {
            //记录上一个
            mOldTextView?.setUnSelectTextStyle()
            textView.setSelectTextStyle()
            mOldTextView = textView
        }
        println("点击选择:" + textView.text)
        //每次点击后进行赋值
        mKeyboardContent?.invoke(textView.text.toString())
    }

    private fun TextView.setSelectTextStyle() {
        setBackgroundResource(mRectSelectBackGround)
        setTextColor(mRectSelectTextColor)
    }

    private fun TextView.setUnSelectTextStyle() {
        setBackgroundResource(mRectBackGround)
        setTextColor(mRectTextColor)
    }

    private fun createLinearLayout(): LinearLayout? {
        val layout = LinearLayout(context)
        layout.orientation = HORIZONTAL
        return layout
    }

    private var mKeyboardContent: ((content: String) -> Unit?)? = null
    fun keyboardContent(block: (String) -> Unit) {
        mKeyboardContent = block
    }

    /**
     * 键盘“完成”按键
     */
    private var mKeyboardCompleted: (() -> Unit)? = null
    fun keyboardCompleted(block: () -> Unit) {
        mKeyboardCompleted = block
    }

    /**
     * 键盘“删除”按键
     */
    private var mKeyboardDelete: (() -> Unit?)? = null
    fun keyboardDelete(block: () -> Unit) {
        mKeyboardDelete = block
    }

    fun openProhibit(isOpen: Boolean) {
        //禁止解开
        mNumProhibit = isOpen
        mTempTextViewList.forEach {
            if (isOpen) {
                it.setTextColor(mRectTextColor)
            } else {
                it.setTextColor(mNumProhibitColor)
            }
        }
    }

    /**
     * 获取屏幕的宽
     */
    private fun getScreenWidth(): Int {
        return resources.displayMetrics.widthPixels
    }

    /**
     * DP转像素
     */
    private fun px2sp(pxValue: Float): Float {
        val fontScale = resources.displayMetrics.scaledDensity
        return pxValue / fontScale + 0.5f
    }
}

自定义属性 attrs.xml

 <declare-styleable name="LicensePlateView">
        <!--        整体的背景颜色-->
        <attr name="lp_background" format="color" />
        <!--        整体的背景图片-->
        <attr name="lp_background_img" format="reference" />
        <!--        格子的边距-->
        <attr name="lp_rect_spacing" format="dimension" />
        <!--        格子的高度-->
        <attr name="lp_rect_height" format="dimension" />
        <!--        格子的距离上边-->
        <attr name="lp_rect_margin_top" format="dimension" />
        <!--        左右距离-->
        <attr name="lp_margin_left_right" format="dimension" />
        <!--        上边距离-->
        <attr name="lp_margin_top" format="dimension" />
        <!--        下边距离-->
        <attr name="lp_margin_bottom" format="dimension" />
        <!--        格子的背景-->
        <attr name="lp_rect_background" format="reference" />
        <!--        格子选择后的背景-->
        <attr name="lp_rect_select_background" format="reference" />

        <!--        格子的文字大小-->
        <attr name="lp_rect_text_size" format="dimension" />
        <!--        格子的文字颜色-->
        <attr name="lp_rect_text_color" format="color" />
        <!--        格子的文字选中颜色-->
        <attr name="lp_rect_select_text_color" format="color" />

        <!--是否显示完成按钮-->
        <attr name="lp_is_show_complete" format="boolean" />
        <!--完成按钮文字大小-->
        <attr name="lp_complete_text_size" format="dimension" />
        <!--完成按钮文字颜色-->
        <attr name="lp_complete_text_color" format="color" />
        <!--完成按钮文字内容-->
        <attr name="lp_complete_text" format="string" />
        <!--完成按钮距离上边-->
        <attr name="lp_complete_margin_top" format="dimension" />
        <!--完成按钮距离下边-->
        <attr name="lp_complete_margin_bottom" format="dimension" />
        <!--完成按钮距离右边-->
        <attr name="lp_complete_margin_right" format="dimension" />
        <!--是否触发点击效果-->
        <attr name="lp_text_click_effect" format="boolean" />

    </declare-styleable>

 

posted @ 2023-05-23 21:38  Liu Siyuan  阅读(5)  评论(0编辑  收藏  举报