diff --git a/lib_base/build.gradle b/lib_base/build.gradle index 1e5b37c..4ed366a 100644 --- a/lib_base/build.gradle +++ b/lib_base/build.gradle @@ -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 - } \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/text/HtmlBuilder.java b/lib_base/src/github/java/com/jaredrummler/android/util/HtmlBuilder.java similarity index 99% rename from lib_base/src/main/java/com/android/base/utils/android/text/HtmlBuilder.java rename to lib_base/src/github/java/com/jaredrummler/android/util/HtmlBuilder.java index 2730953..10c5323 100644 --- a/lib_base/src/main/java/com/android/base/utils/android/text/HtmlBuilder.java +++ b/lib_base/src/github/java/com/jaredrummler/android/util/HtmlBuilder.java @@ -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 { } -} +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/adapter/recycler/ItemViewBinder.kt b/lib_base/src/main/java/com/android/base/adapter/recycler/ItemViewBinder.kt index 67aca4b..68921e0 100644 --- a/lib_base/src/main/java/com/android/base/adapter/recycler/ItemViewBinder.kt +++ b/lib_base/src/main/java/com/android/base/adapter/recycler/ItemViewBinder.kt @@ -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 diff --git a/lib_base/src/main/java/com/android/base/kotlin/KtViewHolder.kt b/lib_base/src/main/java/com/android/base/adapter/recycler/KtViewHolder.kt similarity index 83% rename from lib_base/src/main/java/com/android/base/kotlin/KtViewHolder.kt rename to lib_base/src/main/java/com/android/base/adapter/recycler/KtViewHolder.kt index 2637902..51374e6 100644 --- a/lib_base/src/main/java/com/android/base/kotlin/KtViewHolder.kt +++ b/lib_base/src/main/java/com/android/base/adapter/recycler/KtViewHolder.kt @@ -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 diff --git a/lib_base/src/main/java/com/android/base/adapter/recycler/SimpleRecyclerAdapter.kt b/lib_base/src/main/java/com/android/base/adapter/recycler/SimpleRecyclerAdapter.kt index 6c6d357..d36aa62 100644 --- a/lib_base/src/main/java/com/android/base/adapter/recycler/SimpleRecyclerAdapter.kt +++ b/lib_base/src/main/java/com/android/base/adapter/recycler/SimpleRecyclerAdapter.kt @@ -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]. diff --git a/lib_base/src/main/java/com/android/base/kotlin/LiveDataEx.kt b/lib_base/src/main/java/com/android/base/app/aac/LiveDataEx.kt similarity index 93% rename from lib_base/src/main/java/com/android/base/kotlin/LiveDataEx.kt rename to lib_base/src/main/java/com/android/base/app/aac/LiveDataEx.kt index 9829b2a..ae47b20 100644 --- a/lib_base/src/main/java/com/android/base/kotlin/LiveDataEx.kt +++ b/lib_base/src/main/java/com/android/base/app/aac/LiveDataEx.kt @@ -1,4 +1,4 @@ -package com.android.base.kotlin +package com.android.base.app.aac import androidx.lifecycle.MutableLiveData diff --git a/lib_base/src/main/java/com/android/base/app/fragment/Fragments.kt b/lib_base/src/main/java/com/android/base/app/fragment/Fragments.kt index ea080bb..a63f3b4 100644 --- a/lib_base/src/main/java/com/android/base/app/fragment/Fragments.kt +++ b/lib_base/src/main/java/com/android/base/app/fragment/Fragments.kt @@ -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 等*/ diff --git a/lib_base/src/main/java/com/android/base/app/ui/UIEx.kt b/lib_base/src/main/java/com/android/base/app/ui/UIEx.kt index 96b1b60..2e9d427 100644 --- a/lib_base/src/main/java/com/android/base/app/ui/UIEx.kt +++ b/lib_base/src/main/java/com/android/base/app/ui/UIEx.kt @@ -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 RefreshListLayout.processListResultWithStatus(list: List?, onEmpty: (() -> Unit)? = null) { if (isLoadingMore) { - if (!Checker.isEmpty(list)) { + if (!isEmpty(list)) { addData(list) } } else { @@ -33,7 +33,7 @@ fun RefreshListLayout.processListResultWithStatus(list: List?, onEmpty fun RefreshListLayout.processListResultWithoutStatus(list: List?, onEmpty: (() -> Unit)? = null) { if (isLoadingMore) { - if (!Checker.isEmpty(list)) { + if (!isEmpty(list)) { addData(list) } } else { diff --git a/lib_base/src/main/java/com/android/base/imageloader/ProgressManager.java b/lib_base/src/main/java/com/android/base/imageloader/ProgressManager.java index 63a3df6..00c3291 100644 --- a/lib_base/src/main/java/com/android/base/imageloader/ProgressManager.java +++ b/lib_base/src/main/java/com/android/base/imageloader/ProgressManager.java @@ -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) { diff --git a/lib_base/src/main/java/com/android/base/kotlin/ContextEx.kt b/lib_base/src/main/java/com/android/base/kotlin/ContextEx.kt deleted file mode 100644 index 27b3479..0000000 --- a/lib_base/src/main/java/com/android/base/kotlin/ContextEx.kt +++ /dev/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) -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/kotlin/FragmentEx.kt b/lib_base/src/main/java/com/android/base/kotlin/FragmentEx.kt deleted file mode 100644 index ddde674..0000000 --- a/lib_base/src/main/java/com/android/base/kotlin/FragmentEx.kt +++ /dev/null @@ -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) -} diff --git a/lib_base/src/main/java/com/android/base/kotlin/LangEx.kt b/lib_base/src/main/java/com/android/base/kotlin/LangEx.kt deleted file mode 100644 index fb97338..0000000 --- a/lib_base/src/main/java/com/android/base/kotlin/LangEx.kt +++ /dev/null @@ -1,58 +0,0 @@ -package com.android.base.kotlin - -/** - * 参考: - * - [Boolean扩展](https://blog.kotliner.cn/2017/06/19/interesting-booleanext/) - */ -sealed class Ext constructor(val boolean: Boolean) - -/** 如果该对象不是null,则执行action */ -fun T?.ifNonNull(action: T.() -> E): Ext { - if (this != null) { - return WithData(action()) - } - return Otherwise -} - -/** 如果该对象是null,则执行action */ -fun T?.ifNull(action: () -> E) { - if (this == null) { - action() - } -} - -inline fun Boolean.yes(block: () -> T): Ext = when { - this -> { - WithData(block()) - } - else -> Otherwise -} - -inline fun Boolean.no(block: () -> T) = when { - this -> Otherwise - else -> { - WithData(block()) - } -} - -object Otherwise : Ext(true) - -class WithData(val data: T) : Ext(false) - -/**除此以外*/ -inline infix fun Ext.otherwise(block: () -> T): T { - return when (this) { - is Otherwise -> block() - is WithData -> this.data - } -} - -inline operator fun Boolean.invoke(block: () -> T) = yes(block) - -fun Any?.javaClassName(): String { - return if (this == null) { - "" - } else { - this::class.java.name - } -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/kotlin/ResourceEx.kt b/lib_base/src/main/java/com/android/base/kotlin/ResourceEx.kt deleted file mode 100644 index 114457e..0000000 --- a/lib_base/src/main/java/com/android/base/kotlin/ResourceEx.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.android.base.kotlin - -import android.content.res.TypedArray - -inline fun 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() - } - } -} diff --git a/lib_base/src/main/java/com/android/base/kotlin/SizeEx.kt b/lib_base/src/main/java/com/android/base/kotlin/SizeEx.kt deleted file mode 100644 index a555455..0000000 --- a/lib_base/src/main/java/com/android/base/kotlin/SizeEx.kt +++ /dev/null @@ -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) \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/kotlin/ViewEx.kt b/lib_base/src/main/java/com/android/base/kotlin/ViewEx.kt deleted file mode 100644 index 5d16678..0000000 --- a/lib_base/src/main/java/com/android/base/kotlin/ViewEx.kt +++ /dev/null @@ -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.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 { - return onClickObservable(500) -} - -fun View.onClickObservable(milliseconds: Long): Observable { - 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) -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/ActFragWrapper.java b/lib_base/src/main/java/com/android/base/utils/android/ActFragWrapper.java index 27de2e3..d5beac6 100644 --- a/lib_base/src/main/java/com/android/base/utils/android/ActFragWrapper.java +++ b/lib_base/src/main/java/com/android/base/utils/android/ActFragWrapper.java @@ -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)); + } } } + } \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/ResourceUtils.java b/lib_base/src/main/java/com/android/base/utils/android/ResourceUtils.java deleted file mode 100644 index c09e07d..0000000 --- a/lib_base/src/main/java/com/android/base/utils/android/ResourceUtils.java +++ /dev/null @@ -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); - } -} diff --git a/lib_base/src/main/java/com/android/base/utils/android/TintUtils.java b/lib_base/src/main/java/com/android/base/utils/android/TintUtils.java deleted file mode 100644 index 517c131..0000000 --- a/lib_base/src/main/java/com/android/base/utils/android/TintUtils.java +++ /dev/null @@ -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: - *
- *     {@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);
- * 
- */ -@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; - } - -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/UnitConverter.java b/lib_base/src/main/java/com/android/base/utils/android/UnitConverter.java deleted file mode 100644 index 1d53afd..0000000 --- a/lib_base/src/main/java/com/android/base/utils/android/UnitConverter.java +++ /dev/null @@ -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; - } -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/ViewUtils.java b/lib_base/src/main/java/com/android/base/utils/android/ViewUtils.java deleted file mode 100644 index 568a608..0000000 --- a/lib_base/src/main/java/com/android/base/utils/android/ViewUtils.java +++ /dev/null @@ -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 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; - } - -} diff --git a/lib_base/src/main/java/com/android/base/utils/android/XAppUtils.java b/lib_base/src/main/java/com/android/base/utils/android/XAppUtils.java index 7ffc62b..b035c4c 100644 --- a/lib_base/src/main/java/com/android/base/utils/android/XAppUtils.java +++ b/lib_base/src/main/java/com/android/base/utils/android/XAppUtils.java @@ -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"); diff --git a/lib_base/src/main/java/com/android/base/utils/android/anim/ActivityAnimUtils.java b/lib_base/src/main/java/com/android/base/utils/android/anim/ActivityAnimUtils.java deleted file mode 100644 index 3fbd324..0000000 --- a/lib_base/src/main/java/com/android/base/utils/android/anim/ActivityAnimUtils.java +++ /dev/null @@ -1,73 +0,0 @@ -package com.android.base.utils.android.anim; - -import android.app.Activity; -import android.app.ActivityOptions; -import android.content.Intent; -import android.transition.Explode; -import android.transition.Fade; -import android.transition.Slide; -import android.view.View; -import android.view.Window; - -import com.android.base.utils.android.compat.AndroidVersion; - -import androidx.annotation.AnimRes; -import androidx.appcompat.app.AppCompatActivity; -import androidx.core.app.ActivityCompat; -import androidx.core.app.ActivityOptionsCompat; - -public class ActivityAnimUtils { - - private ActivityAnimUtils() { - throw new UnsupportedOperationException("no need instantiation"); - } - - public static void startActivity(Activity activity, Intent intent, View share) { - if (AndroidVersion.atLeast(21)) { - ActivityOptions options = ActivityOptions.makeSceneTransitionAnimation(activity, share, share.getTransitionName()); - activity.startActivity(intent, options.toBundle()); - } else {//小于5.0,使用makeScaleUpAnimation - ActivityOptionsCompat options = ActivityOptionsCompat.makeScaleUpAnimation(share, share.getWidth() / 2, share.getHeight() / 2, 0, 0); - ActivityCompat.startActivity(activity, intent, options.toBundle()); - } - } - - /////////////////////////////////////////////////////////////////////////// - // Enter And Exit Transition - /////////////////////////////////////////////////////////////////////////// - - public static final int TYPE_EXPLODE = 1; - public static final int TYPE_SLIDE = 2; - public static final int TYPE_FADE = 3; - - /** - * @param activity context - * @param type {@link #TYPE_EXPLODE},{@link #TYPE_SLIDE},{@link #TYPE_FADE} - */ - private static void setTransition(Activity activity, int type) { - if (AndroidVersion.atLeast(21)) { - Window window = activity.getWindow(); - window.requestFeature(Window.FEATURE_CONTENT_TRANSITIONS); - switch (type) { - case TYPE_EXPLODE: - window.setEnterTransition(new Explode()); - window.setExitTransition(new Explode()); - break; - case TYPE_SLIDE: - window.setEnterTransition(new Slide()); - window.setExitTransition(new Slide()); - break; - case TYPE_FADE: - window.setEnterTransition(new Fade()); - window.setExitTransition(new Fade()); - break; - } - } - } - - public static void finishWithAnimation(AppCompatActivity activity, @AnimRes int enterAnim, @AnimRes int exitAnim) { - activity.supportFinishAfterTransition(); - activity.overridePendingTransition(enterAnim, exitAnim); - } - -} diff --git a/lib_base/src/main/java/com/android/base/utils/android/SpCache.java b/lib_base/src/main/java/com/android/base/utils/android/cache/SpCache.java similarity index 99% rename from lib_base/src/main/java/com/android/base/utils/android/SpCache.java rename to lib_base/src/main/java/com/android/base/utils/android/cache/SpCache.java index 5219e5a..bb3384e 100644 --- a/lib_base/src/main/java/com/android/base/utils/android/SpCache.java +++ b/lib_base/src/main/java/com/android/base/utils/android/cache/SpCache.java @@ -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); } -} +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/kotlin/UtilsEx.kt b/lib_base/src/main/java/com/android/base/utils/android/compat/AndroidVersionEx.kt similarity index 61% rename from lib_base/src/main/java/com/android/base/kotlin/UtilsEx.kt rename to lib_base/src/main/java/com/android/base/utils/android/compat/AndroidVersionEx.kt index c086ae5..05dfa52 100644 --- a/lib_base/src/main/java/com/android/base/kotlin/UtilsEx.kt +++ b/lib_base/src/main/java/com/android/base/utils/android/compat/AndroidVersionEx.kt @@ -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) diff --git a/lib_base/src/main/java/com/android/base/utils/android/text/RoundedBackgroundSpan.java b/lib_base/src/main/java/com/android/base/utils/android/text/RoundedBackgroundSpan.java deleted file mode 100644 index 2ec23a4..0000000 --- a/lib_base/src/main/java/com/android/base/utils/android/text/RoundedBackgroundSpan.java +++ /dev/null @@ -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); - } - -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/views/ActivityAnimUtils.kt b/lib_base/src/main/java/com/android/base/utils/android/views/ActivityAnimUtils.kt new file mode 100644 index 0000000..c91a142 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/android/views/ActivityAnimUtils.kt @@ -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) +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/kotlin/AttrStyleEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/AttrStyleEx.kt similarity index 88% rename from lib_base/src/main/java/com/android/base/kotlin/AttrStyleEx.kt rename to lib_base/src/main/java/com/android/base/utils/android/views/AttrStyleEx.kt index 2949ea6..c8a2819 100644 --- a/lib_base/src/main/java/com/android/base/kotlin/AttrStyleEx.kt +++ b/lib_base/src/main/java/com/android/base/utils/android/views/AttrStyleEx.kt @@ -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 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() diff --git a/lib_base/src/main/java/com/android/base/kotlin/DialogEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/DialogEx.kt similarity index 83% rename from lib_base/src/main/java/com/android/base/kotlin/DialogEx.kt rename to lib_base/src/main/java/com/android/base/utils/android/views/DialogEx.kt index f5f6076..7d1e920 100644 --- a/lib_base/src/main/java/com/android/base/kotlin/DialogEx.kt +++ b/lib_base/src/main/java/com/android/base/utils/android/views/DialogEx.kt @@ -1,4 +1,4 @@ -package com.android.base.kotlin +package com.android.base.utils.android.views import android.app.Dialog diff --git a/lib_base/src/main/java/com/android/base/kotlin/MenuEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/MenuEx.kt similarity index 94% rename from lib_base/src/main/java/com/android/base/kotlin/MenuEx.kt rename to lib_base/src/main/java/com/android/base/utils/android/views/MenuEx.kt index b9f483e..2237f8b 100644 --- a/lib_base/src/main/java/com/android/base/kotlin/MenuEx.kt +++ b/lib_base/src/main/java/com/android/base/utils/android/views/MenuEx.kt @@ -1,4 +1,4 @@ -package com.android.base.kotlin +package com.android.base.utils.android.views import android.view.Menu import android.view.MenuItem diff --git a/lib_base/src/main/java/com/android/base/utils/android/views/ResourceEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/ResourceEx.kt new file mode 100644 index 0000000..5ea10ae --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/android/views/ResourceEx.kt @@ -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.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 { + 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) +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/views/RoundedBackgroundSpan.kt b/lib_base/src/main/java/com/android/base/utils/android/views/RoundedBackgroundSpan.kt new file mode 100644 index 0000000..9bf014a --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/android/views/RoundedBackgroundSpan.kt @@ -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) + } + +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/views/ScrollViewEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/ScrollViewEx.kt new file mode 100644 index 0000000..d69a164 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/android/views/ScrollViewEx.kt @@ -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) +} diff --git a/lib_base/src/main/java/com/android/base/utils/android/views/SizeEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/SizeEx.kt new file mode 100644 index 0000000..7c47d34 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/android/views/SizeEx.kt @@ -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 +} diff --git a/lib_base/src/main/java/com/android/base/kotlin/TextViewEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/TextViewEx.kt similarity index 61% rename from lib_base/src/main/java/com/android/base/kotlin/TextViewEx.kt rename to lib_base/src/main/java/com/android/base/utils/android/views/TextViewEx.kt index 62fd841..15a894b 100644 --- a/lib_base/src/main/java/com/android/base/kotlin/TextViewEx.kt +++ b/lib_base/src/main/java/com/android/base/utils/android/views/TextViewEx.kt @@ -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(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 + } } \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/views/TintUtils.kt b/lib_base/src/main/java/com/android/base/utils/android/views/TintUtils.kt new file mode 100644 index 0000000..98fd0b9 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/android/views/TintUtils.kt @@ -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 +} diff --git a/lib_base/src/main/java/com/android/base/utils/android/views/ViewEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/ViewEx.kt new file mode 100644 index 0000000..1ca2826 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/android/views/ViewEx.kt @@ -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.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 { + return onClickObservable(500) +} + +fun View.onClickObservable(milliseconds: Long): Observable { + 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 View.find(@IdRes viewId: Int): V { + return findViewById(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 + } + } +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/android/views/WebViewEx.kt b/lib_base/src/main/java/com/android/base/utils/android/views/WebViewEx.kt new file mode 100644 index 0000000..642449f --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/android/views/WebViewEx.kt @@ -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 +} diff --git a/lib_base/src/main/java/com/android/base/utils/common/Checker.java b/lib_base/src/main/java/com/android/base/utils/common/Checker.java deleted file mode 100644 index e2f0429..0000000 --- a/lib_base/src/main/java/com/android/base/utils/common/Checker.java +++ /dev/null @@ -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 boolean isEmpty(T[] t) { - return t == null || t.length == 0; - } - - public static boolean notEmpty(T[] t) { - return !isEmpty(t); - } - - public static T requireNonNull(T obj) { - if (obj == null) - throw new NullPointerException(); - return obj; - } - - public static T requireNonNull(T obj, String message) { - if (obj == null) - throw new NullPointerException(message); - return obj; - } - - public static boolean nonNull(Object obj) { - return obj != null; - } - -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/common/Checker.kt b/lib_base/src/main/java/com/android/base/utils/common/Checker.kt new file mode 100644 index 0000000..0e607a1 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/common/Checker.kt @@ -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 isEmpty(t: Array?): Boolean { + return t == null || t.isEmpty() +} + +fun notEmpty(t: Array): Boolean { + return !isEmpty(t) +} + +fun requireNonNull(obj: T?): T { + if (obj == null) { + throw NullPointerException("requireNonNull failed") + } + return obj +} + +fun 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 +} diff --git a/lib_base/src/main/java/com/android/base/utils/common/CloseUtils.java b/lib_base/src/main/java/com/android/base/utils/common/CloseUtils.java deleted file mode 100644 index 3515087..0000000 --- a/lib_base/src/main/java/com/android/base/utils/common/CloseUtils.java +++ /dev/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); - } - } - -} diff --git a/lib_base/src/main/java/com/android/base/utils/common/CollectionUtils.java b/lib_base/src/main/java/com/android/base/utils/common/CollectionUtils.java deleted file mode 100644 index e285ca4..0000000 --- a/lib_base/src/main/java/com/android/base/utils/common/CollectionUtils.java +++ /dev/null @@ -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 ArrayList toArrayList(List list) { - if (list == null) { - return new ArrayList<>(0); - } - if (list instanceof ArrayList) { - return (ArrayList) list; - } - return new ArrayList<>(list); - } - -} diff --git a/lib_base/src/main/java/com/android/base/kotlin/Collections.kt b/lib_base/src/main/java/com/android/base/utils/common/Collections.kt similarity index 51% rename from lib_base/src/main/java/com/android/base/kotlin/Collections.kt rename to lib_base/src/main/java/com/android/base/utils/common/Collections.kt index 78e2629..9f17492 100644 --- a/lib_base/src/main/java/com/android/base/kotlin/Collections.kt +++ b/lib_base/src/main/java/com/android/base/utils/common/Collections.kt @@ -1,9 +1,15 @@ -package com.android.base.kotlin +package com.android.base.utils.common -import com.android.base.utils.common.CollectionUtils +fun List?.toArrayList(copy: Boolean = false): ArrayList { + + if (this == null) { + return ArrayList(0) + } + + return if (!copy && this is java.util.ArrayList) { + this + } else ArrayList(this) -fun List?.toArrayList(): ArrayList { - return CollectionUtils.toArrayList(this) } fun MutableList.removeWhich(filter: (E) -> Boolean): Boolean { diff --git a/lib_base/src/main/java/com/android/base/utils/common/FileUtils.java b/lib_base/src/main/java/com/android/base/utils/common/FileUtils.java deleted file mode 100644 index 2096e20..0000000 --- a/lib_base/src/main/java/com/android/base/utils/common/FileUtils.java +++ /dev/null @@ -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); - } -} diff --git a/lib_base/src/main/java/com/android/base/utils/common/Files.kt b/lib_base/src/main/java/com/android/base/utils/common/Files.kt new file mode 100644 index 0000000..2beb48a --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/common/Files.kt @@ -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) +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/common/Lang.kt b/lib_base/src/main/java/com/android/base/utils/common/Lang.kt new file mode 100644 index 0000000..16e6103 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/common/Lang.kt @@ -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 constructor(val boolean: Boolean) + +/** 如果该对象不是null,则执行action */ +fun T?.ifNonNull(action: T.() -> E): Ext { + if (this != null) { + return WithData(action()) + } + return Otherwise +} + +/** 如果该对象是null,则执行action */ +fun T?.ifNull(action: () -> E) { + if (this == null) { + action() + } +} + +inline fun Boolean.yes(block: () -> T): Ext = when { + this -> { + WithData(block()) + } + else -> Otherwise +} + +inline fun Boolean.no(block: () -> T) = when { + this -> Otherwise + else -> { + WithData(block()) + } +} + +object Otherwise : Ext(true) + +class WithData(val data: T) : Ext(false) + +/**除此以外*/ +inline infix fun Ext.otherwise(block: () -> T): T { + return when (this) { + is Otherwise -> block() + is WithData -> this.data + } +} + +inline operator fun 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) + } +} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/utils/common/StringChecker.java b/lib_base/src/main/java/com/android/base/utils/common/StringChecker.java deleted file mode 100644 index eba3232..0000000 --- a/lib_base/src/main/java/com/android/base/utils/common/StringChecker.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.android.base.utils.common; - -import java.util.regex.Pattern; - -public class StringChecker { - - private StringChecker() { - throw new UnsupportedOperationException("no need instantiation"); - } - - private static final String CHINA_PHONE_REG = "^1\\d{10}$"; - private static final String ID_CARD_REG = "[1-9]\\d{13,16}[a-zA-Z0-9]{1}"; - private static final String EMAIL_REG = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*"; - private static final String DIGIT_REG = "\\-?[1-9]\\d+\""; - private static final String URL_REG = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?"; - private static final String CHINESE_REGEX = "^[\u4E00-\u9FA5]+$"; - private static final String DECIMALS_REG = "\\-?[1-9]\\d+(\\.\\d+)?"; - private static final String LETTERS_REG = ".*[a-zA-Z]++.*"; - private static final String DIGITAL_REG = ".*[0-9]++.*"; - private static final String DIGITAL_LETTER_ONLY_REG = "^[A-Za-z0-9]+$"; - - /** - * 验证中国的手机号 - * - * @return 验证成功返回 true,验证失败返回 false - */ - public static boolean isChinaPhoneNumber(String mobile) { - return !isEmpty(mobile) && Pattern.matches(CHINA_PHONE_REG, mobile); - } - - public static boolean containsLetter(String text) { - return !isEmpty(text) && Pattern.matches(LETTERS_REG, text); - } - - public static boolean containsDigital(String text) { - return !isEmpty(text) && Pattern.matches(DIGITAL_REG, text); - } - - public static boolean containsDigtalLetterOnly(String text) { - return !isEmpty(text) && Pattern.matches(DIGITAL_LETTER_ONLY_REG, text); - } - - /** - * 验证身份证号码 - * - * @param idCard 居民身份证号码15位或18位,最后一位可能是数字或字母 - * @return 验证成功返回true,验证失败返回false - */ - public static boolean isIdCard(String idCard) { - return !isEmpty(idCard) && Pattern.matches(ID_CARD_REG, idCard); - } - - /** - * 验证Email - * - * @param email email地址,格式:zhangsan@sina.com,zhangsan@xxx.com.cn,xxx代表邮件服务商 - * @return 验证成功返回true,验证失败返回false - */ - public static boolean isEmail(String email) { - return !isEmpty(email) && Pattern.matches(EMAIL_REG, email); - } - - /** - * 验证整数(正整数和负整数) - * - * @param digit 一位或多位0-9之间的整数 - * @return 验证成功返回true,验证失败返回false - */ - public static boolean isDigit(String digit) { - return !isEmpty(digit) && Pattern.matches(DIGIT_REG, digit); - } - - /** - * 验证整数和浮点数(正负整数和正负浮点数) - * - * @param decimals 一位或多位0-9之间的浮点数,如:1.23,233.30 - * @return 验证成功返回true,验证失败返回false - */ - public static boolean isDecimals(String decimals) { - return !isEmpty(decimals) && Pattern.matches(DECIMALS_REG, decimals); - } - - /** - * 验证中文 - * - * @param chinese 中文字符 - * @return 验证成功返回true,验证失败返回false - */ - public static boolean isChinese(String chinese) { - return !isEmpty(chinese) && Pattern.matches(CHINESE_REGEX, chinese); - } - - /** - * 验证URL地址 - * - * @param url url - * @return 验证成功返回true,验证失败返回false - */ - public static boolean isURL(String url) { - return !isEmpty(url) && Pattern.matches(URL_REG, url); - } - - /** - * 获取字符串的字符个数 - */ - public static int getCharLength(String string) { - if (isEmpty(string)) { - return 0; - } - return string.trim().toCharArray().length; - } - - public static boolean isCharLength(String string, int length) { - return null != string && ((isEmpty(string) && length == 0) || (string.trim().toCharArray().length == length)); - } - - public static boolean isLengthIn(String string, int min, int max) { - int length = string == null ? 0 : string.length(); - return length <= max && length >= min; - } - - public static boolean isEmpty(CharSequence str) { - return str == null || str.toString().trim().length() == 0; - } - -} diff --git a/lib_base/src/main/java/com/android/base/utils/common/Strings.kt b/lib_base/src/main/java/com/android/base/utils/common/Strings.kt new file mode 100644 index 0000000..35def2c --- /dev/null +++ b/lib_base/src/main/java/com/android/base/utils/common/Strings.kt @@ -0,0 +1,120 @@ +@file:JvmName("Strings") + +package com.android.base.utils.common + +import java.util.regex.Pattern + + +private const val CHINA_PHONE_REG = "^1\\d{10}$" +private const val ID_CARD_REG = "[1-9]\\d{13,16}[a-zA-Z0-9]{1}" +private const val EMAIL_REG = "\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*" +private const val DIGIT_REG = "\\-?[1-9]\\d+\"" +private const val URL_REG = "(https?://(w{3}\\.)?)?\\w+\\.\\w+(\\.[a-zA-Z]+)*(:\\d{1,5})?(/\\w*)*(\\??(.+=.*)?(&.+=.*)?)?" +private const val CHINESE_REGEX = "^[\u4E00-\u9FA5]+$" +private const val DECIMALS_REG = "\\-?[1-9]\\d+(\\.\\d+)?" +private const val LETTERS_REG = ".*[a-zA-Z]++.*" +private const val DIGITAL_REG = ".*[0-9]++.*" +private const val DIGITAL_LETTER_ONLY_REG = "^[A-Za-z0-9]+$" + +/** + * 验证中国的手机号 + * + * @return 验证成功返回 true,验证失败返回 false + */ +fun isChinaPhoneNumber(mobile: String): Boolean { + return !isEmpty(mobile) && Pattern.matches(CHINA_PHONE_REG, mobile) +} + +fun containsLetter(text: String): Boolean { + return !isEmpty(text) && Pattern.matches(LETTERS_REG, text) +} + +fun containsDigital(text: String): Boolean { + return !isEmpty(text) && Pattern.matches(DIGITAL_REG, text) +} + +fun containsDigtalLetterOnly(text: String): Boolean { + return !isEmpty(text) && Pattern.matches(DIGITAL_LETTER_ONLY_REG, text) +} + +/** + * 验证身份证号码 + * + * @param idCard 居民身份证号码15位或18位,最后一位可能是数字或字母 + * @return 验证成功返回true,验证失败返回false + */ +fun isIdCard(idCard: String): Boolean { + return !isEmpty(idCard) && Pattern.matches(ID_CARD_REG, idCard) +} + +/** + * 验证Email + * + * @param email email地址,格式:zhangsan@sina.com,zhangsan@xxx.com.cn,xxx代表邮件服务商 + * @return 验证成功返回true,验证失败返回false + */ +fun isEmail(email: String): Boolean { + return !isEmpty(email) && Pattern.matches(EMAIL_REG, email) +} + +/** + * 验证整数(正整数和负整数) + * + * @param digit 一位或多位0-9之间的整数 + * @return 验证成功返回true,验证失败返回false + */ +fun isDigit(digit: String): Boolean { + return !isEmpty(digit) && Pattern.matches(DIGIT_REG, digit) +} + +/** + * 验证整数和浮点数(正负整数和正负浮点数) + * + * @param decimals 一位或多位0-9之间的浮点数,如:1.23,233.30 + * @return 验证成功返回true,验证失败返回false + */ +fun isDecimals(decimals: String): Boolean { + return !isEmpty(decimals) && Pattern.matches(DECIMALS_REG, decimals) +} + +/** + * 验证中文 + * + * @param chinese 中文字符 + * @return 验证成功返回true,验证失败返回false + */ +fun isChinese(chinese: String): Boolean { + return !isEmpty(chinese) && Pattern.matches(CHINESE_REGEX, chinese) +} + +/** + * 验证URL地址 + * + * @param url url + * @return 验证成功返回true,验证失败返回false + */ +fun isURL(url: String): Boolean { + return !isEmpty(url) && Pattern.matches(URL_REG, url) +} + +/** + * 获取字符串的字符个数 + */ +fun getCharLength(string: String): Int { + return if (isEmpty(string)) { + 0 + } else string.trim { it <= ' ' }.toCharArray().size +} + +fun isCharLength(string: String?, length: Int): Boolean { + return null != string && (isEmpty(string) && length == 0 || string.trim { it <= ' ' }.toCharArray().size == length) +} + +fun isLengthIn(string: String?, min: Int, max: Int): Boolean { + val length = string?.length ?: 0 + return length in min..max +} + +fun isEmpty(str: CharSequence?): Boolean { + return str == null || str.toString().trim { it <= ' ' }.isEmpty() +} diff --git a/lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java b/lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java index cfbda9e..4f9ed1a 100644 --- a/lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java +++ b/lib_base/src/main/java/com/android/base/widget/SimpleMultiStateView.java @@ -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(); diff --git a/lib_base/src/main/java/com/android/base/widget/viewpager/PageNumberView.java b/lib_base/src/main/java/com/android/base/widget/viewpager/PageNumberView.java deleted file mode 100644 index 5943dac..0000000 --- a/lib_base/src/main/java/com/android/base/widget/viewpager/PageNumberView.java +++ /dev/null @@ -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(); - } - -} \ No newline at end of file diff --git a/lib_base/src/main/java/com/android/base/widget/viewpager/PageNumberView.kt b/lib_base/src/main/java/com/android/base/widget/viewpager/PageNumberView.kt new file mode 100644 index 0000000..d814a07 --- /dev/null +++ b/lib_base/src/main/java/com/android/base/widget/viewpager/PageNumberView.kt @@ -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 = "/" + } + +} \ No newline at end of file