to kotlin...

androidx
Zhanty 5 years ago
parent 367f2cb703
commit 77682bbd1d
  1. 8
      lib_base/build.gradle
  2. 2
      lib_base/src/github/java/com/jaredrummler/android/util/HtmlBuilder.java
  3. 1
      lib_base/src/main/java/com/android/base/adapter/recycler/ItemViewBinder.kt
  4. 3
      lib_base/src/main/java/com/android/base/adapter/recycler/KtViewHolder.kt
  5. 1
      lib_base/src/main/java/com/android/base/adapter/recycler/SimpleRecyclerAdapter.kt
  6. 2
      lib_base/src/main/java/com/android/base/app/aac/LiveDataEx.kt
  7. 2
      lib_base/src/main/java/com/android/base/app/fragment/Fragments.kt
  8. 6
      lib_base/src/main/java/com/android/base/app/ui/UIEx.kt
  9. 6
      lib_base/src/main/java/com/android/base/imageloader/ProgressManager.java
  10. 15
      lib_base/src/main/java/com/android/base/kotlin/ContextEx.kt
  11. 18
      lib_base/src/main/java/com/android/base/kotlin/FragmentEx.kt
  12. 58
      lib_base/src/main/java/com/android/base/kotlin/LangEx.kt
  13. 21
      lib_base/src/main/java/com/android/base/kotlin/ResourceEx.kt
  14. 8
      lib_base/src/main/java/com/android/base/kotlin/SizeEx.kt
  15. 172
      lib_base/src/main/java/com/android/base/kotlin/ViewEx.kt
  16. 10
      lib_base/src/main/java/com/android/base/utils/android/ActFragWrapper.java
  17. 83
      lib_base/src/main/java/com/android/base/utils/android/ResourceUtils.java
  18. 76
      lib_base/src/main/java/com/android/base/utils/android/TintUtils.java
  19. 72
      lib_base/src/main/java/com/android/base/utils/android/UnitConverter.java
  20. 208
      lib_base/src/main/java/com/android/base/utils/android/ViewUtils.java
  21. 6
      lib_base/src/main/java/com/android/base/utils/android/XAppUtils.java
  22. 73
      lib_base/src/main/java/com/android/base/utils/android/anim/ActivityAnimUtils.java
  23. 2
      lib_base/src/main/java/com/android/base/utils/android/cache/SpCache.java
  24. 16
      lib_base/src/main/java/com/android/base/utils/android/compat/AndroidVersionEx.kt
  25. 43
      lib_base/src/main/java/com/android/base/utils/android/text/RoundedBackgroundSpan.java
  26. 39
      lib_base/src/main/java/com/android/base/utils/android/views/ActivityAnimUtils.kt
  27. 5
      lib_base/src/main/java/com/android/base/utils/android/views/AttrStyleEx.kt
  28. 2
      lib_base/src/main/java/com/android/base/utils/android/views/DialogEx.kt
  29. 2
      lib_base/src/main/java/com/android/base/utils/android/views/MenuEx.kt
  30. 121
      lib_base/src/main/java/com/android/base/utils/android/views/ResourceEx.kt
  31. 26
      lib_base/src/main/java/com/android/base/utils/android/views/RoundedBackgroundSpan.kt
  32. 22
      lib_base/src/main/java/com/android/base/utils/android/views/ScrollViewEx.kt
  33. 61
      lib_base/src/main/java/com/android/base/utils/android/views/SizeEx.kt
  34. 72
      lib_base/src/main/java/com/android/base/utils/android/views/TextViewEx.kt
  35. 54
      lib_base/src/main/java/com/android/base/utils/android/views/TintUtils.kt
  36. 397
      lib_base/src/main/java/com/android/base/utils/android/views/ViewEx.kt
  37. 14
      lib_base/src/main/java/com/android/base/utils/android/views/WebViewEx.kt
  38. 59
      lib_base/src/main/java/com/android/base/utils/common/Checker.java
  39. 49
      lib_base/src/main/java/com/android/base/utils/common/Checker.kt
  40. 62
      lib_base/src/main/java/com/android/base/utils/common/CloseUtils.java
  41. 23
      lib_base/src/main/java/com/android/base/utils/common/CollectionUtils.java
  42. 14
      lib_base/src/main/java/com/android/base/utils/common/Collections.kt
  43. 90
      lib_base/src/main/java/com/android/base/utils/common/FileUtils.java
  44. 68
      lib_base/src/main/java/com/android/base/utils/common/Files.kt
  45. 117
      lib_base/src/main/java/com/android/base/utils/common/Lang.kt
  46. 126
      lib_base/src/main/java/com/android/base/utils/common/StringChecker.java
  47. 120
      lib_base/src/main/java/com/android/base/utils/common/Strings.kt
  48. 4
      lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java
  49. 111
      lib_base/src/main/java/com/android/base/widget/viewpager/PageNumberView.java
  50. 100
      lib_base/src/main/java/com/android/base/widget/viewpager/PageNumberView.kt

