diff options
-rw-r--r-- | core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt | 253 |
1 files changed, 131 insertions, 122 deletions
diff --git a/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt index 4757a00..07c2cee 100644 --- a/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt +++ b/core/src/main/kotlin/ca/allanwang/kau/utils/ViewUtils.kt @@ -50,25 +50,25 @@ import kotlin.math.max @KauUtils inline fun <T : View> T.visible(): T { - visibility = View.VISIBLE - return this + visibility = View.VISIBLE + return this } @KauUtils inline fun <T : View> T.invisible(): T { - visibility = View.INVISIBLE - return this + visibility = View.INVISIBLE + return this } @KauUtils inline fun <T : View> T.gone(): T { - visibility = View.GONE - return this + visibility = View.GONE + return this } @KauUtils inline fun <T : View> T.invisibleIf(invisible: Boolean): T = - if (invisible) invisible() else visible() + if (invisible) invisible() else visible() @KauUtils inline fun <T : View> T.visibleIf(visible: Boolean): T = if (visible) visible() else gone() @@ -78,55 +78,64 @@ inline fun <T : View> T.goneIf(gone: Boolean): T = visibleIf(!gone) @KauUtils inline val View.isVisible: Boolean - get() = visibility == View.VISIBLE + get() = visibility == View.VISIBLE @KauUtils inline val View.isInvisible: Boolean - get() = visibility == View.INVISIBLE + get() = visibility == View.INVISIBLE @KauUtils inline val View.isGone: Boolean - get() = visibility == View.GONE + get() = visibility == View.GONE + +/** + * Measure the height of a view if it had match_parent for width and no height restrictions + */ +inline val View.unboundedHeight: Int + get() { + measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED) + return measuredHeight + } @KauUtils inline fun View.setBackgroundColorRes(@ColorRes color: Int) = - setBackgroundColor(context.color(color)) + setBackgroundColor(context.color(color)) fun View.snackbar( - text: String, - duration: Int = Snackbar.LENGTH_LONG, - builder: Snackbar.() -> Unit = {} + text: String, + duration: Int = Snackbar.LENGTH_LONG, + builder: Snackbar.() -> Unit = {} ): Snackbar { - val snackbar = Snackbar.make(this, text, duration) - snackbar.builder() - snackbar.show() - return snackbar + val snackbar = Snackbar.make(this, text, duration) + snackbar.builder() + snackbar.show() + return snackbar } fun View.snackbar( - @StringRes textId: Int, - duration: Int = Snackbar.LENGTH_LONG, - builder: Snackbar.() -> Unit = {} + @StringRes textId: Int, + duration: Int = Snackbar.LENGTH_LONG, + builder: Snackbar.() -> Unit = {} ) = - snackbar(context.string(textId), duration, builder) + snackbar(context.string(textId), duration, builder) @KauUtils fun ImageView.setIcon( - icon: IIcon?, - sizeDp: Int = 24, - @ColorInt color: Int = Color.WHITE, - builder: IconicsDrawable.() -> Unit = {} + icon: IIcon?, + sizeDp: Int = 24, + @ColorInt color: Int = Color.WHITE, + builder: IconicsDrawable.() -> Unit = {} ) { - icon ?: return - setImageDrawable(icon.toDrawable(context, sizeDp = sizeDp, color = color, builder = builder)) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - imageTintList = ColorStateList.valueOf(color) - } + icon ?: return + setImageDrawable(icon.toDrawable(context, sizeDp = sizeDp, color = color, builder = builder)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + imageTintList = ColorStateList.valueOf(color) + } } @KauUtils inline val FloatingActionButton.isHidden - get() = !isShown + get() = !isShown fun FloatingActionButton.showIf(show: Boolean) = if (show) show() else hide() @@ -134,7 +143,7 @@ fun FloatingActionButton.hideIf(hide: Boolean) = if (hide) hide() else show() @KauUtils fun ViewGroup.inflate(layoutId: Int, attachToRoot: Boolean = false): View = - LayoutInflater.from(context).inflate(layoutId, this, attachToRoot) + LayoutInflater.from(context).inflate(layoutId, this, attachToRoot) /** * Set left margin to a value in px @@ -184,14 +193,14 @@ fun View.setMargin(margin: Int) = setMargins(margin, KAU_ALL) */ @KauUtils private fun View.setMargins(margin: Int, flag: Int): Boolean { - val p = (layoutParams as? ViewGroup.MarginLayoutParams) ?: return false - p.setMargins( - if (flag and KAU_LEFT > 0) margin else p.leftMargin, - if (flag and KAU_TOP > 0) margin else p.topMargin, - if (flag and KAU_RIGHT > 0) margin else p.rightMargin, - if (flag and KAU_BOTTOM > 0) margin else p.bottomMargin - ) - return true + val p = (layoutParams as? ViewGroup.MarginLayoutParams) ?: return false + p.setMargins( + if (flag and KAU_LEFT > 0) margin else p.leftMargin, + if (flag and KAU_TOP > 0) margin else p.topMargin, + if (flag and KAU_RIGHT > 0) margin else p.rightMargin, + if (flag and KAU_BOTTOM > 0) margin else p.bottomMargin + ) + return true } /** @@ -241,41 +250,41 @@ fun View.setPadding(padding: Int) = setPadding(padding, KAU_ALL) */ @KauUtils private fun View.setPadding(padding: Int, flag: Int) { - setPadding( - if (flag and KAU_LEFT > 0) padding else paddingLeft, - if (flag and KAU_TOP > 0) padding else paddingTop, - if (flag and KAU_RIGHT > 0) padding else paddingRight, - if (flag and KAU_BOTTOM > 0) padding else paddingBottom - ) + setPadding( + if (flag and KAU_LEFT > 0) padding else paddingLeft, + if (flag and KAU_TOP > 0) padding else paddingTop, + if (flag and KAU_RIGHT > 0) padding else paddingRight, + if (flag and KAU_BOTTOM > 0) padding else paddingBottom + ) } @KauUtils fun View.hideKeyboard() { - clearFocus() - (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow( - windowToken, - 0 - ) + clearFocus() + (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).hideSoftInputFromWindow( + windowToken, + 0 + ) } @KauUtils fun View.showKeyboard() { - requestFocus() - (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput( - this, - InputMethodManager.SHOW_IMPLICIT - ) + requestFocus() + (context.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager).showSoftInput( + this, + InputMethodManager.SHOW_IMPLICIT + ) } @RequiresApi(Build.VERSION_CODES.LOLLIPOP) @KauUtils fun View.setRippleBackground(@ColorInt foregroundColor: Int, @ColorInt backgroundColor: Int) { - background = createSimpleRippleDrawable(foregroundColor, backgroundColor) + background = createSimpleRippleDrawable(foregroundColor, backgroundColor) } @KauUtils inline val View.parentViewGroup: ViewGroup - get() = parent as ViewGroup + get() = parent as ViewGroup inline val EditText.value: String get() = text.toString().trim() @@ -285,28 +294,28 @@ inline val TextInputEditText.value: String get() = text.toString().trim() * Generates a recycler view with match parent and a linearlayoutmanager, since it's so commonly used */ fun Context.fullLinearRecycler( - rvAdapter: RecyclerView.Adapter<*>? = null, - configs: RecyclerView.() -> Unit = {} + rvAdapter: RecyclerView.Adapter<*>? = null, + configs: RecyclerView.() -> Unit = {} ) = - RecyclerView(this).apply { - layoutManager = LinearLayoutManager(this@fullLinearRecycler) - layoutParams = - RecyclerView.LayoutParams( - RecyclerView.LayoutParams.MATCH_PARENT, - RecyclerView.LayoutParams.MATCH_PARENT - ) - if (rvAdapter != null) { - adapter = rvAdapter - } - configs() + RecyclerView(this).apply { + layoutManager = LinearLayoutManager(this@fullLinearRecycler) + layoutParams = + RecyclerView.LayoutParams( + RecyclerView.LayoutParams.MATCH_PARENT, + RecyclerView.LayoutParams.MATCH_PARENT + ) + if (rvAdapter != null) { + adapter = rvAdapter } + configs() + } /** * Sets a linear layout manager along with an adapter */ fun RecyclerView.withLinearAdapter(rvAdapter: RecyclerView.Adapter<*>) = apply { - layoutManager = LinearLayoutManager(context) - adapter = rvAdapter + layoutManager = LinearLayoutManager(context) + adapter = rvAdapter } /** @@ -315,28 +324,28 @@ fun RecyclerView.withLinearAdapter(rvAdapter: RecyclerView.Adapter<*>) = apply { * If it is already shown, scaling and alpha animations will be added to the action */ inline fun <T : ImageView> T.fadeScaleTransition( - duration: Long = 500L, - minScale: Float = 0.7f, - crossinline action: T.() -> Unit + duration: Long = 500L, + minScale: Float = 0.7f, + crossinline action: T.() -> Unit ) { - if (!isVisible) { - action() - } else { - var transitioned = false - ValueAnimator.ofFloat(1.0f, 0.0f, 1.0f).apply { - this.duration = duration - addUpdateListener { - val x = it.animatedValue as Float - scaleXY = x * (1 - minScale) + minScale - imageAlpha = (x * 255).toInt() - if (it.animatedFraction > 0.5f && !transitioned) { - transitioned = true - action() - } - } - start() + if (!isVisible) { + action() + } else { + var transitioned = false + ValueAnimator.ofFloat(1.0f, 0.0f, 1.0f).apply { + this.duration = duration + addUpdateListener { + val x = it.animatedValue as Float + scaleXY = x * (1 - minScale) + minScale + imageAlpha = (x * 255).toInt() + if (it.animatedFraction > 0.5f && !transitioned) { + transitioned = true + action() } + } + start() } + } } /** @@ -344,45 +353,45 @@ inline fun <T : ImageView> T.fadeScaleTransition( * The fab will reappear when scrolling has stopped or if the user scrolls up */ fun FloatingActionButton.hideOnDownwardsScroll(recycler: RecyclerView) { - recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() { + recycler.addOnScrollListener(object : RecyclerView.OnScrollListener() { - override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { - if (newState == RecyclerView.SCROLL_STATE_IDLE && !isShown) { - show() - } - } + override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { + if (newState == RecyclerView.SCROLL_STATE_IDLE && !isShown) { + show() + } + } - override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { - if (dy > 0 && isShown) { - hide() - } else if (dy < 0 && isHidden) { - show() - } - } - }) + override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { + if (dy > 0 && isShown) { + hide() + } else if (dy < 0 && isHidden) { + show() + } + } + }) } inline var View.scaleXY - get() = max(scaleX, scaleY) - set(value) { - scaleX = value - scaleY = value - } + get() = max(scaleX, scaleY) + set(value) { + scaleX = value + scaleY = value + } /** * Creates an on touch listener that only emits on a short single tap */ @SuppressLint("ClickableViewAccessibility") inline fun View.setOnSingleTapListener(crossinline onSingleTap: (v: View, event: MotionEvent) -> Unit) { - setOnTouchListener { v, event -> - when (event.actionMasked) { - MotionEvent.ACTION_DOWN -> true - MotionEvent.ACTION_UP -> { - if (event.eventTime - event.downTime < 100) - onSingleTap(v, event) - true - } - else -> false - } + setOnTouchListener { v, event -> + when (event.actionMasked) { + MotionEvent.ACTION_DOWN -> true + MotionEvent.ACTION_UP -> { + if (event.eventTime - event.downTime < 100) + onSingleTap(v, event) + true + } + else -> false } + } } |