import android.app.Activity
import android.app.Dialog
import android.content.ClipData
import android.content.Context
import android.graphics.drawable.Drawable
import android.os.Parcel
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.InputMethodManager
import androidx.annotation.*
import androidx.core.content.ContextCompat
import androidx.core.os.ParcelCompat
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
/**
* Desc:Context相关拓展函数、顶层函数
* Author: hy
* Date: 2019/7/15 16:16
**/
inline fun <reified T : Activity> Fragment.startActivity(vararg params: Pair<String, Any?>) =
activity?.let {
Internals.internalStartActivity(it, T::class.java, params)
}
inline fun <reified T : Activity> Context.startActivity(vararg params: Pair<String, Any?>) =
Internals.internalStartActivity(this, T::class.java, params)
inline fun <reified T : Activity> Activity.startActivity(vararg params: Pair<String, Any?>) =
Internals.internalStartActivity(this, T::class.java, params)
inline fun <reified T : Activity> Fragment.startActivityForRes(requestCode: Int, vararg params: Pair<String, Any?>) =
activity?.let {
startActivityForResult(Internals.createIntent(it, T::class.java, params), requestCode)
}
inline fun <reified T : Activity> Activity.startActivityForRes(requestCode: Int, vararg params: Pair<String, Any?>) =
startActivityForResult(Internals.createIntent(this, T::class.java, params), requestCode)
fun Context.getDrawableByAttr(@AttrRes attr: Int): Drawable? {
val ta = obtainStyledAttributes(intArrayOf(attr))
val drawable = ta.getDrawable(0)
ta.recycle()
return drawable
}
fun Context.getThemeByAttr(@AttrRes attr: Int): Int {
val ta = obtainStyledAttributes(intArrayOf(attr))
val theme = ta.getResourceId(0, 0)
ta.recycle()
return theme
}
/**
* 复制到粘贴板
*/
/*fun Context.copyText(string: String) {
val cm = getSystemService(Context.CLIPBOARD_SERVICE)
as android.content.ClipboardManager
val clip = ClipData.newPlainText("", string)
cm.primaryClip = clip
}*/
fun Context.getString(@StringRes id: Int): String = getString(id)
fun Fragment.inflate(@LayoutRes id: Int, root: ViewGroup? = null, attachToRoot: Boolean = false): View = LayoutInflater.from(context).inflate(id, root, attachToRoot)
fun Activity.inflate(@LayoutRes id: Int, root: ViewGroup? = null, attachToRoot: Boolean = false): View = LayoutInflater.from(this).inflate(id, root, attachToRoot)
fun View.inflate(@LayoutRes id: Int, root: ViewGroup? = null, attachToRoot: Boolean = false): View = LayoutInflater.from(this.context).inflate(id, root, attachToRoot)
fun Fragment.horizontalLinearLayoutManager() = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false)
fun Fragment.verticalLinearLayoutManager() = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
fun Fragment.gridLayoutManager(spanCount: Int) = GridLayoutManager(context, spanCount)
fun Activity.horizontalLinearLayoutManager() = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
fun Activity.verticalLinearLayoutManager() = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
fun Activity.gridLayoutManager(spanCount: Int) = GridLayoutManager(this, spanCount)
fun Context.horizontalLinearLayoutManager() = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
fun Context.verticalLinearLayoutManager() = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
fun Context.gridLayoutManager(spanCount: Int) = GridLayoutManager(this, spanCount)
fun View.findColor(@ColorRes corRes: Int): Int = ContextCompat.getColor(context, corRes)
fun Fragment.findColor(@ColorRes corRes: Int): Int = ContextCompat.getColor(context!!, corRes)
fun Context.findColor(@ColorRes id: Int): Int = ContextCompat.getColor(this, id)
fun Activity.findColor(@ColorRes id: Int): Int = ContextCompat.getColor(this, id)
/**
* 返回contentView
*/
inline val Activity.contentView: View?
get() = findOptional<ViewGroup>(android.R.id.content)?.getChildAt(0)
inline fun <reified T : View> View.find(@IdRes id: Int): T = findViewById(id)
inline fun <reified T : View> Activity.find(@IdRes id: Int): T = findViewById(id)
inline fun <reified T : View> Fragment.find(@IdRes id: Int): T = view?.findViewById(id) as T
inline fun <reified T : View> Dialog.find(@IdRes id: Int): T = findViewById(id)
inline fun <reified T : View> View.findOptional(@IdRes id: Int): T? = findViewById(id) as? T
inline fun <reified T : View> Activity.findOptional(@IdRes id: Int): T? = findViewById(id) as? T
inline fun <reified T : View> Fragment.findOptional(@IdRes id: Int): T? = view?.findViewById(id) as? T
inline fun <reified T : View> Dialog.findOptional(@IdRes id: Int): T? = findViewById(id) as? T
fun <T : Fragment> T.withArguments(params: Array<out Pair<String, Any?>>): T {
arguments = Internals.bundleOf(params)
return this
}
/**
* 显示软键盘
*/
fun View.showSoftInput() {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
postDelayed({
requestFocus()
imm.showSoftInput(this, InputMethodManager.SHOW_FORCED)
}, 60)
}
/**
* 隐藏软键盘
*/
fun View.hideSoftInput() {
val imm = context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(this.windowToken, 0)
}
fun Activity.hideSoftInput() {
val imm = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
if (currentFocus != null) {
imm.hideSoftInputFromWindow(currentFocus!!.windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
}
}
/** Write a boolean to a Parcel. */
fun Parcel.writeBooleanUsingCompat(value: Boolean) = ParcelCompat.writeBoolean(this, value)
/** Read a boolean from a Parcel. */
fun Parcel.readBooleanUsingCompat() = ParcelCompat.readBoolean(this)
上面代码关联的Internals,实际跳转逻辑
import android.app.Activity
import android.app.Service
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Parcelable
import java.io.Serializable
/**
* Desc:
* Author: hy
* Date: 2019/7/15 16:54
**/
object Internals {
@JvmStatic
fun <T> createIntent(ctx: Context, clazz: Class<out T>, params: Array<out Pair<String, Any?>>): Intent {
val intent = Intent(ctx, clazz)
if (params.isNotEmpty()) fillIntentArguments(intent, params)
return intent
}
@JvmStatic
fun internalStartActivity(
ctx: Context,
activity: Class<out Activity>,
params: Array<out Pair<String, Any?>>
) {
ctx.startActivity(createIntent(ctx, activity, params))
}
@JvmStatic
fun internalStartActivityForResult(
act: Activity,
activity: Class<out Activity>,
requestCode: Int,
params: Array<out Pair<String, Any?>>
) {
act.startActivityForResult(createIntent(act, activity, params), requestCode)
}
@JvmStatic
fun internalStartService(
ctx: Context,
service: Class<out Service>,
params: Array<out Pair<String, Any?>>
): ComponentName? = ctx.startService(createIntent(ctx, service, params))
@JvmStatic
fun internalStopService(
ctx: Context,
service: Class<out Service>,
params: Array<out Pair<String, Any?>>
): Boolean = ctx.stopService(createIntent(ctx, service, params))
@JvmStatic
private fun fillIntentArguments(intent: Intent, params: Array<out Pair<String, Any?>>) {
params.forEach {
when (val value = it.second) {
null -> intent.putExtra(it.first, null as Serializable?)
is Int -> intent.putExtra(it.first, value)
is Long -> intent.putExtra(it.first, value)
is CharSequence -> intent.putExtra(it.first, value)
is String -> intent.putExtra(it.first, value)
is Float -> intent.putExtra(it.first, value)
is Double -> intent.putExtra(it.first, value)
is Char -> intent.putExtra(it.first, value)
is Short -> intent.putExtra(it.first, value)
is Boolean -> intent.putExtra(it.first, value)
is Serializable -> intent.putExtra(it.first, value)
is Bundle -> intent.putExtra(it.first, value)
is Parcelable -> intent.putExtra(it.first, value)
is Array<*> -> when {
value.isArrayOf<CharSequence>() -> intent.putExtra(it.first, value)
value.isArrayOf<String>() -> intent.putExtra(it.first, value)
value.isArrayOf<Parcelable>() -> intent.putExtra(it.first, value)
else -> throw Exception("Intent extra ${it.first} has wrong type ${value.javaClass.name}")
}
is IntArray -> intent.putExtra(it.first, value)
is LongArray -> intent.putExtra(it.first, value)
is FloatArray -> intent.putExtra(it.first, value)
is DoubleArray -> intent.putExtra(it.first, value)
is CharArray -> intent.putExtra(it.first, value)
is ShortArray -> intent.putExtra(it.first, value)
is BooleanArray -> intent.putExtra(it.first, value)
else -> throw Exception("Intent extra ${it.first} has wrong type ${value.javaClass.name}")
}
return@forEach
}
}
fun bundleOf(params: Array<out Pair<String, Any?>>): Bundle {
val b = Bundle()
for (p in params) {
val (k, v) = p
when (v) {
null -> b.putSerializable(k, null)
is Boolean -> b.putBoolean(k, v)
is Byte -> b.putByte(k, v)
is Char -> b.putChar(k, v)
is Short -> b.putShort(k, v)
is Int -> b.putInt(k, v)
is Long -> b.putLong(k, v)
is Float -> b.putFloat(k, v)
is Double -> b.putDouble(k, v)
is String -> b.putString(k, v)
is CharSequence -> b.putCharSequence(k, v)
is Parcelable -> b.putParcelable(k, v)
is Serializable -> b.putSerializable(k, v)
is BooleanArray -> b.putBooleanArray(k, v)
is ByteArray -> b.putByteArray(k, v)
is CharArray -> b.putCharArray(k, v)
is DoubleArray -> b.putDoubleArray(k, v)
is FloatArray -> b.putFloatArray(k, v)
is IntArray -> b.putIntArray(k, v)
is LongArray -> b.putLongArray(k, v)
is Array<*> -> {
@Suppress("UNCHECKED_CAST")
when {
v.isArrayOf<Parcelable>() -> b.putParcelableArray(k, v as Array<out Parcelable>)
v.isArrayOf<CharSequence>() -> b.putCharSequenceArray(k, v as Array<out CharSequence>)
v.isArrayOf<String>() -> b.putStringArray(k, v as Array<out String>)
else -> throw Exception("Unsupported bundle component (${v.javaClass})")
}
}
is ShortArray -> b.putShortArray(k, v)
is Bundle -> b.putBundle(k, v)
else -> throw Exception("Unsupported bundle component (${v.javaClass})")
}
}
return b
}
}
和屏幕相关工具类
import android.content.Context
import android.content.res.Resources
import android.util.TypedValue
/**
* Desc:
* Author: hy
* Date: 2019/4/8 14:54
**/
private val displayMetrics = Resources.getSystem().displayMetrics
val Float.dp: Float
@JvmName("dp2px")
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this, displayMetrics)
val Int.dp: Int
@JvmName("dp2px")
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, this.toFloat(), displayMetrics).toInt()
val Float.sp: Float
@JvmName("sp2px")
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this, displayMetrics)
val Int.sp: Int
@JvmName("sp2px")
get() = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, this.toFloat(), displayMetrics).toInt()
val Number.px: Number
get() = this
val Number.px2dp: Int
@JvmName("px2dp")
get() = (this.toFloat() / displayMetrics.density).toInt()
val Number.px2sp: Int
@JvmName("px2sp")
get() = (this.toFloat() / displayMetrics.scaledDensity).toInt()
val SCREEN_WIDTH: Int
@JvmName("SCREEN_WIDTH")
get() = displayMetrics.widthPixels
val SCREEN_HEIGHT: Int
@JvmName("SCREEN_HEIGHT")
get() = displayMetrics.heightPixels
val STATUS_BAR_HEIGHT: Int
@JvmName("STATUS_BAR_HEIGHT")
get() {
val resourceId = Resources.getSystem().getIdentifier("status_bar_height", "dimen", "android")
return Resources.getSystem().getDimensionPixelSize(resourceId)
}
val Context.ACTION_BAR_HEIGHT: Int
@JvmName("ACTION_BAR_HEIGHT")
get() {
val tv = TypedValue()
return if (theme.resolveAttribute(android.R.attr.actionBarSize, tv, true)) {
TypedValue.complexToDimensionPixelSize(tv.data, resources.displayMetrics)
} else 0
}
val NAVIGATION_BAR_HEIGHT: Int
@JvmName("NAVIGATION_BAR_HEIGHT")
get() {
val resourceId = Resources.getSystem().getIdentifier("navigation_bar_height", "dimen", "android")
return if (resourceId != 0) {
Resources.getSystem().getDimensionPixelOffset(resourceId)
} else {
0
}
}