to kotlin...

androidx
Zhanty 5 years ago
parent 367f2cb703
commit 77682bbd1d
  1. 8
      lib_base/build.gradle
  2. 4
      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. 4
      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"
}
sourceSets {
main {
java.srcDirs += "src/github/java"
res.srcDirs += "src/github/res"
}
}
}
dependencies {
@ -118,5 +125,4 @@ dependencies {
api thirdLibraries.utilcode
api thirdLibraries.jOOR
api thirdLibraries.supportOptional
}

@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.base.utils.android.text;
package com.jaredrummler.android.util;
import android.os.Build;
import android.text.Html;
@ -580,4 +580,4 @@ public class HtmlBuilder {
}
}
}

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

@ -1,7 +1,6 @@
package com.android.base.kotlin
package com.android.base.adapter.recycler
import android.view.View
import com.android.base.adapter.recycler.ViewHolder
import kotlinx.android.extensions.CacheImplementation
import kotlinx.android.extensions.ContainerOptions
import kotlinx.android.extensions.LayoutContainer

@ -4,7 +4,6 @@ import android.content.Context
import android.view.LayoutInflater
import android.view.View
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].

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

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

@ -2,9 +2,9 @@ package com.android.base.imageloader;
import android.os.Handler;
import android.os.Looper;
import android.text.TextUtils;
import com.android.base.utils.common.Checker;
import com.android.base.utils.common.StringChecker;
import java.io.IOException;
import java.lang.ref.WeakReference;
@ -111,7 +111,7 @@ final class ProgressManager {
@UiThread
void addLoadListener(String url, ProgressListener listener) {
//check
if (StringChecker.isEmpty(url)) {
if (TextUtils.isEmpty(url)) {
throw new NullPointerException("url cannot be null");
}
if (listener == null) {
@ -147,7 +147,7 @@ final class ProgressManager {
@UiThread
@SuppressWarnings("WeakerAccess")
public void setListener(String url, ProgressListener progressListener) {
if (StringChecker.isEmpty(url)) {
if (TextUtils.isEmpty(url)) {
throw new NullPointerException("url cannot be 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);
} else {
FragmentActivity activity = mFragment.getActivity();
activity.startService(intent);
if (activity != null) {
activity.startService(intent);
}
}
}
@ -63,7 +65,11 @@ public class ActFragWrapper {
if (mActivity != null) {
mActivity.stopService(new Intent(mActivity, payPalServiceClass));
} 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.webkit.MimeTypeMap;
import com.android.base.utils.common.FileUtils;
import com.android.base.utils.common.StringChecker;
import com.android.base.utils.common.Strings;
import com.blankj.utilcode.util.FileUtils;
import java.io.File;
import java.util.List;
@ -45,7 +45,7 @@ public class XAppUtils {
if (Build.VERSION.SDK_INT <= 23) {
context.startActivity(getInstallAppIntent23(file));
} 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);
}
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.SharedPreferences;
@ -206,4 +206,4 @@ public class SpCache {
getSharedPreferences().unregisterOnSharedPreferenceChangeListener(listener);
}
}
}

@ -1,6 +1,4 @@
package com.android.base.kotlin
import com.android.base.utils.android.compat.AndroidVersion
package com.android.base.utils.android.compat
inline fun ifSDKAbove(sdkVersion: Int, block: () -> Unit) {
@ -21,10 +19,8 @@ inline fun ifSDKAtLeast(sdkVersion: Int, block: () -> Unit) {
}
}
inline fun ignoreCrash(code: () -> Unit) {
try {
code()
} catch (e: Exception) {
e.printStackTrace()
}
}
fun isSDKAbove(sdkVersion: Int) = AndroidVersion.above(sdkVersion)
fun isSDKAt(sdkVersion: Int) = AndroidVersion.at(sdkVersion)
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.ContextWrapper
@ -23,6 +23,7 @@ val Context.contextThemeWrapper: ContextThemeWrapper
@StyleRes
fun View.attrStyle(@AttrRes attrColor: Int): Int = contextThemeWrapper.attrStyle(attrColor)
@StyleRes
private fun ContextThemeWrapper.attrStyle(@AttrRes attrRes: Int): Int =
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 {
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 result = block(a)
a.recycle()

@ -1,4 +1,4 @@
package com.android.base.kotlin
package com.android.base.utils.android.views
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.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.text.Editable
import android.text.InputFilter
import android.text.Spanned
import android.text.TextWatcher
import android.text.method.LinkMovementMethod
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.core.content.ContextCompat
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))
@ -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)
}
fun TextView.leftDrawable(@DrawableRes id: Int) {
fun TextView.setLeftDrawable(@DrawableRes id: Int) {
this.setCompoundDrawablesWithIntrinsicBounds(id, 0, 0, 0)
}
fun TextView.rightDrawable(@DrawableRes id: Int) {
fun TextView.setRightDrawable(@DrawableRes id: Int) {
this.setCompoundDrawablesWithIntrinsicBounds(0, 0, id, 0)
}
fun TextView.bottomDrawable(@DrawableRes id: Int) {
fun TextView.setBottomDrawable(@DrawableRes id: Int) {
this.setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, id)
}
fun TextView.topDrawable(drawable: Drawable, retain: Boolean = false) {
if (retain) {
fun TextView.setTopDrawable(drawable: Drawable, retainOthers: Boolean = false) {
if (retainOthers) {
val compoundDrawables = this.compoundDrawables
this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], drawable, compoundDrawables[2], compoundDrawables[3])
} else {
@ -80,8 +85,8 @@ fun TextView.topDrawable(drawable: Drawable, retain: Boolean = false) {
}
}
fun TextView.leftDrawable(drawable: Drawable, retain: Boolean = false) {
if (retain) {
fun TextView.setLeftDrawable(drawable: Drawable, retainOthers: Boolean = false) {
if (retainOthers) {
val compoundDrawables = this.compoundDrawables
this.setCompoundDrawablesWithIntrinsicBounds(drawable, compoundDrawables[1], compoundDrawables[2], compoundDrawables[3])
} else {
@ -89,8 +94,8 @@ fun TextView.leftDrawable(drawable: Drawable, retain: Boolean = false) {
}
}
fun TextView.rightDrawable(drawable: Drawable, retain: Boolean = false) {
if (retain) {
fun TextView.setRightDrawable(drawable: Drawable, retainOthers: Boolean = false) {
if (retainOthers) {
val compoundDrawables = this.compoundDrawables
this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], compoundDrawables[1], drawable, compoundDrawables[3])
} else {
@ -98,8 +103,8 @@ fun TextView.rightDrawable(drawable: Drawable, retain: Boolean = false) {
}
}
fun TextView.bottomDrawable(drawable: Drawable, retain: Boolean = false) {
if (retain) {
fun TextView.setBottomDrawable(drawable: Drawable, retainOthers: Boolean = false) {
if (retainOthers) {
val compoundDrawables = this.compoundDrawables
this.setCompoundDrawablesWithIntrinsicBounds(compoundDrawables[0], compoundDrawables[1], compoundDrawables[2], drawable)
} else {
@ -118,4 +123,45 @@ fun Button.enableByEditText(et: EditText, checker: (s: CharSequence?) -> Boolean
btn.isEnabled = checker(s)
}
})
}
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 {

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