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