不带有搜索历史的仿ios搜索框

不带有搜索历史的仿ios搜索框

需求分析

  1. 输入框右侧添加放大镜和清空除按钮,未输入内容显示放大镜,输入内容则显示清空按钮,注:放大镜和清空按钮在同一个位置
  2. 点击回车搜索时如果输入框内有内容则隐藏右侧清空按钮和放大镜隐藏
  3. 收起软键盘时操作同回车搜索操作一样

实现逻辑

创建自定义View

@SuppressLint("AppCompatCustomView")
class ClearEditText(context: Context, attr: AttributeSet) : EditText(context, attr), TextView.OnEditorActionListener, View.OnFocusChangeListener, ViewTreeObserver.OnGlobalLayoutListener {
    
}

定义成员变量

	private var rightClearDrawable: Drawable? = null
    private var drawable: Drawable? = null
    private var searchDrawable: Drawable? = null

初始化初始属性

init {
    /*获取删除按钮图片的Drawable对象*/
    drawable = ContextCompat.getDrawable(context, R.drawable.login_phone_close)
    searchDrawable = ContextCompat.getDrawable(context, R.drawable.ic_serach)

    /*设置图片的范围*/
    drawable!!.setBounds(0, 0, convertDpToPixel(13f).toInt(), convertDpToPixel(13f).toInt())
    searchDrawable!!.setBounds(0, 0, convertDpToPixel(15f).toInt(), convertDpToPixel(15f).toInt())

    /*设置EditText和删除按钮图片的间距*/
    compoundDrawablePadding = context.resources.getDimensionPixelSize(R.dimen.dp5)

    /*输入框内容监听*/
    afterTextChanged {
        /*判断输入框有没有内容,设置是否显示删除按钮*/
        if ("" != text.toString().trim { it <= ' ' } && text.toString().trim { it <= ' ' }.isNotEmpty()) {
            setHideClearDrawable(true)
        } else {
            setHideClearDrawable(false)
        }
    }
    
    if (logo_location == 1) {
        setCompoundDrawables(searchDrawable, compoundDrawables[1], rightClearDrawable, compoundDrawables[3])
    }

    /*设置是否显示删除按钮*/
    setHideClearDrawable(false)

    setOnEditorActionListener(this)

    onFocusChangeListener = this

    rootView.viewTreeObserver.addOnGlobalLayoutListener(this)
}

fun convertDpToPixel(dp: Float): Float {
    val metrics = context.resources.displayMetrics
    return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)
}
创建EditTextExtensionFunction,定义扩展函数
fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
    this.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

        override fun afterTextChanged(editable: Editable?) {
            afterTextChanged.invoke(editable.toString())
        }
    })
}

@SuppressLint("ClickableViewAccessibility")
fun ClearEditText.searchClearTouch(event: MotionEvent) {
    /*判断手指按下的x坐标*/
    val x = event.x

    /*获取自定义EditText宽度*/
    val width = this.width.toFloat()

    /*获取EditText右Padding值*/
    val totalPaddingRight = this.totalPaddingRight.toFloat()

    /*判断手指按下的区域是否在删除按钮宽高范围内*/
    if (event.action == MotionEvent.ACTION_UP) {
        if (x > width - totalPaddingRight && x < width && event.y < this.height) {
            val drawable = compoundDrawables[2]
            if ("" != text.toString().trim { it <= ' ' } && text.toString().trim { it <= ' ' }.isNotEmpty() && drawable != null) {
                this.setText("")
            }
        }
    }
}

判断显示图标是放大镜还是清空按钮

private fun setHideClearDrawable(isVisible: Boolean) {
        /*是否显示删除按钮*/
        rightClearDrawable = if (isVisible) {
            drawable
        } else {
            if (logo_location == 2) searchDrawable else null
        }

        /*给EditText左,上,右,下设置图片*/
        setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], rightClearDrawable, compoundDrawables[3])
    }

监听点击事件

这里判断点击位置是否是清空按钮

override fun onTouchEvent(event: MotionEvent): Boolean {
    searchClearTouch(event)
    return super.onTouchEvent(event)
}

监听回车事件

判断输入框输入内容,如果为空则不隐藏按钮,反之则隐藏

override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
    if (actionId == EditorInfo.IME_ACTION_SEARCH) {
        clearFocus()
        if (!TextUtils.isEmpty(text)) {
            setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], null, compoundDrawables[3])
            hideSoftInput()
        }
    }
    return false
}

监听是否获取焦点

