引言:本文仅记录自己项目中使用到的扩展类、则需使用!(均为kt文件)
一、ActivityExpand
/**
* 启动Activity
*/
fun AppCompatActivity.startPager(actClass: Class<*>) {
startActivity(Intent(this, actClass))
}
/**
* 启动Activity
*/
fun Context.startPager(actClass: Class<*>) {
startActivity(Intent(this, actClass))
}
/**
* 传递intent,启动Activity
*/
fun Context.startPager(intents: Intent, actClass: Class<*>) {
intents.setClass(this, actClass)
startActivity(intents)
}
/**
* 待餐传递
*/
fun Activity.startPager(intents: Intent, actClass: Class<*>) {
intents.setClass(this, actClass)
startActivity(intents)
}
使用:
二、ContextExand(兼容6.0 及一下老设备写法)
fun Context.getColors(@ColorRes id: Int) = ContextCompat.getColor(this, id)
fun Context.getDrawables(@DrawableRes id: Int) = ContextCompat.getDrawable(this, id)
三、DecimalExpand
fun String.fenToYuanByString() = BigDecimal(this).fenToYuanByNumber()
fun Int.fenToYuanByString() = BigDecimal(this).fenToYuanByNumber()
fun String.fenToYuanByStringNoZero(): String {
return try {
val result = BigDecimal(this).fenToYuanByNumber().toString()
result.subSequence(0, result.indexOf(".")).toString()
} catch (e: Exception) {
BigDecimal(this).fenToYuanByNumber().toString()
}
}
fun Int.fenToYuanByStringNoZero(): String {
return try {
val result = BigDecimal(this).fenToYuanByNumber().toString()
result.subSequence(0, result.indexOf(".")).toString()
} catch (e: Exception) {
BigDecimal(this).fenToYuanByNumber().toString()
}
}
fun BigDecimal.fenToYuanByNumber(): BigDecimal =
this.divide(BigDecimal(100), 2, RoundingMode.HALF_UP)
格式化money 保留2位数
四、FloatExpand(dp、sp像素转换)
fun Float.dp2Px() = ConvertUtils.dp2px(this).toFloat()
fun Float.px2Dp() = ConvertUtils.px2dp(this).toFloat()
fun Float.sp2Px() = ConvertUtils.sp2px(this).toFloat()
用到了第三方库(当然也可以不用、懒得折腾了):
implementation 'com.blankj:utilcodex:1.31.1'
使用:
五、LongExpand
//格式化时间
fun Long.formatDate(format: String) = SimpleDateFormat(format, Locale.CHINA).format(Date(this))
/**
* this ==单位秒
* 返回对应的秒数 eg 1s 2s
*/
fun Long.formatSeconds(): String = when {
this <= 0 -> {
"00:00"
}
this < 60 -> {
format(Locale.getDefault(), "00:%02d", this % 60)
}
this < 3600 -> {
format(
Locale.getDefault(),
"%02d:%02d",
this / 60,
this % 60
)
}
else -> {
format(
Locale.getDefault(),
"%02d:%02d:%02d",
this / 3600,
this % 3600 / 60,
this % 60
)
}
}
六、ObjectExpand(对象转json字符串)
fun Any.toJson(): String {
return try {
GsonUtils.toJson(this)
} catch (e: Exception) {
""
}
}
七、StringExpand
/**
* 是否包含英文字母与数字
*/
fun String.isLetter(): Boolean {
val regex = "^[a-z0-9A-Z].*"
return this.matches(Regex(regex))
}
/**
* 是否包含英文字符
*/
fun String.isContainLetter(): Boolean {
val regex = ".*[a-zA-Z]+.*"
return Pattern.compile(regex, Pattern.CASE_INSENSITIVE or Pattern.DOTALL).matcher(this)
.matches()
}
/**
* 全部为英文字母?
*/
fun String.isAllLetter(): Boolean {
val regex = "[a-zA-Z]+"
return this.matches(Regex(regex))
}
/**
* 判断是否包含.0 .00的数据类型
* 整数
*/
fun String.convertInteger(): String {
val subs = splitToMutableList(".")
return if (subs.last() == "0") {
removeSuffix(".0")
} else if (subs.last() == "00") {
removeSuffix(".00")
} else {
this
}
}
/**
* 隐藏中间的手机号 188****7502
*/
fun String.hideMiddlePhone(): String {
val msg = replaceRange(3..6, "")
return StringBuilder(msg).apply {
for (index in 0..length) {
if (index == 3) {
insert(index, "****")
}
}
}.toString()
}
/**
* 隐藏身份证、
*/
fun String.hideIcCard(): String {
val last = this.length - 4
val msg = replaceRange(4..last, "")
return StringBuilder(msg).apply {
for (index in 0..length) {
if (index == 4) {
insert(index, "******")
}
}
}.toString()
}
//截取 根据表达式
fun String.splitToMutableList(regex: String) = split(regex).toMutableList()
/**
* 转为实体类对象
*/
fun <T> String.toJsonObject(type: Class<T>): T? {
return try {
GsonUtils.fromJson(this, type)
} catch (e: Exception) {
null
}
}
/**
* 转为list实体类对象
*/
fun <T> String.toJsonListObject(type: Class<T>): List<T>? {
return try {
GsonUtils.fromJson<List<T>?>(this, GsonUtils.getListType(type))
} catch (e: Exception) {
null
}
}
八、RecycleViewExpand
/**
* 是否滚动到底部
*/
fun RecyclerView.isSlideToBottom(): Boolean {
return this.computeVerticalScrollExtent() + this.computeVerticalScrollOffset() >= this.computeVerticalScrollRange()
}
fun RecyclerView.isSlideToTop(): Boolean {
return if (layoutManager is LinearLayoutManager) {
val firstItemPosition =
(layoutManager as LinearLayoutManager).findFirstCompletelyVisibleItemPosition()
firstItemPosition == 0
} else false
}
九、ViewExpand(包含了EditText、ScrollView、ImageView等)
fun View.showAnim(duration: Long, listener: AnimatorListenerAdapter?) {
ObjectAnimator.ofFloat(this, "alpha", 0f, 1f).run {
this.duration = duration
addListener(listener)
start()
}
}
/**
* 隐藏动画
*/
fun View.hideAnim(duration: Long, listener: AnimatorListenerAdapter?): Animator {
return ObjectAnimator.ofFloat(this, "alpha", 1f, 0f).apply {
this.duration = duration
if (listener != null) {
addListener(listener)
}
start()
}
}
fun View.hideAnimate(duration: Long = 500, alpha: Float = 0f, listener: AnimatorListenerAdapter) {
this.animate().alpha(alpha).setDuration(duration).setListener(listener).start()
}
/**
* 扩大点击作用域
* @param expandTouch 扩大的点击区域
*/
fun View.setTouchDelegate(expandTouch: Int) {
try {
val parentView = this.parent as View
parentView.post {
val rect = Rect()
this.getHitRect(rect)
rect.top -= expandTouch
rect.bottom += expandTouch
rect.left -= expandTouch
rect.right += expandTouch
parentView.touchDelegate = TouchDelegate(rect, this)
}
} catch (e: Exception) {
}
}
/**
* 点击放大
* implementation 'com.github.SherlockGougou:BigImageViewPager:androidx-6.2.0'
*/
fun ImageView.clickBigger(uri: String, showDownBt: Boolean = true) {
setOnClickListener {
ImagePreview.getInstance().setContext(this.context).setImage(uri)// 图片
.setShowCloseButton(true)// 是否显示关闭按钮
.setShowDownButton(showDownBt)// 是否显示下载按钮
.setFolderName(
this.context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString()
)// 设置下载到的文件夹名(保存到根目录)
.start()
}
}
/**
* 点击放大
*/
fun ImageView.clickBigger(
listUri: List<String>, defaultIndex: Int = 0, showDownBt: Boolean = true
) {
setOnClickListener {
ImagePreview.getInstance().setContext(this.context).setImageList(listUri)// 图片
.setIndex(defaultIndex).setShowCloseButton(true)// 是否显示关闭按钮
.setShowDownButton(showDownBt)// 是否显示下载按钮
.setFolderName(
this.context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString()
)// 设置下载到的文件夹名(保存到根目录)
.start()
}
}
/**
* 清除点击放大逻辑
*/
fun ImageView.clearClickBigger() {
setOnClickListener(null)
}
fun View.show() {
visibility = View.VISIBLE
}
fun View.hide() {
visibility = View.INVISIBLE
}
fun View.goneHide() {
visibility = View.GONE
}
/**
* 禁止输入空格 禁止后xml中的限制将失效。
* @param limitLength 限制文本输入长度
*/
fun EditText.noSpace(limitLength: Int = 1000) {
filters = arrayOf(object : InputFilter {
override fun filter(
source: CharSequence?, p1: Int, p2: Int, p3: Spanned?, p4: Int, p5: Int
): CharSequence? {
return when {
source.isNullOrBlank() -> ""
source.contains("\\n") -> {
source.toString().replace("\\n", "")
}
source.contains("\\b") -> {
source.toString().replace("\\b", "")
}
else -> null
}
}
}, InputFilter.LengthFilter(limitLength))
}
//禁止\n \b 符号
fun EditText.noSymbol(limitLength: Int = 1000) {
filters = arrayOf(object : InputFilter {
override fun filter(
source: CharSequence?, p1: Int, p2: Int, p3: Spanned?, p4: Int, p5: Int
): CharSequence? {
return when {
source?.contains("\\n") == true -> {
source.toString().replace("\\n", "")
}
source?.contains("\\b") == true -> {
source.toString().replace("\\b", "")
}
else -> null
}
}
}, InputFilter.LengthFilter(limitLength))
}
//只输入中文
fun EditText.onlyCN(limitLength: Int = -1) {
if (limitLength != -1) {
filters = arrayOf(object : InputFilter {
override fun filter(
source: CharSequence?, start: Int, end: Int, p3: Spanned?, p4: Int, p5: Int
): CharSequence? {
try {
for (index in start..end) {
return if (!isChinese(source?.get(index))) "" else source
}
} catch (e: Exception) {
}
return null
}
}, InputFilter.LengthFilter(10))
} else {
filters = arrayOf(object : InputFilter {
override fun filter(
source: CharSequence?, start: Int, end: Int, p3: Spanned?, p4: Int, p5: Int
): CharSequence? {
try {
for (index in start..end) {
return if (!isChinese(source?.get(index))) "" else source
}
} catch (e: Exception) {
}
return null
}
})
}
}
/**
* 判定输入汉字
*
* @param c
* @return
*/
fun isChinese(c: Char?): Boolean {
if (c == null) {
return false
}
val ub = Character.UnicodeBlock.of(c)
return ub === Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub === Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub === Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub === Character.UnicodeBlock.GENERAL_PUNCTUATION || ub === Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub === Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS
}
/**
* 设置Hint字体大小
*/
fun EditText.setHintTextSize(hint: String, sizeSp: Int) {
val sp = SpannableString(hint).apply {
setSpan(
AbsoluteSizeSpan(sizeSp, true), 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
setHint(sp)
}
fun EditText.setHintTextSize(sizeSp: Int) {
val sp = SpannableString(hint).apply {
setSpan(
AbsoluteSizeSpan(sizeSp, true), 0, length, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE
)
}
hint = sp
}
/**
* 设置过滤器、一般用于提现等金额操作、
* 保留两位小数
*/
fun EditText.formatMoney() {
filters = arrayOf(AmountInputFilter())
}
/**
* 限制输入小数位数
*/
fun EditText.limitInputNUm(numLimitLength:Int) {
filters = arrayOf(AmountInputFilter(numLimitLength))
}
fun EditText.clearFilter() {
filters = arrayOf()
}
class AmountInputFilter : InputFilter {
constructor()
constructor(numLimitLength: Int) {
this.numLimitLength = numLimitLength
}
/**
* 最大数字,我们取int型最大值
*/
val MAX_VALUE = Int.MAX_VALUE
/**
* 小数点后的数字的位数
*/
var numLimitLength = 2
var p: Pattern? = null
init {
//除数字以外的
p = Pattern.compile("[0-9]*")
}
override fun filter(
source: CharSequence,
start: Int,
end: Int,
dest: Spanned,
dstart: Int,
dend: Int
): CharSequence {
val oldtext = dest.toString()
//第一个输入.或者0,返回
if (dest.toString() == "" && source.isNotEmpty() && (source[0].toString() == "." || source[0].toString() == "0")) return ""
// 验证删除等按键 排除首字符.
if (TextUtils.isEmpty(source)
|| (TextUtils.isEmpty(oldtext)
&& source[0].toString() == ".")
) {
return ""
}
// 验证非数字或者小数点的情况
val m = p!!.matcher(source)
if (oldtext.contains(".")) {
// 已经存在小数点的情况下,只能输入数字
if (!m.matches()) {
return ""
}
} else {
// 未输入小数点的情况下,可以输入小数点和数字
if (!m.matches() && source != ".") {
return ""
}
}
// 验证输入金额的大小
if (source.toString() != "") {
val dold = (oldtext + source.toString()).toDouble()
if (dold > MAX_VALUE) {
return dest.subSequence(dstart, dend)
} else if (dold == MAX_VALUE.toDouble()) {
if (source.toString() == ".") {
return dest.subSequence(dstart, dend)
}
}
}
// 验证小数位精度是否正确
if (oldtext.contains(".")) {
val index = oldtext.indexOf(".")
val len = dend - index
// 小数位只能2位
if (len > numLimitLength) {
return dest.subSequence(dstart, dend)
}
}
return dest.subSequence(dstart, dend).toString() + source.toString()
}
}
/**
* 全局置灰
* 一般我们都知道图像是由一个一个像素点组成的,而像素点是通过RGBA(红绿蓝,透明度)来控制的,这个是数字方向的。
* 但是在我们早期的彩色电视机中,我们经常会调整彩电的色调,饱和度和亮度,其中色调就是物体的颜色,饱和度就是颜色的纯度,从0到100%来描述,亮度就是颜色的相对明暗程度。
* 既然饱和度为0就可以变成灰色,那么我们通过设置ColorMatrix然后给到Paint画笔。
*/
fun setWindowsViewGray(view: View) {
try {
val paint = Paint()
val cm = ColorMatrix()
cm.setSaturation(0f)
paint.colorFilter = ColorMatrixColorFilter(cm)
view.setLayerType(View.LAYER_TYPE_HARDWARE, paint)
} catch (e: Exception) {
e.printStackTrace()
} catch (e: Error) {
e.printStackTrace()
}
}
/**
* 恢复原色
*/
fun setWindowsViewPrimaryColor(view: View) {
try {
val paint = Paint()
val cm = ColorMatrix()
cm.setSaturation(1f)
paint.colorFilter = ColorMatrixColorFilter(cm)
view.setLayerType(View.LAYER_TYPE_HARDWARE, paint)
} catch (e: Exception) {
e.printStackTrace()
} catch (e: Error) {
e.printStackTrace()
}
}
/**
* 是否到底部
*/
fun ScrollView.isBottom() = (this.getChildAt(0).height - this.height == this.scrollY)
/**
* 是否到底部 带有误差
*/
fun ScrollView.isBottom(deviationPx: Int) =
((this.getChildAt(0).height - this.height) - deviationPx <= this.scrollY)
/**
* 滚动到顶部
*/
fun ScrollView.scrollTop() = this.fullScroll(ScrollView.FOCUS_UP)
/**
* 滚动到底部
*/
fun ScrollView.scrollBottom() = this.fullScroll(ScrollView.FOCUS_DOWN)
十、ImageView 使用Coil的扩展
依赖:
//coil 图片加载框架Kotlin 推荐 implementation("io.coil-kt:coil:1.1.1") implementation("io.coil-kt:coil-gif:0.9.5")
//加载一个圆角为10dp的图片
/**
* corner.dp2Px() 也可以自行进行dp转换
* placeholder errorPic 、自行替换、展位图 及加载错误图
*/
fun ImageRequest.Builder.coilSet(
corner: Float = 10f,
@DrawableRes placeholder: Int = R.drawable.ic_qg_placeholder,
@DrawableRes errorPic: Int = R.drawable.ic_qg_placeholder,
scale: Scale = Scale.FILL
) {
placeholder(placeholder)
error(errorPic)
transformations(RoundedCornersTransformation(corner.dp2Px()))
scale(scale)
}
//corner.dp2Px()参考FloatExpand扩展函数
使用:
val test_uri1 =
"https://img2020.cnblogs.com/blog/1289812/202005/1289812-20200509091913298-1286944090.png"
fun test1() {
val imageView = ImageView(this)
//加载一个圆角为10dp的图片
imageView.load(test_uri1) {
coilSet()
}
}