用Kotlin自定义一个搜索框控件

您所在的位置:网站首页 android怎么做搜索框 用Kotlin自定义一个搜索框控件

用Kotlin自定义一个搜索框控件

2024-07-09 12:45| 来源: 网络整理| 查看: 265

前言

Kotlin作为谷歌力推的Android一级开发语言,当然是有它的独到之处的,Kotlin也使用了一段时间了,今天心血来潮,用它来自定义一个搜索框控件,话不多说,先上图 在这里插入图片描述

思路

从效果图可以看出,无非就是三个控件组合而成的:一个文本编辑框EditText和两个ImageView。所以这个自定义控件得继承ViewGroup,而整个布局,要么是用自定义好的一个XML布局文件,再要么就是自己摆放控件位置,这里我选择自己来摆放控件位置

初始化

格式化的步骤,唯一需要注意的是,在这里,将三个控件添加到父控件中去,以及不能因为Kotlin中函数有默认值,就偷懒只写一个包含所有参数的构造函数

class Search : ViewGroup, TextWatcher, TextView.OnEditorActionListener, ValueAnimator.AnimatorUpdateListener, View.OnFocusChangeListener { private var mSearchListener: OnSearchListener? = null interface OnSearchListener { fun search(s: String) } fun setOnSearchListener(listener: OnSearchListener) { mSearchListener = listener } private var mText: String? = null private var mCollapsed = false private var percent = 1f private var mWidth = -1 private var mHeight = -1 private var mAnimator: ValueAnimator? = null private var mEndElement: AnimatorElement? = null private var mStartElement: AnimatorElement? = null private val mEvaluator = AnimatorEvaluator() private var clearIconPadding = 0 private var editPaddingLeft = 0 private var editPaddingTop = 0 private var editPaddingRight = 0 private var editPaddingBottom = 0 private var parentPaddingLeft = 0 private var parentPaddingTop = 0 private var parentPaddingRight = 0 private var parentPaddingBottom = 0 private var clearDrawable: Drawable? = null private var searchDrawable: Drawable? = null private lateinit var clear: ImageView private lateinit var search: ImageView private lateinit var edit: AutoCompleteTextView constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { init(context, attrs) } constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : super(context, attrs, defStyleAttr) { init(context, attrs) } @RequiresApi(Build.VERSION_CODES.LOLLIPOP) constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) { init(context, attrs) } private fun init(context: Context, attrs: AttributeSet?) { clear = ImageView(context) search = ImageView(context) edit = AutoCompleteTextView(context) edit.addTextChangedListener(this) edit.setOnEditorActionListener(this) edit.setSingleLine(true) edit.imeOptions = EditorInfo.IME_ACTION_SEARCH edit.onFocusChangeListener = this edit.gravity = Gravity.CENTER_VERTICAL search.setOnClickListener { search() } clear.setOnClickListener { edit.text.clear() } attachViewToParent(edit, -1, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)) attachViewToParent(clear, -1, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)) attachViewToParent(search, -1, LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)) val ta = context.obtainStyledAttributes(attrs, R.styleable.Search) clearIconPadding = ta.getDimensionPixelOffset(R.styleable.Search_searchClearIconPadding, 0) editPaddingLeft = ta.getDimensionPixelOffset(R.styleable.Search_searchEditPaddingLeft, 0) editPaddingTop = ta.getDimensionPixelOffset(R.styleable.Search_searchEditPaddingTop, 0) editPaddingRight = ta.getDimensionPixelOffset(R.styleable.Search_searchEditPaddingRight, 0) editPaddingBottom = ta.getDimensionPixelOffset(R.styleable.Search_searchEditPaddingBottom, 0) clearDrawable = ta.getDrawable(R.styleable.Search_searchClearIcon) ?: ResourcesCompat.getDrawable(resources, R.drawable.ic_clear_icon, null) searchDrawable = ta.getDrawable(R.styleable.Search_searchSearchIcon) ?: ResourcesCompat.getDrawable(resources, R.drawable.ic_search_icon, null) ViewCompat.setBackground(edit, ta.getDrawable(R.styleable.Search_searchBackground)) val textSize = ta.getDimensionPixelOffset(R.styleable.Search_searchTextSize, 0) if (textSize > 0) edit.textSize = textSize.toFloat() val textColor = ta.getColor(R.styleable.Search_searchTextColor, 0) if (textColor > 0) edit.setTextColor(ta.getColor(R.styleable.Search_searchTextColor, 0)) ta.recycle() clear.setImageDrawable(clearDrawable) search.setImageDrawable(searchDrawable) edit.setPadding(editPaddingLeft, editPaddingTop, editPaddingRight + (clearDrawable?.intrinsicWidth ?: 0), editPaddingBottom) parentPaddingLeft = paddingLeft parentPaddingTop = paddingTop parentPaddingRight = paddingRight parentPaddingBottom = paddingBottom } ...... }

在这里插入图片描述

这里添加进父控件用的是attachViewToParent,而非addViewInLayout,具体原因,官方文档说得很清楚

onMeasure

主要就是计算自适应时的高度,即wrap_content,也就是说计算三个控件中的最大高度值加上间距值

override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { measureChildren(widthMeasureSpec, heightMeasureSpec)// 测量子View尺寸信息 val widthMode = MeasureSpec.getMode(widthMeasureSpec) val suggestWidth = MeasureSpec.getSize(widthMeasureSpec) val heightMode = MeasureSpec.getMode(heightMeasureSpec) val suggestHeight = MeasureSpec.getSize(heightMeasureSpec) when (widthMode) { MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED -> { } MeasureSpec.EXACTLY -> { } } var height = edit.textSize.toInt() val searchH = searchDrawable?.intrinsicHeight ?: 0 if (searchH > height) height = searchH val clearH = clearDrawable?.intrinsicHeight ?: 0 if (clearH > height) height = clearH when (heightMode) { MeasureSpec.AT_MOST, MeasureSpec.UNSPECIFIED -> height += parentPaddingTop + parentPaddingBottom + editPaddingTop + editPaddingBottom MeasureSpec.EXACTLY -> height = suggestHeight } setMeasuredDimension(suggestWidth, height) } onLayout

摆放位置,唯一需要注意的是(0,0)坐标点是以自定义控件的左上角为基准,而非是屏幕的左上角为基准

override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) { val w = r - l val h = b - t println("layout -> w:$w,h:$h") if (mWidth == -1) mWidth = w if (mHeight == -1) mHeight = h val searchW = searchDrawable?.intrinsicWidth ?: 0 val clearW = clearDrawable?.intrinsicWidth ?: 0 val searchL = searchLeft(w, searchW).toInt() search.layout(searchL, parentPaddingTop, searchL + searchW, h - parentPaddingBottom) clear.layout( w - parentPaddingRight - searchW - clearW - editPaddingRight, parentPaddingTop + editPaddingTop, w - parentPaddingRight - searchW - editPaddingRight, h - parentPaddingBottom - editPaddingBottom ) edit.layout( (percent * parentPaddingLeft).toInt(), (percent * parentPaddingTop).toInt(), editRightForCollapse(w).toInt(), h - (percent * parentPaddingBottom).toInt() ) }

以上,动画,属性动画,注意下始末值即可



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3