监听获取焦点和失去焦点,失去焦点是输入框内又内容的情况下需要隐藏按钮反之显示

override fun onFocusChange(v: View?, hasFocus: Boolean) {
    if (hasFocus) {
          // 此处为得到焦点时的处理内容
          if (!TextUtils.isEmpty(text)) {
              setHideClearDrawable(true)
          } else {
              setHideClearDrawable(false)
          }
    } else {
        // 此处为失去焦点时的处理内容
        hideSoftInput()
        if (!TextUtils.isEmpty(text)) {
            setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], null, compoundDrawables[3])
        }
    }
}

监听软键盘

通过View树监听判断软键盘是否弹出

var rootViewVisibleHeight = 0

override fun onGlobalLayout() {
    val rect = Rect()
    rootView.getWindowVisibleDisplayFrame(rect)
    var visibleHeight = rect.height()

    if (rootViewVisibleHeight == 0) {
        //拷贝一份,用于比较值的改变
        rootViewVisibleHeight = visibleHeight
        return
    }
    //软键盘显示/隐藏状态没有改变
    if (rootViewVisibleHeight == visibleHeight) {
        return
    }

    if (rootViewVisibleHeight - visibleHeight > 200) {
        rootViewVisibleHeight = visibleHeight
        return
    }

    if (visibleHeight - rootViewVisibleHeight > 200) {
        clearFocus()
        rootViewVisibleHeight = visibleHeight
        return
    }
}

扩展

扩展自定义属性,使用更灵活,可根据需要自行扩展

 <declare-styleable name="ClearEditText">
     <attr name="clears_icon" format="reference"/>
     <attr name="logo" format="reference"/>
     <attr name="logo_location" format="integer">
         <enum name="left" value="1"/>
         <enum name="right" value="2"/>
     </attr>
</declare-styleable>
val obtainStyledAttributes = context.obtainStyledAttributes(attr, R.styleable.ClearEditText)
clear_icon = obtainStyledAttributes.getResourceId(R.styleable.ClearEditText_clears_icon, 0)
logo = obtainStyledAttributes.getResourceId(R.styleable.ClearEditText_logo, 0)
logo_location = obtainStyledAttributes.getInteger(R.styleable.ClearEditText_logo_location, 2)
obtainStyledAttributes.recycle()

为了方便扩展其他独立操作给出自定义回调接口

private var mOnEditorActionListener: MyOnEditorActionListener? = null
private var mOnFocusChangeListener: MyOnFocusChangeListener? = null
private var onSoftKeyShowListener: OnSoftKeyShowListener? = null

fun setOnSoftKeyShowListener(onSoftKeyShowListener: OnSoftKeyShowListener){
    this.onSoftKeyShowListener = onSoftKeyShowListener
}

interface OnSoftKeyShowListener {
    fun onSoftKeyShow(isShow: Boolean)
}

fun setMyOnEditorActionListener(l: MyOnEditorActionListener?) {
    mOnEditorActionListener = l
}

interface MyOnEditorActionListener {
    fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?)
}

fun setMyOnFocusChangeListener(f: MyOnFocusChangeListener) {
    mOnFocusChangeListener = f;
}

interface MyOnFocusChangeListener {
    fun onFocusChange(v: View?, hasFocus: Boolean)
}

源码

ClearEditText

package com.zhengyou.jxdkj.kotlin.view

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.util.AttributeSet
import android.util.DisplayMetrics
import android.view.KeyEvent
import android.view.MotionEvent
import android.view.View
import android.view.ViewTreeObserver
import android.view.inputmethod.EditorInfo
import android.widget.EditText
import android.widget.TextView
import androidx.core.content.ContextCompat
import com.zhengyou.jxdkj.R
import com.zhengyou.jxdkj.kotlin.extension.*
import kotlinx.android.synthetic.main.view_sys_msg.view.*