@ -45,6 +45,13 @@ android {
jvmTarget = "1.8" jvmTarget = "1.8"
} }
sourceSets {
main {
java.srcDirs += "src/github/java"
res.srcDirs += "src/github/res"
}
}
} }
dependencies { dependencies {
@ -118,5 +125,4 @@ dependencies {
api thirdLibraries.utilcode api thirdLibraries.utilcode
api thirdLibraries.jOOR api thirdLibraries.jOOR
api thirdLibraries.supportOptional api thirdLibraries.supportOptional
} }

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package com.android.base.utils.android.text; package com.jaredrummler.android.util;
import android.os.Build; import android.os.Build;
import android.text.Html; import android.text.Html;

@ -4,7 +4,6 @@ import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView import androidx.recyclerview.widget.RecyclerView
import com.android.base.kotlin.KtViewHolder
/** /**
* @author Ztiany * @author Ztiany

@ -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

@ -4,7 +4,6 @@ import android.content.Context
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import com.android.base.kotlin.KtViewHolder
/** /**
* A simple way to build a simple list. If you want to build a multi type list, perhaps you need to use [MultiTypeAdapter]. * A simple way to build a simple list. If you want to build a multi type list, perhaps you need to use [MultiTypeAdapter].

@ -1,4 +1,4 @@
package com.android.base.kotlin package com.android.base.app.aac
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData

@ -12,7 +12,7 @@ import androidx.fragment.app.FragmentTransaction
import com.android.base.app.activity.ActivityDelegate import com.android.base.app.activity.ActivityDelegate
import com.android.base.app.activity.ActivityDelegateOwner import com.android.base.app.activity.ActivityDelegateOwner
import com.android.base.app.activity.ActivityStatus import com.android.base.app.activity.ActivityStatus
import com.android.base.kotlin.javaClassName import com.android.base.utils.common.javaClassName
import kotlin.reflect.KClass import kotlin.reflect.KClass
/**被此 annotation 标注的方法,表示需要使用 [Fragment] 的全类名作为 [FragmentTransaction] 中相关方法的 flag 参数的实参,比如 add/replace 等*/ /**被此 annotation 标注的方法,表示需要使用 [Fragment] 的全类名作为 [FragmentTransaction] 中相关方法的 flag 参数的实参,比如 add/replace 等*/

@ -3,12 +3,12 @@
package com.android.base.app.ui package com.android.base.app.ui
import com.android.base.app.BaseKit import com.android.base.app.BaseKit
import com.android.base.utils.common.Checker import com.android.base.utils.common.isEmpty
import timber.log.Timber import timber.log.Timber
fun <T> RefreshListLayout<T>.processListResultWithStatus(list: List<T>?, onEmpty: (() -> Unit)? = null) { fun <T> RefreshListLayout<T>.processListResultWithStatus(list: List<T>?, onEmpty: (() -> Unit)? = null) {
if (isLoadingMore) { if (isLoadingMore) {
if (!Checker.isEmpty(list)) { if (!isEmpty(list)) {
addData(list) addData(list)
} }
} else { } else {
@ -33,7 +33,7 @@ fun <T> RefreshListLayout<T>.processListResultWithStatus(list: List<T>?, onEmpty
fun <T> RefreshListLayout<T>.processListResultWithoutStatus(list: List<T>?, onEmpty: (() -> Unit)? = null) { fun <T> RefreshListLayout<T>.processListResultWithoutStatus(list: List<T>?, onEmpty: (() -> Unit)? = null) {
if (isLoadingMore) { if (isLoadingMore) {
if (!Checker.isEmpty(list)) { if (!isEmpty(list)) {
addData(list) addData(list)
} }
} else { } else {

@ -2,9 +2,9 @@ package com.android.base.imageloader;
import android.os.Handler; import android.os.Handler;
import android.os.Looper; import android.os.Looper;
import android.text.TextUtils;
import com.android.base.utils.common.Checker; import com.android.base.utils.common.Checker;
import com.android.base.utils.common.StringChecker;
import java.io.IOException; import java.io.IOException;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
@ -111,7 +111,7 @@ final class ProgressManager {
@UiThread @UiThread
void addLoadListener(String url, ProgressListener listener) { void addLoadListener(String url, ProgressListener listener) {
//check //check
if (StringChecker.isEmpty(url)) { if (TextUtils.isEmpty(url)) {
throw new NullPointerException("url cannot be null"); throw new NullPointerException("url cannot be null");
} }
if (listener == null) { if (listener == null) {
@ -147,7 +147,7 @@ final class ProgressManager {
@UiThread @UiThread
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public void setListener(String url, ProgressListener progressListener) { public void setListener(String url, ProgressListener progressListener) {
if (StringChecker.isEmpty(url)) { if (TextUtils.isEmpty(url)) {
throw new NullPointerException("url cannot be null"); throw new NullPointerException("url cannot be null");
} }
if (progressListener == null) { if (progressListener == null) {

@ -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)
}

@ -55,7 +55,9 @@ public class ActFragWrapper {
mActivity.startService(intent); mActivity.startService(intent);
} else { } else {
FragmentActivity activity = mFragment.getActivity(); FragmentActivity activity = mFragment.getActivity();
activity.startService(intent); if (activity != null) {
activity.startService(intent);
}
} }
} }
@ -63,7 +65,11 @@ public class ActFragWrapper {
if (mActivity != null) { if (mActivity != null) {
mActivity.stopService(new Intent(mActivity, payPalServiceClass)); mActivity.stopService(new Intent(mActivity, payPalServiceClass));
} else { } else {
mFragment.getActivity().stopService(new Intent(mFragment.getActivity(), payPalServiceClass)); FragmentActivity activity = mFragment.getActivity();
if (activity != null) {
activity.stopService(new Intent(activity, payPalServiceClass));
}
} }
} }
} }

@ -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;
}
}

@ -9,8 +9,8 @@ import android.net.Uri;
import android.os.Build; import android.os.Build;
import android.webkit.MimeTypeMap; import android.webkit.MimeTypeMap;
import com.android.base.utils.common.FileUtils; import com.android.base.utils.common.Strings;
import com.android.base.utils.common.StringChecker; import com.blankj.utilcode.util.FileUtils;
import java.io.File; import java.io.File;
import java.util.List; import java.util.List;
@ -45,7 +45,7 @@ public class XAppUtils {
if (Build.VERSION.SDK_INT <= 23) { if (Build.VERSION.SDK_INT <= 23) {
context.startActivity(getInstallAppIntent23(file)); context.startActivity(getInstallAppIntent23(file));
} else { } else {
Intent intent = getInstallAppIntent24(context, file, StringChecker.isEmpty(authority) ? (context.getPackageName() + ".fileProvider") : authority); Intent intent = getInstallAppIntent24(context, file, Strings.isEmpty(authority) ? (context.getPackageName() + ".fileProvider") : authority);
context.startActivity(intent); context.startActivity(intent);
} }
Timber.d("installApp open activity successfully"); Timber.d("installApp open activity successfully");

@ -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,6 +1,4 @@
package com.android.base.kotlin package com.android.base.utils.android.compat
import com.android.base.utils.android.compat.AndroidVersion
inline fun ifSDKAbove(sdkVersion: Int, block: () -> Unit) { inline fun ifSDKAbove(sdkVersion: Int, block: () -> Unit) {
@ -21,10 +19,8 @@ inline fun ifSDKAtLeast(sdkVersion: Int, block: () -> Unit) {
} }
} }
inline fun ignoreCrash(code: () -> Unit) { fun isSDKAbove(sdkVersion: Int) = AndroidVersion.above(sdkVersion)
try {
code() fun isSDKAt(sdkVersion: Int) = AndroidVersion.at(sdkVersion)
} catch (e: Exception) {
e.printStackTrace() fun isSDKAtLeast(sdkVersion: Int) = AndroidVersion.atLeast(sdkVersion)
}
}

@ -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.content.Context import android.content.Context
import android.content.ContextWrapper import android.content.ContextWrapper
@ -23,6 +23,7 @@ val Context.contextThemeWrapper: ContextThemeWrapper
@StyleRes @StyleRes
fun View.attrStyle(@AttrRes attrColor: Int): Int = contextThemeWrapper.attrStyle(attrColor) fun View.attrStyle(@AttrRes attrColor: Int): Int = contextThemeWrapper.attrStyle(attrColor)
@StyleRes @StyleRes
private fun ContextThemeWrapper.attrStyle(@AttrRes attrRes: Int): Int = private fun ContextThemeWrapper.attrStyle(@AttrRes attrRes: Int): Int =
attr(attrRes) { attr(attrRes) {
@ -31,7 +32,7 @@ private fun ContextThemeWrapper.attrStyle(@AttrRes attrRes: Int): Int =
private fun <R> ContextThemeWrapper.attr(@AttrRes attrRes: Int, block: (TypedArray)->R): R { private fun <R> ContextThemeWrapper.attr(@AttrRes attrRes: Int, block: (TypedArray)->R): R {
val typedValue = TypedValue() val typedValue = TypedValue()
if (!theme.resolveAttribute(attrRes, typedValue, true)) throw IllegalArgumentException("$attrRes is not resolvable") require(theme.resolveAttribute(attrRes, typedValue, true)) { "$attrRes is not resolvable" }
val a = obtainStyledAttributes(typedValue.data, intArrayOf(attrRes)) val a = obtainStyledAttributes(typedValue.data, intArrayOf(attrRes))
val result = block(a) val result = block(a)
a.recycle() a.recycle()

@ -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
}

@ -1,13 +1,18 @@
package com.android.base.kotlin package com.android.base.utils.android.views
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.text.Editable import android.text.Editable
import android.text.InputFilter
import android.text.Spanned
import android.text.TextWatcher import android.text.TextWatcher
import android.text.method.LinkMovementMethod
import android.widget.Button import android.widget.Button
import android.widget.EditText import android.widget.EditText
import android.widget.TextView import android.widget.TextView
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
import com.android.base.interfaces.adapter.TextWatcherAdapter import com.android.base.interfaces.adapter.TextWatcherAdapter
import com.google.android.material.textfield.TextInputLayout
inline fun TextView.textWatcher(init: KTextWatcher.() -> Unit) = addTextChangedListener(KTextWatcher().apply(init)) inline fun TextView.textWatcher(init: KTextWatcher.() -> Unit) = addTextChangedListener(KTextWatcher().apply(init))
@ -55,24 +60,24 @@ class KTextWatcher : TextWatcher {
} }
fun TextView.topDrawable(@DrawableRes id: Int) { fun TextView.setTopDrawable(@DrawableRes id: Int) {
this.setCompoundDrawablesWithIntrinsicBounds(0, id, 0, 0) this.setCompoundDrawablesWithIntrinsicBounds(0, id, 0, 0)
} }
fun TextView.leftDrawable(@DrawableRes id: Int) { fun TextView.setLeftDrawable(@DrawableRes id: Int) {
this.setCompoundDrawablesWithIntrinsicBounds(id, 0, 0, 0) this.setCompoundDrawablesWithIntrinsicBounds(id, 0, 0, 0)
} }
fun TextView.rightDrawable(@DrawableRes id: Int) { fun TextView.setRightDrawable(@DrawableRes id: Int) {
this.setCompoundDrawablesWithIntrinsicBounds(0, 0, id, 0) this.setCompoundDrawablesWithIntrinsicBounds(0, 0, id, 0)
} }
fun TextView.bottomDrawable(@DrawableRes id: Int) { fun TextView.setBottomDrawable(@DrawableRes id: Int) {
this.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, id) this.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, id)
} }
fun TextView.topDrawable(drawable: Drawable, retain: Boolean = false) { fun TextView.setTopDrawable(drawable: Drawable, retainOthers: Boolean = false) {
if (retain) { if (retainOthers) {
val compoundDrawables = this.compoundDrawables val compoundDrawables = this.compoundDrawables
this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], drawable, compoundDrawables[2], compoundDrawables[3]) this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], drawable, compoundDrawables[2], compoundDrawables[3])
} else { } else {
@ -80,8 +85,8 @@ fun TextView.topDrawable(drawable: Drawable, retain: Boolean = false) {
} }
} }
fun TextView.leftDrawable(drawable: Drawable, retain: Boolean = false) { fun TextView.setLeftDrawable(drawable: Drawable, retainOthers: Boolean = false) {
if (retain) { if (retainOthers) {
val compoundDrawables = this.compoundDrawables val compoundDrawables = this.compoundDrawables
this.setCompoundDrawablesWithIntrinsicBounds(drawable, compoundDrawables[1], compoundDrawables[2], compoundDrawables[3]) this.setCompoundDrawablesWithIntrinsicBounds(drawable, compoundDrawables[1], compoundDrawables[2], compoundDrawables[3])
} else { } else {
@ -89,8 +94,8 @@ fun TextView.leftDrawable(drawable: Drawable, retain: Boolean = false) {
} }
} }
fun TextView.rightDrawable(drawable: Drawable, retain: Boolean = false) { fun TextView.setRightDrawable(drawable: Drawable, retainOthers: Boolean = false) {
if (retain) { if (retainOthers) {
val compoundDrawables = this.compoundDrawables val compoundDrawables = this.compoundDrawables
this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], compoundDrawables[1], drawable, compoundDrawables[3]) this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], compoundDrawables[1], drawable, compoundDrawables[3])
} else { } else {
@ -98,8 +103,8 @@ fun TextView.rightDrawable(drawable: Drawable, retain: Boolean = false) {
} }
} }
fun TextView.bottomDrawable(drawable: Drawable, retain: Boolean = false) { fun TextView.setBottomDrawable(drawable: Drawable, retainOthers: Boolean = false) {
if (retain) { if (retainOthers) {
val compoundDrawables = this.compoundDrawables val compoundDrawables = this.compoundDrawables
this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], compoundDrawables[1], compoundDrawables[2], drawable) this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], compoundDrawables[1], compoundDrawables[2], drawable)
} else { } else {
@ -119,3 +124,44 @@ fun Button.enableByEditText(et: EditText, checker: (s: CharSequence?) -> Boolean
} }
}) })
} }
fun TextInputLayout.textStr(): String {
val editText = this.editText
return editText?.text?.toString() ?: ""
}
fun EditText.textStr(): String {
return this.text?.toString() ?: ""
}
fun TextView.enableSpanClickable() {
// 响应点击事件的话必须设置以下属性
movementMethod = LinkMovementMethod.getInstance()
// 去掉点击事件后的高亮
highlightColor = ContextCompat.getColor(context, android.R.color.transparent)
}
fun EditText.disableEmojiEntering() {
val filter = EmojiExcludeFilter()
val oldFilters = filters
val oldFiltersLength = oldFilters.size
val newFilters = arrayOfNulls<InputFilter>(oldFiltersLength + 1)
if (oldFiltersLength > 0) {
System.arraycopy(oldFilters, 0, newFilters, 0, oldFiltersLength)
}
//添加新的过滤规则
newFilters[oldFiltersLength] = filter
filters = newFilters
}
private class EmojiExcludeFilter : InputFilter {
override fun filter(source: CharSequence, start: Int, end: Int, dest: Spanned, dstart: Int, dend: Int): CharSequence? {
for (i in start until end) {
val type = Character.getType(source[i])
if (type == Character.SURROGATE.toInt() || type == Character.OTHER_SYMBOL.toInt()) {
return ""
}
}
return null
}
}

