[TOC]
@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)
}
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)
}
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)
}
}
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>
这里有一个很好的答案解释了如何在Ruby中下载文件而不将其加载到内存中:https://stackoverflow.com/a/29743394/4852737require'open-uri'download=open('http://example.com/image.png')IO.copy_stream(download,'~/image.png')我如何验证下载文件的IO.copy_stream调用是否真的成功——这意味着下载的文件与我打算下载的文件完全相同,而不是下载一半的损坏文件?documentation说IO.copy_stream返回它复制的字节数,但是当我还没有下
我使用Nokogiri(Rubygem)css搜索寻找某些在我的html里面。看起来Nokogiri的css搜索不喜欢正则表达式。我想切换到Nokogiri的xpath搜索,因为这似乎支持搜索字符串中的正则表达式。如何在xpath搜索中实现下面提到的(伪)css搜索?require'rubygems'require'nokogiri'value=Nokogiri::HTML.parse(ABBlaCD3"HTML_END#my_blockisgivenmy_bl="1"#my_eqcorrespondstothisregexmy_eq="\/[0-9]+\/"#FIXMEThefoll
我正在尝试解析一个文本文件,该文件每行包含可变数量的单词和数字,如下所示:foo4.500bar3.001.33foobar如何读取由空格而不是换行符分隔的文件?有什么方法可以设置File("file.txt").foreach方法以使用空格而不是换行符作为分隔符? 最佳答案 接受的答案将slurp文件,这可能是大文本文件的问题。更好的解决方案是IO.foreach.它是惯用的,将按字符流式传输文件:File.foreach(filename,""){|string|putsstring}包含“thisisanexample”结果的
1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里
使用rspec-rails3.0+,测试设置分为spec_helper和rails_helper我注意到生成的spec_helper不需要'rspec/rails'。这会导致zeus崩溃:spec_helper.rb:5:in`':undefinedmethod`configure'forRSpec:Module(NoMethodError)对thisissue最常见的回应是需要'rspec/rails'。但这是否会破坏仅使用spec_helper拆分rails规范和PORO规范的全部目的?或者这无关紧要,因为Zeus无论如何都会预加载Rails?我应该在我的spec_helper中做
寻找有用的ruby的好网站是什么? 最佳答案 AgileWebDevelopment列出插件(虽然不是rubygems,我不确定为什么),并允许人们对它们进行评级。RubyToolbox按类别列出gem并比较它们的受欢迎程度。Rubygems有一个搜索框。StackOverflow对最有用的rails插件和rubygems有疑问。 关于ruby-如何搜索有用的ruby,我们在StackOverflow上找到一个类似的问题: https://stacko
假设我有一个类A,里面有一些方法。假设stringmethodName是这些方法之一,我已经知道我想给它什么参数。它们在散列中{'param1'=>value1,'param2'=>value2}所以我有:params={'param1'=>value1,'param2'=>value2}a=A.new()a.send(methodName,value1,value2)#callmethodnamewithbothparams我希望能够通过传递我的哈希以某种方式调用该方法。这可能吗? 最佳答案 确保methodName是一个符号,而
我有很多这样的文档:foo_1foo_2foo_3bar_1foo_4...我想通过获取foo_[X]的所有实例并将它们中的每一个替换为foo_[X+1]来转换它们。在这个例子中:foo_2foo_3foo_4bar_1foo_5...我可以用gsub和一个block来做到这一点吗?如果不是,最干净的方法是什么?我真的在寻找一个优雅的解决方案,因为我总是可以暴力破解它,但我觉得有一些正则表达式技巧值得学习。 最佳答案 我(完全)不懂Ruby,但类似这样的东西应该可以工作:"foo_1foo_2".gsub(/(foo_)(\d+)/
当我进入Rails控制台时,我已将pry设置为加载代替irb。我找不到该页面或不记得如何将其恢复为默认行为,因为它似乎干扰了我的Rubymine调试器。有什么建议吗? 最佳答案 我刚发现问题,pry-railsgem。忘记了它的目的是让“railsconsole”打开pry。 关于ruby-on-rails-带有Pry的Rails控制台,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/question
print"Enteryourpassword:"pass=STDIN.noecho(&:gets)puts"Yourpasswordis#{pass}!"输出:Enteryourpassword:input.rb:2:in`':undefinedmethod`noecho'for#>(NoMethodError) 最佳答案 一开始require'io/console'后来的Ruby1.9.3 关于ruby-为什么不能使用类IO的实例方法noecho?,我们在StackOverflow上