@SuppressLint("AppCompatCustomView")
class ClearEditText(context: Context, attr: AttributeSet) : EditText(context, attr),
    TextView.OnEditorActionListener, View.OnFocusChangeListener,
    ViewTreeObserver.OnGlobalLayoutListener {
    var rootViewVisibleHeight = 0
    var clear_icon = 0
    var logo = 0
    var logo_location = 0

    private var rightClearDrawable: Drawable? = null
    private var drawable: Drawable? = null
    private var searchDrawable: Drawable? = null
    private var mOnEditorActionListener: MyOnEditorActionListener? = null
    private var mOnFocusChangeListener: MyOnFocusChangeListener? = null
    private var onSoftKeyShowListener: OnSoftKeyShowListener? = null

    init {

        val obtainStyledAttributes = context.obtainStyledAttributes(attr, R.styleable.ClearEditText)
        clear_icon = obtainStyledAttributes.getResourceId(R.styleable.ClearEditText_clears_icon, 0)
        logo = obtainStyledAttributes.getResourceId(R.styleable.ClearEditText_logo, 0)
        logo_location = obtainStyledAttributes.getInteger(R.styleable.ClearEditText_logo_location, 2)
        obtainStyledAttributes.recycle()

        /*获取删除按钮图片的Drawable对象*/
        drawable = ContextCompat.getDrawable(context, if (clear_icon == 0) R.drawable.login_phone_close else clear_icon)
        searchDrawable = ContextCompat.getDrawable(context, if (logo == 0) R.drawable.ic_serach else logo)

        /*设置图片的范围*/
        drawable!!.setBounds(0, 0, convertDpToPixel(13f).toInt(), convertDpToPixel(13f).toInt())
        searchDrawable!!.setBounds(0, 0, convertDpToPixel(15f).toInt(), convertDpToPixel(15f).toInt()
        )

        /*设置EditText和删除按钮图片的间距*/
        compoundDrawablePadding = context.resources.getDimensionPixelSize(R.dimen.dp5)

        /*输入框内容监听*/
        afterTextChanged {
            /*判断输入框有没有内容,设置是否显示删除按钮*/
            if ("" != text.toString().trim { it <= ' ' } && text.toString().trim { it <= ' ' }.isNotEmpty()) {
                setHideClearDrawable(true)
            } else {
                setHideClearDrawable(false)
            }
        }

        /*设置是否显示删除按钮*/
        setHideClearDrawable(false)

        if (logo_location == 1) {
            setCompoundDrawables(searchDrawable, compoundDrawables[1], rightClearDrawable, compoundDrawables[3])
        }

        setOnEditorActionListener(this)

        onFocusChangeListener = this

        rootView.viewTreeObserver.addOnGlobalLayoutListener(this)
    }

    private fun setHideClearDrawable(isVisible: Boolean) {
        /*是否显示删除按钮*/
        rightClearDrawable = if (isVisible) {
            drawable
        } else {
            if (logo_location == 2) searchDrawable else null
        }

        /*给EditText左,上,右,下设置图片*/
        setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], rightClearDrawable, compoundDrawables[3])
    }

    /**
     * 监听点击事件是否点击到清空按钮
     */
    override fun onTouchEvent(event: MotionEvent): Boolean {
        searchClearTouch(event)
        return super.onTouchEvent(event)
    }

    /**
     * 监听回车时间
     */
    override fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?): Boolean {
        if (actionId == EditorInfo.IME_ACTION_SEARCH) {
            clearFocus()
            if (!TextUtils.isEmpty(text)) {
                setCompoundDrawables(compoundDrawables[0], compoundDrawables[1], null, compoundDrawables[3])
                hideSoftInput()
            }
        }
        mOnEditorActionListener?.let {
            it.onEditorAction(v, actionId, event)
        }
        return false
    }

    /**
     * 监听是否获取焦点
     */
    override fun onFocusChange(v: View?, hasFocus: Boolean) {
        if (hasFocus) {
            // 此处为得到焦点时的处理内容
            if (!TextUtils.isEmpty(text)) {
                setHideClearDrawable(true)
            } else {
                setHideClearDrawable(false)
            }
        } else {
            // 此处为失去焦点时的处理内容
            hideSoftInput()
            if (!TextUtils.isEmpty(text)) {
                setCompoundDrawables(compoundDrawables[0], compoundDrawables[1],
                    null, compoundDrawables[3])
            }
        }
        mOnFocusChangeListener?.onFocusChange(v, hasFocus)
    }

    override fun onGlobalLayout() {
        val rect = Rect()
        rootView.getWindowVisibleDisplayFrame(rect)
        var visibleHeight = rect.height()

        if (rootViewVisibleHeight == 0) {
            //拷贝一份,用于比较值的改变
            rootViewVisibleHeight = visibleHeight
            return
        }
        //软键盘显示/隐藏状态没有改变
        if (rootViewVisibleHeight == visibleHeight) {
            return
        }

        if (rootViewVisibleHeight - visibleHeight > 200) {
            onSoftKeyShowListener?.onSoftKeyShow(true)
            rootViewVisibleHeight = visibleHeight
            return
        }

        if (visibleHeight - rootViewVisibleHeight > 200) {
            clearFocus()
            onSoftKeyShowListener?.onSoftKeyShow(false)
            rootViewVisibleHeight = visibleHeight
            return
        }
    }

    fun convertDpToPixel(dp: Float): Float {
        val metrics = context.resources.displayMetrics
        return dp * (metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)
    }

    fun setOnSoftKeyShowListener(onSoftKeyShowListener: OnSoftKeyShowListener) {
        this.onSoftKeyShowListener = onSoftKeyShowListener
    }

    interface OnSoftKeyShowListener {
        fun onSoftKeyShow(isShow: Boolean)
    }

    fun setMyOnEditorActionListener(l: MyOnEditorActionListener?) {
        mOnEditorActionListener = l
    }

    interface MyOnEditorActionListener {
        fun onEditorAction(v: TextView?, actionId: Int, event: KeyEvent?)
    }

    fun setMyOnFocusChangeListener(f: MyOnFocusChangeListener) {
        mOnFocusChangeListener = f;
    }

    interface MyOnFocusChangeListener {
        fun onFocusChange(v: View?, hasFocus: Boolean)
    }
}

