Skip to content

Instantly share code, notes, and snippets.

@ar-g
Last active October 12, 2017 13:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ar-g/98b21f6a6ad3935d3df38416cb1dcfc8 to your computer and use it in GitHub Desktop.
Save ar-g/98b21f6a6ad3935d3df38416cb1dcfc8 to your computer and use it in GitHub Desktop.
Custom flat view for performance sake
package classifieds.yalla.features.ad.page.widget
import android.content.Context
import android.graphics.Canvas
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.OvalShape
import android.support.v4.content.ContextCompat
import android.text.Layout
import android.text.TextUtils
import android.view.Gravity
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.ImageView
import classifieds.yalla.R
import classifieds.yalla.shared.utils.ViewUtils
import classifieds.yalla.shared.utils.ViewUtils.dpToPx
import classifieds.yalla.shared.utils.ViewUtils.spToPx
import com.facebook.fbui.textlayoutbuilder.TextLayoutBuilder
class PaidFeatureView(ctx: Context) : ViewGroup(ctx) {
private val extendFeatureBtn: Button
lateinit var featureIcon: ImageView
private var titleLayout: Layout? = null
private var statusLayout: Layout? = null
private var dateLayout: Layout? = null
private var title: String? = null
private var status: String? = null
private var date: String? = null
private var titleHeight: Int = 0
private var statusHeight: Int = 0
private var statusWidth: Int = 0
private var dotWidth: Int = 0
private val content0_25x: Int
private val content: Int
private val content2x: Int
private val whiteColor: Int
private var leftWithoutIcon: Int = 0
private var titleTop: Int = 0
private var statusTop: Int = 0
private val titleTextLayoutBuilder: TextLayoutBuilder
private val statusTextLayoutBuilder: TextLayoutBuilder
private var dateTextLayoutBuilder: TextLayoutBuilder? = null
private var dotDrawable: ShapeDrawable? = null
private var centerTop: Int = 0
init {
setWillNotDraw(false)
content0_25x = resources.getDimensionPixelSize(R.dimen.content0_25x)
content = resources.getDimensionPixelSize(R.dimen.content)
content2x = resources.getDimensionPixelSize(R.dimen.content2x)
whiteColor = ContextCompat.getColor(context, R.color.white)
extendFeatureBtn = Button(context)
extendFeatureBtn.setText(R.string.payment_extend)
extendFeatureBtn.textSize = 12f
extendFeatureBtn.setTextColor(whiteColor)
extendFeatureBtn.gravity = Gravity.CENTER
extendFeatureBtn.setPadding(0, 0, 0, 0)
extendFeatureBtn.layoutParams = MarginLayoutParams(dpToPx(resources, 90f), dpToPx(resources, 24f))
ViewUtils.setBackground(extendFeatureBtn, ContextCompat.getDrawable(context, R.drawable.round_green_btn_selector))
ViewUtils.setStateListAnimator(extendFeatureBtn, R.drawable.button_state_list_anim_material)
addView(extendFeatureBtn)
initFeatureIcon(context)
val primaryTextColor = ContextCompat.getColor(context, R.color.primary_text)
titleTextLayoutBuilder = TextLayoutBuilder()
.setTextColor(primaryTextColor)
.setTextSize(spToPx(resources, 15f).toInt())
.setShouldWarmText(true)
.setSingleLine(true)
statusTextLayoutBuilder = TextLayoutBuilder()
.setTextColor(primaryTextColor)
.setTextSize(spToPx(resources, 12f).toInt())
.setShouldWarmText(true)
.setSingleLine(true)
setPadding(content2x, content2x, content2x, content2x)
}
private fun initDate() {
if (dateTextLayoutBuilder == null) {
dateTextLayoutBuilder = TextLayoutBuilder()
.setTextColor(ContextCompat.getColor(context, R.color.secondary_text))
.setTextSize(spToPx(resources, 12f).toInt())
.setShouldWarmText(true)
.setSingleLine(true)
.setEllipsize(TextUtils.TruncateAt.END)
}
if (dotDrawable == null) {
dotWidth = dpToPx(resources, 5f)
dotDrawable = ShapeDrawable(OvalShape())
dotDrawable?.intrinsicHeight = dotWidth
dotDrawable?.intrinsicWidth = dotWidth
dotDrawable?.paint?.color = ContextCompat.getColor(context, R.color.secondary_text)
}
}
private fun initFeatureIcon(context: Context) {
featureIcon = ImageView(context)
val size: Int = dpToPx(resources, 34f)
featureIcon.layoutParams = LayoutParams(size, size)
addView(featureIcon)
}
fun setOnExtendButtonClickListener(l: View.OnClickListener?) {
extendFeatureBtn.setOnClickListener(l)
}
fun setTitle(title: String?) {
if (this.title.equals(title)) {
return
}
this.title = title
requestLayout()
invalidate()
}
fun statusActive(dateTo: String?) {
if (dateTo == null) {
date = null
} else {
initDate()
status = resources.getString(R.string.payment_active)
statusTextLayoutBuilder.textColor = ContextCompat.getColor(context, R.color.green_light)
date = String.format(resources.getString(R.string.payment_to_date), dateTo)
}
requestLayout()
invalidate()
}
fun statusInactive() {
status = resources.getString(R.string.payment_inactive)
statusTextLayoutBuilder.textColor = ContextCompat.getColor(context, R.color.pink)
requestLayout()
invalidate()
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val width = MeasureSpec.getSize(widthMeasureSpec)
var height = paddingTop + paddingBottom
featureIcon.measure(
MeasureSpec.makeMeasureSpec(featureIcon.layoutParams.width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(featureIcon.layoutParams.height, MeasureSpec.EXACTLY)
)
height += featureIcon.measuredHeight
extendFeatureBtn.measure(
MeasureSpec.makeMeasureSpec(extendFeatureBtn.layoutParams.width, MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(extendFeatureBtn.layoutParams.height, MeasureSpec.EXACTLY)
)
leftWithoutIcon = featureIcon.measuredWidth + paddingLeft + content2x
val widthLeft = width - (leftWithoutIcon + extendFeatureBtn.measuredWidth + paddingRight + content2x)
titleLayout = titleTextLayoutBuilder
.setText(title)
.setMaxWidth(widthLeft)
.build()
titleHeight = titleLayout?.height ?: 0
statusLayout = statusTextLayoutBuilder
.setText(status)
.setMaxWidth(widthLeft)
.build()
statusHeight = statusLayout?.height ?: 0
statusWidth = statusLayout?.width ?: 0
dateTextLayoutBuilder?.let {
dateLayout = it
.setText(date)
.setMaxWidth(widthLeft - (statusWidth + dotWidth))
.build()
}
setMeasuredDimension(width, height)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
val parentTop = paddingTop
val parentLeft = paddingLeft
val parentBottom = bottom - top - paddingBottom
val height = parentBottom - parentTop
centerTop = height / 2
titleTop = centerTop - content0_25x
statusTop = centerTop + content0_25x
val featureIconTop = parentTop + (height - featureIcon.measuredHeight) / 2
featureIcon.layout(
parentLeft,
featureIconTop,
parentLeft + featureIcon.measuredWidth,
featureIconTop + featureIcon.measuredHeight
)
val extendFeatureBtnTop: Int = parentTop + (height - extendFeatureBtn.measuredHeight) / 2
val extendFeatureBtnLeft: Int = right - paddingRight - extendFeatureBtn.measuredWidth
extendFeatureBtn.layout(
extendFeatureBtnLeft,
extendFeatureBtnTop,
extendFeatureBtnLeft + extendFeatureBtn.measuredWidth,
extendFeatureBtnTop + extendFeatureBtn.measuredHeight
)
dotDrawable?.let {
val dotLeft = leftWithoutIcon + statusWidth + content
val dotTop = titleTop + statusTop + content0_25x * 2 + it.intrinsicHeight / 2
it.setBounds(
dotLeft,
dotTop,
dotLeft + it.intrinsicWidth,
dotTop + it.intrinsicHeight
)
}
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawColor(whiteColor)
canvas.save()
canvas.translate(leftWithoutIcon.toFloat(), titleTop.toFloat())
titleLayout?.draw(canvas)
statusLayout?.let {
canvas.translate(0f, statusTop.toFloat())
it.draw(canvas)
canvas.translate(dotWidth + content2x + statusWidth.toFloat(), 0f)
dateLayout?.draw(canvas)
}
canvas.restore()
dotDrawable?.draw(canvas)
}
override fun hasOverlappingRendering(): Boolean {
return false
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment