parent
367f2cb703
commit
77682bbd1d
@ -1,7 +1,6 @@ |
|||||||
package com.android.base.kotlin |
package com.android.base.adapter.recycler |
||||||
|
|
||||||
import android.view.View |
import android.view.View |
||||||
import com.android.base.adapter.recycler.ViewHolder |
|
||||||
import kotlinx.android.extensions.CacheImplementation |
import kotlinx.android.extensions.CacheImplementation |
||||||
import kotlinx.android.extensions.ContainerOptions |
import kotlinx.android.extensions.ContainerOptions |
||||||
import kotlinx.android.extensions.LayoutContainer |
import kotlinx.android.extensions.LayoutContainer |
@ -1,4 +1,4 @@ |
|||||||
package com.android.base.kotlin |
package com.android.base.app.aac |
||||||
|
|
||||||
import androidx.lifecycle.MutableLiveData |
import androidx.lifecycle.MutableLiveData |
||||||
|
|
@ -1,15 +0,0 @@ |
|||||||
package com.android.base.kotlin |
|
||||||
|
|
||||||
import android.content.Context |
|
||||||
import android.graphics.drawable.Drawable |
|
||||||
import androidx.annotation.ColorRes |
|
||||||
import androidx.annotation.DrawableRes |
|
||||||
import androidx.core.content.ContextCompat |
|
||||||
|
|
||||||
fun Context.colorFromId(@ColorRes id: Int): Int { |
|
||||||
return ContextCompat.getColor(this, id) |
|
||||||
} |
|
||||||
|
|
||||||
fun Context.drawableFromId(@DrawableRes id: Int): Drawable? { |
|
||||||
return ContextCompat.getDrawable(this, id) |
|
||||||
} |
|
@ -1,18 +0,0 @@ |
|||||||
package com.android.base.kotlin |
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable |
|
||||||
import androidx.annotation.ColorRes |
|
||||||
import androidx.annotation.DrawableRes |
|
||||||
import androidx.core.content.ContextCompat |
|
||||||
import androidx.fragment.app.Fragment |
|
||||||
|
|
||||||
|
|
||||||
fun Fragment.colorFromId(@ColorRes colorRes: Int): Int { |
|
||||||
val safeContext = context ?: return 0 |
|
||||||
return ContextCompat.getColor(safeContext, colorRes) |
|
||||||
} |
|
||||||
|
|
||||||
fun Fragment.drawableFromId(@DrawableRes colorRes: Int): Drawable? { |
|
||||||
val safeContext = context ?: return null |
|
||||||
return ContextCompat.getDrawable(safeContext, colorRes) |
|
||||||
} |
|
@ -1,58 +0,0 @@ |
|||||||
package com.android.base.kotlin |
|
||||||
|
|
||||||
/** |
|
||||||
* 参考: |
|
||||||
* - [Boolean扩展](https://blog.kotliner.cn/2017/06/19/interesting-booleanext/) |
|
||||||
*/ |
|
||||||
sealed class Ext<out T> constructor(val boolean: Boolean) |
|
||||||
|
|
||||||
/** 如果该对象不是null,则执行action */ |
|
||||||
fun <T, E> T?.ifNonNull(action: T.() -> E): Ext<E> { |
|
||||||
if (this != null) { |
|
||||||
return WithData(action()) |
|
||||||
} |
|
||||||
return Otherwise |
|
||||||
} |
|
||||||
|
|
||||||
/** 如果该对象是null,则执行action */ |
|
||||||
fun <T, E> T?.ifNull(action: () -> E) { |
|
||||||
if (this == null) { |
|
||||||
action() |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inline fun <T> Boolean.yes(block: () -> T): Ext<T> = when { |
|
||||||
this -> { |
|
||||||
WithData(block()) |
|
||||||
} |
|
||||||
else -> Otherwise |
|
||||||
} |
|
||||||
|
|
||||||
inline fun <T> Boolean.no(block: () -> T) = when { |
|
||||||
this -> Otherwise |
|
||||||
else -> { |
|
||||||
WithData(block()) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
object Otherwise : Ext<Nothing>(true) |
|
||||||
|
|
||||||
class WithData<out T>(val data: T) : Ext<T>(false) |
|
||||||
|
|
||||||
/**除此以外*/ |
|
||||||
inline infix fun <T> Ext<T>.otherwise(block: () -> T): T { |
|
||||||
return when (this) { |
|
||||||
is Otherwise -> block() |
|
||||||
is WithData<T> -> this.data |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inline operator fun <T> Boolean.invoke(block: () -> T) = yes(block) |
|
||||||
|
|
||||||
fun Any?.javaClassName(): String { |
|
||||||
return if (this == null) { |
|
||||||
"" |
|
||||||
} else { |
|
||||||
this::class.java.name |
|
||||||
} |
|
||||||
} |
|
@ -1,21 +0,0 @@ |
|||||||
package com.android.base.kotlin |
|
||||||
|
|
||||||
import android.content.res.TypedArray |
|
||||||
|
|
||||||
inline fun <T : TypedArray?, R> T.use(block: (T) -> R): R { |
|
||||||
var recycled = false |
|
||||||
try { |
|
||||||
return block(this) |
|
||||||
} catch (e: Exception) { |
|
||||||
recycled = true |
|
||||||
try { |
|
||||||
this?.recycle() |
|
||||||
} catch (exception: Exception) { |
|
||||||
} |
|
||||||
throw e |
|
||||||
} finally { |
|
||||||
if (!recycled) { |
|
||||||
this?.recycle() |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
@ -1,8 +0,0 @@ |
|||||||
package com.android.base.kotlin |
|
||||||
|
|
||||||
import com.android.base.utils.android.UnitConverter |
|
||||||
|
|
||||||
fun dip(value: Int): Int = UnitConverter.dpToPx(value) |
|
||||||
fun dip(value: Float): Float = UnitConverter.dpToPx(value) |
|
||||||
fun sp(value: Int): Int = UnitConverter.spToPx(value) |
|
||||||
fun sp(value: Float): Float = UnitConverter.spToPx(value) |
|
@ -1,172 +0,0 @@ |
|||||||
package com.android.base.kotlin |
|
||||||
|
|
||||||
import android.graphics.drawable.Drawable |
|
||||||
import android.view.View |
|
||||||
import android.view.View.FOCUS_DOWN |
|
||||||
import android.view.View.FOCUS_UP |
|
||||||
import android.view.ViewGroup |
|
||||||
import android.view.ViewTreeObserver |
|
||||||
import android.widget.ScrollView |
|
||||||
import androidx.annotation.ColorRes |
|
||||||
import androidx.annotation.DrawableRes |
|
||||||
import androidx.core.content.ContextCompat |
|
||||||
import androidx.core.view.ViewCompat |
|
||||||
import androidx.core.widget.NestedScrollView |
|
||||||
import com.android.base.rx.subscribeIgnoreError |
|
||||||
import com.android.base.utils.android.ViewUtils |
|
||||||
import com.android.base.utils.android.compat.AndroidVersion.atLeast |
|
||||||
import com.jakewharton.rxbinding3.view.clicks |
|
||||||
import io.reactivex.Observable |
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers |
|
||||||
import java.util.concurrent.TimeUnit |
|
||||||
|
|
||||||
fun View.visibleOrGone(visible: Boolean) { |
|
||||||
if (visible) { |
|
||||||
this.visibility = View.VISIBLE |
|
||||||
} else { |
|
||||||
this.visibility = View.GONE |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fun View.visibleOrInvisible(visible: Boolean) { |
|
||||||
if (visible) { |
|
||||||
this.visibility = View.VISIBLE |
|
||||||
} else { |
|
||||||
this.visibility = View.INVISIBLE |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
fun View.visible() { |
|
||||||
this.visibility = View.VISIBLE |
|
||||||
} |
|
||||||
|
|
||||||
fun View.invisible() { |
|
||||||
this.visibility = View.INVISIBLE |
|
||||||
} |
|
||||||
|
|
||||||
fun View.gone() { |
|
||||||
this.visibility = View.GONE |
|
||||||
} |
|
||||||
|
|
||||||
fun View.isVisible() = this.visibility == View.VISIBLE |
|
||||||
fun View.isInvisible() = this.visibility == View.INVISIBLE |
|
||||||
fun View.isGone() = this.visibility == View.GONE |
|
||||||
|
|
||||||
fun View.realContext() = ViewUtils.getRealContext(this) |
|
||||||
|
|
||||||
inline fun View.doOnLayoutAvailable(crossinline block: () -> Unit) { |
|
||||||
//isLaidOut 方法作用:如果 view 已经通过至少一个布局,则返回true,因为它最后一次附加到窗口或从窗口分离。 |
|
||||||
ViewCompat.isLaidOut(this).yes { |
|
||||||
block() |
|
||||||
}.otherwise { |
|
||||||
addOnLayoutChangeListener(object : View.OnLayoutChangeListener { |
|
||||||
override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) { |
|
||||||
removeOnLayoutChangeListener(this) |
|
||||||
block() |
|
||||||
} |
|
||||||
}) |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
inline fun <T : View> T.onGlobalLayoutOnce(crossinline action: T.() -> Unit) { |
|
||||||
val t: T = this |
|
||||||
t.viewTreeObserver |
|
||||||
.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { |
|
||||||
override fun onGlobalLayout() { |
|
||||||
action.invoke(t) |
|
||||||
if (atLeast(16)) { |
|
||||||
viewTreeObserver.removeOnGlobalLayoutListener(this) |
|
||||||
} else { |
|
||||||
@Suppress("DEPRECATION") |
|
||||||
viewTreeObserver.removeGlobalOnLayoutListener(this) |
|
||||||
} |
|
||||||
} |
|
||||||
}) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.setPaddingAll(padding: Int) { |
|
||||||
this.setPadding(padding, padding, padding, padding) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.setPaddingLeft(padding: Int) { |
|
||||||
this.setPadding(padding, paddingTop, paddingRight, paddingBottom) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.setPaddRight(padding: Int) { |
|
||||||
this.setPadding(paddingLeft, paddingTop, padding, paddingBottom) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.setPaddingTop(padding: Int) { |
|
||||||
this.setPadding(paddingLeft, padding, paddingRight, paddingBottom) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.setPaddingBottom(padding: Int) { |
|
||||||
this.setPadding(paddingLeft, paddingTop, paddingRight, padding) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.colorFromId(@ColorRes colorRes: Int): Int { |
|
||||||
val safeContext = context ?: return 0 |
|
||||||
return ContextCompat.getColor(safeContext, colorRes) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.drawableFromId(@DrawableRes colorRes: Int): Drawable? { |
|
||||||
val safeContext = context ?: return null |
|
||||||
return ContextCompat.getDrawable(safeContext, colorRes) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.setWidth(width: Int) { |
|
||||||
val params = layoutParams ?: ViewGroup.LayoutParams(0, 0) |
|
||||||
params.width = width |
|
||||||
layoutParams = params |
|
||||||
} |
|
||||||
|
|
||||||
fun View.setHeight(height: Int) { |
|
||||||
val params = layoutParams ?: ViewGroup.LayoutParams(0, 0) |
|
||||||
params.height = height |
|
||||||
layoutParams = params |
|
||||||
} |
|
||||||
|
|
||||||
fun View.setSize(width: Int, height: Int) { |
|
||||||
val params = layoutParams ?: ViewGroup.LayoutParams(0, 0) |
|
||||||
params.width = width |
|
||||||
params.height = height |
|
||||||
layoutParams = params |
|
||||||
} |
|
||||||
|
|
||||||
fun View.onDebouncedClick(onClick: (View) -> Unit) { |
|
||||||
onClickObservable(500) |
|
||||||
.subscribeIgnoreError { onClick(this) } |
|
||||||
} |
|
||||||
|
|
||||||
fun View.onDebouncedClick(milliseconds: Long, onClick: (View) -> Unit) { |
|
||||||
onClickObservable(milliseconds) |
|
||||||
.subscribeIgnoreError { onClick(this) } |
|
||||||
} |
|
||||||
|
|
||||||
fun View.onClickObservable(): Observable<Unit> { |
|
||||||
return onClickObservable(500) |
|
||||||
} |
|
||||||
|
|
||||||
fun View.onClickObservable(milliseconds: Long): Observable<Unit> { |
|
||||||
return clicks() |
|
||||||
.throttleFirst(milliseconds, TimeUnit.MILLISECONDS) |
|
||||||
.observeOn(AndroidSchedulers.mainThread()) |
|
||||||
} |
|
||||||
|
|
||||||
inline val ViewGroup.views get() = (0 until childCount).map { getChildAt(it) } |
|
||||||
|
|
||||||
fun ScrollView.scrollToBottom() { |
|
||||||
fullScroll(FOCUS_DOWN) |
|
||||||
} |
|
||||||
|
|
||||||
fun ScrollView.scrollToTop() { |
|
||||||
fullScroll(FOCUS_UP) |
|
||||||
} |
|
||||||
|
|
||||||
fun NestedScrollView.scrollToBottom() { |
|
||||||
fullScroll(FOCUS_DOWN) |
|
||||||
} |
|
||||||
|
|
||||||
fun NestedScrollView.scrollToTop() { |
|
||||||
fullScroll(FOCUS_UP) |
|
||||||
} |
|
@ -1,83 +0,0 @@ |
|||||||
package com.android.base.utils.android; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.content.res.TypedArray; |
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
import android.net.Uri; |
|
||||||
|
|
||||||
import com.android.base.utils.BaseUtils; |
|
||||||
|
|
||||||
import androidx.annotation.ArrayRes; |
|
||||||
import androidx.annotation.AttrRes; |
|
||||||
import androidx.annotation.NonNull; |
|
||||||
import androidx.annotation.StringRes; |
|
||||||
|
|
||||||
|
|
||||||
public class ResourceUtils { |
|
||||||
|
|
||||||
private ResourceUtils() { |
|
||||||
throw new UnsupportedOperationException("no need instantiation"); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* @param name 资源的名称,如 ic_launcher 或者 com.example.android/drawable/ic_launcher(这是,下面两个参数可以省略) |
|
||||||
* @param defType 资源的类型,如 drawable |
|
||||||
* @param defPackage 包名 |
|
||||||
* @return 资源id |
|
||||||
*/ |
|
||||||
public static int getResource(String name, String defType, String defPackage) { |
|
||||||
return BaseUtils.getResources().getIdentifier(name, defType, defPackage); |
|
||||||
} |
|
||||||
|
|
||||||
public static CharSequence getText(@StringRes int id) { |
|
||||||
return BaseUtils.getResources().getText(id); |
|
||||||
} |
|
||||||
|
|
||||||
public static String getString(@StringRes int id) { |
|
||||||
return BaseUtils.getResources().getString(id); |
|
||||||
} |
|
||||||
|
|
||||||
public static String getString(@StringRes int id, Object... formatArgs) { |
|
||||||
return BaseUtils.getResources().getString(id, formatArgs); |
|
||||||
} |
|
||||||
|
|
||||||
public static String[] getStringArray(@ArrayRes int id) { |
|
||||||
return BaseUtils.getResources().getStringArray(id); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static int[] getIntArray(@ArrayRes int id) { |
|
||||||
return BaseUtils.getResources().getIntArray(id); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static Uri createUriByResource(int id) { |
|
||||||
return Uri.parse("android.resource://" + BaseUtils.getAppContext().getPackageName() + "/" + id); |
|
||||||
} |
|
||||||
|
|
||||||
public static Uri createUriByAssets(String path) { |
|
||||||
return Uri.parse("file:///android_asset/" + path); |
|
||||||
} |
|
||||||
|
|
||||||
public static int getStyledColor(@NonNull Context context, @AttrRes int attr) { |
|
||||||
TypedArray a = context.obtainStyledAttributes(null, new int[]{attr}); |
|
||||||
try { |
|
||||||
return a.getColor(0, 0x000000); |
|
||||||
} finally { |
|
||||||
a.recycle(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static Drawable getStyledDrawable(@NonNull Context context, @AttrRes int attr) { |
|
||||||
TypedArray a = context.obtainStyledAttributes(null, new int[]{attr}); |
|
||||||
try { |
|
||||||
return a.getDrawable(0); |
|
||||||
} finally { |
|
||||||
a.recycle(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static int getDimensPixelSize(int dimenId) { |
|
||||||
return BaseUtils.getResources().getDimensionPixelSize(dimenId); |
|
||||||
} |
|
||||||
} |
|
@ -1,76 +0,0 @@ |
|||||||
package com.android.base.utils.android; |
|
||||||
|
|
||||||
import android.content.res.ColorStateList; |
|
||||||
import android.graphics.Bitmap; |
|
||||||
import android.graphics.Canvas; |
|
||||||
import android.graphics.Paint; |
|
||||||
import android.graphics.PorterDuff; |
|
||||||
import android.graphics.PorterDuffColorFilter; |
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
|
|
||||||
import androidx.core.graphics.drawable.DrawableCompat; |
|
||||||
|
|
||||||
/** |
|
||||||
* usage: |
|
||||||
* <pre> |
|
||||||
* {@code |
|
||||||
* |
|
||||||
* int[][] states = new int[][]{ |
|
||||||
* new int[]{android.R.attr.state_selected}, // pressed
|
|
||||||
* new int[]{-android.R.attr.state_selected} // unpressed
|
|
||||||
* }; |
|
||||||
* |
|
||||||
* int[] colors = new int[]{ |
|
||||||
* Color.BLACK, |
|
||||||
* Color.GRAY |
|
||||||
* }; |
|
||||||
* |
|
||||||
* ColorStateList colorStateList = new ColorStateList(states, colors); |
|
||||||
* Drawable aaa = ContextCompat.getDrawable(getContext(), R.drawable.aaa); |
|
||||||
* Drawable bbb = ContextCompat.getDrawable(getContext(), R.drawable.bbb); |
|
||||||
* Drawable aaaTint = TintUtils.tint(aaa, colorStateList); |
|
||||||
* Drawable bbbTint = TintUtils.tint(bbb, colorStateList); |
|
||||||
* aaaTv.setCompoundDrawablesWithIntrinsicBounds(null, aaaTint, null, null); |
|
||||||
* bbbTv.setCompoundDrawablesWithIntrinsicBounds(null, bbbTint, null, null); |
|
||||||
* </pre> |
|
||||||
*/ |
|
||||||
@SuppressWarnings("unused,WeakerAccess") |
|
||||||
public class TintUtils { |
|
||||||
|
|
||||||
private TintUtils() { |
|
||||||
} |
|
||||||
|
|
||||||
public static Drawable tint(Drawable originDrawable, int color) { |
|
||||||
return tint(originDrawable, ColorStateList.valueOf(color)); |
|
||||||
} |
|
||||||
|
|
||||||
public static Drawable tint(Drawable originDrawable, int color, PorterDuff.Mode tintMode) { |
|
||||||
return tint(originDrawable, ColorStateList.valueOf(color), tintMode); |
|
||||||
} |
|
||||||
|
|
||||||
public static Drawable tint(Drawable originDrawable, ColorStateList colorStateList) { |
|
||||||
return tint(originDrawable, colorStateList, null); |
|
||||||
} |
|
||||||
|
|
||||||
public static Drawable tint(Drawable originDrawable, ColorStateList colorStateList, PorterDuff.Mode tintMode) { |
|
||||||
Drawable tintDrawable = DrawableCompat.wrap(originDrawable); |
|
||||||
if (tintMode != null) { |
|
||||||
DrawableCompat.setTintMode(tintDrawable, tintMode); |
|
||||||
} |
|
||||||
DrawableCompat.setTintList(tintDrawable, colorStateList); |
|
||||||
return tintDrawable; |
|
||||||
} |
|
||||||
|
|
||||||
public static Bitmap tintBitmap(Bitmap inBitmap, int tintColor) { |
|
||||||
if (inBitmap == null) { |
|
||||||
return null; |
|
||||||
} |
|
||||||
Bitmap outBitmap = Bitmap.createBitmap(inBitmap.getWidth(), inBitmap.getHeight(), inBitmap.getConfig()); |
|
||||||
Canvas canvas = new Canvas(outBitmap); |
|
||||||
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG); |
|
||||||
paint.setColorFilter(new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN)); |
|
||||||
canvas.drawBitmap(inBitmap, 0, 0, paint); |
|
||||||
return outBitmap; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,72 +0,0 @@ |
|||||||
package com.android.base.utils.android; |
|
||||||
|
|
||||||
|
|
||||||
import android.util.DisplayMetrics; |
|
||||||
import android.util.TypedValue; |
|
||||||
|
|
||||||
import com.android.base.utils.BaseUtils; |
|
||||||
|
|
||||||
public class UnitConverter { |
|
||||||
|
|
||||||
private UnitConverter() { |
|
||||||
throw new UnsupportedOperationException("no need instantiation"); |
|
||||||
} |
|
||||||
|
|
||||||
public static float dpToPx(float dp) { |
|
||||||
return dp * BaseUtils.getDisplayMetrics().density; |
|
||||||
} |
|
||||||
|
|
||||||
public static int dpToPx(int dp) { |
|
||||||
return (int) (dp * BaseUtils.getDisplayMetrics().density + 0.5f); |
|
||||||
} |
|
||||||
|
|
||||||
public static float pxToDp(float px) { |
|
||||||
return px / BaseUtils.getDisplayMetrics().density; |
|
||||||
} |
|
||||||
|
|
||||||
public static int pxToDp(int px) { |
|
||||||
return (int) (px / BaseUtils.getDisplayMetrics().density + 0.5f); |
|
||||||
} |
|
||||||
|
|
||||||
public static float spToPx(float sp) { |
|
||||||
return sp * BaseUtils.getDisplayMetrics().scaledDensity; |
|
||||||
} |
|
||||||
|
|
||||||
public static int spToPx(int sp) { |
|
||||||
return (int) (sp * BaseUtils.getDisplayMetrics().scaledDensity + 0.5f); |
|
||||||
} |
|
||||||
|
|
||||||
public static float pxToSp(float px) { |
|
||||||
return px / BaseUtils.getDisplayMetrics().scaledDensity; |
|
||||||
} |
|
||||||
|
|
||||||
public static int pxToSp(int px) { |
|
||||||
return (int) (px / BaseUtils.getDisplayMetrics().scaledDensity + 0.5f); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 各种单位转换,该方法存在于{@link TypedValue} 中 |
|
||||||
* |
|
||||||
* @param unit 单位 |
|
||||||
* @param value 值 |
|
||||||
* @return 转换结果 |
|
||||||
*/ |
|
||||||
public static float applyDimension(int unit, float value) { |
|
||||||
DisplayMetrics metrics = BaseUtils.getDisplayMetrics(); |
|
||||||
switch (unit) { |
|
||||||
case TypedValue.COMPLEX_UNIT_PX: |
|
||||||
return value; |
|
||||||
case TypedValue.COMPLEX_UNIT_DIP: |
|
||||||
return value * metrics.density; |
|
||||||
case TypedValue.COMPLEX_UNIT_SP: |
|
||||||
return value * metrics.scaledDensity; |
|
||||||
case TypedValue.COMPLEX_UNIT_PT: |
|
||||||
return value * metrics.xdpi * (1.0f / 72); |
|
||||||
case TypedValue.COMPLEX_UNIT_IN: |
|
||||||
return value * metrics.xdpi; |
|
||||||
case TypedValue.COMPLEX_UNIT_MM: |
|
||||||
return value * metrics.xdpi * (1.0f / 25.4f); |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
} |
|
@ -1,208 +0,0 @@ |
|||||||
package com.android.base.utils.android; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.graphics.Bitmap; |
|
||||||
import android.graphics.Canvas; |
|
||||||
import android.graphics.Picture; |
|
||||||
import android.graphics.drawable.Drawable; |
|
||||||
import android.os.Build; |
|
||||||
import android.view.View; |
|
||||||
import android.view.ViewGroup; |
|
||||||
import android.webkit.WebView; |
|
||||||
import android.widget.TextView; |
|
||||||
|
|
||||||
import androidx.annotation.IdRes; |
|
||||||
import androidx.annotation.Nullable; |
|
||||||
import androidx.fragment.app.FragmentActivity; |
|
||||||
|
|
||||||
public class ViewUtils { |
|
||||||
|
|
||||||
private ViewUtils() { |
|
||||||
} |
|
||||||
|
|
||||||
private static final int ACTION_VISIBLE = 0x01; |
|
||||||
private static final int ACTION_GONE = 0x02; |
|
||||||
private static final int ACTION_INVISIBLE = 0x03; |
|
||||||
private static final int ACTION_DISABLE = 0x04; |
|
||||||
private static final int ACTION_ENABLE = 0x05; |
|
||||||
|
|
||||||
public static boolean measureWithMaxSize(View view) { |
|
||||||
ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); |
|
||||||
if (layoutParams == null || (layoutParams.width == ViewGroup.LayoutParams.MATCH_PARENT && layoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
int size = 1 << 30 - 1;//即后30位
|
|
||||||
int measureSpec = View.MeasureSpec.makeMeasureSpec(size, View.MeasureSpec.AT_MOST); |
|
||||||
view.measure(measureSpec, measureSpec); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean measureWithScreenSize(View view) { |
|
||||||
ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); |
|
||||||
if (layoutParams == null || (layoutParams.width == ViewGroup.LayoutParams.MATCH_PARENT && layoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
view.measure( |
|
||||||
View.MeasureSpec.makeMeasureSpec(WindowUtils.getScreenWidth(), View.MeasureSpec.AT_MOST), |
|
||||||
View.MeasureSpec.makeMeasureSpec(WindowUtils.getScreenHeight(), View.MeasureSpec.AT_MOST)); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean measureWithSize(View view, int width, int height) { |
|
||||||
ViewGroup.LayoutParams layoutParams = view.getLayoutParams(); |
|
||||||
if (layoutParams == null || (layoutParams.width == ViewGroup.LayoutParams.MATCH_PARENT && layoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
view.measure( |
|
||||||
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.AT_MOST), |
|
||||||
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST)); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static void disable(View view1, View view2) { |
|
||||||
view1.setEnabled(false); |
|
||||||
view2.setEnabled(false); |
|
||||||
} |
|
||||||
|
|
||||||
public static void disable(View view1, View view2, View view3) { |
|
||||||
view1.setEnabled(false); |
|
||||||
view2.setEnabled(false); |
|
||||||
view3.setEnabled(false); |
|
||||||
} |
|
||||||
|
|
||||||
public static void disable(View view1, View view2, View view3, View... views) { |
|
||||||
view1.setEnabled(false); |
|
||||||
view2.setEnabled(false); |
|
||||||
view3.setEnabled(false); |
|
||||||
doAction(ACTION_DISABLE, views); |
|
||||||
} |
|
||||||
|
|
||||||
public static void enable(View view1, View view2) { |
|
||||||
view1.setEnabled(true); |
|
||||||
view2.setEnabled(true); |
|
||||||
} |
|
||||||
|
|
||||||
public static void enable(View view1, View view2, View view3) { |
|
||||||
view1.setEnabled(true); |
|
||||||
view2.setEnabled(true); |
|
||||||
view3.setEnabled(true); |
|
||||||
} |
|
||||||
|
|
||||||
public static void enable(View view1, View view2, View view3, View... views) { |
|
||||||
view1.setEnabled(true); |
|
||||||
view2.setEnabled(true); |
|
||||||
view3.setEnabled(true); |
|
||||||
doAction(ACTION_ENABLE, views); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static void gone(View view1, View view2) { |
|
||||||
view1.setVisibility(View.GONE); |
|
||||||
view2.setVisibility(View.GONE); |
|
||||||
} |
|
||||||
|
|
||||||
public static void gone(View view1, View view2, View view3) { |
|
||||||
view1.setVisibility(View.GONE); |
|
||||||
view2.setVisibility(View.GONE); |
|
||||||
view3.setVisibility(View.GONE); |
|
||||||
} |
|
||||||
|
|
||||||
public static void gone(View view1, View view2, View view3, View... views) { |
|
||||||
view1.setVisibility(View.GONE); |
|
||||||
view2.setVisibility(View.GONE); |
|
||||||
view3.setVisibility(View.GONE); |
|
||||||
doAction(ACTION_GONE, views); |
|
||||||
} |
|
||||||
|
|
||||||
public static void visible(View view1, View view2) { |
|
||||||
view1.setVisibility(View.VISIBLE); |
|
||||||
view2.setVisibility(View.VISIBLE); |
|
||||||
} |
|
||||||
|
|
||||||
public static void visible(View view1, View view2, View view3) { |
|
||||||
view1.setVisibility(View.VISIBLE); |
|
||||||
view2.setVisibility(View.VISIBLE); |
|
||||||
view3.setVisibility(View.VISIBLE); |
|
||||||
} |
|
||||||
|
|
||||||
public static void visible(View view1, View view2, View view3, View... views) { |
|
||||||
view1.setVisibility(View.VISIBLE); |
|
||||||
view2.setVisibility(View.VISIBLE); |
|
||||||
view3.setVisibility(View.VISIBLE); |
|
||||||
doAction(ACTION_VISIBLE, views); |
|
||||||
} |
|
||||||
|
|
||||||
public static void invisible(View view1, View view2) { |
|
||||||
view1.setVisibility(View.INVISIBLE); |
|
||||||
view2.setVisibility(View.INVISIBLE); |
|
||||||
} |
|
||||||
|
|
||||||
public static void invisible(View view1, View view2, View view3) { |
|
||||||
view1.setVisibility(View.INVISIBLE); |
|
||||||
view2.setVisibility(View.INVISIBLE); |
|
||||||
view3.setVisibility(View.INVISIBLE); |
|
||||||
} |
|
||||||
|
|
||||||
public static void invisible(View view1, View view2, View view3, View... views) { |
|
||||||
view1.setVisibility(View.INVISIBLE); |
|
||||||
view2.setVisibility(View.INVISIBLE); |
|
||||||
view3.setVisibility(View.INVISIBLE); |
|
||||||
doAction(ACTION_INVISIBLE, views); |
|
||||||
} |
|
||||||
|
|
||||||
private static void doAction(int action, View... views) { |
|
||||||
for (View view : views) { |
|
||||||
if (action == ACTION_GONE) { |
|
||||||
view.setVisibility(View.GONE); |
|
||||||
} else if (action == ACTION_INVISIBLE) { |
|
||||||
view.setVisibility(View.INVISIBLE); |
|
||||||
} else if (action == ACTION_VISIBLE) { |
|
||||||
view.setVisibility(View.VISIBLE); |
|
||||||
} else if (action == ACTION_ENABLE) { |
|
||||||
view.setEnabled(true); |
|
||||||
} else if (action == ACTION_DISABLE) { |
|
||||||
view.setEnabled(false); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void setBackgroundDrawable(View view, Drawable drawable) { |
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { |
|
||||||
view.setBackground(drawable); |
|
||||||
} else { |
|
||||||
view.setBackgroundDrawable(drawable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static <V extends View> V find(View view, @IdRes int viewId) { |
|
||||||
@SuppressWarnings("unchecked") |
|
||||||
V v = (V) view.findViewById(viewId); |
|
||||||
return v; |
|
||||||
} |
|
||||||
|
|
||||||
public static Bitmap captureBitmapFromWebView(WebView webView) { |
|
||||||
Picture snapShot = webView.capturePicture(); |
|
||||||
Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(), snapShot.getHeight(), Bitmap.Config.ARGB_8888); |
|
||||||
Canvas canvas = new Canvas(bmp); |
|
||||||
snapShot.draw(canvas); |
|
||||||
return bmp; |
|
||||||
} |
|
||||||
|
|
||||||
public static void clearTextDrawable(TextView textView) { |
|
||||||
textView.setCompoundDrawables(null, null, null, null); |
|
||||||
} |
|
||||||
|
|
||||||
@Nullable |
|
||||||
public static FragmentActivity getRealContext(View view) { |
|
||||||
Context context = view.getContext(); |
|
||||||
while (context instanceof android.content.ContextWrapper) { |
|
||||||
if (context instanceof FragmentActivity) { |
|
||||||
return (FragmentActivity) context; |
|
||||||
} |
|
||||||
context = ((android.content.ContextWrapper) context).getBaseContext(); |
|
||||||
} |
|
||||||
return null; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,73 +0,0 @@ |
|||||||
package com.android.base.utils.android.anim; |
|
||||||
|
|
||||||
import android.app.Activity; |
|
||||||
import android.app.ActivityOptions; |
|
||||||
import android.content.Intent; |
|
||||||
import android.transition.Explode; |
|
||||||
import android.transition.Fade; |
|
||||||
import android.transition.Slide; |
|
||||||
import android.view.View; |
|
||||||
import android.view.Window; |
|
||||||
|
|
||||||
import com.android.base.utils.android.compat.AndroidVersion; |
|
||||||
|
|
||||||
import androidx.annotation.AnimRes; |
|
||||||
import androidx.appcompat.app.AppCompatActivity; |
|
||||||
import androidx.core.app.ActivityCompat; |
|
||||||
import androidx.core.app.ActivityOptionsCompat; |
|
||||||
|
|
||||||
public class ActivityAnimUtils { |
|
||||||
|
|
||||||
private ActivityAnimUtils() { |
|
||||||
throw new UnsupportedOperationException("no need instantiation"); |
|
||||||
} |
|
||||||
|
|
||||||
public static void startActivity(Activity activity, Intent intent, View share) { |
|
||||||
if (AndroidVersion.atLeast(21)) { |
|
||||||
ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, share, share.getTransitionName()); |
|
||||||
activity.startActivity(intent, options.toBundle()); |
|
||||||
} else {//小于5.0,使用makeScaleUpAnimation
|
|
||||||
ActivityOptionsCompat options = ActivityOptionsCompat.makeScaleUpAnimation(share, share.getWidth() / 2, share.getHeight() / 2, 0, 0); |
|
||||||
ActivityCompat.startActivity(activity, intent, options.toBundle()); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
// Enter And Exit Transition
|
|
||||||
///////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
public static final int TYPE_EXPLODE = 1; |
|
||||||
public static final int TYPE_SLIDE = 2; |
|
||||||
public static final int TYPE_FADE = 3; |
|
||||||
|
|
||||||
/** |
|
||||||
* @param activity context |
|
||||||
* @param type {@link #TYPE_EXPLODE},{@link #TYPE_SLIDE},{@link #TYPE_FADE} |
|
||||||
*/ |
|
||||||
private static void setTransition(Activity activity, int type) { |
|
||||||
if (AndroidVersion.atLeast(21)) { |
|
||||||
Window window = activity.getWindow(); |
|
||||||
window.requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); |
|
||||||
switch (type) { |
|
||||||
case TYPE_EXPLODE: |
|
||||||
window.setEnterTransition(new Explode()); |
|
||||||
window.setExitTransition(new Explode()); |
|
||||||
break; |
|
||||||
case TYPE_SLIDE: |
|
||||||
window.setEnterTransition(new Slide()); |
|
||||||
window.setExitTransition(new Slide()); |
|
||||||
break; |
|
||||||
case TYPE_FADE: |
|
||||||
window.setEnterTransition(new Fade()); |
|
||||||
window.setExitTransition(new Fade()); |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void finishWithAnimation(AppCompatActivity activity, @AnimRes int enterAnim, @AnimRes int exitAnim) { |
|
||||||
activity.supportFinishAfterTransition(); |
|
||||||
activity.overridePendingTransition(enterAnim, exitAnim); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,4 +1,4 @@ |
|||||||
package com.android.base.utils.android; |
package com.android.base.utils.android.cache; |
||||||
|
|
||||||
import android.content.Context; |
import android.content.Context; |
||||||
import android.content.SharedPreferences; |
import android.content.SharedPreferences; |
@ -1,43 +0,0 @@ |
|||||||
package com.android.base.utils.android.text; |
|
||||||
|
|
||||||
import android.graphics.Canvas; |
|
||||||
import android.graphics.Paint; |
|
||||||
import android.graphics.RectF; |
|
||||||
import android.text.style.ReplacementSpan; |
|
||||||
|
|
||||||
import androidx.annotation.NonNull; |
|
||||||
|
|
||||||
/** |
|
||||||
* 圆角背景Span |
|
||||||
*/ |
|
||||||
public class RoundedBackgroundSpan extends ReplacementSpan { |
|
||||||
|
|
||||||
private int mPadding; |
|
||||||
private int mBackgroundColor; |
|
||||||
private int mTextColor; |
|
||||||
private int mCorner; |
|
||||||
|
|
||||||
public RoundedBackgroundSpan(int backgroundColor, int textColor, int padding, int corner) { |
|
||||||
super(); |
|
||||||
mBackgroundColor = backgroundColor; |
|
||||||
mTextColor = textColor; |
|
||||||
mCorner = corner; |
|
||||||
mPadding = padding; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public int getSize(@NonNull Paint paint, CharSequence text, int start, int end, Paint.FontMetricsInt fm) { |
|
||||||
return (int) (mPadding + paint.measureText(text.subSequence(start, end).toString()) + mPadding); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void draw(@NonNull Canvas canvas, CharSequence text, int start, int end, float x, int top, int y, int bottom, @NonNull Paint paint) { |
|
||||||
float width = paint.measureText(text.subSequence(start, end).toString()); |
|
||||||
RectF rect = new RectF(x, top, x + width + (2 * mPadding), bottom); |
|
||||||
paint.setColor(mBackgroundColor); |
|
||||||
canvas.drawRoundRect(rect, mCorner, mCorner, paint); |
|
||||||
paint.setColor(mTextColor); |
|
||||||
canvas.drawText(text, start, end, x + mPadding, y, paint); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,39 @@ |
|||||||
|
package com.android.base.utils.android.views |
||||||
|
|
||||||
|
import android.app.Activity |
||||||
|
import android.app.ActivityOptions |
||||||
|
import android.content.Intent |
||||||
|
import android.transition.Transition |
||||||
|
import android.view.View |
||||||
|
import android.view.Window |
||||||
|
import androidx.annotation.AnimRes |
||||||
|
import androidx.appcompat.app.AppCompatActivity |
||||||
|
import androidx.core.app.ActivityCompat |
||||||
|
import androidx.core.app.ActivityOptionsCompat |
||||||
|
import com.android.base.utils.android.compat.AndroidVersion |
||||||
|
|
||||||
|
|
||||||
|
fun Activity.startActivityWithTransition(intent: Intent, share: View) { |
||||||
|
if (AndroidVersion.atLeast(21)) { |
||||||
|
val options = ActivityOptions.makeSceneTransitionAnimation(this, share, share.transitionName) |
||||||
|
startActivity(intent, options.toBundle()) |
||||||
|
} else {//小于5.0,使用makeScaleUpAnimation |
||||||
|
val options = ActivityOptionsCompat.makeScaleUpAnimation(share, share.width / 2, share.height / 2, 0, 0) |
||||||
|
ActivityCompat.startActivity(this, intent, options.toBundle()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun Activity.setTransition(type: Transition) { |
||||||
|
if (AndroidVersion.atLeast(21)) { |
||||||
|
with(window) { |
||||||
|
requestFeature(Window.FEATURE_CONTENT_TRANSITIONS) |
||||||
|
enterTransition = type |
||||||
|
exitTransition = type |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun AppCompatActivity.finishWithAnimation(@AnimRes enterAnim: Int, @AnimRes exitAnim: Int) { |
||||||
|
supportFinishAfterTransition() |
||||||
|
overridePendingTransition(enterAnim, exitAnim) |
||||||
|
} |
@ -1,4 +1,4 @@ |
|||||||
package com.android.base.kotlin |
package com.android.base.utils.android.views |
||||||
|
|
||||||
import android.app.Dialog |
import android.app.Dialog |
||||||
|
|
@ -1,4 +1,4 @@ |
|||||||
package com.android.base.kotlin |
package com.android.base.utils.android.views |
||||||
|
|
||||||
import android.view.Menu |
import android.view.Menu |
||||||
import android.view.MenuItem |
import android.view.MenuItem |
@ -0,0 +1,121 @@ |
|||||||
|
@file:JvmName("Resources") |
||||||
|
|
||||||
|
package com.android.base.utils.android.views |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.content.res.TypedArray |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import android.net.Uri |
||||||
|
import android.view.View |
||||||
|
import androidx.annotation.* |
||||||
|
|
||||||
|
import androidx.core.content.ContextCompat |
||||||
|
import androidx.fragment.app.Fragment |
||||||
|
import com.android.base.utils.BaseUtils |
||||||
|
|
||||||
|
inline fun <T : TypedArray?, R> T.use(block: (T) -> R): R { |
||||||
|
var recycled = false |
||||||
|
try { |
||||||
|
return block(this) |
||||||
|
} catch (e: Exception) { |
||||||
|
recycled = true |
||||||
|
try { |
||||||
|
this?.recycle() |
||||||
|
} catch (exception: Exception) { |
||||||
|
} |
||||||
|
throw e |
||||||
|
} finally { |
||||||
|
if (!recycled) { |
||||||
|
this?.recycle() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun Fragment.colorFromId(@ColorRes colorRes: Int): Int { |
||||||
|
val safeContext = context ?: return 0 |
||||||
|
return ContextCompat.getColor(safeContext, colorRes) |
||||||
|
} |
||||||
|
|
||||||
|
fun Fragment.drawableFromId(@DrawableRes colorRes: Int): Drawable? { |
||||||
|
val safeContext = context ?: return null |
||||||
|
return ContextCompat.getDrawable(safeContext, colorRes) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.colorFromId(@ColorRes colorRes: Int): Int { |
||||||
|
val safeContext = context ?: return 0 |
||||||
|
return ContextCompat.getColor(safeContext, colorRes) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.drawableFromId(@DrawableRes colorRes: Int): Drawable? { |
||||||
|
val safeContext = context ?: return null |
||||||
|
return ContextCompat.getDrawable(safeContext, colorRes) |
||||||
|
} |
||||||
|
|
||||||
|
fun Context.colorFromId(@ColorRes id: Int): Int { |
||||||
|
return ContextCompat.getColor(this, id) |
||||||
|
} |
||||||
|
|
||||||
|
fun Context.drawableFromId(@DrawableRes id: Int): Drawable? { |
||||||
|
return ContextCompat.getDrawable(this, id) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* - [name] 资源的名称,如 ic_launcher 或者 com.example.android/drawable/ic_launcher(这是,下面两个参数可以省略) |
||||||
|
* - [defType] 资源的类型,如 drawable |
||||||
|
* - [defPackage] 包名 |
||||||
|
* |
||||||
|
* 返回资源 id |
||||||
|
*/ |
||||||
|
fun getResource(name: String, defType: String, defPackage: String): Int { |
||||||
|
return BaseUtils.getResources().getIdentifier(name, defType, defPackage) |
||||||
|
} |
||||||
|
|
||||||
|
fun getText(@StringRes id: Int): CharSequence { |
||||||
|
return BaseUtils.getResources().getText(id) |
||||||
|
} |
||||||
|
|
||||||
|
fun getString(@StringRes id: Int): String { |
||||||
|
return BaseUtils.getResources().getString(id) |
||||||
|
} |
||||||
|
|
||||||
|
fun getString(@StringRes id: Int, vararg formatArgs: Any): String { |
||||||
|
return BaseUtils.getResources().getString(id, *formatArgs) |
||||||
|
} |
||||||
|
|
||||||
|
fun getStringArray(@ArrayRes id: Int): Array<String> { |
||||||
|
return BaseUtils.getResources().getStringArray(id) |
||||||
|
} |
||||||
|
|
||||||
|
fun getIntArray(@ArrayRes id: Int): IntArray { |
||||||
|
return BaseUtils.getResources().getIntArray(id) |
||||||
|
} |
||||||
|
|
||||||
|
fun createUriByResource(id: Int): Uri { |
||||||
|
return Uri.parse("android.resource://" + BaseUtils.getAppContext().packageName + "/" + id) |
||||||
|
} |
||||||
|
|
||||||
|
fun createUriByAssets(path: String): Uri { |
||||||
|
return Uri.parse("file:///android_asset/$path") |
||||||
|
} |
||||||
|
|
||||||
|
fun getStyledColor(context: Context, @AttrRes attr: Int): Int { |
||||||
|
val a = context.obtainStyledAttributes(null, intArrayOf(attr)) |
||||||
|
try { |
||||||
|
return a.getColor(0, 0x000000) |
||||||
|
} finally { |
||||||
|
a.recycle() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun getStyledDrawable(context: Context, @AttrRes attr: Int): Drawable? { |
||||||
|
val a = context.obtainStyledAttributes(null, intArrayOf(attr)) |
||||||
|
try { |
||||||
|
return a.getDrawable(0) |
||||||
|
} finally { |
||||||
|
a.recycle() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun getDimensionPixelSize(dimenId: Int): Int { |
||||||
|
return BaseUtils.getResources().getDimensionPixelSize(dimenId) |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package com.android.base.utils.android.views |
||||||
|
|
||||||
|
import android.graphics.Canvas |
||||||
|
import android.graphics.Paint |
||||||
|
import android.graphics.RectF |
||||||
|
import android.text.style.ReplacementSpan |
||||||
|
|
||||||
|
/** |
||||||
|
* 圆角背景Span |
||||||
|
*/ |
||||||
|
class RoundedBackgroundSpan(private val backgroundColor: Int, private val textColor: Int, private val padding: Int, private val corner: Int) : ReplacementSpan() { |
||||||
|
|
||||||
|
override fun getSize(paint: Paint, text: CharSequence, start: Int, end: Int, fm: Paint.FontMetricsInt?): Int { |
||||||
|
return (padding.toFloat() + paint.measureText(text.subSequence(start, end).toString()) + padding.toFloat()).toInt() |
||||||
|
} |
||||||
|
|
||||||
|
override fun draw(canvas: Canvas, text: CharSequence, start: Int, end: Int, x: Float, top: Int, y: Int, bottom: Int, paint: Paint) { |
||||||
|
val width = paint.measureText(text.subSequence(start, end).toString()) |
||||||
|
val rect = RectF(x, top.toFloat(), x + width + (2 * padding).toFloat(), bottom.toFloat()) |
||||||
|
paint.color = backgroundColor |
||||||
|
canvas.drawRoundRect(rect, corner.toFloat(), corner.toFloat(), paint) |
||||||
|
paint.color = textColor |
||||||
|
canvas.drawText(text, start, end, x + padding, y.toFloat(), paint) |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
package com.android.base.utils.android.views |
||||||
|
|
||||||
|
import android.view.View |
||||||
|
import android.widget.ScrollView |
||||||
|
import androidx.core.widget.NestedScrollView |
||||||
|
|
||||||
|
|
||||||
|
fun ScrollView.scrollToBottom() { |
||||||
|
fullScroll(View.FOCUS_DOWN) |
||||||
|
} |
||||||
|
|
||||||
|
fun ScrollView.scrollToTop() { |
||||||
|
fullScroll(View.FOCUS_UP) |
||||||
|
} |
||||||
|
|
||||||
|
fun NestedScrollView.scrollToBottom() { |
||||||
|
fullScroll(View.FOCUS_DOWN) |
||||||
|
} |
||||||
|
|
||||||
|
fun NestedScrollView.scrollToTop() { |
||||||
|
fullScroll(View.FOCUS_UP) |
||||||
|
} |
@ -0,0 +1,61 @@ |
|||||||
|
package com.android.base.utils.android.views |
||||||
|
|
||||||
|
import android.util.TypedValue |
||||||
|
import com.android.base.utils.BaseUtils |
||||||
|
|
||||||
|
fun dip(value: Int): Int = dpToPx(value) |
||||||
|
fun dip(value: Float): Float = dpToPx(value) |
||||||
|
fun sp(value: Int): Int = spToPx(value) |
||||||
|
fun sp(value: Float): Float = spToPx(value) |
||||||
|
|
||||||
|
fun dpToPx(dp: Float): Float { |
||||||
|
return dp * BaseUtils.getDisplayMetrics().density |
||||||
|
} |
||||||
|
|
||||||
|
fun dpToPx(dp: Int): Int { |
||||||
|
return (dp * BaseUtils.getDisplayMetrics().density + 0.5f).toInt() |
||||||
|
} |
||||||
|
|
||||||
|
fun pxToDp(px: Float): Float { |
||||||
|
return px / BaseUtils.getDisplayMetrics().density |
||||||
|
} |
||||||
|
|
||||||
|
fun pxToDp(px: Int): Int { |
||||||
|
return (px / BaseUtils.getDisplayMetrics().density + 0.5f).toInt() |
||||||
|
} |
||||||
|
|
||||||
|
fun spToPx(sp: Float): Float { |
||||||
|
return sp * BaseUtils.getDisplayMetrics().scaledDensity |
||||||
|
} |
||||||
|
|
||||||
|
fun spToPx(sp: Int): Int { |
||||||
|
return (sp * BaseUtils.getDisplayMetrics().scaledDensity + 0.5f).toInt() |
||||||
|
} |
||||||
|
|
||||||
|
fun pxToSp(px: Float): Float { |
||||||
|
return px / BaseUtils.getDisplayMetrics().scaledDensity |
||||||
|
} |
||||||
|
|
||||||
|
fun pxToSp(px: Int): Int { |
||||||
|
return (px / BaseUtils.getDisplayMetrics().scaledDensity + 0.5f).toInt() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 各种单位转换,该方法存在于[TypedValue] 中 |
||||||
|
* |
||||||
|
* @param unit 单位 |
||||||
|
* @param value 值 |
||||||
|
* @return 转换结果 |
||||||
|
*/ |
||||||
|
fun applyDimension(unit: Int, value: Float): Float { |
||||||
|
val metrics = BaseUtils.getDisplayMetrics() |
||||||
|
when (unit) { |
||||||
|
TypedValue.COMPLEX_UNIT_PX -> return value |
||||||
|
TypedValue.COMPLEX_UNIT_DIP -> return value * metrics.density |
||||||
|
TypedValue.COMPLEX_UNIT_SP -> return value * metrics.scaledDensity |
||||||
|
TypedValue.COMPLEX_UNIT_PT -> return value * metrics.xdpi * (1.0F / 72) |
||||||
|
TypedValue.COMPLEX_UNIT_IN -> return value * metrics.xdpi |
||||||
|
TypedValue.COMPLEX_UNIT_MM -> return value * metrics.xdpi * (1.0F / 25.4F) |
||||||
|
} |
||||||
|
return 0f |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
package com.android.base.utils.android.views |
||||||
|
|
||||||
|
import android.content.res.ColorStateList |
||||||
|
import android.graphics.* |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import androidx.core.graphics.drawable.DrawableCompat |
||||||
|
|
||||||
|
|
||||||
|
fun tintBitmap(inBitmap: Bitmap, tintColor: Int): Bitmap { |
||||||
|
val outBitmap = Bitmap.createBitmap(inBitmap.width, inBitmap.height, inBitmap.config) |
||||||
|
val canvas = Canvas(outBitmap) |
||||||
|
val paint = Paint(Paint.ANTI_ALIAS_FLAG) |
||||||
|
paint.colorFilter = PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN) |
||||||
|
canvas.drawBitmap(inBitmap, 0f, 0f, paint) |
||||||
|
return outBitmap |
||||||
|
} |
||||||
|
|
||||||
|
fun tint(originDrawable: Drawable, color: Int): Drawable { |
||||||
|
return tint(originDrawable, ColorStateList.valueOf(color)) |
||||||
|
} |
||||||
|
|
||||||
|
fun tint(originDrawable: Drawable, color: Int, tintMode: PorterDuff.Mode? = null): Drawable { |
||||||
|
return tint(originDrawable, ColorStateList.valueOf(color), tintMode) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* usage: |
||||||
|
* ``` |
||||||
|
* int[][] states = new int[][]{ |
||||||
|
* new int[]{android.R.attr.state_selected}, // pressed |
||||||
|
* new int[]{-android.R.attr.state_selected} // unpressed |
||||||
|
* }; |
||||||
|
* int[] colors = new int[]{ |
||||||
|
* Color.BLACK, |
||||||
|
* Color.GRAY |
||||||
|
* }; |
||||||
|
* ColorStateList colorStateList = new ColorStateList(states, colors); |
||||||
|
* Drawable aaa = ContextCompat.getDrawable(getContext(), R.drawable.aaa); |
||||||
|
* Drawable bbb = ContextCompat.getDrawable(getContext(), R.drawable.bbb); |
||||||
|
* Drawable aaaTint = TintUtils.tint(aaa, colorStateList); |
||||||
|
* Drawable bbbTint = TintUtils.tint(bbb, colorStateList); |
||||||
|
* aaaTv.setCompoundDrawablesWithIntrinsicBounds(null, aaaTint, null, null); |
||||||
|
* bbbTv.setCompoundDrawablesWithIntrinsicBounds(null, bbbTint, null, null); |
||||||
|
* ``` |
||||||
|
*/ |
||||||
|
@JvmOverloads |
||||||
|
fun tint(originDrawable: Drawable, colorStateList: ColorStateList, tintMode: PorterDuff.Mode? = null): Drawable { |
||||||
|
val tintDrawable = DrawableCompat.wrap(originDrawable) |
||||||
|
if (tintMode != null) { |
||||||
|
DrawableCompat.setTintMode(tintDrawable, tintMode) |
||||||
|
} |
||||||
|
DrawableCompat.setTintList(tintDrawable, colorStateList) |
||||||
|
return tintDrawable |
||||||
|
} |
@ -0,0 +1,397 @@ |
|||||||
|
package com.android.base.utils.android.views |
||||||
|
|
||||||
|
import android.annotation.SuppressLint |
||||||
|
import android.graphics.drawable.Drawable |
||||||
|
import android.os.Build |
||||||
|
import android.view.MotionEvent |
||||||
|
import android.view.View |
||||||
|
import android.view.ViewGroup |
||||||
|
import android.view.ViewTreeObserver |
||||||
|
import androidx.annotation.IdRes |
||||||
|
import androidx.core.view.ViewCompat |
||||||
|
import androidx.fragment.app.FragmentActivity |
||||||
|
import com.android.base.rx.subscribeIgnoreError |
||||||
|
import com.android.base.utils.android.WindowUtils |
||||||
|
import com.android.base.utils.android.compat.AndroidVersion.atLeast |
||||||
|
import com.android.base.utils.common.otherwise |
||||||
|
import com.android.base.utils.common.yes |
||||||
|
import com.jakewharton.rxbinding3.view.clicks |
||||||
|
import io.reactivex.Observable |
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers |
||||||
|
import java.util.concurrent.TimeUnit |
||||||
|
|
||||||
|
fun View.visibleOrGone(visible: Boolean) { |
||||||
|
if (visible) { |
||||||
|
this.visibility = View.VISIBLE |
||||||
|
} else { |
||||||
|
this.visibility = View.GONE |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun View.visibleOrInvisible(visible: Boolean) { |
||||||
|
if (visible) { |
||||||
|
this.visibility = View.VISIBLE |
||||||
|
} else { |
||||||
|
this.visibility = View.INVISIBLE |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun View.visible() { |
||||||
|
this.visibility = View.VISIBLE |
||||||
|
} |
||||||
|
|
||||||
|
fun View.invisible() { |
||||||
|
this.visibility = View.INVISIBLE |
||||||
|
} |
||||||
|
|
||||||
|
fun View.gone() { |
||||||
|
this.visibility = View.GONE |
||||||
|
} |
||||||
|
|
||||||
|
fun View.isVisible() = this.visibility == View.VISIBLE |
||||||
|
fun View.isInvisible() = this.visibility == View.INVISIBLE |
||||||
|
fun View.isGone() = this.visibility == View.GONE |
||||||
|
|
||||||
|
val View.realContext: FragmentActivity? |
||||||
|
get() { |
||||||
|
var context = context |
||||||
|
while (context is android.content.ContextWrapper) { |
||||||
|
if (context is FragmentActivity) { |
||||||
|
return context |
||||||
|
} |
||||||
|
context = context.baseContext |
||||||
|
} |
||||||
|
return null |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setClickFeedback(pressAlpha: Float = 0.5F) { |
||||||
|
this.setOnTouchListener { v, event -> |
||||||
|
when (event.action) { |
||||||
|
MotionEvent.ACTION_DOWN -> { |
||||||
|
v.alpha = pressAlpha |
||||||
|
} |
||||||
|
MotionEvent.ACTION_UP -> { |
||||||
|
v.alpha = 1F |
||||||
|
} |
||||||
|
MotionEvent.ACTION_CANCEL -> { |
||||||
|
v.alpha = 1F |
||||||
|
} |
||||||
|
} |
||||||
|
false |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline fun View.doOnLayoutAvailable(crossinline block: () -> Unit) { |
||||||
|
//isLaidOut 方法作用:如果 view 已经通过至少一个布局,则返回true,因为它最后一次附加到窗口或从窗口分离。 |
||||||
|
ViewCompat.isLaidOut(this).yes { |
||||||
|
block() |
||||||
|
}.otherwise { |
||||||
|
addOnLayoutChangeListener(object : View.OnLayoutChangeListener { |
||||||
|
override fun onLayoutChange(v: View?, left: Int, top: Int, right: Int, bottom: Int, oldLeft: Int, oldTop: Int, oldRight: Int, oldBottom: Int) { |
||||||
|
removeOnLayoutChangeListener(this) |
||||||
|
block() |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline fun <T : View> T.onGlobalLayoutOnce(crossinline action: T.() -> Unit) { |
||||||
|
val t: T = this |
||||||
|
t.viewTreeObserver |
||||||
|
.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener { |
||||||
|
override fun onGlobalLayout() { |
||||||
|
action.invoke(t) |
||||||
|
if (atLeast(16)) { |
||||||
|
viewTreeObserver.removeOnGlobalLayoutListener(this) |
||||||
|
} else { |
||||||
|
@Suppress("DEPRECATION") |
||||||
|
viewTreeObserver.removeGlobalOnLayoutListener(this) |
||||||
|
} |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setPaddingAll(padding: Int) { |
||||||
|
this.setPadding(padding, padding, padding, padding) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setPaddingLeft(padding: Int) { |
||||||
|
this.setPadding(padding, paddingTop, paddingRight, paddingBottom) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setPaddRight(padding: Int) { |
||||||
|
this.setPadding(paddingLeft, paddingTop, padding, paddingBottom) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setPaddingTop(padding: Int) { |
||||||
|
this.setPadding(paddingLeft, padding, paddingRight, paddingBottom) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setPaddingBottom(padding: Int) { |
||||||
|
this.setPadding(paddingLeft, paddingTop, paddingRight, padding) |
||||||
|
} |
||||||
|
|
||||||
|
fun newLayoutParams(width: Int = ViewGroup.MarginLayoutParams.WRAP_CONTENT, height: Int = ViewGroup.MarginLayoutParams.WRAP_CONTENT): ViewGroup.LayoutParams { |
||||||
|
return ViewGroup.LayoutParams(width, height) |
||||||
|
} |
||||||
|
|
||||||
|
fun newMarginLayoutParams(width: Int = ViewGroup.MarginLayoutParams.WRAP_CONTENT, height: Int = ViewGroup.MarginLayoutParams.WRAP_CONTENT): ViewGroup.MarginLayoutParams { |
||||||
|
return ViewGroup.MarginLayoutParams(width, height) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setTopMargin(topMargin: Int) { |
||||||
|
val params: ViewGroup.LayoutParams? = layoutParams |
||||||
|
if (params is ViewGroup.MarginLayoutParams) { |
||||||
|
params.topMargin = topMargin |
||||||
|
} else { |
||||||
|
layoutParams = newMarginLayoutParams().apply { |
||||||
|
this.topMargin = topMargin |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setBottomMargin(bottomMargin: Int) { |
||||||
|
val params: ViewGroup.LayoutParams? = layoutParams |
||||||
|
if (params is ViewGroup.MarginLayoutParams) { |
||||||
|
params.bottomMargin = bottomMargin |
||||||
|
} else { |
||||||
|
layoutParams = newMarginLayoutParams().apply { |
||||||
|
this.bottomMargin = bottomMargin |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setLeftMargin(leftMargin: Int) { |
||||||
|
val params: ViewGroup.LayoutParams? = layoutParams |
||||||
|
if (params is ViewGroup.MarginLayoutParams) { |
||||||
|
params.leftMargin = leftMargin |
||||||
|
} else { |
||||||
|
layoutParams = newMarginLayoutParams().apply { |
||||||
|
this.leftMargin = leftMargin |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setRightMargin(rightMargin: Int) { |
||||||
|
val params: ViewGroup.LayoutParams? = layoutParams |
||||||
|
if (params is ViewGroup.MarginLayoutParams) { |
||||||
|
params.rightMargin = rightMargin |
||||||
|
} else { |
||||||
|
layoutParams = newMarginLayoutParams().apply { |
||||||
|
this.rightMargin = rightMargin |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setRightMargins(leftMargin: Int, topMargin: Int, rightMargin: Int, bottomMargin: Int) { |
||||||
|
val params: ViewGroup.LayoutParams? = layoutParams |
||||||
|
if (params is ViewGroup.MarginLayoutParams) { |
||||||
|
params.rightMargin = rightMargin |
||||||
|
params.leftMargin = leftMargin |
||||||
|
params.bottomMargin = bottomMargin |
||||||
|
params.topMargin = topMargin |
||||||
|
} else { |
||||||
|
layoutParams = newMarginLayoutParams().apply { |
||||||
|
this.rightMargin = rightMargin |
||||||
|
this.leftMargin = leftMargin |
||||||
|
this.bottomMargin = bottomMargin |
||||||
|
this.topMargin = topMargin |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setWidth(width: Int) { |
||||||
|
val params = layoutParams ?: ViewGroup.LayoutParams(0, 0) |
||||||
|
params.width = width |
||||||
|
layoutParams = params |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setHeight(height: Int) { |
||||||
|
val params = layoutParams ?: ViewGroup.LayoutParams(0, 0) |
||||||
|
params.height = height |
||||||
|
layoutParams = params |
||||||
|
} |
||||||
|
|
||||||
|
fun View.setSize(width: Int, height: Int) { |
||||||
|
val params = layoutParams ?: ViewGroup.LayoutParams(0, 0) |
||||||
|
params.width = width |
||||||
|
params.height = height |
||||||
|
layoutParams = params |
||||||
|
} |
||||||
|
|
||||||
|
fun View.onDebouncedClick(onClick: (View) -> Unit) { |
||||||
|
onClickObservable(500) |
||||||
|
.subscribeIgnoreError { onClick(this) } |
||||||
|
} |
||||||
|
|
||||||
|
fun View.onDebouncedClick(milliseconds: Long, onClick: (View) -> Unit) { |
||||||
|
onClickObservable(milliseconds) |
||||||
|
.subscribeIgnoreError { onClick(this) } |
||||||
|
} |
||||||
|
|
||||||
|
fun View.onClickObservable(): Observable<Unit> { |
||||||
|
return onClickObservable(500) |
||||||
|
} |
||||||
|
|
||||||
|
fun View.onClickObservable(milliseconds: Long): Observable<Unit> { |
||||||
|
return clicks() |
||||||
|
.throttleFirst(milliseconds, TimeUnit.MILLISECONDS) |
||||||
|
.observeOn(AndroidSchedulers.mainThread()) |
||||||
|
} |
||||||
|
|
||||||
|
inline val ViewGroup.views get() = (0 until childCount).map { getChildAt(it) } |
||||||
|
|
||||||
|
fun View.measureSelf(): Boolean { |
||||||
|
val layoutParams = layoutParams |
||||||
|
if (layoutParams == null || layoutParams.width == ViewGroup.LayoutParams.MATCH_PARENT && layoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT) { |
||||||
|
return false |
||||||
|
} |
||||||
|
val size = 1 shl 30 - 1//即后30位 |
||||||
|
val measureSpec = View.MeasureSpec.makeMeasureSpec(size, View.MeasureSpec.AT_MOST) |
||||||
|
measure(measureSpec, measureSpec) |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
fun View.measureSelfWithScreenSize(): Boolean { |
||||||
|
val layoutParams = layoutParams |
||||||
|
if (layoutParams == null || layoutParams.width == ViewGroup.LayoutParams.MATCH_PARENT && layoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT) { |
||||||
|
return false |
||||||
|
} |
||||||
|
measure( |
||||||
|
View.MeasureSpec.makeMeasureSpec(WindowUtils.getScreenWidth(), View.MeasureSpec.AT_MOST), |
||||||
|
View.MeasureSpec.makeMeasureSpec(WindowUtils.getScreenHeight(), View.MeasureSpec.AT_MOST)) |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
fun View.measureSelf(width: Int, height: Int): Boolean { |
||||||
|
val layoutParams = layoutParams |
||||||
|
if (layoutParams == null || layoutParams.width == ViewGroup.LayoutParams.MATCH_PARENT && layoutParams.height == ViewGroup.LayoutParams.MATCH_PARENT) { |
||||||
|
return false |
||||||
|
} |
||||||
|
measure( |
||||||
|
View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.AT_MOST), |
||||||
|
View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.AT_MOST)) |
||||||
|
return true |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressLint("ObsoleteSdkInt") |
||||||
|
fun View.setBgDrawable(drawable: Drawable) { |
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { |
||||||
|
background = drawable |
||||||
|
} else { |
||||||
|
setBackgroundDrawable(drawable) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST") |
||||||
|
fun <V : View> View.find(@IdRes viewId: Int): V { |
||||||
|
return findViewById<View>(viewId) as V |
||||||
|
} |
||||||
|
|
||||||
|
private const val ACTION_VISIBLE = 0x01 |
||||||
|
private const val ACTION_GONE = 0x02 |
||||||
|
private const val ACTION_INVISIBLE = 0x03 |
||||||
|
private const val ACTION_DISABLE = 0x04 |
||||||
|
private const val ACTION_ENABLE = 0x05 |
||||||
|
|
||||||
|
fun disable(view1: View, view2: View) { |
||||||
|
view1.isEnabled = false |
||||||
|
view2.isEnabled = false |
||||||
|
} |
||||||
|
|
||||||
|
fun disable(view1: View, view2: View, view3: View) { |
||||||
|
view1.isEnabled = false |
||||||
|
view2.isEnabled = false |
||||||
|
view3.isEnabled = false |
||||||
|
} |
||||||
|
|
||||||
|
fun disable(view1: View, view2: View, view3: View, vararg views: View) { |
||||||
|
view1.isEnabled = false |
||||||
|
view2.isEnabled = false |
||||||
|
view3.isEnabled = false |
||||||
|
doAction(ACTION_DISABLE, *views) |
||||||
|
} |
||||||
|
|
||||||
|
fun enable(view1: View, view2: View) { |
||||||
|
view1.isEnabled = true |
||||||
|
view2.isEnabled = true |
||||||
|
} |
||||||
|
|
||||||
|
fun enable(view1: View, view2: View, view3: View) { |
||||||
|
view1.isEnabled = true |
||||||
|
view2.isEnabled = true |
||||||
|
view3.isEnabled = true |
||||||
|
} |
||||||
|
|
||||||
|
fun enable(view1: View, view2: View, view3: View, vararg views: View) { |
||||||
|
view1.isEnabled = true |
||||||
|
view2.isEnabled = true |
||||||
|
view3.isEnabled = true |
||||||
|
doAction(ACTION_ENABLE, *views) |
||||||
|
} |
||||||
|
|
||||||
|
fun gone(view1: View, view2: View) { |
||||||
|
view1.visibility = View.GONE |
||||||
|
view2.visibility = View.GONE |
||||||
|
} |
||||||
|
|
||||||
|
fun gone(view1: View, view2: View, view3: View) { |
||||||
|
view1.visibility = View.GONE |
||||||
|
view2.visibility = View.GONE |
||||||
|
view3.visibility = View.GONE |
||||||
|
} |
||||||
|
|
||||||
|
fun gone(view1: View, view2: View, view3: View, vararg views: View) { |
||||||
|
view1.visibility = View.GONE |
||||||
|
view2.visibility = View.GONE |
||||||
|
view3.visibility = View.GONE |
||||||
|
doAction(ACTION_GONE, *views) |
||||||
|
} |
||||||
|
|
||||||
|
fun visible(view1: View, view2: View) { |
||||||
|
view1.visibility = View.VISIBLE |
||||||
|
view2.visibility = View.VISIBLE |
||||||
|
} |
||||||
|
|
||||||
|
fun visible(view1: View, view2: View, view3: View) { |
||||||
|
view1.visibility = View.VISIBLE |
||||||
|
view2.visibility = View.VISIBLE |
||||||
|
view3.visibility = View.VISIBLE |
||||||
|
} |
||||||
|
|
||||||
|
fun visible(view1: View, view2: View, view3: View, vararg views: View) { |
||||||
|
view1.visibility = View.VISIBLE |
||||||
|
view2.visibility = View.VISIBLE |
||||||
|
view3.visibility = View.VISIBLE |
||||||
|
doAction(ACTION_VISIBLE, *views) |
||||||
|
} |
||||||
|
|
||||||
|
fun invisible(view1: View, view2: View) { |
||||||
|
view1.visibility = View.INVISIBLE |
||||||
|
view2.visibility = View.INVISIBLE |
||||||
|
} |
||||||
|
|
||||||
|
fun invisible(view1: View, view2: View, view3: View) { |
||||||
|
view1.visibility = View.INVISIBLE |
||||||
|
view2.visibility = View.INVISIBLE |
||||||
|
view3.visibility = View.INVISIBLE |
||||||
|
} |
||||||
|
|
||||||
|
fun invisible(view1: View, view2: View, view3: View, vararg views: View) { |
||||||
|
view1.visibility = View.INVISIBLE |
||||||
|
view2.visibility = View.INVISIBLE |
||||||
|
view3.visibility = View.INVISIBLE |
||||||
|
doAction(ACTION_INVISIBLE, *views) |
||||||
|
} |
||||||
|
|
||||||
|
private fun doAction(action: Int, vararg views: View) { |
||||||
|
for (view in views) { |
||||||
|
when (action) { |
||||||
|
ACTION_GONE -> view.visibility = View.GONE |
||||||
|
ACTION_INVISIBLE -> view.visibility = View.INVISIBLE |
||||||
|
ACTION_VISIBLE -> view.visibility = View.VISIBLE |
||||||
|
ACTION_ENABLE -> view.isEnabled = true |
||||||
|
ACTION_DISABLE -> view.isEnabled = false |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package com.android.base.utils.android.views |
||||||
|
|
||||||
|
import android.graphics.Bitmap |
||||||
|
import android.graphics.Canvas |
||||||
|
import android.webkit.WebView |
||||||
|
|
||||||
|
|
||||||
|
fun captureBitmapFromWebView(webView: WebView): Bitmap { |
||||||
|
val snapShot = webView.capturePicture() |
||||||
|
val bmp = Bitmap.createBitmap(snapShot.width, snapShot.height, Bitmap.Config.ARGB_8888) |
||||||
|
val canvas = Canvas(bmp) |
||||||
|
snapShot.draw(canvas) |
||||||
|
return bmp |
||||||
|
} |
@ -1,59 +0,0 @@ |
|||||||
package com.android.base.utils.common; |
|
||||||
|
|
||||||
import java.util.Collection; |
|
||||||
import java.util.Map; |
|
||||||
|
|
||||||
/** |
|
||||||
* 对象检查工具 |
|
||||||
*/ |
|
||||||
public class Checker { |
|
||||||
|
|
||||||
private Checker() { |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isEmpty(Collection<?> data) { |
|
||||||
return data == null || data.size() == 0; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean notEmpty(Collection<?> data) { |
|
||||||
return !isEmpty(data); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isNull(Object o) { |
|
||||||
return o == null; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isEmpty(Map<?, ?> map) { |
|
||||||
return map == null || map.size() == 0; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean notEmpty(Map<?, ?> map) { |
|
||||||
return !isEmpty(map); |
|
||||||
} |
|
||||||
|
|
||||||
public static <T> boolean isEmpty(T[] t) { |
|
||||||
return t == null || t.length == 0; |
|
||||||
} |
|
||||||
|
|
||||||
public static <T> boolean notEmpty(T[] t) { |
|
||||||
return !isEmpty(t); |
|
||||||
} |
|
||||||
|
|
||||||
public static <T> T requireNonNull(T obj) { |
|
||||||
if (obj == null) |
|
||||||
throw new NullPointerException(); |
|
||||||
return obj; |
|
||||||
} |
|
||||||
|
|
||||||
public static <T> T requireNonNull(T obj, String message) { |
|
||||||
if (obj == null) |
|
||||||
throw new NullPointerException(message); |
|
||||||
return obj; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean nonNull(Object obj) { |
|
||||||
return obj != null; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,49 @@ |
|||||||
|
@file:JvmName("Checker") |
||||||
|
|
||||||
|
package com.android.base.utils.common |
||||||
|
|
||||||
|
fun isEmpty(data: Collection<*>?): Boolean { |
||||||
|
return data == null || data.isEmpty() |
||||||
|
} |
||||||
|
|
||||||
|
fun notEmpty(data: Collection<*>?): Boolean { |
||||||
|
return !isEmpty(data) |
||||||
|
} |
||||||
|
|
||||||
|
fun isNull(o: Any?): Boolean { |
||||||
|
return o == null |
||||||
|
} |
||||||
|
|
||||||
|
fun isEmpty(map: Map<*, *>?): Boolean { |
||||||
|
return map == null || map.isEmpty() |
||||||
|
} |
||||||
|
|
||||||
|
fun notEmpty(map: Map<*, *>): Boolean { |
||||||
|
return !isEmpty(map) |
||||||
|
} |
||||||
|
|
||||||
|
fun <T> isEmpty(t: Array<T>?): Boolean { |
||||||
|
return t == null || t.isEmpty() |
||||||
|
} |
||||||
|
|
||||||
|
fun <T> notEmpty(t: Array<T>): Boolean { |
||||||
|
return !isEmpty(t) |
||||||
|
} |
||||||
|
|
||||||
|
fun <T> requireNonNull(obj: T?): T { |
||||||
|
if (obj == null) { |
||||||
|
throw NullPointerException("requireNonNull failed") |
||||||
|
} |
||||||
|
return obj |
||||||
|
} |
||||||
|
|
||||||
|
fun <T> requireNonNull(obj: T?, message: String): T { |
||||||
|
if (obj == null) { |
||||||
|
throw NullPointerException("requireNonNull failed: %s".format(message)) |
||||||
|
} |
||||||
|
return obj |
||||||
|
} |
||||||
|
|
||||||
|
fun nonNull(obj: Any?): Boolean { |
||||||
|
return obj != null |
||||||
|
} |
@ -1,62 +0,0 @@ |
|||||||
package com.android.base.utils.common; |
|
||||||
|
|
||||||
import java.io.Closeable; |
|
||||||
import java.io.IOException; |
|
||||||
|
|
||||||
|
|
||||||
public class CloseUtils { |
|
||||||
|
|
||||||
private CloseUtils() { |
|
||||||
throw new UnsupportedOperationException("u can't instantiate me..."); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 安静关闭IO |
|
||||||
*/ |
|
||||||
public static void closeIO(Closeable closeable) { |
|
||||||
if (closeable != null) { |
|
||||||
try { |
|
||||||
closeable.close(); |
|
||||||
} catch (IOException e) { |
|
||||||
e.printStackTrace(); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 关闭IO |
|
||||||
*/ |
|
||||||
public static void closeIOQuietly(Closeable closeable) { |
|
||||||
if (closeable != null) { |
|
||||||
try { |
|
||||||
closeable.close(); |
|
||||||
} catch (IOException ignored) { |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 关闭IO |
|
||||||
* |
|
||||||
* @param closeables closeable |
|
||||||
*/ |
|
||||||
public static void closeIO(Closeable... closeables) { |
|
||||||
if (closeables == null) return; |
|
||||||
for (Closeable closeable : closeables) { |
|
||||||
closeIO(closeable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 安静关闭IO |
|
||||||
* |
|
||||||
* @param closeables closeable |
|
||||||
*/ |
|
||||||
public static void closeIOQuietly(Closeable... closeables) { |
|
||||||
if (closeables == null) return; |
|
||||||
for (Closeable closeable : closeables) { |
|
||||||
closeIOQuietly(closeable); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,23 +0,0 @@ |
|||||||
package com.android.base.utils.common; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
|
|
||||||
public class CollectionUtils { |
|
||||||
|
|
||||||
private CollectionUtils() { |
|
||||||
throw new UnsupportedOperationException(); |
|
||||||
} |
|
||||||
|
|
||||||
public static <T> ArrayList<T> toArrayList(List<T> list) { |
|
||||||
if (list == null) { |
|
||||||
return new ArrayList<>(0); |
|
||||||
} |
|
||||||
if (list instanceof ArrayList) { |
|
||||||
return (ArrayList<T>) list; |
|
||||||
} |
|
||||||
return new ArrayList<>(list); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -1,9 +1,15 @@ |
|||||||
package com.android.base.kotlin |
package com.android.base.utils.common |
||||||
|
|
||||||
import com.android.base.utils.common.CollectionUtils |
fun <E> List<E>?.toArrayList(copy: Boolean = false): ArrayList<E> { |
||||||
|
|
||||||
|
if (this == null) { |
||||||
|
return ArrayList(0) |
||||||
|
} |
||||||
|
|
||||||
|
return if (!copy && this is java.util.ArrayList<E>) { |
||||||
|
this |
||||||
|
} else ArrayList(this) |
||||||
|
|
||||||
fun <E> List<E>?.toArrayList(): ArrayList<E> { |
|
||||||
return CollectionUtils.toArrayList(this) |
|
||||||
} |
} |
||||||
|
|
||||||
fun <E> MutableList<E>.removeWhich(filter: (E) -> Boolean): Boolean { |
fun <E> MutableList<E>.removeWhich(filter: (E) -> Boolean): Boolean { |
@ -1,90 +0,0 @@ |
|||||||
package com.android.base.utils.common; |
|
||||||
|
|
||||||
import android.util.Log; |
|
||||||
|
|
||||||
import java.io.File; |
|
||||||
|
|
||||||
/** |
|
||||||
* @author Ztiany |
|
||||||
* Email: 1169654504@qq.com |
|
||||||
* Date : 2016-11-30 16:29 |
|
||||||
*/ |
|
||||||
public class FileUtils { |
|
||||||
|
|
||||||
private static final String TAG = FileUtils.class.getSimpleName(); |
|
||||||
|
|
||||||
private FileUtils() { |
|
||||||
throw new UnsupportedOperationException("no need instantiation"); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean makeFilePath(File file) { |
|
||||||
if (file == null) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
File parent = file.getParentFile(); |
|
||||||
return parent.exists() || makeDir(parent); |
|
||||||
} |
|
||||||
|
|
||||||
private static boolean makeDir(File file) { |
|
||||||
return file != null && (file.exists() || file.mkdirs()); |
|
||||||
} |
|
||||||
|
|
||||||
public static long sizeOfFile(File file) { |
|
||||||
if (file == null || !file.exists()) { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
if (file.isDirectory()) { |
|
||||||
long length = 0; |
|
||||||
for (File subFile : file.listFiles()) { |
|
||||||
length += sizeOfFile(subFile); |
|
||||||
} |
|
||||||
return length; |
|
||||||
} else { |
|
||||||
return file.length(); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static void deleteFile(File file) { |
|
||||||
if (file.isDirectory()) { |
|
||||||
for (File subFile : file.listFiles()) { |
|
||||||
deleteFile(subFile); |
|
||||||
} |
|
||||||
} else { |
|
||||||
boolean delete = file.delete(); |
|
||||||
Log.d(TAG, "delete:" + delete); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isFileExists(File file) { |
|
||||||
return file != null && file.isFile() && file.exists(); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取全路径中的文件拓展名 |
|
||||||
* |
|
||||||
* @param file 文件 |
|
||||||
* @return 文件拓展名 |
|
||||||
*/ |
|
||||||
public static String getFileExtension(File file) { |
|
||||||
if (file == null) return null; |
|
||||||
return getFileExtension(file.getPath()); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取全路径中的文件拓展名 |
|
||||||
* |
|
||||||
* @param filePath 文件路径 |
|
||||||
* @return 文件拓展名 |
|
||||||
*/ |
|
||||||
public static String getFileExtension(String filePath) { |
|
||||||
if (StringChecker.isEmpty(filePath)) { |
|
||||||
return filePath; |
|
||||||
} |
|
||||||
int lastPoi = filePath.lastIndexOf('.'); |
|
||||||
int lastSep = filePath.lastIndexOf(File.separator); |
|
||||||
if (lastPoi == -1 || lastSep >= lastPoi) { |
|
||||||
return ""; |
|
||||||
} |
|
||||||
return filePath.substring(lastPoi + 1); |
|
||||||
} |
|
||||||
} |
|
@ -0,0 +1,68 @@ |
|||||||
|
@file:JvmName("Files") |
||||||
|
|
||||||
|
package com.android.base.utils.common |
||||||
|
|
||||||
|
import com.blankj.utilcode.util.FileUtils |
||||||
|
import timber.log.Timber |
||||||
|
import java.io.File |
||||||
|
|
||||||
|
fun File?.makeFilePath(): Boolean { |
||||||
|
if (this == null) { |
||||||
|
return false |
||||||
|
} |
||||||
|
val parent = this.parentFile |
||||||
|
return parent.exists() || makeDir(parent) |
||||||
|
} |
||||||
|
|
||||||
|
private fun makeDir(file: File?): Boolean { |
||||||
|
return file != null && (file.exists() || file.mkdirs()) |
||||||
|
} |
||||||
|
|
||||||
|
fun File?.sizeOf(): Long { |
||||||
|
if (this == null || !this.exists()) { |
||||||
|
return 0 |
||||||
|
} |
||||||
|
return if (this.isDirectory) { |
||||||
|
var length: Long = 0 |
||||||
|
for (subFile in this.listFiles()) { |
||||||
|
length += subFile.sizeOf() |
||||||
|
} |
||||||
|
length |
||||||
|
} else { |
||||||
|
this.length() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun File.deleteSelf() { |
||||||
|
if (this.isDirectory) { |
||||||
|
for (subFile in this.listFiles()) { |
||||||
|
subFile.deleteSelf() |
||||||
|
} |
||||||
|
} else { |
||||||
|
val delete = this.delete() |
||||||
|
Timber.d("deleteFile: $delete") |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
fun File?.isFileExists(): Boolean { |
||||||
|
return this != null && this.isFile && this.exists() |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取全路径中的文件拓展名 |
||||||
|
* |
||||||
|
* @return 文件拓展名 |
||||||
|
*/ |
||||||
|
fun File?.getFileExtension(): String? { |
||||||
|
return if (this == null) null else getFileExtension(this.path) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取全路径中的文件拓展名 |
||||||
|
* |
||||||
|
* @param filePath 文件路径 |
||||||
|
* @return 文件拓展名 |
||||||
|
*/ |
||||||
|
fun getFileExtension(filePath: String): String { |
||||||
|
return FileUtils.getFileExtension(filePath) |
||||||
|
} |
@ -0,0 +1,117 @@ |
|||||||
|
@file:JvmName("Lang") |
||||||
|
|
||||||
|
package com.android.base.utils.common |
||||||
|
|
||||||
|
import java.io.Closeable |
||||||
|
import java.io.IOException |
||||||
|
|
||||||
|
/** 参考: [Boolean扩展](https://blog.kotliner.cn/2017/06/19/interesting-booleanext/) */ |
||||||
|
sealed class Ext<out T> constructor(val boolean: Boolean) |
||||||
|
|
||||||
|
/** 如果该对象不是null,则执行action */ |
||||||
|
fun <T, E> T?.ifNonNull(action: T.() -> E): Ext<E> { |
||||||
|
if (this != null) { |
||||||
|
return WithData(action()) |
||||||
|
} |
||||||
|
return Otherwise |
||||||
|
} |
||||||
|
|
||||||
|
/** 如果该对象是null,则执行action */ |
||||||
|
fun <T, E> T?.ifNull(action: () -> E) { |
||||||
|
if (this == null) { |
||||||
|
action() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline fun <T> Boolean.yes(block: () -> T): Ext<T> = when { |
||||||
|
this -> { |
||||||
|
WithData(block()) |
||||||
|
} |
||||||
|
else -> Otherwise |
||||||
|
} |
||||||
|
|
||||||
|
inline fun <T> Boolean.no(block: () -> T) = when { |
||||||
|
this -> Otherwise |
||||||
|
else -> { |
||||||
|
WithData(block()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
object Otherwise : Ext<Nothing>(true) |
||||||
|
|
||||||
|
class WithData<out T>(val data: T) : Ext<T>(false) |
||||||
|
|
||||||
|
/**除此以外*/ |
||||||
|
inline infix fun <T> Ext<T>.otherwise(block: () -> T): T { |
||||||
|
return when (this) { |
||||||
|
is Otherwise -> block() |
||||||
|
is WithData<T> -> this.data |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline operator fun <T> Boolean.invoke(block: () -> T) = yes(block) |
||||||
|
|
||||||
|
fun Any?.javaClassName(): String { |
||||||
|
return if (this == null) { |
||||||
|
"" |
||||||
|
} else { |
||||||
|
this::class.java.name |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
inline fun ignoreCrash(code: () -> Unit) { |
||||||
|
try { |
||||||
|
code() |
||||||
|
} catch (e: Exception) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 安静关闭IO |
||||||
|
*/ |
||||||
|
fun closeIO(closeable: Closeable?) { |
||||||
|
if (closeable != null) { |
||||||
|
try { |
||||||
|
closeable.close() |
||||||
|
} catch (e: IOException) { |
||||||
|
e.printStackTrace() |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 关闭IO |
||||||
|
*/ |
||||||
|
fun closeIOQuietly(closeable: Closeable?) { |
||||||
|
if (closeable != null) { |
||||||
|
try { |
||||||
|
closeable.close() |
||||||
|
} catch (ignored: IOException) { |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 关闭IO |
||||||
|
* |
||||||
|
* @param closeables closeable |
||||||
|
*/ |
||||||
|
fun closeIO(vararg closeables: Closeable?) { |
||||||
|
for (closeable in closeables) { |
||||||
|
closeIO(closeable) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 安静关闭IO |
||||||
|
* |
||||||
|
* @param closeables closeable |
||||||
|
*/ |
||||||
|
fun closeIOQuietly(vararg closeables: Closeable?) { |
||||||
|
for (closeable in closeables) { |
||||||
|
closeIOQuietly(closeable) |
||||||
|
} |
||||||
|
} |
@ -1,126 +0,0 @@ |
|||||||
package com.android.base.utils.common; |
|
||||||
|
|
||||||
import java.util.regex.Pattern; |
|
||||||
|
|
||||||
public class StringChecker { |
|
||||||
|
|
||||||
private StringChecker() { |
|
||||||
throw new UnsupportedOperationException("no need instantiation"); |
|
||||||
} |
|
||||||
|
|
||||||
private static final String CHINA_PHONE_REG = "^1\\d{10}$"; |
|
||||||
private static final String ID_CARD_REG = "[1-9]\\d{13,16}[a-zA-Z0-9]{1}"; |
|
||||||
private static final String EMAIL_REG = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; |
|
||||||
private static final String DIGIT_REG = "\\-?[1-9]\\d+\""; |
|
||||||
private static final String URL_REG = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?"; |
|
||||||
private static final String CHINESE_REGEX = "^[\u4E00-\u9FA5]+$"; |
|
||||||
private static final String DECIMALS_REG = "\\-?[1-9]\\d+(\\.\\d+)?"; |
|
||||||
private static final String LETTERS_REG = ".*[a-zA-Z]++.*"; |
|
||||||
private static final String DIGITAL_REG = ".*[0-9]++.*"; |
|
||||||
private static final String DIGITAL_LETTER_ONLY_REG = "^[A-Za-z0-9]+$"; |
|
||||||
|
|
||||||
/** |
|
||||||
* 验证中国的手机号 |
|
||||||
* |
|
||||||
* @return 验证成功返回 true,验证失败返回 false |
|
||||||
*/ |
|
||||||
public static boolean isChinaPhoneNumber(String mobile) { |
|
||||||
return !isEmpty(mobile) && Pattern.matches(CHINA_PHONE_REG, mobile); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean containsLetter(String text) { |
|
||||||
return !isEmpty(text) && Pattern.matches(LETTERS_REG, text); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean containsDigital(String text) { |
|
||||||
return !isEmpty(text) && Pattern.matches(DIGITAL_REG, text); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean containsDigtalLetterOnly(String text) { |
|
||||||
return !isEmpty(text) && Pattern.matches(DIGITAL_LETTER_ONLY_REG, text); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 验证身份证号码 |
|
||||||
* |
|
||||||
* @param idCard 居民身份证号码15位或18位,最后一位可能是数字或字母 |
|
||||||
* @return 验证成功返回true,验证失败返回false |
|
||||||
*/ |
|
||||||
public static boolean isIdCard(String idCard) { |
|
||||||
return !isEmpty(idCard) && Pattern.matches(ID_CARD_REG, idCard); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 验证Email |
|
||||||
* |
|
||||||
* @param email email地址,格式:zhangsan@sina.com,zhangsan@xxx.com.cn,xxx代表邮件服务商 |
|
||||||
* @return 验证成功返回true,验证失败返回false |
|
||||||
*/ |
|
||||||
public static boolean isEmail(String email) { |
|
||||||
return !isEmpty(email) && Pattern.matches(EMAIL_REG, email); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 验证整数(正整数和负整数) |
|
||||||
* |
|
||||||
* @param digit 一位或多位0-9之间的整数 |
|
||||||
* @return 验证成功返回true,验证失败返回false |
|
||||||
*/ |
|
||||||
public static boolean isDigit(String digit) { |
|
||||||
return !isEmpty(digit) && Pattern.matches(DIGIT_REG, digit); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 验证整数和浮点数(正负整数和正负浮点数) |
|
||||||
* |
|
||||||
* @param decimals 一位或多位0-9之间的浮点数,如:1.23,233.30 |
|
||||||
* @return 验证成功返回true,验证失败返回false |
|
||||||
*/ |
|
||||||
public static boolean isDecimals(String decimals) { |
|
||||||
return !isEmpty(decimals) && Pattern.matches(DECIMALS_REG, decimals); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 验证中文 |
|
||||||
* |
|
||||||
* @param chinese 中文字符 |
|
||||||
* @return 验证成功返回true,验证失败返回false |
|
||||||
*/ |
|
||||||
public static boolean isChinese(String chinese) { |
|
||||||
return !isEmpty(chinese) && Pattern.matches(CHINESE_REGEX, chinese); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 验证URL地址 |
|
||||||
* |
|
||||||
* @param url url |
|
||||||
* @return 验证成功返回true,验证失败返回false |
|
||||||
*/ |
|
||||||
public static boolean isURL(String url) { |
|
||||||
return !isEmpty(url) && Pattern.matches(URL_REG, url); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* 获取字符串的字符个数 |
|
||||||
*/ |
|
||||||
public static int getCharLength(String string) { |
|
||||||
if (isEmpty(string)) { |
|
||||||
return 0; |
|
||||||
} |
|
||||||
return string.trim().toCharArray().length; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isCharLength(String string, int length) { |
|
||||||
return null != string && ((isEmpty(string) && length == 0) || (string.trim().toCharArray().length == length)); |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isLengthIn(String string, int min, int max) { |
|
||||||
int length = string == null ? 0 : string.length(); |
|
||||||
return length <= max && length >= min; |
|
||||||
} |
|
||||||
|
|
||||||
public static boolean isEmpty(CharSequence str) { |
|
||||||
return str == null || str.toString().trim().length() == 0; |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,120 @@ |
|||||||
|
@file:JvmName("Strings") |
||||||
|
|
||||||
|
package com.android.base.utils.common |
||||||
|
|
||||||
|
import java.util.regex.Pattern |
||||||
|
|
||||||
|
|
||||||
|
private const val CHINA_PHONE_REG = "^1\\d{10}$" |
||||||
|
private const val ID_CARD_REG = "[1-9]\\d{13,16}[a-zA-Z0-9]{1}" |
||||||
|
private const val EMAIL_REG = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*" |
||||||
|
private const val DIGIT_REG = "\\-?[1-9]\\d+\"" |
||||||
|
private const val URL_REG = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?" |
||||||
|
private const val CHINESE_REGEX = "^[\u4E00-\u9FA5]+$" |
||||||
|
private const val DECIMALS_REG = "\\-?[1-9]\\d+(\\.\\d+)?" |
||||||
|
private const val LETTERS_REG = ".*[a-zA-Z]++.*" |
||||||
|
private const val DIGITAL_REG = ".*[0-9]++.*" |
||||||
|
private const val DIGITAL_LETTER_ONLY_REG = "^[A-Za-z0-9]+$" |
||||||
|
|
||||||
|
/** |
||||||
|
* 验证中国的手机号 |
||||||
|
* |
||||||
|
* @return 验证成功返回 true,验证失败返回 false |
||||||
|
*/ |
||||||
|
fun isChinaPhoneNumber(mobile: String): Boolean { |
||||||
|
return !isEmpty(mobile) && Pattern.matches(CHINA_PHONE_REG, mobile) |
||||||
|
} |
||||||
|
|
||||||
|
fun containsLetter(text: String): Boolean { |
||||||
|
return !isEmpty(text) && Pattern.matches(LETTERS_REG, text) |
||||||
|
} |
||||||
|
|
||||||
|
fun containsDigital(text: String): Boolean { |
||||||
|
return !isEmpty(text) && Pattern.matches(DIGITAL_REG, text) |
||||||
|
} |
||||||
|
|
||||||
|
fun containsDigtalLetterOnly(text: String): Boolean { |
||||||
|
return !isEmpty(text) && Pattern.matches(DIGITAL_LETTER_ONLY_REG, text) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 验证身份证号码 |
||||||
|
* |
||||||
|
* @param idCard 居民身份证号码15位或18位,最后一位可能是数字或字母 |
||||||
|
* @return 验证成功返回true,验证失败返回false |
||||||
|
*/ |
||||||
|
fun isIdCard(idCard: String): Boolean { |
||||||
|
return !isEmpty(idCard) && Pattern.matches(ID_CARD_REG, idCard) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 验证Email |
||||||
|
* |
||||||
|
* @param email email地址,格式:zhangsan@sina.com,zhangsan@xxx.com.cn,xxx代表邮件服务商 |
||||||
|
* @return 验证成功返回true,验证失败返回false |
||||||
|
*/ |
||||||
|
fun isEmail(email: String): Boolean { |
||||||
|
return !isEmpty(email) && Pattern.matches(EMAIL_REG, email) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 验证整数(正整数和负整数) |
||||||
|
* |
||||||
|
* @param digit 一位或多位0-9之间的整数 |
||||||
|
* @return 验证成功返回true,验证失败返回false |
||||||
|
*/ |
||||||
|
fun isDigit(digit: String): Boolean { |
||||||
|
return !isEmpty(digit) && Pattern.matches(DIGIT_REG, digit) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 验证整数和浮点数(正负整数和正负浮点数) |
||||||
|
* |
||||||
|
* @param decimals 一位或多位0-9之间的浮点数,如:1.23,233.30 |
||||||
|
* @return 验证成功返回true,验证失败返回false |
||||||
|
*/ |
||||||
|
fun isDecimals(decimals: String): Boolean { |
||||||
|
return !isEmpty(decimals) && Pattern.matches(DECIMALS_REG, decimals) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 验证中文 |
||||||
|
* |
||||||
|
* @param chinese 中文字符 |
||||||
|
* @return 验证成功返回true,验证失败返回false |
||||||
|
*/ |
||||||
|
fun isChinese(chinese: String): Boolean { |
||||||
|
return !isEmpty(chinese) && Pattern.matches(CHINESE_REGEX, chinese) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 验证URL地址 |
||||||
|
* |
||||||
|
* @param url url |
||||||
|
* @return 验证成功返回true,验证失败返回false |
||||||
|
*/ |
||||||
|
fun isURL(url: String): Boolean { |
||||||
|
return !isEmpty(url) && Pattern.matches(URL_REG, url) |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* 获取字符串的字符个数 |
||||||
|
*/ |
||||||
|
fun getCharLength(string: String): Int { |
||||||
|
return if (isEmpty(string)) { |
||||||
|
0 |
||||||
|
} else string.trim { it <= ' ' }.toCharArray().size |
||||||
|
} |
||||||
|
|
||||||
|
fun isCharLength(string: String?, length: Int): Boolean { |
||||||
|
return null != string && (isEmpty(string) && length == 0 || string.trim { it <= ' ' }.toCharArray().size == length) |
||||||
|
} |
||||||
|
|
||||||
|
fun isLengthIn(string: String?, min: Int, max: Int): Boolean { |
||||||
|
val length = string?.length ?: 0 |
||||||
|
return length in min..max |
||||||
|
} |
||||||
|
|
||||||
|
fun isEmpty(str: CharSequence?): Boolean { |
||||||
|
return str == null || str.toString().trim { it <= ' ' }.isEmpty() |
||||||
|
} |
@ -1,111 +0,0 @@ |
|||||||
package com.android.base.widget.viewpager; |
|
||||||
|
|
||||||
import android.content.Context; |
|
||||||
import android.content.res.TypedArray; |
|
||||||
import android.graphics.Canvas; |
|
||||||
import android.graphics.Color; |
|
||||||
import android.graphics.Paint; |
|
||||||
import android.util.AttributeSet; |
|
||||||
import android.view.View; |
|
||||||
|
|
||||||
import com.android.base.R; |
|
||||||
import com.android.base.utils.android.UnitConverter; |
|
||||||
|
|
||||||
|
|
||||||
public class PageNumberView extends View implements IPagerNumberView { |
|
||||||
|
|
||||||
private static final String DIVISION = "/"; |
|
||||||
|
|
||||||
private int mPageSize; |
|
||||||
private int mPosition; |
|
||||||
|
|
||||||
private int mCenterX; |
|
||||||
|
|
||||||
private Paint mPaint; |
|
||||||
private int mTextHeight; |
|
||||||
private int mTextBaseLine; |
|
||||||
|
|
||||||
public PageNumberView(Context context) { |
|
||||||
this(context, null); |
|
||||||
} |
|
||||||
|
|
||||||
public PageNumberView(Context context, AttributeSet attrs) { |
|
||||||
this(context, attrs, 0); |
|
||||||
} |
|
||||||
|
|
||||||
public PageNumberView(Context context, AttributeSet attrs, int defStyleAttr) { |
|
||||||
super(context, attrs, defStyleAttr); |
|
||||||
|
|
||||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.PageNumberView); |
|
||||||
|
|
||||||
/*是否可以缩放*/ |
|
||||||
int color = typedArray.getColor(R.styleable.PageNumberView_pnv_text_color, Color.BLACK); |
|
||||||
/*用于支持5.0的transition动画*/ |
|
||||||
int size = typedArray.getDimensionPixelSize(R.styleable.PageNumberView_pnv_text_size, UnitConverter.spToPx(14)); |
|
||||||
|
|
||||||
typedArray.recycle(); |
|
||||||
|
|
||||||
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); |
|
||||||
mPaint.setTextSize(size); |
|
||||||
mPaint.setColor(color); |
|
||||||
|
|
||||||
Paint.FontMetricsInt fontMetricsInt = mPaint.getFontMetricsInt(); |
|
||||||
mTextHeight = fontMetricsInt.bottom - fontMetricsInt.top; |
|
||||||
mTextBaseLine = mTextHeight - fontMetricsInt.bottom; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { |
|
||||||
String text = String.valueOf(mPageSize); |
|
||||||
float textWidth = mPaint.measureText(text); |
|
||||||
float divisionWidth = mPaint.measureText(DIVISION); |
|
||||||
setMeasuredDimension((int) (textWidth * 2 + divisionWidth), mTextHeight); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void onDraw(Canvas canvas) { |
|
||||||
super.onDraw(canvas); |
|
||||||
float divisionHalfSize = mPaint.measureText(DIVISION) / 2; |
|
||||||
float left = mCenterX - divisionHalfSize; |
|
||||||
float right = mCenterX + divisionHalfSize; |
|
||||||
String positionText = String.valueOf(mPosition); |
|
||||||
String sizeText = String.valueOf(mPageSize); |
|
||||||
canvas.drawText(DIVISION, left, mTextBaseLine, mPaint); |
|
||||||
canvas.drawText(positionText, left - mPaint.measureText(positionText), mTextBaseLine, mPaint); |
|
||||||
canvas.drawText(sizeText, right, mTextBaseLine, mPaint); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
protected void onSizeChanged(int w, int h, int oldw, int oldh) { |
|
||||||
super.onSizeChanged(w, h, oldw, oldh); |
|
||||||
mCenterX = w / 2; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setPageScrolled(int position, @SuppressWarnings("UnusedParameters") float positionOffset) { |
|
||||||
mPosition = position; |
|
||||||
if (mPageSize > 1) { |
|
||||||
if (mPosition == 0) { |
|
||||||
mPosition = mPageSize; |
|
||||||
} else if (mPosition == mPageSize + 1) { |
|
||||||
mPosition = 1; |
|
||||||
} |
|
||||||
} else { |
|
||||||
mPosition = mPageSize; |
|
||||||
} |
|
||||||
invalidate(); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setViewPager(ZViewPager viewPager) { |
|
||||||
//no op
|
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public void setPageSize(int pageSize) { |
|
||||||
mPageSize = pageSize; |
|
||||||
mPosition = pageSize;//只有一個的時候
|
|
||||||
requestLayout(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,100 @@ |
|||||||
|
package com.android.base.widget.viewpager |
||||||
|
|
||||||
|
import android.content.Context |
||||||
|
import android.graphics.Canvas |
||||||
|
import android.graphics.Color |
||||||
|
import android.graphics.Paint |
||||||
|
import android.util.AttributeSet |
||||||
|
import android.view.View |
||||||
|
import com.android.base.R |
||||||
|
import com.android.base.utils.android.views.dip |
||||||
|
|
||||||
|
|
||||||
|
class PageNumberView @JvmOverloads constructor( |
||||||
|
context: Context, |
||||||
|
attrs: AttributeSet? = null, |
||||||
|
defStyleAttr: Int = 0 |
||||||
|
) : View(context, attrs, defStyleAttr), IPagerNumberView { |
||||||
|
|
||||||
|
private var mPageSize: Int = 0 |
||||||
|
private var mPosition: Int = 0 |
||||||
|
|
||||||
|
private var mCenterX: Int = 0 |
||||||
|
|
||||||
|
private val mPaint: Paint |
||||||
|
private val mTextHeight: Int |
||||||
|
private val mTextBaseLine: Int |
||||||
|
|
||||||
|
init { |
||||||
|
|
||||||
|
val typedArray = context.obtainStyledAttributes(attrs, R.styleable.PageNumberView) |
||||||
|
|
||||||
|
/*是否可以缩放*/ |
||||||
|
val color = typedArray.getColor(R.styleable.PageNumberView_pnv_text_color, Color.BLACK) |
||||||
|
/*用于支持5.0的transition动画*/ |
||||||
|
val size = typedArray.getDimensionPixelSize(R.styleable.PageNumberView_pnv_text_size, dip(14)) |
||||||
|
|
||||||
|
typedArray.recycle() |
||||||
|
|
||||||
|
mPaint = Paint(Paint.ANTI_ALIAS_FLAG) |
||||||
|
mPaint.textSize = size.toFloat() |
||||||
|
mPaint.color = color |
||||||
|
|
||||||
|
val fontMetricsInt = mPaint.fontMetricsInt |
||||||
|
mTextHeight = fontMetricsInt.bottom - fontMetricsInt.top |
||||||
|
mTextBaseLine = mTextHeight - fontMetricsInt.bottom |
||||||
|
} |
||||||
|
|
||||||
|
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { |
||||||
|
val text = mPageSize.toString() |
||||||
|
val textWidth = mPaint.measureText(text) |
||||||
|
val divisionWidth = mPaint.measureText(DIVISION) |
||||||
|
setMeasuredDimension((textWidth * 2 + divisionWidth).toInt(), mTextHeight) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onDraw(canvas: Canvas) { |
||||||
|
super.onDraw(canvas) |
||||||
|
val divisionHalfSize = mPaint.measureText(DIVISION) / 2 |
||||||
|
val left = mCenterX - divisionHalfSize |
||||||
|
val right = mCenterX + divisionHalfSize |
||||||
|
val positionText = mPosition.toString() |
||||||
|
val sizeText = mPageSize.toString() |
||||||
|
canvas.drawText(DIVISION, left, mTextBaseLine.toFloat(), mPaint) |
||||||
|
canvas.drawText(positionText, left - mPaint.measureText(positionText), mTextBaseLine.toFloat(), mPaint) |
||||||
|
canvas.drawText(sizeText, right, mTextBaseLine.toFloat(), mPaint) |
||||||
|
} |
||||||
|
|
||||||
|
override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) { |
||||||
|
super.onSizeChanged(w, h, oldw, oldh) |
||||||
|
mCenterX = w / 2 |
||||||
|
} |
||||||
|
|
||||||
|
override fun setPageScrolled(position: Int, positionOffset: Float) { |
||||||
|
mPosition = position |
||||||
|
if (mPageSize > 1) { |
||||||
|
if (mPosition == 0) { |
||||||
|
mPosition = mPageSize |
||||||
|
} else if (mPosition == mPageSize + 1) { |
||||||
|
mPosition = 1 |
||||||
|
} |
||||||
|
} else { |
||||||
|
mPosition = mPageSize |
||||||
|
} |
||||||
|
invalidate() |
||||||
|
} |
||||||
|
|
||||||
|
override fun setViewPager(viewPager: ZViewPager) { |
||||||
|
//no op |
||||||
|
} |
||||||
|
|
||||||
|
override fun setPageSize(pageSize: Int) { |
||||||
|
mPageSize = pageSize |
||||||
|
mPosition = pageSize//只有一個的時候 |
||||||
|
requestLayout() |
||||||
|
} |
||||||
|
|
||||||
|
companion object { |
||||||
|
private const val DIVISION = "/" |
||||||
|
} |
||||||
|
|
||||||
|
} |
Loading…
Reference in new issue