EditTextExtensionFunction

package com.zhengyou.jxdkj.kotlin.extension

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Rect
import android.text.Editable
import android.text.TextWatcher
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import com.scwang.smart.refresh.layout.SmartRefreshLayout
import com.scwang.smart.refresh.layout.api.RefreshLayout
import com.zhengyou.jxdkj.kotlin.view.ClearEditText
import com.zhengyou.jxdkj.widget.view.AnimHeader

/**
 * 扩展函数
 */
fun EditText.afterTextChanged(afterTextChanged: (String) -> Unit) {
    this.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

        override fun afterTextChanged(editable: Editable?) {
            afterTextChanged.invoke(editable.toString())
        }
    })
}

fun EditText.onTextChanged(onTextChanged: (String, Int, Int, Int) -> Unit) {
    this.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
            onTextChanged.invoke(s.toString(), start, before, count)

        }

        override fun afterTextChanged(editable: Editable?) {
        }
    })
}

fun EditText.beforeTextChanged(addTextChangedListener: (String, Int, Int, Int) -> Unit) {
    this.addTextChangedListener(object : TextWatcher {
        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
            addTextChangedListener.invoke(s.toString(), start, count, after)
        }

        override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
        }

        override fun afterTextChanged(editable: Editable?) {
        }
    })
}

@SuppressLint("ClickableViewAccessibility")
fun ClearEditText.searchClearTouch(event: MotionEvent) {
    /*判断手指按下的x坐标*/
    val x = event.x

    /*获取自定义EditText宽度*/
    val width = this.width.toFloat()

    /*获取EditText右Padding值*/
    val totalPaddingRight = this.totalPaddingRight.toFloat()

    /*判断手指按下的区域是否在删除按钮宽高范围内*/
    if (event.action == MotionEvent.ACTION_UP) {
        if (x > width - totalPaddingRight && x < width && event.y < this.height) {
            val drawable = compoundDrawables[2]
            if ("" != text.toString().trim { it <= ' ' } && text.toString().trim { it <= ' ' }.isNotEmpty() && drawable != null) {
                this.setText("")
            }
        }
    }
}

var rootViewVisibleHeight = 0

fun EditText.softKeyIsShow(): Boolean? {
    val rect = Rect()
    rootView.getWindowVisibleDisplayFrame(rect)
    var visibleHeight = rect.height()

    if (rootViewVisibleHeight == 0) {
        //拷贝一份,用于比较值的改变
        rootViewVisibleHeight = visibleHeight
        return null
    }
    //软键盘显示/隐藏状态没有改变
    if (rootViewVisibleHeight == visibleHeight) {
        return null
    }

    if (rootViewVisibleHeight - visibleHeight > 200) {
        rootViewVisibleHeight = visibleHeight
        return true
    }

    if (visibleHeight - rootViewVisibleHeight > 200) {
        rootViewVisibleHeight = visibleHeight
        return false
    }
    return false
}

fun EditText.hideSoftInput(){
    val im = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
    if (im != null && windowToken != null) {
        im.hideSoftInputFromWindow(windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
    }
}
<declare-styleable name="ClearEditText">
     <attr name="clears_icon" format="reference"/>
     <attr name="logo" format="reference"/>
     <attr name="logo_location" format="integer">
         <enum name="left" value="1"/>
         <enum name="right" value="2"/>
     </attr>
 </declare-styleable>
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值