@ -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.comzhangsan@xxx.com.cnxxx代表邮件服务商
* @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.23233.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.comzhangsan@xxx.com.cnxxx代表邮件服务商
* @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.23233.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()
}

@ -2,13 +2,13 @@ package com.android.base.widget;
import android.content.Context; import android.content.Context;
import android.content.res.TypedArray; import android.content.res.TypedArray;
import android.text.TextUtils;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import com.android.base.R; import com.android.base.R;
import com.android.base.app.ui.StateLayout; import com.android.base.app.ui.StateLayout;
import com.android.base.app.ui.StateLayoutConfig; import com.android.base.app.ui.StateLayoutConfig;
import com.android.base.utils.common.StringChecker;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import timber.log.Timber; import timber.log.Timber;
@ -54,7 +54,7 @@ public class SimpleMultiStateView extends MultiStateView implements StateLayout
private void initProcessor(TypedArray typedArray) { private void initProcessor(TypedArray typedArray) {
String processorPath = typedArray.getString(R.styleable.SimpleMultiStateView_msv_state_processor); String processorPath = typedArray.getString(R.styleable.SimpleMultiStateView_msv_state_processor);
if (!StringChecker.isEmpty(processorPath)) { if (!TextUtils.isEmpty(processorPath)) {
try { try {
Class<?> processorClass = Class.forName(processorPath); Class<?> processorClass = Class.forName(processorPath);
mStateProcessor = (StateProcessor) processorClass.newInstance(); mStateProcessor = (StateProcessor) processorClass.newInstance();

@ -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…
Cancel
Save